Преглед изворни кода

ipops: adding detailed_ip_type() functions

Returns the detailed type of the given IP, analogue to perl's Net::IP ip_iptype()
(see also http://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.txt,
http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.txt,
RFC 5735 and RFC 6598: PRIVATE, SHARED, LOOPBACK, IPV4MAP, DISCARD etc)
Lucian Balaceanu пре 9 година
родитељ
комит
2cf9dbadfc

+ 146 - 48
modules/ipops/README

@@ -32,14 +32,17 @@ Iñaki Baz Castillo
               4.4. is_ipv6 (ip)
               4.4. is_ipv6 (ip)
               4.5. is_ipv6_reference (ip)
               4.5. is_ipv6_reference (ip)
               4.6. ip_type (ip)
               4.6. ip_type (ip)
-              4.7. compare_ips (ip1, ip2)
-              4.8. compare_pure_ips (ip1, ip2)
-              4.9. is_ip_rfc1918 (ip)
-              4.10. is_in_subnet (ip, subnets_list)
-              4.11. dns_sys_match_ip(hostname, ipaddr)
-              4.12. dns_int_match_ip(hostname, ipaddr)
-              4.13. dns_query(hostname, pvid)
-              4.14. srv_query(srvcname, pvid)
+              4.7. detailed_ip_type (ip, result)
+              4.8. detailed_ipv4_type (ip, result)
+              4.9. detailed_ipv6_type (ip, result)
+              4.10. compare_ips (ip1, ip2)
+              4.11. compare_pure_ips (ip1, ip2)
+              4.12. is_ip_rfc1918 (ip)
+              4.13. is_in_subnet (ip, subnets_list)
+              4.14. dns_sys_match_ip(hostname, ipaddr)
+              4.15. dns_int_match_ip(hostname, ipaddr)
+              4.16. dns_query(hostname, pvid)
+              4.17. srv_query(srvcname, pvid)
 
 
    List of Examples
    List of Examples
 
 
@@ -49,14 +52,17 @@ Iñaki Baz Castillo
    1.4. is_ipv6 usage
    1.4. is_ipv6 usage
    1.5. is_ipv6_reference usage
    1.5. is_ipv6_reference usage
    1.6. ip_type usage
    1.6. ip_type usage
-   1.7. compare_ips usage
-   1.8. compare_pure_ips usage
-   1.9. is_ip_rfc1918 usage
-   1.10. is_in_subnet usage
-   1.11. dns_sys_match_ip usage
-   1.12. dns_int_match_ip usage
-   1.13. dns_query usage
-   1.14. srv_query usage
+   1.7. detailed_ip_type usage
+   1.8. detailed_ipv4_type usage
+   1.9. detailed_ipv6_type usage
+   1.10. compare_ips usage
+   1.11. compare_pure_ips usage
+   1.12. is_ip_rfc1918 usage
+   1.13. is_in_subnet usage
+   1.14. dns_sys_match_ip usage
+   1.15. dns_int_match_ip usage
+   1.16. dns_query usage
+   1.17. srv_query usage
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -77,14 +83,17 @@ Chapter 1. Admin Guide
         4.4. is_ipv6 (ip)
         4.4. is_ipv6 (ip)
         4.5. is_ipv6_reference (ip)
         4.5. is_ipv6_reference (ip)
         4.6. ip_type (ip)
         4.6. ip_type (ip)
-        4.7. compare_ips (ip1, ip2)
-        4.8. compare_pure_ips (ip1, ip2)
-        4.9. is_ip_rfc1918 (ip)
-        4.10. is_in_subnet (ip, subnets_list)
-        4.11. dns_sys_match_ip(hostname, ipaddr)
-        4.12. dns_int_match_ip(hostname, ipaddr)
-        4.13. dns_query(hostname, pvid)
-        4.14. srv_query(srvcname, pvid)
+        4.7. detailed_ip_type (ip, result)
+        4.8. detailed_ipv4_type (ip, result)
+        4.9. detailed_ipv6_type (ip, result)
+        4.10. compare_ips (ip1, ip2)
+        4.11. compare_pure_ips (ip1, ip2)
+        4.12. is_ip_rfc1918 (ip)
+        4.13. is_in_subnet (ip, subnets_list)
+        4.14. dns_sys_match_ip(hostname, ipaddr)
+        4.15. dns_int_match_ip(hostname, ipaddr)
+        4.16. dns_query(hostname, pvid)
+        4.17. srv_query(srvcname, pvid)
 
 
 1. Overview
 1. Overview
 
 
@@ -132,14 +141,17 @@ Chapter 1. Admin Guide
    4.4. is_ipv6 (ip)
    4.4. is_ipv6 (ip)
    4.5. is_ipv6_reference (ip)
    4.5. is_ipv6_reference (ip)
    4.6. ip_type (ip)
    4.6. ip_type (ip)
-   4.7. compare_ips (ip1, ip2)
-   4.8. compare_pure_ips (ip1, ip2)
-   4.9. is_ip_rfc1918 (ip)
-   4.10. is_in_subnet (ip, subnets_list)
-   4.11. dns_sys_match_ip(hostname, ipaddr)
-   4.12. dns_int_match_ip(hostname, ipaddr)
-   4.13. dns_query(hostname, pvid)
-   4.14. srv_query(srvcname, pvid)
+   4.7. detailed_ip_type (ip, result)
+   4.8. detailed_ipv4_type (ip, result)
+   4.9. detailed_ipv6_type (ip, result)
+   4.10. compare_ips (ip1, ip2)
+   4.11. compare_pure_ips (ip1, ip2)
+   4.12. is_ip_rfc1918 (ip)
+   4.13. is_in_subnet (ip, subnets_list)
+   4.14. dns_sys_match_ip(hostname, ipaddr)
+   4.15. dns_int_match_ip(hostname, ipaddr)
+   4.16. dns_query(hostname, pvid)
+   4.17. srv_query(srvcname, pvid)
 
 
 4.1.  is_ip (ip)
 4.1.  is_ip (ip)
 
 
@@ -265,7 +277,93 @@ switch($rc) {
 }
 }
 ...
 ...
 
 
-4.7.  compare_ips (ip1, ip2)
+4.7.  detailed_ip_type (ip, result)
+
+   Returns the detailed type of the given IP () (see
+   http://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.t
+   xt,
+   http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-sp
+   ecial-registry.txt, RFC 5735 and RFC 6598: PRIVATE, SHARED, LOOPBACK,
+   IPV4MAP, DISCARD etc).
+
+   Parameters:
+     * ip - String or pseudo-variable containing the IP to evaluate.
+     * result - String or pseudo-variable containing the detailed type of
+       the IP.
+          + IPv4 - PUBLIC, RIVATE, SHARED, LOOPBACK, LINK-LOCAL, RESERVED,
+            TEST-NET, 6TO4-RELAY, MULTICAST, BROADCAST
+          + IPv6 - UNSPECIFIED, LOOPBACK, IPV4MAP, RESERVED, DISCARD,
+            GLOBAL-UNICAST, TEREDO, BMWG, DOCUMENTATION, ORCHID, 6TO4,
+            UNIQUE-LOCAL-UNICAST, LINK-LOCAL-UNICAST, MULTICAST
+
+   Return value:
+     * 1 - successful operation
+     * negative value - error occured
+
+   This function can be used from ALL ROUTES
+
+   Example 1.7.  detailed_ip_type usage
+...
+    detailed_ip_type("192.168.1.2","$var(result)");
+    xlog("L_ERR","IP address is of detailed type: $var(result) ");
+...
+
+4.8.  detailed_ipv4_type (ip, result)
+
+   Returns the detailed type of the given IP () (see RFC 5735 and RFC
+   6598).
+
+   Parameters:
+     * ip - String or pseudo-variable containing the IP to evaluate.
+     * result - String or pseudo-variable containing the detailed type of
+       the IP.
+          + IPv4 - PUBLIC, PRIVATE, SHARED, LOOPBACK, LINK-LOCAL,
+            RESERVED, TEST-NET, 6TO4-RELAY, MULTICAST, BROADCAST
+
+   Return value:
+     * 1 - successful operation
+     * negative value - error occured
+
+   This function can be used from ALL ROUTES
+
+   Example 1.8.  detailed_ipv4_type usage
+...
+    detailed_ipv4_type("192.168.1.2","$var(result)");
+    xlog("L_ERR","IP address is of detailed type: $var(result) ");
+...
+
+4.9.  detailed_ipv6_type (ip, result)
+
+   Returns the detailed type of the given IP () (see
+   http://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.t
+   xt,
+   http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-sp
+   ecial-registry.txt).
+
+   Parameters:
+     * ip - String or pseudo-variable containing the IP to evaluate.
+     * result - String or pseudo-variable containing the detailed type of
+       the IP.
+          + IPv6 - UNSPECIFIED, LOOPBACK, IPV4MAP, RESERVED, DISCARD,
+            GLOBAL-UNICAST, TEREDO, BMWG, DOCUMENTATION, ORCHID, 6TO4,
+            UNIQUE-LOCAL-UNICAST, LINK-LOCAL-UNICAST, MULTICAST
+
+   Return value:
+     * 1 - successful operation
+     * negative value - error occured
+
+   This function can be used from ALL ROUTES
+
+   Example 1.9.  detailed_ipv6_type usage
+...
+    detailed_ipv6_type("2001:8d8:7c0:402:217:72:194:30","$var(result)");
+    xlog("L_ERR","IP address is of detailed type: $var(result) ");
+
+    detailed_ipv6_type("[2001:8d8:7c0:402:217:72:194:30]","$var(result)");
+    xlog("L_ERR","IP address is of detailed type: $var(result) ");
+...
+
+4.10.  compare_ips (ip1, ip2)
 
 
    Returns TRUE if both IP addresses are the same. FALSE otherwise. This
    Returns TRUE if both IP addresses are the same. FALSE otherwise. This
    function also allows comparing an IPv6 address against an IPv6
    function also allows comparing an IPv6 address against an IPv6
@@ -279,7 +377,7 @@ switch($rc) {
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
 
 
-   Example 1.7.  compare_ips usage
+   Example 1.10.  compare_ips usage
 ...
 ...
 if (compare_ips("1080:0000:0000:0000:0008:0800:200C:417A", "[1080::8:800:200C:41
 if (compare_ips("1080:0000:0000:0000:0008:0800:200C:417A", "[1080::8:800:200C:41
 7A]")) {
 7A]")) {
@@ -287,7 +385,7 @@ if (compare_ips("1080:0000:0000:0000:0008:0800:200C:417A", "[1080::8:800:200C:41
 }
 }
 ...
 ...
 
 
-4.8.  compare_pure_ips (ip1, ip2)
+4.11.  compare_pure_ips (ip1, ip2)
 
 
    Returns TRUE if both IP's are the same. FALSE otherwise. This function
    Returns TRUE if both IP's are the same. FALSE otherwise. This function
    does NOT allow comparing an IPv6 against an IPv6 reference.
    does NOT allow comparing an IPv6 against an IPv6 reference.
@@ -301,14 +399,14 @@ if (compare_ips("1080:0000:0000:0000:0008:0800:200C:417A", "[1080::8:800:200C:41
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
 
 
-   Example 1.8.  compare_pure_ips usage
+   Example 1.11.  compare_pure_ips usage
 ...
 ...
 if (compare_pure_ips($si, "1080::8:800:200C:417A")) {
 if (compare_pure_ips($si, "1080::8:800:200C:417A")) {
   xlog("L_INFO", "both are the same IP\n");
   xlog("L_INFO", "both are the same IP\n");
 }
 }
 ...
 ...
 
 
-4.9.  is_ip_rfc1918 (ip)
+4.12.  is_ip_rfc1918 (ip)
 
 
    Returns TRUE if the argument is a private IPv4 according to RFC 1918.
    Returns TRUE if the argument is a private IPv4 according to RFC 1918.
    FALSE otherwise.
    FALSE otherwise.
@@ -319,14 +417,14 @@ if (compare_pure_ips($si, "1080::8:800:200C:417A")) {
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
 
 
-   Example 1.9.  is_ip_rfc1918 usage
+   Example 1.12.  is_ip_rfc1918 usage
 ...
 ...
 if (is_ip_rfc1918("10.0.123.123")) {
 if (is_ip_rfc1918("10.0.123.123")) {
   xlog("L_INFO", "it's a private IPv4\n");
   xlog("L_INFO", "it's a private IPv4\n");
 }
 }
 ...
 ...
 
 
-4.10.  is_in_subnet (ip, subnets_list)
+4.13.  is_in_subnet (ip, subnets_list)
 
 
    Returns TRUE if the first argument is an IP address within the (CIDR
    Returns TRUE if the first argument is an IP address within the (CIDR
    notation) subnets list in the second argument. FALSE otherwise.
    notation) subnets list in the second argument. FALSE otherwise.
@@ -339,7 +437,7 @@ if (is_ip_rfc1918("10.0.123.123")) {
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
 
 
-   Example 1.10.  is_in_subnet usage
+   Example 1.13.  is_in_subnet usage
 ...
 ...
 if (is_in_subnet("10.0.123.123", "10.0.123.1/24")) {
 if (is_in_subnet("10.0.123.123", "10.0.123.1/24")) {
   xlog("L_INFO", "it's in the subnet\n");
   xlog("L_INFO", "it's in the subnet\n");
@@ -350,7 +448,7 @@ if (is_in_subnet("10.0.123.123", "10.0.0.0/16,192.168.0.0/24")) {
 }
 }
 ...
 ...
 
 
-4.11.  dns_sys_match_ip(hostname, ipaddr)
+4.14.  dns_sys_match_ip(hostname, ipaddr)
 
 
    Returns TRUE if ipaddr is associated by DNS to hostname. FALSE
    Returns TRUE if ipaddr is associated by DNS to hostname. FALSE
    otherwise. It does not use the internal DNS resolver, but directly
    otherwise. It does not use the internal DNS resolver, but directly
@@ -366,14 +464,14 @@ if (is_in_subnet("10.0.123.123", "10.0.0.0/16,192.168.0.0/24")) {
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.11.  dns_sys_match_ip usage
+   Example 1.14.  dns_sys_match_ip usage
 ...
 ...
 if (!dns_sys_match_ip("myhost.com", "1.2.3.4")) {
 if (!dns_sys_match_ip("myhost.com", "1.2.3.4")) {
     xdbg("ip address not associated with hostname\n");
     xdbg("ip address not associated with hostname\n");
 }
 }
 ...
 ...
 
 
-4.12.  dns_int_match_ip(hostname, ipaddr)
+4.15.  dns_int_match_ip(hostname, ipaddr)
 
 
    Returns TRUE if ipaddr is associated by DNS to hostname. FALSE
    Returns TRUE if ipaddr is associated by DNS to hostname. FALSE
    otherwise. It uses internal DNS resolver. At this moment, the function
    otherwise. It uses internal DNS resolver. At this moment, the function
@@ -390,14 +488,14 @@ if (!dns_sys_match_ip("myhost.com", "1.2.3.4")) {
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.12.  dns_int_match_ip usage
+   Example 1.15.  dns_int_match_ip usage
 ...
 ...
 if (!dns_int_match_ip("myhost.com", "1.2.3.4")) {
 if (!dns_int_match_ip("myhost.com", "1.2.3.4")) {
     xdbg("ip address not associated with hostname\n");
     xdbg("ip address not associated with hostname\n");
 }
 }
 ...
 ...
 
 
-4.13.  dns_query(hostname, pvid)
+4.16.  dns_query(hostname, pvid)
 
 
    Store the IP addresses and their type that correspond to hostname in a
    Store the IP addresses and their type that correspond to hostname in a
    config variable $dns(pvid=>key).
    config variable $dns(pvid=>key).
@@ -409,7 +507,7 @@ if (!dns_int_match_ip("myhost.com", "1.2.3.4")) {
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.13.  dns_query usage
+   Example 1.16.  dns_query usage
 ...
 ...
 if(dns_query("test.com", "xyz"))
 if(dns_query("test.com", "xyz"))
 {
 {
@@ -425,7 +523,7 @@ if(dns_query("test.com", "xyz"))
 }
 }
 ...
 ...
 
 
-4.14.  srv_query(srvcname, pvid)
+4.17.  srv_query(srvcname, pvid)
 
 
    Queries DNS SRV records to resolve a service/protocol name into a list
    Queries DNS SRV records to resolve a service/protocol name into a list
    of priorities, weights, ports, and targets sorted by priority and
    of priorities, weights, ports, and targets sorted by priority and
@@ -451,7 +549,7 @@ if(dns_query("test.com", "xyz"))
      * target [index] - target host name
      * target [index] - target host name
      * weight [index] - weight number as defined by RFC 2782
      * weight [index] - weight number as defined by RFC 2782
 
 
-   Example 1.14.  srv_query usage
+   Example 1.17.  srv_query usage
 ...
 ...
 if (srv_query ("_sip._udp.example.com", "udp") > 0) {
 if (srv_query ("_sip._udp.example.com", "udp") > 0) {
   $var(cnt) = $srvquery(udp=>count);
   $var(cnt) = $srvquery(udp=>count);

+ 177 - 0
modules/ipops/detailed_ip_type.c

@@ -0,0 +1,177 @@
+/*
+ * $Id$
+ *
+ * Functions that operate on IP addresses
+ *
+ * Copyright (C) 2012 Hugh Waite (crocodile-rcs.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <unistd.h>
+#include "../../dprint.h"
+#include "../../trim.h"
+#include "../../str.h"
+#include "detailed_ip_type.h"
+
+static ip4_node IPv4ranges[IPv4RANGES_SIZE] = {
+        { 0xffffffff,  "BROADCAST",  0xffffffff },  // 255.255.255.255/32
+        { 0xcb007100,  "TEST-NET",   0xffffff00 },  // 203.0.113/24
+        { 0xc6336400,  "TEST-NET",   0xffffff00 },  // 198.51.100/24
+        { 0xc0586300,  "6TO4-RELAY", 0xffffff00 },  // 192.88.99.0/24
+        { 0xc0000200,  "TEST-NET",   0xffffff00 },  // 192.0.2/24
+        { 0xc0000000,  "RESERVED",   0xffffff00 },  // 192.0.0/24
+        { 0xc0a80000,  "PRIVATE",    0xffff0000 },  // 192.168/16
+        { 0xa9fe0000,  "LINK-LOCAL", 0xffff0000 },  // 169.254/16
+        { 0xc6120000,  "RESERVED",   0xfffe0000 },  // 198.18/15
+        { 0xac100000,  "PRIVATE",    0xfffe0000 },  // 172.16/12
+        { 0x64400000,  "SHARED",     0xffc00000 },  // 100.64/10
+        { 0x7f000000,  "LOOPBACK",   0xff000000 },  // 127.0/8
+        { 0x0a000000,  "PRIVATE",    0xff000000 },  // 10/8
+        { 0x0,         "PRIVATE",    0xff000000 },  // 0/8
+        { 0xf0000000,  "RESERVED",   0xf0000000 },  // 240/4
+        { 0xe0000000,  "MULTICAST",  0xf0000000 }   // 224/4
+};
+
+static  ip6_node IPv6ranges[IPv6RANGES_SIZE] = {
+    { {0x00000000, 0x00000000, 0x00000000, 0x00000000} , "UNSPECIFIED",         {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} },  //::/128
+    { {0x00000000, 0x00000000, 0x00000000, 0x00000001} , "LOOPBACK",            {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} },  //::1/128
+    { {0x00000000, 0x00000000, 0x0000FFFF, 0x00000000} , "IPV4MAP",             {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000} },  //::FFFF:0:0/96
+    { {0x01000000, 0x00000000, 0x00000000, 0x00000000} , "DISCARD",             {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000} },  //0100::/64
+    { {0x20010002, 0x00000000, 0x00000000, 0x00000000} , "BMWG",                {0xFFFFFFFF, 0xFFFF0000, 0x00000000, 0x00000000} },  //2001:0002::/48
+    { {0x20010000, 0x00000000, 0x00000000, 0x00000000} , "TEREDO",              {0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000} },  //2001::/32
+    { {0x20010DB8, 0x00000000, 0x00000000, 0x00000000} , "DOCUMENTATION",       {0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000} },  //2001:DB8::/32
+    { {0x20010010, 0x00000000, 0x00000000, 0x00000000} , "ORCHID",              {0xFFFFFFF0, 0x00000000, 0x00000000, 0x00000000} },  //2001:10::/28
+    { {0x20020000, 0x00000000, 0x00000000, 0x00000000} , "6TO4",                {0xFFFF0000, 0x00000000, 0x00000000, 0x00000000} },  //2002::/16
+    { {0xFEC00000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xFFC00000, 0x00000000, 0x00000000, 0x00000000} },  //FEC0::/10
+    { {0xFE800000, 0x00000000, 0x00000000, 0x00000000} , "LINK-LOCAL-UNICAST",  {0xFFc00000, 0x00000000, 0x00000000, 0x00000000} },  //FE80::/10
+    { {0xFE000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xFF800000, 0x00000000, 0x00000000, 0x00000000} },  //FE00::/9
+    { {0x00000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xFF000000, 0x00000000, 0x00000000, 0x00000000} },  //::/8
+    { {0x01000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xFF000000, 0x00000000, 0x00000000, 0x00000000} },  //0100::/8
+    { {0xFF000000, 0x00000000, 0x00000000, 0x00000000} , "MULTICAST",           {0xFF000000, 0x00000000, 0x00000000, 0x00000000} },  //FF00::/8
+    { {0x02000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xFE000000, 0x00000000, 0x00000000, 0x00000000} },  //0200::/7
+    { {0xFC000000, 0x00000000, 0x00000000, 0x00000000} , "UNIQUE-LOCAL-UNICAST",{0xFE000000, 0x00000000, 0x00000000, 0x00000000} },  //FC00::/7
+    { {0x04000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xFC000000, 0x00000000, 0x00000000, 0x00000000} },  //400::/6
+    { {0xF8000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xFC000000, 0x00000000, 0x00000000, 0x00000000} },  //F800::/6
+    { {0x08000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xF8000000, 0x00000000, 0x00000000, 0x00000000} },  //0800::/5
+    { {0xF0000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xF8000000, 0x00000000, 0x00000000, 0x00000000} },  //F000::/5
+    { {0xE0000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xF0000000, 0x00000000, 0x00000000, 0x00000000} },  //E000::/4
+    { {0x10000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xF0000000, 0x00000000, 0x00000000, 0x00000000} },  //1000::/4
+    { {0xC0000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xE0000000, 0x00000000, 0x00000000, 0x00000000} },  //C000::/3
+    { {0x20000000, 0x00000000, 0x00000000, 0x00000000} , "GLOBAL-UNICAST",      {0xE0000000, 0x00000000, 0x00000000, 0x00000000} },  //2000::/3
+    { {0x40000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xE0000000, 0x00000000, 0x00000000, 0x00000000} },  //4000::/3
+    { {0x60000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xE0000000, 0x00000000, 0x00000000, 0x00000000} },  //6000::/3
+    { {0x80000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xE0000000, 0x00000000, 0x00000000, 0x00000000} },  //8000::/3
+    { {0xA0000000, 0x00000000, 0x00000000, 0x00000000} , "RESERVED",            {0xE0000000, 0x00000000, 0x00000000, 0x00000000} }   //A000::/3
+
+};
+
+
+int ip6_iptype(str string_ip, char **res)
+{
+  uint32_t in6_addr[4];
+  char in6_string[INET6_ADDRSTRLEN];
+  int i;
+
+  trim(&string_ip);
+  if (string_ip.len >= INET6_ADDRSTRLEN)
+        return 0;
+
+  memcpy(in6_string, string_ip.s, string_ip.len);
+  in6_string[string_ip.len] = '\0';
+
+  if (inet_pton(AF_INET6, in6_string, in6_addr) != 1)  return 0;
+
+  for (i = 0; i < IPv6RANGES_SIZE; i++) {
+      if (((in6_addr[0] & IPv6ranges[i].sub_mask[0]) == IPv6ranges[i].value[0]) &&
+          ((in6_addr[1] & IPv6ranges[i].sub_mask[1]) == IPv6ranges[i].value[1]) &&
+          ((in6_addr[2] & IPv6ranges[i].sub_mask[2]) == IPv6ranges[i].value[2]) &&
+          ((in6_addr[3] & IPv6ranges[i].sub_mask[3]) == IPv6ranges[i].value[3])) {
+          *res = IPv6ranges[i].ip_type;
+          return 1;
+      }
+  }
+  /* the ip must be in the interval, else there is some problem */
+  return 0;
+}
+
+int ip4_iptype(str string_ip, char **res)
+{
+  uint32_t in4_addr;
+  char in4_string[INET_ADDRSTRLEN];
+  int i;
+
+  trim(&string_ip);
+  if (string_ip.len >= INET_ADDRSTRLEN)
+      return 0;
+
+  memcpy(in4_string, string_ip.s, string_ip.len);
+  in4_string[string_ip.len] = '\0';
+
+  if (inet_pton(AF_INET, in4_string, &in4_addr) != 1)  return 0;
+
+  *res = "PUBLIC";
+  for (i = 0; i < IPv4RANGES_SIZE; i++) {
+      if ( (in4_addr & IPv4ranges[i].sub_mask) == IPv4ranges[i].value ) {
+          *res = IPv4ranges[i].ip_type;
+          return 1;
+      }
+  }
+  return 1;
+}
+
+void ipv4ranges_hton() {
+    int pos;
+    uint32_t tmp;
+
+    for (pos=0; pos < IPv4RANGES_SIZE; pos++) {
+        tmp = IPv4ranges[pos].value;
+        IPv4ranges[pos].value = ntohl(tmp);
+        tmp = IPv4ranges[pos].sub_mask;
+        IPv4ranges[pos].sub_mask = ntohl(tmp);
+    }
+}
+
+void ipv6ranges_hton() {
+    int pos;
+    uint32_t tmp;
+
+    for (pos=0; pos < IPv6RANGES_SIZE; pos++) {
+        tmp = IPv6ranges[pos].value[0];
+        IPv6ranges[pos].value[0] = ntohl(tmp);
+        tmp = IPv6ranges[pos].value[1];
+        IPv6ranges[pos].value[1] = ntohl(tmp);
+        tmp = IPv6ranges[pos].value[2];
+        IPv6ranges[pos].value[2] = ntohl(tmp);
+        tmp = IPv6ranges[pos].value[3];
+        IPv6ranges[pos].value[3] = ntohl(tmp);
+
+        tmp = IPv6ranges[pos].sub_mask[0];
+        IPv6ranges[pos].sub_mask[0] = ntohl(tmp);
+        tmp = IPv6ranges[pos].sub_mask[1];
+        IPv6ranges[pos].sub_mask[1] = ntohl(tmp);
+        tmp = IPv6ranges[pos].sub_mask[2];
+        IPv6ranges[pos].sub_mask[2] = ntohl(tmp);
+        tmp = IPv6ranges[pos].sub_mask[3];
+        IPv6ranges[pos].sub_mask[3] = ntohl(tmp);
+    }
+}

+ 53 - 0
modules/ipops/detailed_ip_type.h

@@ -0,0 +1,53 @@
+/*
+ * $Id$
+ *
+ * Functions that operate on IP addresses
+ *
+ * Copyright (C) 2012 Hugh Waite (crocodile-rcs.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+#ifndef _IPOPS_DETAILED_IP_TYPE_H
+#define _IPOPS_DETAILED_IP_TYPE_H
+
+#define IPv4RANGES_SIZE 16
+#define IPv6RANGES_SIZE 29
+
+#include <stdint.h>
+#include "../../str.h"
+
+typedef struct ip4_node {
+    uint32_t value;
+    char *ip_type;
+    uint32_t sub_mask;
+} ip4_node;
+
+typedef struct ip6_node {
+    uint32_t value[4];
+    char *ip_type;
+    uint32_t sub_mask[4];
+} ip6_node;
+
+void ipv6ranges_hton();
+void ipv4ranges_hton();
+int ip6_iptype(str string_ip, char **res);
+int ip4_iptype(str string_ip, char **res);
+
+#endif

+ 199 - 0
modules/ipops/doc/ipops_admin.xml

@@ -359,6 +359,205 @@ switch($rc) {
 
 
     </section>
     </section>
 
 
+    <section id="ipops.f.detailed_ip_type">
+      <title>
+        <function moreinfo="none">detailed_ip_type (ip, result)</function>
+      </title>
+
+      <para>
+        Returns the detailed type of the given IP () (see http://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.txt, http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.txt, RFC 5735 and RFC 6598: PRIVATE, SHARED, LOOPBACK, IPV4MAP, DISCARD etc).
+      </para>
+
+      <para>Parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>ip</emphasis> - String or pseudo-variable containing the IP to evaluate.
+          </para>
+	</listitem>
+        <listitem> 
+   	  <para>
+            <emphasis>result</emphasis> - String or pseudo-variable containing the detailed type of the IP.
+          </para>
+          <para>
+            <itemizedlist>
+              <listitem>  
+		<emphasis> IPv4 </emphasis> - PUBLIC, RIVATE, SHARED, LOOPBACK, LINK-LOCAL, RESERVED, TEST-NET, 6TO4-RELAY, MULTICAST, BROADCAST     
+ 	      </listitem>
+	      <listitem>  
+		<emphasis> IPv6 </emphasis> - UNSPECIFIED,  LOOPBACK, IPV4MAP, RESERVED, DISCARD, GLOBAL-UNICAST, TEREDO, BMWG, DOCUMENTATION, ORCHID, 6TO4, UNIQUE-LOCAL-UNICAST, LINK-LOCAL-UNICAST, MULTICAST     
+ 	      </listitem>              
+  	    </itemizedlist>		
+	  </para>	
+        </listitem>
+      </itemizedlist>
+
+      <para>Return value:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>1</emphasis> - successful operation
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <emphasis>negative value</emphasis> - error occured
+          </para>
+        </listitem>       
+      </itemizedlist>
+
+      <para>
+        This function can be used from ALL ROUTES
+      </para>
+
+      <example>
+        <title>
+          <function>detailed_ip_type</function> usage
+        </title>
+        <programlisting format="linespecific">
+...
+    detailed_ip_type("192.168.1.2","$var(result)");
+    xlog("L_ERR","IP address is of detailed type: $var(result) ");
+...
+        </programlisting>
+      </example>
+
+    </section>
+
+    <section id="ipops.f.detailed_ipv4_type">
+      <title>
+        <function moreinfo="none">detailed_ipv4_type (ip, result)</function>
+      </title>
+
+      <para>
+        Returns the detailed type of the given IP () (see RFC 5735 and RFC 6598).
+      </para>
+
+      <para>Parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>ip</emphasis> - String or pseudo-variable containing the IP to evaluate.
+          </para>
+	</listitem>
+        <listitem> 
+   	  <para>
+            <emphasis>result</emphasis> - String or pseudo-variable containing the detailed type of the IP.
+          </para>
+          <para>
+            <itemizedlist>
+              <listitem>  
+		<emphasis> IPv4 </emphasis> - PUBLIC, PRIVATE, SHARED, LOOPBACK, LINK-LOCAL, RESERVED, TEST-NET, 6TO4-RELAY, MULTICAST, BROADCAST     
+ 	      </listitem>	                 
+  	    </itemizedlist>		
+	  </para>	
+        </listitem>
+      </itemizedlist>
+
+      <para>Return value:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>1</emphasis> - successful operation
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <emphasis>negative value</emphasis> - error occured
+          </para>
+        </listitem>       
+      </itemizedlist>
+
+      <para>
+        This function can be used from ALL ROUTES
+      </para>
+
+      <example>
+        <title>
+          <function>detailed_ipv4_type</function> usage
+        </title>
+        <programlisting format="linespecific">
+...
+    detailed_ipv4_type("192.168.1.2","$var(result)");
+    xlog("L_ERR","IP address is of detailed type: $var(result) ");
+...
+        </programlisting>
+      </example>
+
+    </section>	
+
+    <section id="ipops.f.detailed_ipv6_type">
+      <title>
+        <function moreinfo="none">detailed_ipv6_type (ip, result)</function>
+      </title>
+
+      <para>
+        Returns the detailed type of the given IP () (see http://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.txt, http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.txt).
+      </para>
+
+      <para>Parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>ip</emphasis> - String or pseudo-variable containing the IP to evaluate.
+          </para>
+	</listitem>
+        <listitem> 
+   	  <para>
+            <emphasis>result</emphasis> - String or pseudo-variable containing the detailed type of the IP.
+          </para>
+          <para>
+            <itemizedlist>
+              <listitem>  
+		<emphasis> IPv6 </emphasis> - UNSPECIFIED,  LOOPBACK, IPV4MAP, RESERVED, DISCARD, GLOBAL-UNICAST, TEREDO, BMWG, DOCUMENTATION, ORCHID, 6TO4, UNIQUE-LOCAL-UNICAST, LINK-LOCAL-UNICAST, MULTICAST    
+ 	      </listitem>	                 
+  	    </itemizedlist>		
+	  </para>	
+        </listitem>
+      </itemizedlist>
+
+      <para>Return value:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <emphasis>1</emphasis> - successful operation
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <emphasis>negative value</emphasis> - error occured
+          </para>
+        </listitem>       
+      </itemizedlist>
+
+      <para>
+        This function can be used from ALL ROUTES
+      </para>
+
+      <example>
+        <title>
+          <function>detailed_ipv6_type</function> usage
+        </title>
+        <programlisting format="linespecific">
+...
+    detailed_ipv6_type("2001:8d8:7c0:402:217:72:194:30","$var(result)");
+    xlog("L_ERR","IP address is of detailed type: $var(result) ");
+
+    detailed_ipv6_type("[2001:8d8:7c0:402:217:72:194:30]","$var(result)");
+    xlog("L_ERR","IP address is of detailed type: $var(result) ");	
+...
+        </programlisting>
+      </example>
+
+    </section>	
+
+
     <section id="ipops.f.compare_ips">
     <section id="ipops.f.compare_ips">
       <title>
       <title>
         <function moreinfo="none">compare_ips (ip1, ip2)</function>
         <function moreinfo="none">compare_ips (ip1, ip2)</function>

+ 134 - 2
modules/ipops/ipops_mod.c

@@ -51,10 +51,12 @@
 #include "../../mod_fix.h"
 #include "../../mod_fix.h"
 #include "../../pvar.h"
 #include "../../pvar.h"
 #include "../../resolve.h"
 #include "../../resolve.h"
+#include "../../lvalue.h"
 #include "api.h"
 #include "api.h"
 #include "ipops_pv.h"
 #include "ipops_pv.h"
 #include "ip_parser.h"
 #include "ip_parser.h"
 #include "rfc1918_parser.h"
 #include "rfc1918_parser.h"
+#include "detailed_ip_type.h"
 
 
 MODULE_VERSION
 MODULE_VERSION
 
 
@@ -80,6 +82,7 @@ int _ip_is_in_subnet_v4(struct in_addr *ip, char *net, size_t netlen, int netmas
 int _ip_is_in_subnet_v6(struct in6_addr *ip, char *net, size_t netlen, int netmask);
 int _ip_is_in_subnet_v6(struct in6_addr *ip, char *net, size_t netlen, int netmask);
 int _ip_is_in_subnet_str(void *ip, enum enum_ip_type type, char *s, int slen);
 int _ip_is_in_subnet_str(void *ip, enum enum_ip_type type, char *s, int slen);
 int _ip_is_in_subnet_str_trimmed(void *ip, enum enum_ip_type type, char *b, char *e);
 int _ip_is_in_subnet_str_trimmed(void *ip, enum enum_ip_type type, char *b, char *e);
+static int _detailed_ip_type(unsigned int _type, struct sip_msg* _msg, char* _s,  char *_dst);
 
 
 
 
 /*
 /*
@@ -91,15 +94,20 @@ static int w_is_ipv4(struct sip_msg*, char*);
 static int w_is_ipv6(struct sip_msg*, char*);
 static int w_is_ipv6(struct sip_msg*, char*);
 static int w_is_ipv6_reference(struct sip_msg*, char*);
 static int w_is_ipv6_reference(struct sip_msg*, char*);
 static int w_ip_type(struct sip_msg*, char*);
 static int w_ip_type(struct sip_msg*, char*);
+static int w_detailed_ipv6_type(struct sip_msg* _msg, char* _s,  char *res);
+static int w_detailed_ipv4_type(struct sip_msg* _msg, char* _s,  char *res);
+static int w_detailed_ip_type(struct sip_msg* _msg, char* _s,  char *res);
 static int w_compare_ips(struct sip_msg*, char*, char*);
 static int w_compare_ips(struct sip_msg*, char*, char*);
 static int w_compare_pure_ips(struct sip_msg*, char*, char*);
 static int w_compare_pure_ips(struct sip_msg*, char*, char*);
 static int w_is_ip_rfc1918(struct sip_msg*, char*);
 static int w_is_ip_rfc1918(struct sip_msg*, char*);
 static int w_ip_is_in_subnet(struct sip_msg*, char*, char*);
 static int w_ip_is_in_subnet(struct sip_msg*, char*, char*);
 static int w_dns_sys_match_ip(sip_msg_t*, char*, char*);
 static int w_dns_sys_match_ip(sip_msg_t*, char*, char*);
 static int w_dns_int_match_ip(sip_msg_t*, char*, char*);
 static int w_dns_int_match_ip(sip_msg_t*, char*, char*);
-
+static int fixup_detailed_ip_type(void** param, int param_no);
+static int fixup_free_detailed_ip_type(void** param, int param_no);
 static int w_dns_query(struct sip_msg* msg, char* str1, char* str2);
 static int w_dns_query(struct sip_msg* msg, char* str1, char* str2);
 static int w_srv_query(struct sip_msg* msg, char* str1, char* str2);
 static int w_srv_query(struct sip_msg* msg, char* str1, char* str2);
+static int mod_init(void);
 
 
 static pv_export_t mod_pvs[] = {
 static pv_export_t mod_pvs[] = {
 	{ {"dns", sizeof("dns")-1}, PVT_OTHER, pv_get_dns, 0,
 	{ {"dns", sizeof("dns")-1}, PVT_OTHER, pv_get_dns, 0,
@@ -128,6 +136,12 @@ static cmd_export_t cmds[] =
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
 	{ "ip_type", (cmd_function)w_ip_type, 1, fixup_spve_null, 0,
 	{ "ip_type", (cmd_function)w_ip_type, 1, fixup_spve_null, 0,
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
+	{ "detailed_ipv4_type", (cmd_function)w_detailed_ipv4_type, 2,
+		fixup_detailed_ip_type, fixup_free_detailed_ip_type, ANY_ROUTE },
+	{ "detailed_ipv6_type", (cmd_function)w_detailed_ipv6_type, 2,
+		fixup_detailed_ip_type, fixup_free_detailed_ip_type, ANY_ROUTE },
+	{ "detailed_ip_type", (cmd_function)w_detailed_ip_type, 2,
+		fixup_detailed_ip_type, fixup_free_detailed_ip_type, ANY_ROUTE },
 	{ "compare_ips", (cmd_function)w_compare_ips, 2, fixup_spve_spve, 0,
 	{ "compare_ips", (cmd_function)w_compare_ips, 2, fixup_spve_spve, 0,
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
 	{ "compare_pure_ips", (cmd_function)w_compare_pure_ips, 2, fixup_spve_spve, 0,
 	{ "compare_pure_ips", (cmd_function)w_compare_pure_ips, 2, fixup_spve_spve, 0,
@@ -161,13 +175,64 @@ struct module_exports exports = {
 	0,                         /*!< exported MI functions */
 	0,                         /*!< exported MI functions */
 	mod_pvs,                   /*!< exported pseudo-variables */
 	mod_pvs,                   /*!< exported pseudo-variables */
 	0,                         /*!< extra processes */
 	0,                         /*!< extra processes */
-	0,                         /*!< module initialization function */
+	mod_init,                  /*!< module initialization function */
 	(response_function) 0,     /*!< response handling function */
 	(response_function) 0,     /*!< response handling function */
 	0,                         /*!< destroy function */
 	0,                         /*!< destroy function */
 	0                          /*!< per-child init function */
 	0                          /*!< per-child init function */
 };
 };
 
 
 
 
+static int mod_init(void) {
+    /* turn detailed_ip_type relevant structures to netowork byte order so no need to
+     * transform each ip to host order before comparing */
+    ipv4ranges_hton();
+    ipv6ranges_hton();
+    return 0;
+}
+
+
+/* Fixup functions */
+
+/*
+ * Fix detailed_ipv6_type param: result (writable pvar).
+ */
+static int fixup_detailed_ip_type(void** param, int param_no)
+{
+    if (param_no == 1) {
+        return fixup_spve_null(param, 1);
+    }
+
+    if (param_no == 2) {
+        if (fixup_pvar_null(param, 1) != 0) {
+            LM_ERR("failed to fixup result pvar\n");
+            return -1;
+        }
+        if (((pv_spec_t *) (*param))->setf == NULL) {
+            LM_ERR("result pvar is not writeble\n");
+            return -1;
+        }
+        return 0;
+    }
+
+    LM_ERR("invalid parameter number <%d>\n", param_no);
+    return -1;
+}
+
+static int fixup_free_detailed_ip_type(void** param, int param_no)
+{
+    if (param_no == 1) {
+    //LM_WARN("free function has not been defined for spve\n");
+    return 0;
+    }
+
+    if (param_no == 2) {
+    return fixup_free_pvar_null(param, 1);
+    }
+
+    LM_ERR("invalid parameter number <%d>\n", param_no);
+    return -1;
+}
+
 /*
 /*
  * Module internal functions
  * Module internal functions
  */
  */
@@ -577,6 +642,73 @@ static int w_ip_type(struct sip_msg* _msg, char* _s)
 	}
 	}
 }
 }
 
 
+static int w_detailed_ipv4_type(struct sip_msg* _msg, char* _s,  char *_dst)
+{
+    return _detailed_ip_type(ip_type_ipv4, _msg, _s, _dst);
+}
+
+static int w_detailed_ipv6_type(struct sip_msg* _msg, char* _s,  char *_dst)
+{
+    return _detailed_ip_type(ip_type_ipv6, _msg, _s, _dst);
+}
+
+static int w_detailed_ip_type(struct sip_msg* _msg, char* _s,  char *_dst)
+{
+    /* `ip_type_error` should read `unknown type` */
+    return _detailed_ip_type(ip_type_error, _msg, _s, _dst);
+}
+
+static int _detailed_ip_type(unsigned int _type, struct sip_msg* _msg, char* _s,  char *_dst)
+{
+  str string;
+  pv_spec_t *dst;
+  pv_value_t val;
+  char *res;
+  unsigned int assumed_type;
+
+  if (_s == NULL) {
+    LM_ERR("bad parameter\n");
+    return -2;
+  }
+
+  if (fixup_get_svalue(_msg, (gparam_p)_s, &string))
+  {
+    LM_ERR("cannot print the format for string\n");
+    return -3;
+  }
+
+  assumed_type = (ip_type_error == _type)? ip_parser_execute(string.s, string.len) : _type;
+
+  switch (assumed_type) {
+      case ip_type_ipv4:
+          if (!ip4_iptype(string, &res)) {
+              LM_ERR("bad ip parameter\n");
+              return -1;
+          }
+          break;
+      case ip_type_ipv6_reference:
+      case ip_type_ipv6:
+          /* consider this reference */
+          if (string.s[0] == '[') {
+              string.s++;
+              string.len -= 2;
+          }
+          if (!ip6_iptype(string, &res)) {
+              LM_ERR("bad ip parameter\n");
+              return -1;
+          }
+          break;
+      default:
+          return -1;
+  }
+
+  val.rs.s = res;
+  val.rs.len = strlen(res);
+  val.flags = PV_VAL_STR;
+  dst = (pv_spec_t *)_dst;
+  dst->setf(_msg, &dst->pvp, (int)EQ_T, &val);
+  return 1;
+}
 
 
 /*! \brief Return true if both IP's (string or pv) are equal. This function also allows comparing an IPv6 with an IPv6 reference. */
 /*! \brief Return true if both IP's (string or pv) are equal. This function also allows comparing an IPv6 with an IPv6 reference. */
 static int w_compare_ips(struct sip_msg* _msg, char* _s1, char* _s2)
 static int w_compare_ips(struct sip_msg* _msg, char* _s1, char* _s2)