Browse Source

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 years ago
parent
commit
2cf9dbadfc

+ 146 - 48
modules/ipops/README

@@ -32,14 +32,17 @@ Iñaki Baz Castillo
               4.4. is_ipv6 (ip)
               4.5. is_ipv6_reference (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
 
@@ -49,14 +52,17 @@ Iñaki Baz Castillo
    1.4. is_ipv6 usage
    1.5. is_ipv6_reference 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
 
@@ -77,14 +83,17 @@ Chapter 1. Admin Guide
         4.4. is_ipv6 (ip)
         4.5. is_ipv6_reference (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
 
@@ -132,14 +141,17 @@ Chapter 1. Admin Guide
    4.4. is_ipv6 (ip)
    4.5. is_ipv6_reference (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)
 
@@ -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
    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,
    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
 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
    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,
    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")) {
   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.
    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,
    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")) {
   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
    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,
    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")) {
   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
    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.
 
-   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")) {
     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
    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.
 
-   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")) {
     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
    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.
 
-   Example 1.13.  dns_query usage
+   Example 1.16.  dns_query usage
 ...
 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
    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
      * 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) {
   $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 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">
       <title>
         <function moreinfo="none">compare_ips (ip1, ip2)</function>

+ 134 - 2
modules/ipops/ipops_mod.c

@@ -51,10 +51,12 @@
 #include "../../mod_fix.h"
 #include "../../pvar.h"
 #include "../../resolve.h"
+#include "../../lvalue.h"
 #include "api.h"
 #include "ipops_pv.h"
 #include "ip_parser.h"
 #include "rfc1918_parser.h"
+#include "detailed_ip_type.h"
 
 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_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);
+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_reference(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_pure_ips(struct sip_msg*, char*, 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_dns_sys_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_srv_query(struct sip_msg* msg, char* str1, char* str2);
+static int mod_init(void);
 
 static pv_export_t mod_pvs[] = {
 	{ {"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 },
 	{ "ip_type", (cmd_function)w_ip_type, 1, fixup_spve_null, 0,
 		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,
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
 	{ "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 */
 	mod_pvs,                   /*!< exported pseudo-variables */
 	0,                         /*!< extra processes */
-	0,                         /*!< module initialization function */
+	mod_init,                  /*!< module initialization function */
 	(response_function) 0,     /*!< response handling function */
 	0,                         /*!< destroy 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
  */
@@ -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. */
 static int w_compare_ips(struct sip_msg* _msg, char* _s1, char* _s2)