Kris Rice made mention on Twitter about the free (but limited lifetime) IP address to Country mappings that you can get from Maxmind.
If you ever need to deal with IP addresses, you might find the following utility package I wrote a while back useful. It lets you convert from the string representation of an IP address to its numeric equivalent, and vice-versa. It handles IPv4 and IPv6 with one caveat being that that I didn’t bother with the collapsed zeros for IPv6 so I could keep the performance snappy. Free for your use without warranty or responsibility
SQL> create or replace
2 package ip_util is
3
4 function ip_num_from_str(p_ip_str varchar2) return number deterministic;
5 function ip_str_from_num(p_ipnum number) return varchar2 deterministic;
6
7 end;
8 /
Package created.
SQL>
SQL>
SQL> create or replace
2 package body ip_util is
3
4 --
5 -- constants need to be fixed, not expressions if you want to avoid ora-4068
6 --
7 l_ip41 constant number(12) := 256; -- power(256,1);
8 l_ip42 constant number(12) := 65536; -- power(256,2);
9 l_ip43 constant number(12) := 16777216; -- power(256,3);
10 l_ip44 constant number(12) := 4294967296; -- power(256,4);
11
12 l_ip61 constant number(38) := 65536; --power(65536,1);
13 l_ip62 constant number(38) := 4294967296; --power(65536,2);
14 l_ip63 constant number(38) := 281474976710656; --power(65536,3);
15 l_ip64 constant number(38) := 18446744073709551616; --power(65536,4);
16 l_ip65 constant number(38) := 1208925819614629174706176; --power(65536,5);
17 l_ip66 constant number(38) := 79228162514264337593543950336; --power(65536,6);
18 l_ip67 constant number(38) := 5192296858534827628530496329220096; --power(65536,7);
19
20
21 function ip_num_from_str(p_ip_str varchar2) return number deterministic is
22 l_ip_num number;
23 l_dot1 pls_integer;
24 l_dot2 pls_integer;
25 l_dot3 pls_integer;
26 l_dot4 pls_integer;
27
28 l_colon pls_integer;
29 l_colon_cnt pls_integer;
30 l_hex varchar2(32);
31 l_ip_str varchar2(64);
32 begin
33 if p_ip_str like '%.%' then
34 l_dot1 := instr(p_ip_str,'.');
35 l_dot2 := instr(p_ip_str,'.',l_dot1+1);
36 l_dot3 := instr(p_ip_str,'.',l_dot2+1);
37 l_dot4 := instr(p_ip_str,'.',l_dot3+1);
38 if l_dot4 > 0 then
39 raise_application_error(-20000,'Cannot be resolved to an IP4 address');
40 end if;
41
42 l_ip_num := l_ip43*to_number(substr(p_ip_str,1,l_dot1-1)) +
43 l_ip42*to_number(substr(p_ip_str,l_dot1+1,l_dot2-l_dot1-1)) +
44 l_ip41*to_number(substr(p_ip_str,l_dot2+1,l_dot3-l_dot2-1)) +
45 to_number(substr(p_ip_str,l_dot3+1));
46
47 elsif p_ip_str like '%:%' then
48 --
49 -- Note: The abbreviation of "Consecutive sections of zeroes are replaced with a double colon (::)" is not implemented.
50 --
51 l_colon_cnt := length(p_ip_str)-length(replace(p_ip_str,':'));
52 if l_colon_cnt != 7 then
53 raise_application_error(-20000,'Cannot be resolved to an IP6 address');
54 end if;
55
56 l_ip_str := p_ip_str||':';
57 loop
58 l_colon := instr(l_ip_str,':');
59 l_hex := l_hex || lpad(substr(l_ip_str,1,l_colon-1),4,'0');
60 l_ip_str := substr(l_ip_str,l_colon+1);
61 exit when l_ip_str is null;
62 end loop;
63 l_ip_num := to_number(l_hex,'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
64 end if;
65
66 return l_ip_num;
67 end;
68
69
70 function ip_str_from_num(p_ipnum number) return varchar2 deterministic is
71 begin
72 if p_ipnum < l_ip44 then
73 return mod(trunc(p_ipnum/l_ip43),l_ip41) ||'.'||
74 mod(trunc(p_ipnum/l_ip42),l_ip41) ||'.'||
75 mod(trunc(p_ipnum/l_ip41),l_ip41) ||'.'||
76 mod(p_ipnum,l_ip41);
77 else
78 --
79 -- Note: The abbreviation of "Consecutive sections of zeroes are replaced with a double colon (::)" is not implemented.
80 --
81 return to_char(mod(trunc(p_ipnum/l_ip67),l_ip61),'fmxxxx') ||':'||
82 to_char(mod(trunc(p_ipnum/l_ip66),l_ip61),'fmxxxx') ||':'||
83 to_char(mod(trunc(p_ipnum/l_ip65),l_ip61),'fmxxxx') ||':'||
84 to_char(mod(trunc(p_ipnum/l_ip64),l_ip61),'fmxxxx') ||':'||
85 to_char(mod(trunc(p_ipnum/l_ip63),l_ip61),'fmxxxx') ||':'||
86 to_char(mod(trunc(p_ipnum/l_ip62),l_ip61),'fmxxxx') ||':'||
87 to_char(mod(trunc(p_ipnum/l_ip61),l_ip61),'fmxxxx') ||':'||
88 to_char(mod(p_ipnum,l_ip61),'fmxxxx');
89 end if;
90 end;
91
92 end;
93 /
Package body created.
SQL> select ip_util.ip_num_from_str('192.168.1.2') from dual;
IP_UTIL.IP_NUM_FROM_STR('192.168.1.2')
--------------------------------------
3232235778
SQL> select ip_util.ip_str_from_num(3232235778) from dual;
IP_UTIL.IP_STR_FROM_NUM(3232235778)
-----------------------------------------------------------------------------------------------------------------
192.168.1.2
SQL> select ip_util.ip_num_from_str('2001:db8:0:0:0:ff00:42:8329') ip from dual;
IP
--------------------------------------------
42540766411282592856904265327123268393
SQL> select ip_util.ip_str_from_num(42540766411282592856904265327123268393) from dual;
IP_UTIL.IP_STR_FROM_NUM(42540766411282592856904265327123268393)
-----------------------------------------------------------------------------------------------------------------
2001:db8:0:0:0:ff00:42:8329