Răsfoiți Sursa

permissions: support to load address records from a text file

- new parameter 'address_file' to provide the file name (or full path)
to the file where address records are stored
- note: no support for using a file instead of trusted table
Daniel-Constantin Mierla 5 ani în urmă
părinte
comite
f376c82a9f

+ 307 - 133
src/modules/permissions/address.c

@@ -54,10 +54,18 @@ struct domain_name_list ***domain_list_table = NULL; /* Ptr to current domain na
 static struct domain_name_list **domain_list_table_1 = NULL; /* Ptr to domain name table 1 */
 static struct domain_name_list **domain_list_table_2 = NULL; /* Ptr to domain name table 2 */
 
-
 static db1_con_t* db_handle = 0;
 static db_func_t perm_dbf;
 
+extern str address_file;
+
+typedef struct address_tables_group {
+	struct addr_list **address_table;
+	struct subnet *subnet_table;
+	struct domain_name_list **domain_table;
+
+} address_tables_group_t;
+
 static inline ip_addr_t *strtoipX(str *ips)
 {
 	/* try to figure out INET class */
@@ -71,27 +79,84 @@ static inline ip_addr_t *strtoipX(str *ips)
 	}
 }
 
+int reload_address_insert(address_tables_group_t *atg, unsigned int gid,
+		str *ips, unsigned int mask, unsigned int port, str *tagv)
+{
+	ip_addr_t *ipa;
+
+	ipa = strtoipX(ips);
+	if (ipa==NULL) {
+		LM_DBG("Domain name: %.*s\n", ips->len, ips->s);
+		/* return -1; */
+	} else {
+		if(ipa->af == AF_INET6) {
+			if((int)mask<0 || mask>128) {
+				LM_DBG("failure during IP mask check for v6\n");
+				return -1;
+			}
+			if(mask == 0) {
+				mask = 128;
+			}
+		} else {
+			if((int)mask<0 || mask>32) {
+				LM_DBG("failure during IP mask check for v4\n");
+				return -1;
+			}
+			if(mask == 0) {
+				mask = 32;
+			}
+		}
+	}
+
+	if (ipa!=NULL) {
+		if ( (ipa->af==AF_INET6 && mask==128) || (ipa->af==AF_INET && mask==32) ) {
+			if (addr_hash_table_insert(atg->address_table, gid, ipa, port, tagv)
+					== -1) {
+				LM_ERR("hash table problem\n");
+				return -1;
+			}
+			LM_DBG("Tuple <%u, %.*s, %u> inserted into address hash table\n",
+					gid, ips->len, ips->s, port);
+		} else {
+			if (subnet_table_insert(atg->subnet_table, gid, ipa, mask,
+						port, tagv)
+					== -1) {
+				LM_ERR("subnet table problem\n");
+				return -1;
+			}
+			LM_DBG("Tuple <%u, %.*s, %u, %u> inserted into subnet table\n",
+					gid, ips->len, ips->s, port, mask);
+		}
+	} else {
+		if (domain_name_table_insert(atg->domain_table, gid, ips,
+					port, tagv)
+				== -1) {
+			LM_ERR("domain name table problem\n");
+			return -1;
+		}
+		LM_DBG("Tuple <%u, %.*s, %u> inserted into domain name table\n",
+				gid, ips->len, ips->s, port);
+	}
+	return 0;
+}
+
 /*
- * Reload addr table to new hash table and when done, make new hash table
+ * Reload addr table from database to new hash table and when done, make new hash table
  * current one.
  */
-int reload_address_table(void)
+int reload_address_db_table(address_tables_group_t *atg)
 {
 	db_key_t cols[5];
 	db1_res_t* res = NULL;
 	db_row_t* row;
 	db_val_t* val;
 
-	struct addr_list **new_hash_table;
-	struct subnet *new_subnet_table;
-	struct domain_name_list **new_domain_name_table;
 	int i;
 	unsigned int gid;
 	unsigned int port;
 	unsigned int mask;
 	str ips;
-	ip_addr_t *ipa;
-	char *tagv;
+	str tagv;
 
 	cols[0] = &grp_col;
 	cols[1] = &ip_addr_col;
@@ -109,34 +174,6 @@ int reload_address_table(void)
 		return -1;
 	}
 
-	/* Choose new hash table and free its old contents */
-	if (*addr_hash_table == addr_hash_table_1) {
-		empty_addr_hash_table(addr_hash_table_2);
-		new_hash_table = addr_hash_table_2;
-	} else {
-		empty_addr_hash_table(addr_hash_table_1);
-		new_hash_table = addr_hash_table_1;
-	}
-
-	/* Choose new subnet table */
-	if (*subnet_table == subnet_table_1) {
-		empty_subnet_table(subnet_table_2);
-		new_subnet_table = subnet_table_2;
-	} else {
-		empty_subnet_table(subnet_table_1);
-		new_subnet_table = subnet_table_1;
-	}
-
-	/* Choose new domain name table */
-	if (*domain_list_table == domain_list_table_1) {
-		empty_domain_name_table(domain_list_table_2);
-		new_domain_name_table = domain_list_table_2;
-	} else {
-		empty_domain_name_table(domain_list_table_1);
-		new_domain_name_table = domain_list_table_1;
-	}
-
-
 	row = RES_ROWS(res);
 
 	LM_DBG("Number of rows in address table: %d\n", RES_ROW_N(res));
@@ -179,68 +216,17 @@ int reload_address_table(void)
 		ips.len = strlen(ips.s);
 		mask = VAL_UINT(val + 2);
 		port = VAL_UINT(val + 3);
-		tagv = VAL_NULL(val + 4)?NULL:(char *)VAL_STRING(val + 4);
-		ipa = strtoipX(&ips);
-		if ( ipa==NULL )
-		{
-			LM_DBG("Domain name: %.*s\n", ips.len, ips.s);
-			//	goto dberror;
-		} else {
-			if(ipa->af == AF_INET6) {
-				if((int)mask<0 || mask>128) {
-					LM_DBG("failure during IP mask check for v6\n");
-					goto dberror;
-				}
-			} else {
-				if((int)mask<0 || mask>32) {
-					LM_DBG("failure during IP mask check for v4\n");
-					goto dberror;
-				}
-			}
+		tagv.s = VAL_NULL(val + 4)?NULL:(char *)VAL_STRING(val + 4);
+		if(tagv.s!=NULL) {
+			tagv.len = strlen(tagv.s);
 		}
-
-		if ( ipa ) {
-			if ( (ipa->af==AF_INET6 && mask==128) || (ipa->af==AF_INET && mask==32) ) {
-				if (addr_hash_table_insert(new_hash_table, gid, ipa, port, tagv)
-						== -1) {
-					LM_ERR("hash table problem\n");
-					perm_dbf.free_result(db_handle, res);
-					return -1;
-				}
-				LM_DBG("Tuple <%u, %s, %u> inserted into address hash table\n",
-						gid, ips.s, port);
-			} else {
-				if (subnet_table_insert(new_subnet_table, gid, ipa, mask,
-							port, tagv)
-						== -1) {
-					LM_ERR("subnet table problem\n");
-					perm_dbf.free_result(db_handle, res);
-					return -1;
-				}
-				LM_DBG("Tuple <%u, %s, %u, %u> inserted into subnet table\n",
-						gid, ips.s, port, mask);
-			}
-		} else {
-			if (domain_name_table_insert(new_domain_name_table, gid, &ips,
-						port, tagv)
-					== -1) {
-				LM_ERR("domain name table problem\n");
-				perm_dbf.free_result(db_handle, res);
-				return -1;
-			}
-			LM_DBG("Tuple <%u, %s, %u> inserted into domain name table\n",
-					gid, ips.s, port);
+		if(reload_address_insert(atg, gid, &ips, mask, port, &tagv)<0) {
+			goto dberror;
 		}
 	}
 
 	perm_dbf.free_result(db_handle, res);
 
-	*addr_hash_table = new_hash_table;
-	*subnet_table = new_subnet_table;
-	*domain_list_table = new_domain_name_table;
-
-	LM_DBG("address table reloaded successfully.\n");
-
 	return 1;
 
 dberror:
@@ -249,72 +235,256 @@ dberror:
 	return -1;
 }
 
+/**
+ * macros for parsing address file
+ */
+#define PERM_FADDR_SKIPWS(p) do { \
+		while(*p && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')) { \
+			p++; \
+		} \
+	} while(0)
+
+#define PERM_FADDR_PARSESTR(p, vstr) do { \
+		vstr.s = p; \
+		while(*p && *p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' \
+				&& *p != '#') { \
+			p++; \
+		} \
+		vstr.len = p - vstr.s; \
+	} while(0)
+
+#define PERM_FADDR_PARSENUM(p, vnum) do { \
+		vnum = 0; \
+		while(*p >= '0' && *p <= '9') { \
+			vnum = vnum * 10 + (*p - '0'); \
+			p++; \
+		} \
+	} while(0)
+
+/* end-of-data jump at start of comment or end-of-line */
+#define PERM_FADDR_EODJUMP(p, jumplabel) do { \
+		if(*p == '\0' || *p == '#') { \
+			goto jumplabel; \
+		} \
+	} while(0)
+
 /*
- * Wrapper to reload addr table from mi or rpc
- * we need to open the db_handle
+ * Reload addr table from file to new hash table and when done, make new hash table
+ * current one.
  */
-int reload_address_table_cmd(void)
+int reload_address_file_table(address_tables_group_t *atg)
 {
-	if(!db_url.s) {
-		LM_ERR("db_url not set\n");
+	char line[1024], *p;
+	FILE *f = NULL;
+	int i = 0;
+	int n = 0;
+	unsigned int gid;
+	unsigned int mask;
+	unsigned int port;
+	str ips;
+	str tagv;
+
+	f = fopen(address_file.s, "r");
+	if(f == NULL) {
+		LM_ERR("can't open list file [%s]\n", address_file.s);
 		return -1;
 	}
 
-	if (!db_handle) {
-		db_handle = perm_dbf.init(&db_url);
-		if (!db_handle) {
-			LM_ERR("unable to connect database\n");
-			return -1;
+	p = fgets(line, 1024, f);
+	while(p) {
+		i++;
+		gid = 0;
+		ips.s = NULL;
+		ips.len = 0;
+		mask = 0;
+		port = 0;
+		tagv.s = NULL;
+		tagv.len = 0;
+
+		/* comment line */
+		PERM_FADDR_SKIPWS(p);
+		PERM_FADDR_EODJUMP(p, next_line);
+
+		/* group id */
+		PERM_FADDR_PARSENUM(p, gid);
+
+		PERM_FADDR_SKIPWS(p);
+		PERM_FADDR_EODJUMP(p, error);
+
+		/* address - ip/domain */
+		PERM_FADDR_PARSESTR(p, ips);
+
+		PERM_FADDR_SKIPWS(p);
+		PERM_FADDR_EODJUMP(p, add_record);
+
+		/* mask */
+		PERM_FADDR_PARSENUM(p, mask);
+
+		PERM_FADDR_SKIPWS(p);
+		PERM_FADDR_EODJUMP(p, add_record);
+
+		/* port */
+		PERM_FADDR_PARSENUM(p, port);
+
+		PERM_FADDR_SKIPWS(p);
+		PERM_FADDR_EODJUMP(p, add_record);
+
+		/* tag */
+		PERM_FADDR_PARSESTR(p, tagv);
+
+add_record:
+		if(reload_address_insert(atg, gid, &ips, mask, port, &tagv)<0) {
+			goto error;
 		}
-	}
+		n++;
 
-	if (reload_address_table () != 1) {
-		perm_dbf.close(db_handle);
-		db_handle = 0;
-		return -1;
+next_line:
+		p = fgets(line, 1024, f);
 	}
 
-	perm_dbf.close(db_handle);
-	db_handle = 0;
+	LM_DBG("processed file: %s (%d lines)- added %d records\n", address_file.s,
+			i, n);
 
+	fclose(f);
 	return 1;
+
+error:
+	if(f != NULL) {
+		fclose(f);
+	}
+	return -1;
+
 }
 
 /*
- * Initialize data structures
+ * Reload addr table to new hash table and when done, make new hash table
+ * current one.
  */
-int init_addresses(void)
+int reload_address_table(void)
 {
-	if (!db_url.s) {
-		LM_INFO("db_url parameter of permissions module not set, "
-				"disabling allow_address\n");
-		return 0;
+	int ret = 0;
+	address_tables_group_t atg;
+
+	/* Choose new hash table and free its old contents */
+	if (*addr_hash_table == addr_hash_table_1) {
+		empty_addr_hash_table(addr_hash_table_2);
+		atg.address_table = addr_hash_table_2;
 	} else {
-		if (db_bind_mod(&db_url, &perm_dbf) < 0) {
-			LM_ERR("load a database support module\n");
+		empty_addr_hash_table(addr_hash_table_1);
+		atg.address_table = addr_hash_table_1;
+	}
+
+	/* Choose new subnet table */
+	if (*subnet_table == subnet_table_1) {
+		empty_subnet_table(subnet_table_2);
+		atg.subnet_table = subnet_table_2;
+	} else {
+		empty_subnet_table(subnet_table_1);
+		atg.subnet_table = subnet_table_1;
+	}
+
+	/* Choose new domain name table */
+	if (*domain_list_table == domain_list_table_1) {
+		empty_domain_name_table(domain_list_table_2);
+		atg.domain_table = domain_list_table_2;
+	} else {
+		empty_domain_name_table(domain_list_table_1);
+		atg.domain_table = domain_list_table_1;
+	}
+
+	if(address_file.s==NULL) {
+		ret = reload_address_db_table(&atg);
+	} else {
+		ret = reload_address_file_table(&atg);
+	}
+	if(ret!=1) {
+		return ret;
+	}
+
+	*addr_hash_table = atg.address_table;
+	*subnet_table = atg.subnet_table;
+	*domain_list_table = atg.domain_table;
+
+	LM_DBG("address table reloaded successfully.\n");
+
+
+	return ret;
+}
+
+/*
+ * Wrapper to reload addr table from mi or rpc
+ * we need to open the db_handle
+ */
+int reload_address_table_cmd(void)
+{
+	if(address_file.s==NULL) {
+		if(!db_url.s) {
+			LM_ERR("db_url not set\n");
 			return -1;
 		}
 
-		if (!DB_CAPABILITY(perm_dbf, DB_CAP_QUERY)) {
-			LM_ERR("database module does not implement 'query' function\n");
-			return -1;
+		if (!db_handle) {
+			db_handle = perm_dbf.init(&db_url);
+			if (!db_handle) {
+				LM_ERR("unable to connect database\n");
+				return -1;
+			}
 		}
 	}
 
-	addr_hash_table_1 = addr_hash_table_2 = 0;
-	addr_hash_table = 0;
-
-	db_handle = perm_dbf.init(&db_url);
-	if (!db_handle) {
-		LM_ERR("unable to connect database\n");
+	if (reload_address_table () != 1) {
+		if(address_file.s==NULL) {
+			perm_dbf.close(db_handle);
+			db_handle = 0;
+		}
 		return -1;
 	}
 
-	if(db_check_table_version(&perm_dbf, db_handle, &address_table, TABLE_VERSION) < 0) {
-		DB_TABLE_VERSION_ERROR(address_table);
+	if(address_file.s==NULL) {
 		perm_dbf.close(db_handle);
 		db_handle = 0;
-		return -1;
+	}
+
+	return 1;
+}
+
+/*
+ * Initialize data structures
+ */
+int init_addresses(void)
+{
+	addr_hash_table_1 = addr_hash_table_2 = 0;
+	addr_hash_table = 0;
+
+	if(address_file.s==NULL) {
+		if (!db_url.s) {
+			LM_INFO("db_url parameter of permissions module not set, "
+					"disabling allow_address\n");
+			return 0;
+		} else {
+			if (db_bind_mod(&db_url, &perm_dbf) < 0) {
+				LM_ERR("load a database support module\n");
+				return -1;
+			}
+
+			if (!DB_CAPABILITY(perm_dbf, DB_CAP_QUERY)) {
+				LM_ERR("database module does not implement 'query' function\n");
+				return -1;
+			}
+		}
+
+		db_handle = perm_dbf.init(&db_url);
+		if (!db_handle) {
+			LM_ERR("unable to connect database\n");
+			return -1;
+		}
+
+		if(db_check_table_version(&perm_dbf, db_handle, &address_table, TABLE_VERSION) < 0) {
+			DB_TABLE_VERSION_ERROR(address_table);
+			perm_dbf.close(db_handle);
+			db_handle = 0;
+			return -1;
+		}
 	}
 
 	addr_hash_table_1 = new_addr_hash_table();
@@ -366,8 +536,10 @@ int init_addresses(void)
 		goto error;
 	}
 
-	perm_dbf.close(db_handle);
-	db_handle = 0;
+	if(address_file.s==NULL) {
+		perm_dbf.close(db_handle);
+		db_handle = 0;
+	}
 
 	return 0;
 
@@ -410,8 +582,10 @@ error:
 		domain_list_table = 0;
 	}
 
-	perm_dbf.close(db_handle);
-	db_handle = 0;
+	if(address_file.s==NULL) {
+		perm_dbf.close(db_handle);
+		db_handle = 0;
+	}
 	return -1;
 }
 

+ 21 - 16
src/modules/permissions/hash.c

@@ -443,7 +443,7 @@ void free_addr_hash_table(struct addr_list** table)
  * Add <grp, ip_addr, port> into hash table
  */
 int addr_hash_table_insert(struct addr_list** table, unsigned int grp,
-		ip_addr_t *addr, unsigned int port, char *tagv)
+		ip_addr_t *addr, unsigned int port, str *tagv)
 {
 	struct addr_list *np;
 	unsigned int hash_val;
@@ -451,8 +451,9 @@ int addr_hash_table_insert(struct addr_list** table, unsigned int grp,
 	int len;
 
 	len = sizeof(struct addr_list);
-	if(tagv!=NULL)
-		len += strlen(tagv) + 1;
+	if(tagv!=NULL && tagv->s!=NULL) {
+		len += tagv->len + 1;
+	}
 
 	np = (struct addr_list *) shm_malloc(len);
 	if (np == NULL) {
@@ -465,11 +466,12 @@ int addr_hash_table_insert(struct addr_list** table, unsigned int grp,
 	np->grp = grp;
 	memcpy(&np->addr, addr, sizeof(ip_addr_t));
 	np->port = port;
-	if(tagv!=NULL)
+	if(tagv!=NULL && tagv->s!=NULL)
 	{
 		np->tag.s = (char*)np + sizeof(struct addr_list);
-		np->tag.len = strlen(tagv);
-		strcpy(np->tag.s, tagv);
+		np->tag.len = tagv->len;
+		memcpy(np->tag.s, tagv->s, tagv->len);
+		np->tag.s[np->tag.len] = '\0';
 	}
 
 	addr_str.s = (char*)addr->u.addr;
@@ -646,7 +648,7 @@ struct subnet* new_subnet_table(void)
  */
 int subnet_table_insert(struct subnet* table, unsigned int grp,
 		ip_addr_t *subnet, unsigned int mask,
-		unsigned int port, char *tagv)
+		unsigned int port, str *tagv)
 {
 	int i;
 	unsigned int count;
@@ -659,19 +661,20 @@ int subnet_table_insert(struct subnet* table, unsigned int grp,
 		return 0;
 	}
 
-	if(tagv==NULL)
+	if(tagv==NULL || tagv->s==NULL)
 	{
 		tags.s = NULL;
 		tags.len = 0;
 	} else {
-		tags.len = strlen(tagv);
+		tags.len = tagv->len;
 		tags.s = (char*)shm_malloc(tags.len+1);
 		if(tags.s==NULL)
 		{
 			LM_ERR("No more shared memory\n");
 			return 0;
 		}
-		strcpy(tags.s, tagv);
+		memcpy(tags.s, tagv->s, tags.len);
+		tags.s[tags.len] = '\0';
 	}
 
 	i = count - 1;
@@ -961,15 +964,16 @@ int find_group_in_domain_name_table(struct domain_name_list** table,
  * Add <grp, domain_name, port> into hash table
  */
 int domain_name_table_insert(struct domain_name_list** table, unsigned int grp,
-		str *domain_name, unsigned int port, char *tagv)
+		str *domain_name, unsigned int port, str *tagv)
 {
 	struct domain_name_list *np;
 	unsigned int hash_val;
 	int len;
 
 	len = sizeof(struct domain_name_list) + domain_name->len;
-	if(tagv!=NULL)
-		len += strlen(tagv) + 1;
+	if(tagv!=NULL && tagv->s!=NULL) {
+		len += tagv->len + 1;
+	}
 
 	np = (struct domain_name_list *) shm_malloc(len);
 	if (np == NULL) {
@@ -984,10 +988,11 @@ int domain_name_table_insert(struct domain_name_list** table, unsigned int grp,
 	memcpy(np->domain.s, domain_name->s, domain_name->len);
 	np->domain.len = domain_name->len;
 	np->port = port;
-	if(tagv!=NULL) {
+	if(tagv!=NULL && tagv->s!=NULL) {
 		np->tag.s = (char*)np + sizeof(struct domain_name_list) + domain_name->len;
-		np->tag.len = strlen(tagv);
-		strcpy(np->tag.s, tagv);
+		np->tag.len = tagv->len;
+		memcpy(np->tag.s, tagv->s, np->tag.len);
+		np->tag.s[np->tag.len] = '\0';
 	}
 
 	LM_DBG("** Added domain name: %.*s\n", np->domain.len, np->domain.s);

+ 3 - 3
src/modules/permissions/hash.h

@@ -137,7 +137,7 @@ void destroy_addr_hash_table(struct addr_list** table);
  * Add <group, ip_addr, port> into hash table
  */
 int addr_hash_table_insert(struct addr_list** hash_table, unsigned int grp,
-		ip_addr_t *addr, unsigned int port, char *tagv);
+		ip_addr_t *addr, unsigned int port, str *tagv);
 
 
 /*
@@ -222,7 +222,7 @@ void free_subnet_table(struct subnet* table);
  */
 int subnet_table_insert(struct subnet* table, unsigned int grp,
 			ip_addr_t *subnet, unsigned int mask,
-			unsigned int port, char *tagv);
+			unsigned int port, str *tagv);
 
 
 /*
@@ -269,7 +269,7 @@ int match_domain_name_table(struct domain_name_list** table, unsigned int group,
  * Add <grp, domain_name, port> into hash table
  */
 int domain_name_table_insert(struct domain_name_list** table, unsigned int grp,
-		str *domain_name, unsigned int port, char *tagv);
+		str *domain_name, unsigned int port, str *tagv);
 
 /*
  * Check if an domain_name/port entry exists in hash table in any group.

+ 11 - 0
src/modules/permissions/permissions.c

@@ -80,6 +80,8 @@ str ip_addr_col = str_init("ip_addr");     /* Name of ip address column */
 str mask_col = str_init("mask");           /* Name of mask column */
 str port_col = str_init("port");           /* Name of port column */
 
+static str address_file_param = STR_NULL;  /* Path to file with address records */
+str address_file = STR_NULL;			   /* Full path to file with address records */
 
 /*
  * By default we check all branches
@@ -177,6 +179,7 @@ static param_export_t params[] = {
 	{"peer_tag_avp",       PARAM_STR, &tag_avp_param   },
 	{"peer_tag_mode",      INT_PARAM, &peer_tag_mode     },
 	{"address_table",      PARAM_STR, &address_table   },
+	{"address_file",       PARAM_STR, &address_file_param   },
 	{"grp_col",            PARAM_STR, &grp_col         },
 	{"ip_addr_col",        PARAM_STR, &ip_addr_col     },
 	{"mask_col",           PARAM_STR, &mask_col        },
@@ -630,6 +633,14 @@ static int mod_init(void)
 	}
 
 	if(_perm_load_backends&PERM_LOAD_ADDRESSDB) {
+		if(address_file_param.s!=NULL && address_file_param.len>0) {
+			address_file.s = get_pathname(address_file_param.s);
+			if(address_file.s==NULL) {
+				LM_ERR("failed to set full path to address file\n");
+				return -1;
+			}
+			address_file.len = strlen(address_file.s);
+		}
 		if (init_addresses() != 0) {
 			LM_ERR("failed to initialize the allow_address function\n");
 			return -1;