Просмотр исходного кода

modules/permissions: DNS domain names in address table

Added the possibility to check also against DNS domain names with
allow_address() function.
Now in the address table one group can have exact IPs, subnet IPs
and DNS domain names.
avamanu 12 лет назад
Родитель
Сommit
7d46ff0e54

+ 65 - 50
modules/permissions/README

@@ -14,9 +14,9 @@ Edited by
 
 
 Juha Heinanen
 Juha Heinanen
 
 
-   Copyright © 2003 Miklos Tirpak
+   Copyright © 2003 Miklos Tirpak
 
 
-   Copyright © 2006-2008 Juha Heinanen
+   Copyright © 2006-2008 Juha Heinanen
      __________________________________________________________________
      __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
@@ -250,7 +250,7 @@ Chapter 1. Admin Guide
 
 
    Function for registration checking is called allow_register and the
    Function for registration checking is called allow_register and the
    algorithm is very similar to the algorithm described in Section 1.1,
    algorithm is very similar to the algorithm described in Section 1.1,
-   "Call Routing". The only difference is in the way how pairs are
+   “Call Routing�. The only difference is in the way how pairs are
    created.
    created.
 
 
    Instead of From header field the function uses To header field because
    Instead of From header field the function uses To header field because
@@ -261,8 +261,8 @@ Chapter 1. Admin Guide
    Thus, pairs used in matching will look like this: (To, Contact 1), (To,
    Thus, pairs used in matching will look like this: (To, Contact 1), (To,
    Contact 2), (To, Contact 3), and so on..
    Contact 2), (To, Contact 3), and so on..
 
 
-   The algorithm of matching is same as described in Section 1.1, "Call
-   Routing".
+   The algorithm of matching is same as described in Section 1.1, “Call
+   Routing�.
 
 
 1.3. URI Permissions
 1.3. URI Permissions
 
 
@@ -291,16 +291,25 @@ Chapter 1. Admin Guide
 
 
 1.4. Address Permissions
 1.4. Address Permissions
 
 
-   The module can be used to determine if an address (IP address and port)
-   matches any of the IP subnets stored in cached Kamailio database table.
-   Port 0 in cached database table matches any port. IP address and port
-   to be matched can be either taken from the request
+   The module can be used to determine if an address (IP address and port
+   or DNS domain name) matches any of the addresses stored in cached
+   Kamailio database table. IP addresses in the database table can be
+   subnet addresses. Port 0 in cached database table matches any port. The
+   address and port to be matched can be either taken from the request
    (allow_source_address) or given as pvar arguments (allow_address).
    (allow_source_address) or given as pvar arguments (allow_address).
 
 
-   Addresses stored in cached database table can be grouped together into
-   one or more groups specified by a group identifier (positive integer
-   value, i.e., equal or greater than 1). Group identifier is given as
-   argument to allow_address and allow_source_address functions.
+   Addresses stored in database table can be grouped together into one or
+   more groups specified by a group identifier (positive integer value,
+   i.e., equal or greater than 1). Group identifier is given as argument
+   to allow_address and allow_source_address functions. One group can
+   contain all of the three types of addresses: exact IP address, subnet
+   IP address or DNS domain name.
+
+   When matching is done if the argument is an IP, it is tried to be
+   matched with the records from that group that are of type exact IP or
+   subnet. If the argument is not an IP it is tried to be matched with the
+   records that are DNS domain names. No DNS lookup is performed, only
+   strict matching.
 
 
    As a side effect of matching the address, non-NULL tag (see tag_col
    As a side effect of matching the address, non-NULL tag (see tag_col
    module parameter) is added as value to peer_tag AVP if peer_tag_avp
    module parameter) is added as value to peer_tag AVP if peer_tag_avp
@@ -378,7 +387,7 @@ Chapter 1. Admin Guide
    specify full pathname then the directory in which is the main config
    specify full pathname then the directory in which is the main config
    file is located will be used.
    file is located will be used.
 
 
-   Default value is "permissions.allow".
+   Default value is “permissions.allow�.
 
 
    Example 1.1. Set default_allow_file parameter
    Example 1.1. Set default_allow_file parameter
 ...
 ...
@@ -391,7 +400,7 @@ modparam("permissions", "default_allow_file", "/etc/permissions.allow")
    without parameters. If you don't specify full pathname then the
    without parameters. If you don't specify full pathname then the
    directory in which the main config file is located will be used.
    directory in which the main config file is located will be used.
 
 
-   Default value is "permissions.deny".
+   Default value is “permissions.deny�.
 
 
    Example 1.2. Set default_deny_file parameter
    Example 1.2. Set default_deny_file parameter
 ...
 ...
@@ -426,7 +435,7 @@ Note
 
 
    Including leading dot.
    Including leading dot.
 
 
-   Default value is ".allow".
+   Default value is “.allow�.
 
 
    Example 1.4. Set allow_suffix parameter
    Example 1.4. Set allow_suffix parameter
 ...
 ...
@@ -443,7 +452,7 @@ Note
 
 
    Including leading dot.
    Including leading dot.
 
 
-   Default value is ".deny".
+   Default value is “.deny�.
 
 
    Example 1.5. Set deny_suffix parameter
    Example 1.5. Set deny_suffix parameter
 ...
 ...
@@ -455,7 +464,7 @@ modparam("permissions", "deny_suffix", ".deny")
    This is URL of the database to be used to store rules used by
    This is URL of the database to be used to store rules used by
    allow_trusted function.
    allow_trusted function.
 
 
-   Default value is "NULL".
+   Default value is “NULL�.
 
 
    Example 1.6. Set db_url parameter
    Example 1.6. Set db_url parameter
 ...
 ...
@@ -464,10 +473,10 @@ modparam("permissions", "db_url", "dbdriver://username:password@dbhost/dbname")
 
 
 3.7. address_table (string)
 3.7. address_table (string)
 
 
-   Name of database table containing IP subnet information used by
-   allow_address and allow_source_address functions.
+   Name of database table containing IP subnets and DNS domain names used
+   by allow_address and allow_source_address functions.
 
 
-   Default value is "address".
+   Default value is “address�.
 
 
    Example 1.7. Set address_table parameter
    Example 1.7. Set address_table parameter
 ...
 ...
@@ -479,7 +488,7 @@ modparam("permissions", "address_table", "addr")
    Name of address table column containing group identifier of the
    Name of address table column containing group identifier of the
    address.
    address.
 
 
-   Default value is "grp".
+   Default value is “grp�.
 
 
    Example 1.8. Set grp_col parameter
    Example 1.8. Set grp_col parameter
 ...
 ...
@@ -490,7 +499,7 @@ modparam("permissions", "grp_col", "group_id")
 
 
    Name of address table column containing IP address part of the address.
    Name of address table column containing IP address part of the address.
 
 
-   Default value is "ip_addr".
+   Default value is “ip_addr�.
 
 
    Example 1.9. Set ip_addr_col parameter
    Example 1.9. Set ip_addr_col parameter
 ...
 ...
@@ -502,7 +511,7 @@ modparam("permissions", "ip_addr_col", "ip_address")
    Name of address table column containing network mask of the address.
    Name of address table column containing network mask of the address.
    Possible values are 0-32.
    Possible values are 0-32.
 
 
-   Default value is "mask".
+   Default value is “mask�.
 
 
    Example 1.10. Set mask_col parameter
    Example 1.10. Set mask_col parameter
 ...
 ...
@@ -513,7 +522,7 @@ modparam("permissions", "mask_col", "subnet_length")
 
 
    Name of address table column containing port part of the address.
    Name of address table column containing port part of the address.
 
 
-   Default value is "port".
+   Default value is “port�.
 
 
    Example 1.11. Set port_col parameter
    Example 1.11. Set port_col parameter
 ...
 ...
@@ -537,7 +546,7 @@ modparam("permissions", "db_mode", 1)
    Name of database table containing matching rules used by allow_trusted
    Name of database table containing matching rules used by allow_trusted
    function.
    function.
 
 
-   Default value is "trusted".
+   Default value is “trusted�.
 
 
    Example 1.13. Set trusted_table parameter
    Example 1.13. Set trusted_table parameter
 ...
 ...
@@ -549,7 +558,7 @@ modparam("permissions", "trusted_table", "pbx")
    Name of trusted table column containing source IP address that is
    Name of trusted table column containing source IP address that is
    matched against source IP address of received request.
    matched against source IP address of received request.
 
 
-   Default value is "src_ip".
+   Default value is “src_ip�.
 
 
    Example 1.14. Set source_col parameter
    Example 1.14. Set source_col parameter
 ...
 ...
@@ -560,10 +569,10 @@ modparam("permissions", "source_col", "source_ip_address")
 
 
    Name of trusted table column containing transport protocol that is
    Name of trusted table column containing transport protocol that is
    matched against transport protocol of received request. Possible values
    matched against transport protocol of received request. Possible values
-   that can be stored in proto_col are "any", "udp", "tcp", "tls", "sctp",
-   and "none". Value "any" matches always and value "none" never.
+   that can be stored in proto_col are “any�, “udp�, “tcp�, “tls�, “sctp�,
+   and “none�. Value “any� matches always and value “none� never.
 
 
-   Default value is "proto".
+   Default value is “proto�.
 
 
    Example 1.15. Set proto_col parameter
    Example 1.15. Set proto_col parameter
 ...
 ...
@@ -575,7 +584,7 @@ modparam("permissions", "proto_col", "transport")
    Name of trusted table column containing regular expression that is
    Name of trusted table column containing regular expression that is
    matched against From URI.
    matched against From URI.
 
 
-   Default value is "from_pattern".
+   Default value is “from_pattern�.
 
 
    Example 1.16. Set from_col parameter
    Example 1.16. Set from_col parameter
 ...
 ...
@@ -588,7 +597,7 @@ modparam("permissions", "from_col", "regexp")
    added as value to peer_tag AVP if peer_tag AVP has been defined and if
    added as value to peer_tag AVP if peer_tag AVP has been defined and if
    the address or peer matches.
    the address or peer matches.
 
 
-   Default value is "tag".
+   Default value is “tag�.
 
 
    Example 1.17. Set tag_col parameter
    Example 1.17. Set tag_col parameter
 ...
 ...
@@ -600,7 +609,7 @@ modparam("permissions", "tag_col", "peer_tag")
    If defined, the AVP will be set as side effect of allow_trusted() call
    If defined, the AVP will be set as side effect of allow_trusted() call
    to not NULL tag column value of the matching peer.
    to not NULL tag column value of the matching peer.
 
 
-   Default value is "undefined".
+   Default value is “undefined�.
 
 
    Example 1.18. Set peer_tag_avp parameter
    Example 1.18. Set peer_tag_avp parameter
 ...
 ...
@@ -613,7 +622,7 @@ modparam("permissions", "peer_tag_avp", "$avp(i:707)")
    adds the tags of all matches to the avp. In addition the return value
    adds the tags of all matches to the avp. In addition the return value
    of allow_trusted() is the number of matches.
    of allow_trusted() is the number of matches.
 
 
-   Default value is "0".
+   Default value is “0�.
 
 
    Example 1.19. Set peer_tag_mode parameter
    Example 1.19. Set peer_tag_mode parameter
 ...
 ...
@@ -637,7 +646,7 @@ modparam("permissions", "peer_tag_mode", "1")
 4.1.  allow_routing()
 4.1.  allow_routing()
 
 
    Returns true if all pairs constructed as described in Section 1.1,
    Returns true if all pairs constructed as described in Section 1.1,
-   "Call Routing" have appropriate permissions according to the
+   “Call Routing� have appropriate permissions according to the
    configuration files. This function uses default configuration files
    configuration files. This function uses default configuration files
    specified in default_allow_file and default_deny_file.
    specified in default_allow_file and default_deny_file.
 
 
@@ -653,7 +662,7 @@ if (allow_routing()) {
 4.2.  allow_routing(basename)
 4.2.  allow_routing(basename)
 
 
    Returns true if all pairs constructed as described in Section 1.1,
    Returns true if all pairs constructed as described in Section 1.1,
-   "Call Routing" have appropriate permissions according to the
+   “Call Routing� have appropriate permissions according to the
    configuration files given as parameters.
    configuration files given as parameters.
 
 
    Meaning of the parameters is as follows:
    Meaning of the parameters is as follows:
@@ -676,7 +685,7 @@ if (allow_routing("basename")) {
 4.3.  allow_routing(allow_file,deny_file)
 4.3.  allow_routing(allow_file,deny_file)
 
 
    Returns true if all pairs constructed as described in Section 1.1,
    Returns true if all pairs constructed as described in Section 1.1,
-   "Call Routing" have appropriate permissions according to the
+   “Call Routing� have appropriate permissions according to the
    configuration files given as parameters.
    configuration files given as parameters.
 
 
    Meaning of the parameters is as follows:
    Meaning of the parameters is as follows:
@@ -701,7 +710,7 @@ if (allow_routing("rules.allow", "rules.deny")) {
 4.4.  allow_register(basename)
 4.4.  allow_register(basename)
 
 
    The function returns true if all pairs constructed as described in
    The function returns true if all pairs constructed as described in
-   Section 1.2, "Registration Permissions" have appropriate permissions
+   Section 1.2, “Registration Permissions� have appropriate permissions
    according to the configuration files given as parameters.
    according to the configuration files given as parameters.
 
 
    Meaning of the parameters is as follows:
    Meaning of the parameters is as follows:
@@ -729,7 +738,7 @@ if (method=="REGISTER") {
 4.5.  allow_register(allow_file, deny_file)
 4.5.  allow_register(allow_file, deny_file)
 
 
    The function returns true if all pairs constructed as described in
    The function returns true if all pairs constructed as described in
-   Section 1.2, "Registration Permissions" have appropriate permissions
+   Section 1.2, “Registration Permissions� have appropriate permissions
    according to the configuration files given as parameters.
    according to the configuration files given as parameters.
 
 
    Meaning of the parameters is as follows:
    Meaning of the parameters is as follows:
@@ -758,8 +767,8 @@ if (method=="REGISTER") {
 
 
 4.6.  allow_uri(basename, pvar)
 4.6.  allow_uri(basename, pvar)
 
 
-   Returns true if the pair constructed as described in Section 1.3, "URI
-   Permissions" have appropriate permissions according to the
+   Returns true if the pair constructed as described in Section 1.3, “URI
+   Permissions� have appropriate permissions according to the
    configuration files specified by the parameter.
    configuration files specified by the parameter.
 
 
    Meaning of the parameter is as follows:
    Meaning of the parameter is as follows:
@@ -785,11 +794,15 @@ if (allow_uri("basename", "$avp(i:705)") {  // Check URI stored in $avp(i:705)
 
 
 4.7.  allow_address(group_id, ip_addr_pvar, port_pvar)
 4.7.  allow_address(group_id, ip_addr_pvar, port_pvar)
 
 
-   Returns true if IP address and port given as values of pvar arguments
-   belonging to a group given as group_id argument matches an IP subnet
-   found in cached address table. Cached address table entry containing
-   port value 0 matches any port. group_id argument can be an integer
-   string or a pseudo variable.
+   Returns true if address and port given as values of pvar arguments
+   belonging to a group given as group_id argument matches an IP subnet or
+   a DNS domain name found in cached address table. When matching is done
+   if the argument is an IP, it is tried to be matched with the records
+   from that group that are of type exact IP or subnet. If the argument is
+   not an IP it is tried to be matched with the records that are DNS
+   domain names. No DNS lookup is performed, only strict matching. Cached
+   address table entry containing port value 0 matches any port. group_id
+   argument can be an integer string or a pseudo variable.
 
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
 
@@ -800,8 +813,10 @@ if (allow_uri("basename", "$avp(i:705)") {  // Check URI stored in $avp(i:705)
 if (!allow_address("1", "$si", "$sp")) {
 if (!allow_address("1", "$si", "$sp")) {
         sl_send_reply("403", "Forbidden");
         sl_send_reply("403", "Forbidden");
 };
 };
-// Check IP address/port stored in AVPs i:704/i:705 is in group 2
-if (!allow_address("2", "$avp(i:704)", "$avp(i:705)") {
+// Check address/port stored in AVPs src_adr/src_port is in group 2
+$avp(dst_adr) = "sipdomain.com";
+$avp(dst_port) = "0";
+if (!allow_address("2", "$avp(dst_adr)", "$avp(dst_port)") {
         sl_send_reply("403", "Forbidden");
         sl_send_reply("403", "Forbidden");
 };
 };
 ...
 ...
@@ -862,8 +877,8 @@ if ($var(group) != -1) {
    Checks based either on request's source address and transport protocol
    Checks based either on request's source address and transport protocol
    or source address and transport protocol given in pvar arguments, and
    or source address and transport protocol given in pvar arguments, and
    From URI of request if request can be trusted without authentication.
    From URI of request if request can be trusted without authentication.
-   Returns 1 if a match is found as described in Section 1.5, "Trusted
-   Requests" and -1 otherwise. If a match is found and peer_tag_avp has
+   Returns 1 if a match is found as described in Section 1.5, “Trusted
+   Requests� and -1 otherwise. If a match is found and peer_tag_avp has
    been defined, adds a non-NULL tag column value of the matching peer to
    been defined, adds a non-NULL tag column value of the matching peer to
    AVP peer_tag_avp.
    AVP peer_tag_avp.
 
 

+ 119 - 50
modules/permissions/address.c

@@ -54,6 +54,11 @@ struct subnet **subnet_table;        /* Ptr to current subnet table */
 struct subnet *subnet_table_1;       /* Ptr to subnet table 1 */
 struct subnet *subnet_table_1;       /* Ptr to subnet table 1 */
 struct subnet *subnet_table_2;       /* Ptr to subnet table 2 */
 struct subnet *subnet_table_2;       /* Ptr to subnet table 2 */
 
 
+struct domain_name_list ***domain_list_table;        /* Ptr to current domain name table */
+static struct domain_name_list **domain_list_table_1;       /* Ptr to domain name table 1 */
+static struct domain_name_list **domain_list_table_2;       /* Ptr to domain name table 2 */
+
+
 static db1_con_t* db_handle = 0;
 static db1_con_t* db_handle = 0;
 static db_func_t perm_dbf;
 static db_func_t perm_dbf;
 
 
@@ -87,6 +92,7 @@ int reload_address_table(void)
 
 
 	struct addr_list **new_hash_table;
 	struct addr_list **new_hash_table;
 	struct subnet *new_subnet_table;
 	struct subnet *new_subnet_table;
+	struct domain_name_list **new_domain_name_table;
 	int i;
 	int i;
 	unsigned int gid;
 	unsigned int gid;
 	unsigned int port;
 	unsigned int port;
@@ -129,6 +135,16 @@ int reload_address_table(void)
 		new_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);
 	row = RES_ROWS(res);
 
 
 	LM_DBG("Number of rows in address table: %d\n", RES_ROW_N(res));
 	LM_DBG("Number of rows in address table: %d\n", RES_ROW_N(res));
@@ -173,42 +189,55 @@ int reload_address_table(void)
 		port = VAL_UINT(val + 3);
 		port = VAL_UINT(val + 3);
 		tagv = VAL_NULL(val + 4)?NULL:(char *)VAL_STRING(val + 4);
 		tagv = VAL_NULL(val + 4)?NULL:(char *)VAL_STRING(val + 4);
 		ipa = strtoipX(&ips);
 		ipa = strtoipX(&ips);
-		if(ipa==NULL)
+		if ( ipa==NULL )
 		{
 		{
-			LM_DBG("failure during IP address conversion\n");
-			goto dberror;
-		}
-		if(ipa->af == AF_INET6) {
-			if(mask<0 || mask>128) {
-				LM_DBG("failure during IP mask check for v6\n");
-				goto dberror;
-			}
+			LM_DBG("Domain name: %.*s\n", ips.len, ips.s);
+		//	goto dberror;
 		} else {
 		} else {
-			if(mask<0 || mask>32) {
-				LM_DBG("failure during IP mask check for v4\n");
-				goto dberror;
+			if(ipa->af == AF_INET6) {
+				if(mask<0 || mask>128) {
+					LM_DBG("failure during IP mask check for v6\n");
+					goto dberror;
+				}
+			} else {
+				if(mask<0 || mask>32) {
+					LM_DBG("failure during IP mask check for v4\n");
+					goto dberror;
+				}
 			}
 			}
 		}
 		}
-		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;
+
+		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);
 			}
 			}
-			LM_DBG("Tuple <%u, %s, %u> inserted into address hash table\n",
-					gid, ips.s, port);
 		} else {
 		} else {
-			if (subnet_table_insert(new_subnet_table, gid, ipa, mask,
+				if (domain_name_table_insert(new_domain_name_table, gid, &ips,
 							port, tagv)
 							port, tagv)
 						== -1) {
 						== -1) {
-				LM_ERR("subnet table problem\n");
+				LM_ERR("domain name table problem\n");
 				perm_dbf.free_result(db_handle, res);
 				perm_dbf.free_result(db_handle, res);
 				return -1;
 				return -1;
 			}
 			}
-			LM_DBG("Tuple <%u, %s, %u, %u> inserted into subnet table\n",
-					gid, ips.s, port, mask);
+			LM_DBG("Tuple <%u, %s, %u> inserted into domain name table\n",
+					gid, ips.s, port);
 		}
 		}
 	}
 	}
 
 
@@ -216,6 +245,7 @@ int reload_address_table(void)
 
 
 	*addr_hash_table = new_hash_table;
 	*addr_hash_table = new_hash_table;
 	*subnet_table = new_subnet_table;
 	*subnet_table = new_subnet_table;
+	*domain_list_table = new_domain_name_table;
 
 
 	LM_DBG("address table reloaded successfully.\n");
 	LM_DBG("address table reloaded successfully.\n");
 
 
@@ -293,6 +323,21 @@ int init_addresses(void)
 
 
 	*subnet_table = subnet_table_1;
 	*subnet_table = subnet_table_1;
 
 
+	domain_list_table_1 = new_domain_name_table();
+	if (!domain_list_table_1) goto error;
+
+	domain_list_table_2 = new_domain_name_table();
+	if (!domain_list_table_2) goto error;
+
+	domain_list_table = (struct domain_name_list ***)shm_malloc(sizeof(struct domain_name_list **));
+	if (!domain_list_table) {
+		LM_ERR("no more shm memory for domain name table\n");
+		goto error;
+	}
+
+	*domain_list_table = domain_list_table_1;
+
+
 	if (reload_address_table() == -1) {
 	if (reload_address_table() == -1) {
 		LM_CRIT("reload of address table failed\n");
 		LM_CRIT("reload of address table failed\n");
 		goto error;
 		goto error;
@@ -328,6 +373,20 @@ error:
 		shm_free(subnet_table);
 		shm_free(subnet_table);
 		subnet_table = 0;
 		subnet_table = 0;
 	}
 	}
+
+	if (domain_list_table_1) {
+		free_domain_name_table(domain_list_table_1);
+		domain_list_table_1 = 0;
+	}
+	if (domain_list_table_2) {
+		free_domain_name_table(domain_list_table_2);
+		domain_list_table_2 = 0;
+	}
+	if (domain_list_table) {
+		shm_free(domain_list_table);
+		domain_list_table = 0;
+	}
+
 	perm_dbf.close(db_handle);
 	perm_dbf.close(db_handle);
 	db_handle = 0;
 	db_handle = 0;
 	return -1;
 	return -1;
@@ -361,6 +420,9 @@ void clean_addresses(void)
 	if (subnet_table_1) free_subnet_table(subnet_table_1);
 	if (subnet_table_1) free_subnet_table(subnet_table_1);
 	if (subnet_table_2) free_subnet_table(subnet_table_2);
 	if (subnet_table_2) free_subnet_table(subnet_table_2);
 	if (subnet_table) shm_free(subnet_table);
 	if (subnet_table) shm_free(subnet_table);
+	if (domain_list_table_1) free_domain_name_table(domain_list_table_1);
+	if (domain_list_table_2) free_domain_name_table(domain_list_table_2);
+	if (domain_list_table) shm_free(domain_list_table);
 }
 }
 
 
 
 
@@ -387,10 +449,8 @@ int allow_address(struct sip_msg* _msg, char* _addr_group, char* _addr_sp,
 		LM_ERR("cannot get value of address pvar\n");
 		LM_ERR("cannot get value of address pvar\n");
 		return -1;
 		return -1;
 	}
 	}
-	if ( (ipa=strtoipX(&ips)) == NULL ) {
-		LM_ERR("failed to convert IP address string to in_addr\n");
-		return -1;
-	}
+
+	ipa=strtoipX(&ips);
 
 
 	if (_port_sp==NULL
 	if (_port_sp==NULL
 			|| (fixup_get_ivalue(_msg, (gparam_p)_port_sp, (int*)&port) < 0)) {
 			|| (fixup_get_ivalue(_msg, (gparam_p)_port_sp, (int*)&port) < 0)) {
@@ -398,10 +458,14 @@ int allow_address(struct sip_msg* _msg, char* _addr_group, char* _addr_sp,
 		return -1;
 		return -1;
 	}
 	}
 
 
-	if (match_addr_hash_table(*addr_hash_table, addr_group, ipa, port) == 1)
-		return 1;
-	else
-		return match_subnet_table(*subnet_table, addr_group, ipa, port);
+	if ( ipa ) {
+		if (match_addr_hash_table(*addr_hash_table, addr_group, ipa, port) == 1)
+			return 1;
+		else
+			return match_subnet_table(*subnet_table, addr_group, ipa, port);
+	} else {
+		return match_domain_name_table(*domain_list_table, addr_group, &ips, port);
+	}
 }
 }
 
 
 
 
@@ -479,30 +543,35 @@ int allow_address_group(struct sip_msg* _msg, char* _addr, char* _port)
 		LM_ERR("cannot get value of address pvar\n");
 		LM_ERR("cannot get value of address pvar\n");
 		return -1;
 		return -1;
 	}
 	}
-	if ( (ipa=strtoipX(&ips)) == NULL ) {
-		LM_ERR("failed to convert IP address string to in_addr\n");
-		return -1;
-	}
-
 	if (_port==NULL
 	if (_port==NULL
 			|| (fixup_get_ivalue(_msg, (gparam_p)_port, (int*)&port) < 0)) {
 			|| (fixup_get_ivalue(_msg, (gparam_p)_port, (int*)&port) < 0)) {
 		LM_ERR("cannot get value of port pvar\n");
 		LM_ERR("cannot get value of port pvar\n");
 		return -1;
 		return -1;
 	}
 	}
 
 
-	LM_DBG("looking for <%.*s, %u> in address table\n",
-			ips.len, ips.s, port);
-	group = find_group_in_addr_hash_table(*addr_hash_table,
-			ipa, port);
-	LM_DBG("Found address in group <%d>\n", group);
+	ipa=strtoipX(&ips);
 
 
-	if (group != -1) return group;
+	if ( ipa ) {
+		LM_DBG("looking for <%.*s, %u> in address table\n",
+				ips.len, ips.s, port);
+		group = find_group_in_addr_hash_table(*addr_hash_table,
+				ipa, port);
+		LM_DBG("Found address in group <%d>\n", group);
+
+		if (group != -1) return group;
+
+		LM_DBG("looking for <%.*s, %u> in subnet table\n",
+				ips.len, ips.s, port);
+		group = find_group_in_subnet_table(*subnet_table,
+				ipa, port);
+		LM_DBG("Found a match of subnet in group <%d>\n", group);
+	} else {
+		LM_DBG("looking for <%.*s, %u> in domain_name table\n",
+				ips.len, ips.s, port);
+		group = find_group_in_domain_name_table(*domain_list_table,
+				&ips, port);
+		LM_DBG("Found a match of domain_name in group <%d>\n", group);
+	}
 
 
-	LM_DBG("looking for <%.*s, %u> in subnet table\n",
-			ips.len, ips.s, port);
-	group = find_group_in_subnet_table(*subnet_table,
-			&_msg->rcv.src_ip,
-			_msg->rcv.src_port);
-	LM_DBG("Found a match of subnet in group <%d>\n", group);
 	return group;
 	return group;
 }
 }

+ 3 - 0
modules/permissions/address.h

@@ -34,6 +34,9 @@ extern struct addr_list ***addr_hash_table;
 extern struct subnet **subnet_table; 
 extern struct subnet **subnet_table; 
 
 
 
 
+/* Pointer to current domain name table */
+extern struct domain_name_list ***domain_list_table;
+
 /*
 /*
  * Initialize data structures
  * Initialize data structures
  */
  */

+ 27 - 9
modules/permissions/doc/permissions_admin.xml

@@ -169,19 +169,29 @@
 		<title>Address Permissions</title>
 		<title>Address Permissions</title>
 		<para>
 		<para>
 		The module can be used to determine if an address (IP
 		The module can be used to determine if an address (IP
-		address and port) matches any of the IP subnets
-		stored in cached &kamailio; database table.
-		Port 0 in cached database table matches any port.  IP
+		address and port or DNS domain name) matches any of the
+		addresses stored in cached &kamailio; database table.
+		IP addresses in the database table can be subnet addresses.
+		Port 0 in cached database table matches any port. The
 		address and port to be matched can be either taken from
 		address and port to be matched can be either taken from
 		the request (allow_source_address) or given as pvar
 		the request (allow_source_address) or given as pvar
 		arguments (allow_address).
 		arguments (allow_address).
 		</para>
 		</para>
 		<para>
 		<para>
-		Addresses stored in cached database table can be grouped
+		Addresses stored in database table can be grouped
 		together into one or more groups specified by a group
 		together into one or more groups specified by a group
 		identifier (positive integer value, i.e., equal or greater than 1).
 		identifier (positive integer value, i.e., equal or greater than 1).
 		Group identifier is given as argument to allow_address and
 		Group identifier is given as argument to allow_address and
 		allow_source_address functions.
 		allow_source_address functions.
+		One group can contain all of the three types of addresses: exact 
+		IP address, subnet IP address or DNS domain name.
+		</para>
+		<para>
+		When matching is done if the argument is an IP, it is tried to
+		be matched with the records from that group that are of type exact
+		IP or subnet. If the argument is not an IP it is tried to be matched
+		with the records that are DNS domain names. No DNS lookup is performed,
+		only strict matching.
 		</para>
 		</para>
 		<para>
 		<para>
 		As a side effect of matching the address, non-NULL tag 
 		As a side effect of matching the address, non-NULL tag 
@@ -424,7 +434,7 @@ modparam("permissions", "db_url", "&exampledb;")
 	<section>
 	<section>
 		<title><varname>address_table</varname> (string)</title>
 		<title><varname>address_table</varname> (string)</title>
 		<para>
 		<para>
-		Name of database table containing IP subnet information used by
+		Name of database table containing IP subnets and DNS domain names used by
 		<function moreinfo="none">allow_address</function> and
 		<function moreinfo="none">allow_address</function> and
                 <function moreinfo="none">allow_source_address</function>
                 <function moreinfo="none">allow_source_address</function>
                 functions.
                 functions.
@@ -947,9 +957,15 @@ if (allow_uri("basename", "$avp(i:705)") {  // Check URI stored in $avp(i:705)
 		<function moreinfo="none">allow_address(group_id, ip_addr_pvar, port_pvar)</function>
 		<function moreinfo="none">allow_address(group_id, ip_addr_pvar, port_pvar)</function>
 		</title>
 		</title>
 		<para>
 		<para>
-		Returns true if IP address and port given as values of pvar
+		Returns true if address and port given as values of pvar
 		arguments belonging to a group given as group_id argument
 		arguments belonging to a group given as group_id argument
-		matches an IP subnet found in cached address table.
+		matches an IP subnet or a DNS domain name found in cached
+		address table.
+		When matching is done if the argument is an IP, it is tried to
+		be matched with the records from that group that are of type exact
+		IP or subnet. If the argument is not an IP it is tried to be matched
+		with the records that are DNS domain names. No DNS lookup is performed,
+		only strict matching.
 		Cached address table entry containing port value 0
 		Cached address table entry containing port value 0
 		matches any port.  group_id argument can be an integer
 		matches any port.  group_id argument can be an integer
 		string or a pseudo variable. 
 		string or a pseudo variable. 
@@ -966,8 +982,10 @@ if (allow_uri("basename", "$avp(i:705)") {  // Check URI stored in $avp(i:705)
 if (!allow_address("1", "$si", "$sp")) {
 if (!allow_address("1", "$si", "$sp")) {
 	sl_send_reply("403", "Forbidden");
 	sl_send_reply("403", "Forbidden");
 };
 };
-// Check IP address/port stored in AVPs i:704/i:705 is in group 2
-if (!allow_address("2", "$avp(i:704)", "$avp(i:705)") {
+// Check address/port stored in AVPs src_adr/src_port is in group 2
+$avp(dst_adr) = "sipdomain.com";
+$avp(dst_port) = "0";
+if (!allow_address("2", "$avp(dst_adr)", "$avp(dst_port)") {
 	sl_send_reply("403", "Forbidden");
 	sl_send_reply("403", "Forbidden");
 };
 };
 ...
 ...

+ 217 - 0
modules/permissions/hash.c

@@ -830,3 +830,220 @@ void free_subnet_table(struct subnet* table)
 
 
 	shm_free(table);
 	shm_free(table);
 }
 }
+
+/*
+ * Create and initialize a domain_name table
+ */
+struct domain_name_list** new_domain_name_table(void)
+{
+	struct domain_name_list** ptr;
+
+	/* Initializing hash tables and hash table variable */
+	ptr = (struct domain_name_list **)shm_malloc
+		(sizeof(struct domain_name_list*) * PERM_HASH_SIZE);
+	if (!ptr) {
+		LM_ERR("no shm memory for hash table\n");
+		return 0;
+	}
+
+	memset(ptr, 0, sizeof(struct domain_name*) * PERM_HASH_SIZE);
+	return ptr;
+}
+
+
+/* 
+ * Free contents of hash table, it doesn't destroy the
+ * hash table itself
+ */
+void empty_domain_name_table(struct domain_name_list **table)
+{
+	int i;
+	struct domain_name_list *np, *next;
+
+	for (i = 0; i < PERM_HASH_SIZE; i++) {
+		np = table[i];
+		while (np) {
+			next = np->next;
+			shm_free(np);
+			np = next;
+		}
+		table[i] = 0;
+	}
+}
+
+/*
+ * Release all memory allocated for a hash table
+ */
+void free_domain_name_table(struct domain_name_list** table)
+{
+	if (!table)
+		return;
+
+	empty_domain_name_table(table);
+	shm_free(table);
+}
+
+
+/* 
+ * Check if an entry exists in hash table that has given group, domain_name, and
+ * port.  Port 0 in hash table matches any port.
+ */
+int match_domain_name_table(struct domain_name_list** table, unsigned int group,
+		str *domain_name, unsigned int port)
+{
+	struct domain_name_list *np;
+	avp_value_t val;
+
+	for (np = table[perm_hash(*domain_name)]; np != NULL; np = np->next) {
+		if ( (np->grp == group)
+				&& ((np->port == 0) || (np->port == port))
+				&& np->domain.len == domain_name->len
+				&& strncmp(np->domain.s, domain_name->s, domain_name->len)==0 ) {
+
+			if (tag_avp.n && np->tag.s) {
+				val.s = np->tag;
+				if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, val) != 0) {
+					LM_ERR("setting of tag_avp failed\n");
+					return -1;
+				}
+			}
+
+			return 1;
+		}
+	}
+
+	return -1;
+}
+
+
+/* 
+ * Check if an domain_name/port entry exists in hash table in any group.
+ * Returns first group in which ip_addr/port is found.
+ * Port 0 in hash table matches any port. 
+ */
+int find_group_in_domain_name_table(struct domain_name_list** table,
+		str *domain_name, unsigned int port)
+{
+	struct domain_name_list *np;
+
+	for (np = table[perm_hash(*domain_name)]; np != NULL; np = np->next) {
+		if ( ((np->port == 0) || (np->port == port))
+				&& np->domain.len == domain_name->len
+				&& strncmp(np->domain.s, domain_name->s, domain_name->len)==0 ) {
+			return np->grp;
+		}
+	}
+
+	return -1;
+}
+
+
+/* 
+ * 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)
+{
+	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;
+
+	np = (struct domain_name_list *) shm_malloc(len);
+	if (np == NULL) {
+		LM_ERR("no shm memory for table entry\n");
+		return -1;
+	}
+
+	memset(np, 0, len);
+
+	np->grp = grp;
+	np->domain.s = (char*)np + sizeof(struct domain_name_list);
+	memcpy(np->domain.s, domain_name->s, domain_name->len);
+	np->domain.len = domain_name->len;
+	np->port = port;
+	if(tagv!=NULL) {
+		np->tag.s = (char*)np + sizeof(struct domain_name_list) + domain_name->len;
+		np->tag.len = strlen(tagv);
+		strcpy(np->tag.s, tagv);
+	}
+
+	LM_DBG("** Added domain name: %.*s\n", np->domain.len, np->domain.s);
+
+	hash_val = perm_hash(*domain_name);
+	np->next = table[hash_val];
+	table[hash_val] = np;
+
+	return 1;
+}
+
+
+/*! \brief
+ * RPC: Print addresses stored in hash table 
+ */
+int domain_name_table_rpc_print(struct domain_name_list** table, rpc_t* rpc, void* c)
+{
+	int i;
+	void* th;
+	void* ih;
+	struct domain_name_list *np;
+
+
+	if (rpc->add(c, "{", &th) < 0)
+	{
+		rpc->fault(c, 500, "Internal error creating rpc");
+		return -1;
+	}
+
+	for (i = 0; i < PERM_HASH_SIZE; i++) {
+		np = table[i];
+		while (np) {
+			if(rpc->struct_add(th, "dd{", 
+					"table", i,
+					"group", np->grp,
+					"item", &ih) < 0) {
+				rpc->fault(c, 500, "Internal error creating rpc ih");
+				return -1;
+			}
+
+			if(rpc->struct_add(ih, "S", "domain_name", &np->domain) < 0) {
+				rpc->fault(c, 500, "Internal error creating rpc data (ip)");
+				return -1;
+			}
+			if(rpc->struct_add(ih, "ds", "port",  np->port,
+						"tag",  np->tag.len ? np->tag.s : "NULL") < 0) {
+				rpc->fault(c, 500, "Internal error creating rpc data");
+				return -1;
+			}
+			np = np->next;
+		}
+	}
+	return 0;
+}
+
+/*! \brief
+ * MI: Print domain name stored in hash table 
+ */
+int domain_name_table_mi_print(struct domain_name_list** table, struct mi_node* rpl)
+{
+	int i;
+	struct domain_name_list *np;
+
+	for (i = 0; i < PERM_HASH_SIZE; i++) {
+		np = table[i];
+		while (np) {
+			if (addf_mi_node_child(rpl, 0, 0, 0,
+						"%4d <%u, %.*s, %u> [%s]",
+						i, np->grp, np->domain.len, np->domain.s,
+						np->port, (np->tag.s==NULL)?"":np->tag.s) == 0)
+				return -1;
+			np = np->next;
+		}
+	}
+	return 0;
+}
+
+

+ 54 - 0
modules/permissions/hash.h

@@ -240,4 +240,58 @@ int subnet_table_mi_print(struct subnet* table, struct mi_node* rpl);
 int subnet_table_rpc_print(struct subnet* table, rpc_t* rpc, void* c);
 int subnet_table_rpc_print(struct subnet* table, rpc_t* rpc, void* c);
 
 
 
 
+/*
+ * Structure used to store domain names
+ */
+struct domain_name_list {
+	unsigned int grp;        /* address group */
+	str  domain;        /* domain_name */
+	unsigned int port;       /* port or 0 */
+	str tag;
+	struct domain_name_list* next;
+};
+
+/*
+ * Create a domain_name table
+ */
+struct domain_name_list** new_domain_name_table(void);
+
+/*
+ * Release memory allocated for a subnet table
+ */
+void free_domain_name_table(struct domain_name_list** table);
+
+/* 
+ * Empty contents of domain_name hash table
+ */
+void empty_domain_name_table(struct domain_name_list** table);
+
+/* 
+ * Check if an entry exists in domain_name table that matches given group, domain_name,
+ * and port.  Port 0 in  matches any port.
+ */
+int match_domain_name_table(struct domain_name_list** table, unsigned int group,
+		str *domain_name, unsigned int port);
+
+/* 
+ * 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);
+
+/* 
+ * Check if an domain_name/port entry exists in hash table in any group.
+ * Returns first group in which ip_addr/port is found.
+ * Port 0 in hash table matches any port. 
+ */
+int find_group_in_domain_name_table(struct domain_name_list** table,
+		str *domain_name, unsigned int port);
+
+/*! \brief
+ * RPC: Print addresses stored in hash table 
+ */
+void domain_name_table_print(struct subnet* table, FILE* reply_file);
+int domain_name_table_rpc_print(struct domain_name_list** table, rpc_t* rpc, void* c);
+int domain_name_table_mi_print(struct domain_name_list** table, struct mi_node* rpl);
+
 #endif /* _PERM_HASH_H_ */
 #endif /* _PERM_HASH_H_ */

+ 32 - 0
modules/permissions/mi.c

@@ -196,6 +196,38 @@ void rpc_subnet_dump(rpc_t* rpc, void* c) {
 	return;
 	return;
 }
 }
 
 
+/*
+ * MI function to print domain name table
+ */
+struct mi_root* mi_domain_name_dump(struct mi_root *cmd_tree, void *param)
+{
+	struct mi_root* rpl_tree;
+
+	rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
+	if (rpl_tree==NULL) return 0;
+
+	if(domain_list_table && domain_name_table_mi_print(*domain_list_table, &rpl_tree->node) <  0) {
+		LM_ERR("failed to add a node\n");
+		free_mi_tree(rpl_tree);
+		return 0;
+	}
+
+	return rpl_tree;
+}
+
+
+/*! \brief
+ * RPC function to dump domain name table
+ */
+void rpc_domain_name_dump(rpc_t* rpc, void* c) {
+
+	if ( domain_name_table_rpc_print(*domain_list_table, rpc, c) < 0 ) {
+		LM_DBG("failed to print a subnet_table dump\n");
+	}
+	return;
+}
+
+
 #define MAX_FILE_LEN 128
 #define MAX_FILE_LEN 128
 
 
 /*! \brief
 /*! \brief

+ 4 - 0
modules/permissions/mi.h

@@ -36,6 +36,7 @@
 #define MI_ADDRESS_RELOAD "address_reload"
 #define MI_ADDRESS_RELOAD "address_reload"
 #define MI_ADDRESS_DUMP "address_dump"
 #define MI_ADDRESS_DUMP "address_dump"
 #define MI_SUBNET_DUMP "subnet_dump"
 #define MI_SUBNET_DUMP "subnet_dump"
+#define MI_DOMAIN_DUMP "perm_domain_dump"
 
 
 #define MI_ALLOW_URI "allow_uri"
 #define MI_ALLOW_URI "allow_uri"
 
 
@@ -54,6 +55,9 @@ void rpc_address_dump(rpc_t* rpc, void* c);
 struct mi_root* mi_subnet_dump(struct mi_root *cmd_tree, void *param);
 struct mi_root* mi_subnet_dump(struct mi_root *cmd_tree, void *param);
 void rpc_subnet_dump(rpc_t* rpc, void* c);
 void rpc_subnet_dump(rpc_t* rpc, void* c);
 
 
+struct mi_root* mi_domain_name_dump(struct mi_root *cmd_tree, void *param);
+void rpc_domain_name_dump(rpc_t* rpc, void* c);
+
 struct mi_root* mi_allow_uri(struct mi_root *cmd, void *param);
 struct mi_root* mi_allow_uri(struct mi_root *cmd, void *param);
 void rpc_test_uri(rpc_t* rpc, void* c);
 void rpc_test_uri(rpc_t* rpc, void* c);
 
 

+ 8 - 0
modules/permissions/permissions.c

@@ -188,6 +188,7 @@ static mi_export_t mi_cmds[] = {
 		mi_addr_child_init },
 		mi_addr_child_init },
 	{ MI_ADDRESS_DUMP,    mi_address_dump,    MI_NO_INPUT_FLAG,  0,  0 },
 	{ MI_ADDRESS_DUMP,    mi_address_dump,    MI_NO_INPUT_FLAG,  0,  0 },
 	{ MI_SUBNET_DUMP,     mi_subnet_dump,     MI_NO_INPUT_FLAG,  0,  0 },
 	{ MI_SUBNET_DUMP,     mi_subnet_dump,     MI_NO_INPUT_FLAG,  0,  0 },
+	{ MI_DOMAIN_DUMP,     mi_domain_name_dump,MI_NO_INPUT_FLAG,  0,  0 },
 	{ MI_ALLOW_URI,       mi_allow_uri,       0,  0,  0 },
 	{ MI_ALLOW_URI,       mi_allow_uri,       0,  0,  0 },
 	{ 0, 0, 0, 0, 0 }
 	{ 0, 0, 0, 0, 0 }
 };
 };
@@ -1009,6 +1010,12 @@ static const char* rpc_subnet_dump_doc[2] = {
 	0
 	0
 };
 };
 
 
+static const char* rpc_domain_name_dump_doc[2] = {
+	"Dump permissions domain name table",
+	0
+};
+
+
 static const char* rpc_test_uri_doc[2] = {
 static const char* rpc_test_uri_doc[2] = {
 	"Tests if (URI, Contact) pair is allowed according to allow/deny files",
 	"Tests if (URI, Contact) pair is allowed according to allow/deny files",
 	0
 	0
@@ -1020,6 +1027,7 @@ rpc_export_t permissions_rpc[] = {
 	{"permissions.trustedDump", rpc_trusted_dump, rpc_trusted_dump_doc, 0},
 	{"permissions.trustedDump", rpc_trusted_dump, rpc_trusted_dump_doc, 0},
 	{"permissions.addressDump", rpc_address_dump, rpc_address_dump_doc, 0},
 	{"permissions.addressDump", rpc_address_dump, rpc_address_dump_doc, 0},
 	{"permissions.subnetDump", rpc_subnet_dump, rpc_subnet_dump_doc, 0},
 	{"permissions.subnetDump", rpc_subnet_dump, rpc_subnet_dump_doc, 0},
+	{"permissions.domainDump", rpc_domain_name_dump, rpc_domain_name_dump_doc, 0},
 	{"permissions.testUri", rpc_test_uri, rpc_test_uri_doc, 0},
 	{"permissions.testUri", rpc_test_uri, rpc_test_uri_doc, 0},
 	{0, 0, 0, 0}
 	{0, 0, 0, 0}
 };
 };