mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-11-03 21:43:32 +00:00 
			
		
		
		
	nat: Allow to specify multiple entries in the access-list...
Inside the access-list we have a list of entries that have either one allow or one deny rule... we do not allow to remove a single rule but one has to remove the whole list, in that case talloc will handle cleaning all entries. Right now the matching is O(n*m) as we traverse the list (multiple times) and run the regexp multiple times. One way to make it faster would be to concat all regexps into one.
This commit is contained in:
		@@ -209,6 +209,11 @@ struct bsc_nat_acc_lst {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* the name of the list */
 | 
						/* the name of the list */
 | 
				
			||||||
	const char *name;
 | 
						const char *name;
 | 
				
			||||||
 | 
						struct llist_head fltr_list;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bsc_nat_acc_lst_entry {
 | 
				
			||||||
 | 
						struct llist_head list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* the filter */
 | 
						/* the filter */
 | 
				
			||||||
	char *imsi_allow;
 | 
						char *imsi_allow;
 | 
				
			||||||
@@ -328,4 +333,6 @@ struct bsc_nat_acc_lst *bsc_nat_acc_lst_find(struct bsc_nat *nat, const char *na
 | 
				
			|||||||
struct bsc_nat_acc_lst *bsc_nat_acc_lst_get(struct bsc_nat *nat, const char *name);
 | 
					struct bsc_nat_acc_lst *bsc_nat_acc_lst_get(struct bsc_nat *nat, const char *name);
 | 
				
			||||||
void bsc_nat_acc_lst_delete(struct bsc_nat_acc_lst *lst);
 | 
					void bsc_nat_acc_lst_delete(struct bsc_nat_acc_lst *lst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bsc_nat_acc_lst_entry *bsc_nat_acc_lst_entry_create(struct bsc_nat_acc_lst *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -195,6 +195,34 @@ int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int proto)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int lst_check_allow(struct bsc_nat_acc_lst *lst, const char *mi_string)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bsc_nat_acc_lst_entry *entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(entry, &lst->fltr_list, list) {
 | 
				
			||||||
 | 
							if (!entry->imsi_allow)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (regexec(&entry->imsi_allow_re, mi_string, 0, NULL, 0) == 0)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int lst_check_deny(struct bsc_nat_acc_lst *lst, const char *mi_string)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bsc_nat_acc_lst_entry *entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(entry, &lst->fltr_list, list) {
 | 
				
			||||||
 | 
							if (!entry->imsi_deny)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (regexec(&entry->imsi_deny_re, mi_string, 0, NULL, 0) == 0)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* apply white/black list */
 | 
					/* apply white/black list */
 | 
				
			||||||
static int auth_imsi(struct bsc_connection *bsc, const char *mi_string)
 | 
					static int auth_imsi(struct bsc_connection *bsc, const char *mi_string)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -212,24 +240,22 @@ static int auth_imsi(struct bsc_connection *bsc, const char *mi_string)
 | 
				
			|||||||
	nat_lst = bsc_nat_acc_lst_find(bsc->nat, bsc->nat->acc_lst_name);
 | 
						nat_lst = bsc_nat_acc_lst_find(bsc->nat, bsc->nat->acc_lst_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 1. BSC deny */
 | 
						if (bsc_lst) {
 | 
				
			||||||
	if (bsc_lst && bsc_lst->imsi_deny) {
 | 
							/* 1. BSC deny */
 | 
				
			||||||
		if (regexec(&bsc_lst->imsi_deny_re, mi_string, 0, NULL, 0) == 0) {
 | 
							if (lst_check_deny(bsc_lst, mi_string) == 0) {
 | 
				
			||||||
			LOGP(DNAT, LOGL_ERROR,
 | 
								LOGP(DNAT, LOGL_ERROR,
 | 
				
			||||||
			     "Filtering %s by imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr);
 | 
								     "Filtering %s by imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr);
 | 
				
			||||||
			return -2;
 | 
								return -2;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 2. BSC allow */
 | 
							/* 2. BSC allow */
 | 
				
			||||||
	if (bsc_lst && bsc_lst->imsi_allow) {
 | 
							if (lst_check_allow(bsc_lst, mi_string) == 0)
 | 
				
			||||||
		if (regexec(&bsc_lst->imsi_allow_re, mi_string, 0, NULL, 0) == 0)
 | 
					 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 3. NAT deny */
 | 
						/* 3. NAT deny */
 | 
				
			||||||
	if (nat_lst && nat_lst->imsi_deny) {
 | 
						if (nat_lst) {
 | 
				
			||||||
		if (regexec(&nat_lst->imsi_deny_re, mi_string, 0, NULL, 0) == 0) {
 | 
							if (lst_check_deny(nat_lst, mi_string) == 0) {
 | 
				
			||||||
			LOGP(DNAT, LOGL_ERROR,
 | 
								LOGP(DNAT, LOGL_ERROR,
 | 
				
			||||||
			     "Filtering %s by nat imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr);
 | 
								     "Filtering %s by nat imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr);
 | 
				
			||||||
			return -3;
 | 
								return -3;
 | 
				
			||||||
@@ -440,6 +466,7 @@ struct bsc_nat_acc_lst *bsc_nat_acc_lst_get(struct bsc_nat *nat, const char *nam
 | 
				
			|||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						INIT_LLIST_HEAD(&lst->fltr_list);
 | 
				
			||||||
	lst->name = talloc_strdup(lst, name);
 | 
						lst->name = talloc_strdup(lst, name);
 | 
				
			||||||
	llist_add(&lst->list, &nat->access_lists);
 | 
						llist_add(&lst->list, &nat->access_lists);
 | 
				
			||||||
	return lst;
 | 
						return lst;
 | 
				
			||||||
@@ -450,3 +477,15 @@ void bsc_nat_acc_lst_delete(struct bsc_nat_acc_lst *lst)
 | 
				
			|||||||
	llist_del(&lst->list);
 | 
						llist_del(&lst->list);
 | 
				
			||||||
	talloc_free(lst);
 | 
						talloc_free(lst);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bsc_nat_acc_lst_entry *bsc_nat_acc_lst_entry_create(struct bsc_nat_acc_lst *lst)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bsc_nat_acc_lst_entry *entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						entry = talloc_zero(lst, struct bsc_nat_acc_lst_entry);
 | 
				
			||||||
 | 
						if (!entry)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_add(&entry->list, &lst->fltr_list);
 | 
				
			||||||
 | 
						return entry;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,6 +49,20 @@ static struct cmd_node bsc_node = {
 | 
				
			|||||||
	1,
 | 
						1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void write_acc_lst(struct vty *vty, struct bsc_nat_acc_lst *lst)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bsc_nat_acc_lst_entry *entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(entry, &lst->fltr_list, list) {
 | 
				
			||||||
 | 
							if (entry->imsi_allow)
 | 
				
			||||||
 | 
								vty_out(vty, " access-list %s imsi-allow %s%s",
 | 
				
			||||||
 | 
									lst->name, entry->imsi_allow, VTY_NEWLINE);
 | 
				
			||||||
 | 
							if (entry->imsi_deny)
 | 
				
			||||||
 | 
								vty_out(vty, " access-list %s imsi-deny %s%s",
 | 
				
			||||||
 | 
									lst->name, entry->imsi_deny, VTY_NEWLINE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int config_write_nat(struct vty *vty)
 | 
					static int config_write_nat(struct vty *vty)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct bsc_nat_acc_lst *lst;
 | 
						struct bsc_nat_acc_lst *lst;
 | 
				
			||||||
@@ -66,12 +80,7 @@ static int config_write_nat(struct vty *vty)
 | 
				
			|||||||
		vty_out(vty, " access-list-name %s%s", _nat->acc_lst_name, VTY_NEWLINE);
 | 
							vty_out(vty, " access-list-name %s%s", _nat->acc_lst_name, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(lst, &_nat->access_lists, list) {
 | 
						llist_for_each_entry(lst, &_nat->access_lists, list) {
 | 
				
			||||||
		if (lst->imsi_allow)
 | 
							write_acc_lst(vty, lst);
 | 
				
			||||||
			vty_out(vty, " access-list %s imsi-allow %s%s",
 | 
					 | 
				
			||||||
				lst->name, lst->imsi_allow, VTY_NEWLINE);
 | 
					 | 
				
			||||||
		if (lst->imsi_deny)
 | 
					 | 
				
			||||||
			vty_out(vty, " access-list %s imsi-deny %s%s",
 | 
					 | 
				
			||||||
				lst->name, lst->imsi_deny, VTY_NEWLINE);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
@@ -387,12 +396,17 @@ DEFUN(cfg_lst_imsi_allow,
 | 
				
			|||||||
      "The regexp of allowed IMSIs\n")
 | 
					      "The regexp of allowed IMSIs\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct bsc_nat_acc_lst *acc;
 | 
						struct bsc_nat_acc_lst *acc;
 | 
				
			||||||
 | 
						struct bsc_nat_acc_lst_entry *entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	acc = bsc_nat_acc_lst_get(_nat, argv[0]);
 | 
						acc = bsc_nat_acc_lst_get(_nat, argv[0]);
 | 
				
			||||||
	if (!acc)
 | 
						if (!acc)
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bsc_parse_reg(acc, &acc->imsi_allow_re, &acc->imsi_allow, argc - 1, &argv[1]);
 | 
						entry = bsc_nat_acc_lst_entry_create(acc);
 | 
				
			||||||
 | 
						if (!entry)
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bsc_parse_reg(acc, &entry->imsi_allow_re, &entry->imsi_allow, argc - 1, &argv[1]);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -404,12 +418,17 @@ DEFUN(cfg_lst_imsi_deny,
 | 
				
			|||||||
      "The regexp of to be denied IMSIs\n")
 | 
					      "The regexp of to be denied IMSIs\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct bsc_nat_acc_lst *acc;
 | 
						struct bsc_nat_acc_lst *acc;
 | 
				
			||||||
 | 
						struct bsc_nat_acc_lst_entry *entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	acc = bsc_nat_acc_lst_get(_nat, argv[0]);
 | 
						acc = bsc_nat_acc_lst_get(_nat, argv[0]);
 | 
				
			||||||
	if (!acc)
 | 
						if (!acc)
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bsc_parse_reg(acc, &acc->imsi_deny_re, &acc->imsi_deny, argc - 1, &argv[1]);
 | 
						entry = bsc_nat_acc_lst_entry_create(acc);
 | 
				
			||||||
 | 
						if (!entry)
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bsc_parse_reg(acc, &entry->imsi_deny_re, &entry->imsi_deny, argc - 1, &argv[1]);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -641,6 +641,7 @@ static void test_cr_filter()
 | 
				
			|||||||
	struct msgb *msg = msgb_alloc(4096, "test_cr_filter");
 | 
						struct msgb *msg = msgb_alloc(4096, "test_cr_filter");
 | 
				
			||||||
	struct bsc_nat_parsed *parsed;
 | 
						struct bsc_nat_parsed *parsed;
 | 
				
			||||||
	struct bsc_nat_acc_lst *nat_lst, *bsc_lst;
 | 
						struct bsc_nat_acc_lst *nat_lst, *bsc_lst;
 | 
				
			||||||
 | 
						struct bsc_nat_acc_lst_entry *nat_entry, *bsc_entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct bsc_nat *nat = bsc_nat_alloc();
 | 
						struct bsc_nat *nat = bsc_nat_alloc();
 | 
				
			||||||
	struct bsc_connection *bsc = bsc_connection_alloc(nat);
 | 
						struct bsc_connection *bsc = bsc_connection_alloc(nat);
 | 
				
			||||||
@@ -648,6 +649,12 @@ static void test_cr_filter()
 | 
				
			|||||||
	bsc->cfg->acc_lst_name = "bsc";
 | 
						bsc->cfg->acc_lst_name = "bsc";
 | 
				
			||||||
	nat->acc_lst_name = "nat";
 | 
						nat->acc_lst_name = "nat";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nat_lst = bsc_nat_acc_lst_get(nat, "nat");
 | 
				
			||||||
 | 
						bsc_lst = bsc_nat_acc_lst_get(nat, "bsc");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bsc_entry = bsc_nat_acc_lst_entry_create(bsc_lst);
 | 
				
			||||||
 | 
						nat_entry = bsc_nat_acc_lst_entry_create(nat_lst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(cr_filter); ++i) {
 | 
						for (i = 0; i < ARRAY_SIZE(cr_filter); ++i) {
 | 
				
			||||||
		msgb_reset(msg);
 | 
							msgb_reset(msg);
 | 
				
			||||||
		copy_to_msg(msg, cr_filter[i].data, cr_filter[i].length);
 | 
							copy_to_msg(msg, cr_filter[i].data, cr_filter[i].length);
 | 
				
			||||||
@@ -655,13 +662,13 @@ static void test_cr_filter()
 | 
				
			|||||||
		nat_lst = bsc_nat_acc_lst_get(nat, "nat");
 | 
							nat_lst = bsc_nat_acc_lst_get(nat, "nat");
 | 
				
			||||||
		bsc_lst = bsc_nat_acc_lst_get(nat, "bsc");
 | 
							bsc_lst = bsc_nat_acc_lst_get(nat, "bsc");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bsc_parse_reg(nat_lst, &nat_lst->imsi_deny_re, &nat_lst->imsi_deny,
 | 
							bsc_parse_reg(nat_entry, &nat_entry->imsi_deny_re, &nat_entry->imsi_deny,
 | 
				
			||||||
			      cr_filter[i].nat_imsi_deny ? 1 : 0,
 | 
								      cr_filter[i].nat_imsi_deny ? 1 : 0,
 | 
				
			||||||
			      &cr_filter[i].nat_imsi_deny);
 | 
								      &cr_filter[i].nat_imsi_deny);
 | 
				
			||||||
		bsc_parse_reg(bsc_lst, &bsc_lst->imsi_allow_re, &bsc_lst->imsi_allow,
 | 
							bsc_parse_reg(bsc_entry, &bsc_entry->imsi_allow_re, &bsc_entry->imsi_allow,
 | 
				
			||||||
			      cr_filter[i].bsc_imsi_allow ? 1 : 0,
 | 
								      cr_filter[i].bsc_imsi_allow ? 1 : 0,
 | 
				
			||||||
			      &cr_filter[i].bsc_imsi_allow);
 | 
								      &cr_filter[i].bsc_imsi_allow);
 | 
				
			||||||
		bsc_parse_reg(bsc_lst, &bsc_lst->imsi_deny_re, &bsc_lst->imsi_deny,
 | 
							bsc_parse_reg(bsc_entry, &bsc_entry->imsi_deny_re, &bsc_entry->imsi_deny,
 | 
				
			||||||
			      cr_filter[i].bsc_imsi_deny ? 1 : 0,
 | 
								      cr_filter[i].bsc_imsi_deny ? 1 : 0,
 | 
				
			||||||
			      &cr_filter[i].bsc_imsi_deny);
 | 
								      &cr_filter[i].bsc_imsi_deny);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user