Browse code

geoip2: new module exporting geoip API to configuration file

- uses the latest version of maxmind API/library
- has support for IPv6
- can be used instead of geoip module

Sergey Okhapkin authored on 03/02/2015 15:32:03 • Daniel-Constantin Mierla committed on 03/02/2015 15:32:03
Showing 8 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,15 @@
1
+# $Id$
2
+#
3
+# WARNING: do not run this directly, it should be run by the master Makefile
4
+
5
+include ../../Makefile.defs
6
+auto_gen=
7
+NAME=geoip2.so
8
+LIBS= -lmaxminddb
9
+
10
+DEFS+=-DKAMAILIO_MOD_INTERFACE
11
+
12
+SERLIBPATH=../../lib
13
+SER_LIBS+=$(SERLIBPATH)/kmi/kmi
14
+
15
+include ../../Makefile.modules
0 16
new file mode 100644
... ...
@@ -0,0 +1,146 @@
1
+geoip2 Module
2
+
3
+Sergey Okhapkin
4
+
5
+   callwithus.com
6
+
7
+Edited by
8
+
9
+Daniel-Constantin Mierla
10
+
11
+   <miconda@gmail.com>
12
+
13
+   Copyright © 2010 Daniel-Constantin Mierla (asipto.com)
14
+     __________________________________________________________________
15
+
16
+   Table of Contents
17
+
18
+   1. Admin Guide
19
+
20
+        1. Overview
21
+        2. Dependencies
22
+
23
+              2.1. Kamailio Modules
24
+              2.2. External Libraries or Applications
25
+
26
+        3. Parameters
27
+
28
+              3.1. path (string)
29
+
30
+        4. Functions
31
+
32
+              4.1. geoip2_match(ipaddr, pvc)
33
+
34
+        5. Exported pseudo-variables
35
+
36
+   List of Examples
37
+
38
+   1.1. Set path parameter
39
+   1.2. geoip2_match usage
40
+
41
+Chapter 1. Admin Guide
42
+
43
+   Table of Contents
44
+
45
+   1. Overview
46
+   2. Dependencies
47
+
48
+        2.1. Kamailio Modules
49
+        2.2. External Libraries or Applications
50
+
51
+   3. Parameters
52
+
53
+        3.1. path (string)
54
+
55
+   4. Functions
56
+
57
+        4.1. geoip2_match(ipaddr, pvc)
58
+
59
+   5. Exported pseudo-variables
60
+
61
+1. Overview
62
+
63
+   This module allows real-time queries against the Max Mind GeoIP2
64
+   database to be performed from the config script.
65
+
66
+   The Max Mind GeoIP2 database is a map of IP network address assignments
67
+   to geographical locales that can be useful -- though approximate -- in
68
+   identifying the physical location with which an IP host address is
69
+   associated on a relatively granular level.
70
+
71
+   This database itself can be obtained on a free or commercial basis from
72
+   http://dev.maxmind.com/geoip/. The library libmaxminddb that interfaces
73
+   with the Max Mind API, as well as scripts to automate downloading of
74
+   the on-disk version are available at
75
+   http://dev.maxmind.com/geoip/geoip2/downloadable/.
76
+
77
+   This module exports a new class of pseudo-variables - $gip2(pvc=>key) -
78
+   to enable access to the results of a query to the database.
79
+
80
+   Many queries can be done and store results in different containers to
81
+   be able to use in parallel. Database is loaded at startup in cache.
82
+
83
+2. Dependencies
84
+
85
+   2.1. Kamailio Modules
86
+   2.2. External Libraries or Applications
87
+
88
+2.1. Kamailio Modules
89
+
90
+   The following modules must be loaded before this module:
91
+     * none.
92
+
93
+2.2. External Libraries or Applications
94
+
95
+   The following libraries or applications must be installed before
96
+   running Kamailio with this module loaded:
97
+     * libmaxminddb - the GeoIP2 library.
98
+
99
+3. Parameters
100
+
101
+   3.1. path (string)
102
+
103
+3.1. path (string)
104
+
105
+   Path to the GeoIP2 database file.
106
+
107
+   Default value is “null”.
108
+
109
+   Example 1.1. Set path parameter
110
+...
111
+modparam("geoip2", "path", "/usr/local/share/GeoIP/GeoLite2-City.mmdb")
112
+...
113
+
114
+4. Functions
115
+
116
+   4.1. geoip2_match(ipaddr, pvc)
117
+
118
+4.1.  geoip2_match(ipaddr, pvc)
119
+
120
+   Match ipaddr against the GeoIP database and set the pvc container. The
121
+   function has to be called before accessing a key via: $gip2(pvc=>key).
122
+
123
+   Example 1.2. geoip2_match usage
124
+...
125
+if(geoip2_match("$si", "src"))
126
+    xlog("SIP message from: $gip2(src=>cc)\n");
127
+...
128
+
129
+5. Exported pseudo-variables
130
+
131
+     * $gip2(pvc=>key) - pvc is an identifier for this query result; it is
132
+       designated by the second parameter of geoip2_match(). The key can
133
+       be one of the following:
134
+          + cc - country code
135
+          + tz - time zone
136
+          + zip - postal code
137
+          + lat - latitude
138
+          + lon - longitude
139
+          + nmask - network mask (CIDR format)
140
+          + city - city
141
+          + regc - region
142
+          + regn - region name
143
+          + metro - metro code
144
+
145
+   Exported pseudo-variables are documented at
146
+   http://www.kamailio.org/wiki/.
0 147
new file mode 100644
... ...
@@ -0,0 +1,4 @@
1
+docs = geoip2.xml
2
+
3
+docbook_dir = ../../../docbook
4
+include $(docbook_dir)/Makefile.module
0 5
new file mode 100644
... ...
@@ -0,0 +1,36 @@
1
+<?xml version="1.0" encoding='ISO-8859-1'?>
2
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
3
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
4
+
5
+<!-- Include general documentation entities -->
6
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
7
+%docentities;
8
+
9
+]>
10
+
11
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
12
+    <bookinfo>
13
+	<title>geoip2 Module</title>
14
+	<productname class="trade">&kamailioname;</productname>
15
+	<authorgroup>
16
+	    <author>
17
+		<firstname>Sergey</firstname>
18
+		<surname>Okhapkin</surname>
19
+		<affiliation><orgname>callwithus.com</orgname></affiliation>
20
+	    </author>
21
+	    <editor>
22
+		<firstname>Daniel-Constantin</firstname>
23
+		<surname>Mierla</surname>
24
+		    <email>miconda@gmail.com</email>
25
+	    </editor>
26
+	</authorgroup>
27
+	<copyright>
28
+	    <year>2010</year>
29
+	    <holder>Daniel-Constantin Mierla (asipto.com)</holder>
30
+	</copyright>
31
+    </bookinfo>
32
+    <toc></toc>
33
+    
34
+	<xi:include href="geoip2_admin.xml"/>
35
+    
36
+</book>
0 37
new file mode 100644
... ...
@@ -0,0 +1,175 @@
1
+<?xml version="1.0" encoding='ISO-8859-1'?>
2
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
3
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
4
+
5
+<!-- Include general documentation entities -->
6
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
7
+%docentities;
8
+
9
+]>
10
+
11
+<!-- Module User's Guide -->
12
+
13
+<chapter>
14
+    
15
+    <title>&adminguide;</title>
16
+    
17
+    <section>
18
+	<title>Overview</title>
19
+	<para>
20
+		This module allows real-time queries against the Max Mind GeoIP2 
21
+		database to be performed from the config script.  
22
+	</para>
23
+	<para>
24
+		The Max Mind GeoIP2 database is a map of IP network address assignments 
25
+		to geographical locales that can be useful -- though approximate --
26
+		in identifying the physical location with which an IP host address
27
+		is associated on a relatively granular level.
28
+	</para>
29
+	<para>
30
+		This database itself can be obtained on a free or commercial basis 
31
+		from <ulink url="http://dev.maxmind.com/geoip/">
32
+		http://dev.maxmind.com/geoip/</ulink>. The 
33
+		library libmaxminddb
34
+		that interfaces with the Max Mind API, as well as scripts to
35
+		automate downloading of the on-disk version are available at
36
+		<ulink url="http://dev.maxmind.com/geoip/geoip2/downloadable/">
37
+		http://dev.maxmind.com/geoip/geoip2/downloadable/</ulink>.
38
+	</para>
39
+	<para>
40
+		This module exports a new class of pseudo-variables -
41
+		$gip2(pvc=&gt;key) - to enable access to the results of a query to the
42
+		database.
43
+	</para>
44
+	<para>
45
+		Many queries can be done and store results in different containers to
46
+		be able to use in parallel. Database is loaded at startup in cache.
47
+	</para>
48
+    </section>
49
+    <section>
50
+	<title>Dependencies</title>
51
+	<section>
52
+	    <title>&kamailio; Modules</title>
53
+	    <para>
54
+		The following modules must be loaded before this module:
55
+	    	<itemizedlist>
56
+		    <listitem>
57
+			<para>
58
+			    <emphasis>none</emphasis>.
59
+			</para>
60
+		    </listitem>
61
+	    	</itemizedlist>
62
+	    </para>
63
+	</section>
64
+	<section>
65
+	    <title>External Libraries or Applications</title>
66
+	    <para>
67
+		The following libraries or applications must be installed before running
68
+		&kamailio; with this module loaded:
69
+	    	<itemizedlist>
70
+		    <listitem>
71
+			<para>
72
+			    <emphasis>libmaxminddb</emphasis> - the GeoIP2 library.
73
+			</para>
74
+		    </listitem>
75
+	    	</itemizedlist>
76
+	    </para>
77
+	</section>
78
+    </section>
79
+    <section>
80
+	<title>Parameters</title>
81
+	<section>
82
+	    <title><varname>path</varname> (string)</title>
83
+	    <para>
84
+		Path to the GeoIP2 database file.
85
+	    </para>
86
+	    <para>
87
+		<emphasis>
88
+		    Default value is <quote>null</quote>.
89
+		</emphasis>
90
+	    </para>
91
+	    <example>
92
+		<title>Set <varname>path</varname> parameter</title>
93
+		<programlisting format="linespecific">
94
+...
95
+modparam("geoip2", "path", "/usr/local/share/GeoIP/GeoLite2-City.mmdb")
96
+...
97
+</programlisting>
98
+	    </example>
99
+	</section>
100
+
101
+	</section>
102
+	
103
+    <section>
104
+	<title>Functions</title>
105
+ 	<section>
106
+	    <title>
107
+		<function moreinfo="none">geoip2_match(ipaddr, pvc)</function>
108
+	    </title>
109
+	    <para>
110
+			Match ipaddr against the GeoIP database and set the pvc container. The
111
+			function has to be called before accessing a key via: $gip2(pvc=&gt;key).
112
+	    </para>
113
+		<example>
114
+		<title><function>geoip2_match</function> usage</title>
115
+		<programlisting format="linespecific">
116
+...
117
+if(geoip2_match("$si", "src"))
118
+    xlog("SIP message from: $gip2(src=&gt;cc)\n");
119
+...
120
+</programlisting>
121
+	    </example>
122
+	</section>
123
+	
124
+    </section>
125
+	
126
+	<section>
127
+		<title>Exported pseudo-variables</title>
128
+		<itemizedlist>
129
+			<listitem><para>
130
+				<emphasis>$gip2(pvc=&gt;key)</emphasis> - <emphasis>pvc</emphasis> is an 
131
+				identifier for this query result;  it is designated by the second 
132
+				parameter of geoip2_match(). The <emphasis>key</emphasis> can be one of
133
+				the following:
134
+				</para>
135
+			<itemizedlist>
136
+				<listitem><para>
137
+					<emphasis>cc</emphasis> - country code
138
+				</para></listitem>
139
+				<listitem><para>
140
+					<emphasis>tz</emphasis> - time zone
141
+				</para></listitem>
142
+				<listitem><para>
143
+					<emphasis>zip</emphasis> - postal code
144
+				</para></listitem>
145
+				<listitem><para>
146
+					<emphasis>lat</emphasis> - latitude
147
+				</para></listitem>
148
+				<listitem><para>
149
+					<emphasis>lon</emphasis> - longitude
150
+				</para></listitem>
151
+				<listitem><para>
152
+					<emphasis>nmask</emphasis> - network mask (CIDR format)
153
+				</para></listitem>
154
+				<listitem><para>
155
+					<emphasis>city</emphasis> - city
156
+				</para></listitem>
157
+				<listitem><para>
158
+					<emphasis>regc</emphasis> - region
159
+				</para></listitem>
160
+				<listitem><para>
161
+					<emphasis>regn</emphasis> - region name
162
+				</para></listitem>
163
+				<listitem><para>
164
+					<emphasis>metro</emphasis> - metro code
165
+				</para></listitem>
166
+			</itemizedlist>
167
+			</listitem>
168
+		</itemizedlist>
169
+		<para>
170
+		Exported pseudo-variables are documented at &kamwikilink;.
171
+		</para>
172
+	</section>
173
+
174
+</chapter>
175
+
0 176
new file mode 100644
... ...
@@ -0,0 +1,139 @@
1
+/**
2
+ * $Id$
3
+ *
4
+ * This file is part of Kamailio, a free SIP server.
5
+ *
6
+ * This file is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 2 of the License, or
9
+ * (at your option) any later version
10
+ *
11
+ *
12
+ * This file is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20
+ *
21
+ */
22
+
23
+#include <stdio.h>
24
+#include <unistd.h>
25
+#include <stdlib.h>
26
+#include <string.h>
27
+
28
+#include "../../sr_module.h"
29
+#include "../../dprint.h"
30
+#include "../../ut.h"
31
+#include "../../pvar.h"
32
+#include "../../mod_fix.h"
33
+
34
+#include "geoip2_pv.h"
35
+
36
+MODULE_VERSION
37
+
38
+static char *geoip2_path = NULL;
39
+
40
+static int  mod_init(void);
41
+static void mod_destroy(void);
42
+
43
+static int w_geoip2_match(struct sip_msg* msg, char* str1, char* str2);
44
+static int geoip2_match(struct sip_msg *msg, gparam_t *target, gparam_t *pvname);
45
+
46
+static pv_export_t mod_pvs[] = {
47
+	{ {"gip2", sizeof("gip2")-1}, PVT_OTHER, pv_get_geoip2, 0,
48
+		pv_parse_geoip2_name, 0, 0, 0 },
49
+	{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
50
+};
51
+
52
+
53
+static cmd_export_t cmds[]={
54
+	{"geoip2_match", (cmd_function)w_geoip2_match, 2, fixup_spve_spve,
55
+		0, ANY_ROUTE},
56
+	{0, 0, 0, 0, 0, 0}
57
+};
58
+
59
+static param_export_t params[]={
60
+	{"path",     PARAM_STRING, &geoip2_path},
61
+	{0, 0, 0}
62
+};
63
+
64
+struct module_exports exports = {
65
+	"geoip2",
66
+	DEFAULT_DLFLAGS, /* dlopen flags */
67
+	cmds,
68
+	params,
69
+	0,
70
+	0,              /* exported MI functions */
71
+	mod_pvs,        /* exported pseudo-variables */
72
+	0,              /* extra processes */
73
+	mod_init,       /* module initialization function */
74
+	0,              /* response function */
75
+	mod_destroy,    /* destroy function */
76
+	0               /* per child init function */
77
+};
78
+
79
+
80
+
81
+/**
82
+ * init module function
83
+ */
84
+static int mod_init(void)
85
+{
86
+
87
+	if(geoip2_path==NULL || strlen(geoip2_path)==0)
88
+	{
89
+		LM_ERR("path to GeoIP database file not set\n");
90
+		return -1;
91
+	}
92
+
93
+	if(geoip2_init_pv(geoip2_path)!=0)
94
+	{
95
+		LM_ERR("cannot init for database file at: %s\n", geoip2_path);
96
+		return -1;
97
+	}
98
+	return 0;
99
+}
100
+
101
+/**
102
+ * destroy module function
103
+ */
104
+static void mod_destroy(void)
105
+{
106
+	geoip2_destroy_pv();
107
+}
108
+
109
+static int w_geoip2_match(struct sip_msg* msg, char* str1, char* str2)
110
+{
111
+	return geoip2_match(msg, (gparam_t*)str1, (gparam_t*)str2);
112
+}
113
+
114
+static int geoip2_match(struct sip_msg *msg, gparam_t *target, gparam_t *pvname)
115
+{
116
+	str tomatch;
117
+	str pvclass;
118
+	
119
+	if(msg==NULL)
120
+	{
121
+		LM_ERR("received null msg\n");
122
+		return -1;
123
+	}
124
+
125
+	if(fixup_get_svalue(msg, target, &tomatch)<0)
126
+	{
127
+		LM_ERR("cannot get the address\n");
128
+		return -1;
129
+	}
130
+	if(fixup_get_svalue(msg, pvname, &pvclass)<0)
131
+	{
132
+		LM_ERR("cannot get the pv class\n");
133
+		return -1;
134
+	}
135
+	geoip2_pv_reset(&pvclass);
136
+
137
+	return geoip2_update_pv(&tomatch, &pvclass);
138
+}
139
+
0 140
new file mode 100644
... ...
@@ -0,0 +1,476 @@
1
+/**
2
+ * $Id$
3
+ *
4
+ * This file is part of Kamailio, a free SIP server.
5
+ *
6
+ * This file is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 2 of the License, or
9
+ * (at your option) any later version
10
+ *
11
+ *
12
+ * This file is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20
+ *
21
+ */
22
+
23
+
24
+#include <assert.h>
25
+#include <ctype.h>
26
+#include <string.h>
27
+#include <stdlib.h>
28
+#include <time.h>
29
+
30
+#include "../../dprint.h"
31
+#include "../../hashes.h"
32
+#include "../../pvar.h"
33
+
34
+#include "geoip2_pv.h"
35
+
36
+typedef struct _sr_geoip2_record {
37
+	MMDB_lookup_result_s record;
38
+	str time_zone;
39
+	str zip;
40
+	str city;
41
+	str region_code;
42
+	str region_name;
43
+	str country;
44
+	char latitude[16];
45
+	char longitude[16];
46
+	char metro[16];
47
+	char nmask[8];
48
+	char tomatch[256];
49
+	int flags;
50
+} sr_geoip2_record_t;
51
+
52
+typedef struct _sr_geoip2_item {
53
+	str pvclass;
54
+	unsigned int hashid;
55
+	sr_geoip2_record_t r;
56
+	struct _sr_geoip2_item *next;
57
+} sr_geoip2_item_t;
58
+
59
+typedef struct _geoip2_pv {
60
+	sr_geoip2_item_t *item;
61
+	int type;
62
+} geoip2_pv_t;
63
+
64
+static MMDB_s _handle_GeoIP;
65
+
66
+static sr_geoip2_item_t *_sr_geoip2_list = NULL;
67
+
68
+sr_geoip2_record_t *sr_geoip2_get_record(str *name)
69
+{
70
+	sr_geoip2_item_t *it = NULL;
71
+	unsigned int hashid = 0;
72
+
73
+	hashid =  get_hash1_raw(name->s, name->len);
74
+
75
+	it = _sr_geoip2_list;
76
+	while(it!=NULL)
77
+	{
78
+		if(it->hashid==hashid && it->pvclass.len == name->len
79
+				&& strncmp(it->pvclass.s, name->s, name->len)==0)
80
+			return &it->r;
81
+		it = it->next;
82
+	}
83
+	return NULL;
84
+}
85
+
86
+sr_geoip2_item_t *sr_geoip2_add_item(str *name)
87
+{
88
+	sr_geoip2_item_t *it = NULL;
89
+	unsigned int hashid = 0;
90
+
91
+	hashid =  get_hash1_raw(name->s, name->len);
92
+
93
+	it = _sr_geoip2_list;
94
+	while(it!=NULL)
95
+	{
96
+		if(it->hashid==hashid && it->pvclass.len == name->len
97
+				&& strncmp(it->pvclass.s, name->s, name->len)==0)
98
+			return it;
99
+		it = it->next;
100
+	}
101
+	/* add new */
102
+	it = (sr_geoip2_item_t*)pkg_malloc(sizeof(sr_geoip2_item_t));
103
+	if(it==NULL)
104
+	{
105
+		LM_ERR("no more pkg\n");
106
+		return NULL;
107
+	}
108
+	memset(it, 0, sizeof(sr_geoip2_item_t));
109
+	it->pvclass.s = (char*)pkg_malloc(name->len+1);
110
+	if(it->pvclass.s==NULL)
111
+	{
112
+		LM_ERR("no more pkg.\n");
113
+		pkg_free(it);
114
+		return NULL;
115
+	}
116
+	memcpy(it->pvclass.s, name->s, name->len);
117
+	it->pvclass.s[name->len] = '\0';
118
+	it->pvclass.len = name->len;
119
+	it->hashid = hashid;
120
+	it->next = _sr_geoip2_list;
121
+	_sr_geoip2_list = it;
122
+	return it;
123
+}
124
+
125
+
126
+int pv_parse_geoip2_name(pv_spec_p sp, str *in)
127
+{
128
+	geoip2_pv_t *gpv=NULL;
129
+	char *p;
130
+	str pvc;
131
+	str pvs;
132
+	if(sp==NULL || in==NULL || in->len<=0)
133
+		return -1;
134
+
135
+	gpv = (geoip2_pv_t*)pkg_malloc(sizeof(geoip2_pv_t));
136
+	if(gpv==NULL)
137
+		return -1;
138
+
139
+	memset(gpv, 0, sizeof(geoip2_pv_t));
140
+
141
+	p = in->s;
142
+
143
+	while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
144
+		p++;
145
+	if(p>in->s+in->len || *p=='\0')
146
+		goto error;
147
+	pvc.s = p;
148
+	while(p < in->s + in->len)
149
+	{
150
+		if(*p=='=' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r')
151
+			break;
152
+		p++;
153
+	}
154
+	if(p>in->s+in->len || *p=='\0')
155
+		goto error;
156
+	pvc.len = p - pvc.s;
157
+	if(*p!='=')
158
+	{
159
+		while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
160
+			p++;
161
+		if(p>in->s+in->len || *p=='\0' || *p!='=')
162
+			goto error;
163
+	}
164
+	p++;
165
+	if(*p!='>')
166
+		goto error;
167
+	p++;
168
+
169
+	pvs.len = in->len - (int)(p - in->s);
170
+	pvs.s = p;
171
+	LM_DBG("geoip2 [%.*s] - key [%.*s]\n", pvc.len, pvc.s,
172
+			pvs.len, pvs.s);
173
+
174
+	gpv->item = sr_geoip2_add_item(&pvc);
175
+	if(gpv->item==NULL)
176
+		goto error;
177
+
178
+	switch(pvs.len)
179
+	{
180
+		case 2: 
181
+			if(strncmp(pvs.s, "cc", 2)==0)
182
+				gpv->type = 0;
183
+			else if(strncmp(pvs.s, "tz", 2)==0)
184
+				gpv->type = 1;
185
+			else goto error;
186
+		break;
187
+		case 3: 
188
+			if(strncmp(pvs.s, "zip", 3)==0)
189
+				gpv->type = 2;
190
+			else if(strncmp(pvs.s, "lat", 3)==0)
191
+				gpv->type = 3;
192
+			else if(strncmp(pvs.s, "lon", 3)==0)
193
+				gpv->type = 4;
194
+			else goto error;
195
+		break;
196
+		case 4: 
197
+			if(strncmp(pvs.s, "city", 4)==0)
198
+				gpv->type = 8;
199
+			else if(strncmp(pvs.s, "regc", 4)==0)
200
+				gpv->type = 10;
201
+			else if(strncmp(pvs.s, "regn", 4)==0)
202
+				gpv->type = 11;
203
+			else goto error;
204
+		break;
205
+		case 5: 
206
+			if(strncmp(pvs.s, "metro", 5)==0)
207
+				gpv->type = 12;
208
+			else if(strncmp(pvs.s, "nmask", 5)==0)
209
+				gpv->type = 13;
210
+			else goto error;
211
+		break;
212
+		default:
213
+			goto error;
214
+	}
215
+	sp->pvp.pvn.u.dname = (void*)gpv;
216
+	sp->pvp.pvn.type = PV_NAME_OTHER;
217
+
218
+	return 0;
219
+
220
+error:
221
+	if(gpv!=NULL)
222
+		pkg_free(gpv);
223
+
224
+	LM_ERR("error at PV geoip2 name: %.*s\n", in->len, in->s);
225
+	return -1;
226
+}
227
+
228
+int pv_geoip2_get_strzval(struct sip_msg *msg, pv_param_t *param,
229
+		pv_value_t *res, char *sval)
230
+{
231
+	str s;
232
+	if(sval==NULL)
233
+		return pv_get_null(msg, param, res);
234
+
235
+	s.s = sval;
236
+	s.len = strlen(s.s);
237
+	return pv_get_strval(msg, param, res, &s);
238
+}
239
+
240
+int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
241
+		pv_value_t *res)
242
+{
243
+	geoip2_pv_t *gpv;
244
+	MMDB_entry_data_s entry_data;
245
+
246
+	if(msg==NULL || param==NULL)
247
+		return -1;
248
+
249
+	gpv = (geoip2_pv_t*)param->pvn.u.dname;
250
+	if(gpv==NULL)
251
+		return -1;
252
+	if(gpv->item==NULL)
253
+		return pv_get_null(msg, param, res);
254
+
255
+	switch(gpv->type)
256
+	{
257
+		case 1: /* tz */
258
+			if(gpv->item->r.time_zone.s==NULL)
259
+			{
260
+				if(gpv->item->r.flags&1)
261
+					return pv_get_null(msg, param, res);
262
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
263
+					"location","time_zone", NULL
264
+					) != MMDB_SUCCESS)
265
+					return pv_get_null(msg, param, res);
266
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
267
+					gpv->item->r.time_zone.s = (char *)entry_data.utf8_string;
268
+					gpv->item->r.time_zone.len = entry_data.data_size;
269
+				}
270
+				gpv->item->r.flags |= 1;
271
+			}
272
+			return pv_get_strval(msg, param, res, &gpv->item->r.time_zone);
273
+		case 2: /* zip */
274
+			if(gpv->item->r.zip.s==NULL)
275
+			{
276
+				if(gpv->item->r.flags&32)
277
+					return pv_get_null(msg, param, res);
278
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
279
+					"postal","code", NULL) != MMDB_SUCCESS)
280
+					return pv_get_null(msg, param, res);
281
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
282
+					gpv->item->r.zip.s = (char *)entry_data.utf8_string;
283
+					gpv->item->r.zip.len = entry_data.data_size;
284
+				}
285
+				gpv->item->r.flags |= 32;
286
+			}
287
+			return pv_get_strval(msg, param, res, &gpv->item->r.zip);
288
+		case 3: /* lat */
289
+			if((gpv->item->r.flags&2)==0)
290
+			{
291
+				gpv->item->r.latitude[0] = '\0';
292
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
293
+					"location","latitude", NULL) != MMDB_SUCCESS)
294
+					return pv_get_null(msg, param, res);
295
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_DOUBLE)
296
+					snprintf(gpv->item->r.latitude, 15, "%f", entry_data.double_value);
297
+				gpv->item->r.flags |= 2;
298
+			}
299
+			return pv_geoip2_get_strzval(msg, param, res,
300
+					gpv->item->r.latitude);
301
+		case 4: /* lon */
302
+			if((gpv->item->r.flags&4)==0)
303
+			{
304
+				gpv->item->r.latitude[0] = '\0';
305
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
306
+					"location","longitude", NULL) != MMDB_SUCCESS)
307
+					return pv_get_null(msg, param, res);
308
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_DOUBLE)
309
+					snprintf(gpv->item->r.longitude, 15, "%f", entry_data.double_value);
310
+				gpv->item->r.flags |= 4;
311
+			}
312
+			return pv_geoip2_get_strzval(msg, param, res,
313
+					gpv->item->r.longitude);
314
+		case 8: /* city */
315
+			if(gpv->item->r.city.s==NULL)
316
+			{
317
+				if(gpv->item->r.flags&64)
318
+					return pv_get_null(msg, param, res);
319
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
320
+					"city","names","en", NULL
321
+					) != MMDB_SUCCESS)
322
+					return pv_get_null(msg, param, res);
323
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
324
+					gpv->item->r.city.s = (char *)entry_data.utf8_string;
325
+					gpv->item->r.city.len = entry_data.data_size;
326
+				}
327
+				gpv->item->r.flags |= 64;
328
+			}
329
+			return pv_get_strval(msg, param, res, &gpv->item->r.city);
330
+		case 10: /* regc */
331
+			if(gpv->item->r.region_code.s==NULL)
332
+			{
333
+				if(gpv->item->r.flags&128)
334
+					return pv_get_null(msg, param, res);
335
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
336
+					"subdivisions","0","iso_code", NULL
337
+					) != MMDB_SUCCESS)
338
+					return pv_get_null(msg, param, res);
339
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
340
+					gpv->item->r.region_code.s = (char *)entry_data.utf8_string;
341
+					gpv->item->r.region_code.len = entry_data.data_size;
342
+				}
343
+				gpv->item->r.flags |= 128;
344
+			}
345
+			return pv_get_strval(msg, param, res, &gpv->item->r.region_code);
346
+		case 11: /* regn */
347
+			if(gpv->item->r.region_name.s==NULL)
348
+			{
349
+				if(gpv->item->r.flags&16)
350
+					return pv_get_null(msg, param, res);
351
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
352
+					"subdivisions","0","names","en", NULL
353
+					) != MMDB_SUCCESS)
354
+					return pv_get_null(msg, param, res);
355
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
356
+					gpv->item->r.region_name.s = (char *)entry_data.utf8_string;
357
+					gpv->item->r.region_name.len = entry_data.data_size;
358
+				}
359
+				gpv->item->r.flags |= 16;
360
+			}
361
+			return pv_get_strval(msg, param, res, &gpv->item->r.region_name);
362
+		case 12: /* metro */
363
+			if((gpv->item->r.flags&256)==0)
364
+			{
365
+				gpv->item->r.metro[0] = '\0';
366
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
367
+					"location","metro_code", NULL) != MMDB_SUCCESS)
368
+					return pv_get_null(msg, param, res);
369
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UINT16)
370
+					snprintf(gpv->item->r.metro, 15, "%hd", entry_data.uint16);
371
+				gpv->item->r.flags |= 256;
372
+			}
373
+			return pv_geoip2_get_strzval(msg, param, res,
374
+					gpv->item->r.metro);
375
+		case 13: /* nmask */
376
+			if((gpv->item->r.flags&1024)==0)
377
+			{
378
+				gpv->item->r.nmask[0] = '\0';
379
+				snprintf(gpv->item->r.nmask, 8, "%hd", gpv->item->r.record.netmask);
380
+				gpv->item->r.flags |= 1024;
381
+			}
382
+			return pv_geoip2_get_strzval(msg, param, res,
383
+					gpv->item->r.nmask);
384
+		default: /* cc */
385
+			if(gpv->item->r.country.s==NULL)
386
+			{
387
+				if(gpv->item->r.flags&512)
388
+					return pv_get_null(msg, param, res);
389
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
390
+					"country","iso_code", NULL
391
+					) != MMDB_SUCCESS)
392
+					return pv_get_null(msg, param, res);
393
+				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
394
+					gpv->item->r.country.s = (char *)entry_data.utf8_string;
395
+					gpv->item->r.country.len = entry_data.data_size;
396
+				}
397
+				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
398
+					"traits","is_anonymous_proxy", NULL) == MMDB_SUCCESS
399
+					&& entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_BOOLEAN
400
+					&& entry_data.boolean) {
401
+					gpv->item->r.country.s = "A1";
402
+					gpv->item->r.country.len = 2;
403
+				}
404
+				gpv->item->r.flags |= 512;
405
+			}
406
+			return pv_get_strval(msg, param, res, &gpv->item->r.country);
407
+	}
408
+}
409
+
410
+int geoip2_init_pv(char *path)
411
+{
412
+	int status = MMDB_open(path, MMDB_MODE_MMAP, &_handle_GeoIP);
413
+	
414
+	if(MMDB_SUCCESS != status)
415
+	{
416
+		LM_ERR("cannot open GeoIP database file at: %s\n", path);
417
+		return -1;
418
+	}
419
+	return 0;
420
+}
421
+
422
+void geoip2_destroy_list(void)
423
+{
424
+}
425
+
426
+void geoip2_destroy_pv(void)
427
+{
428
+	MMDB_close(&_handle_GeoIP);
429
+}
430
+
431
+void geoip2_pv_reset(str *name)
432
+{
433
+	sr_geoip2_record_t *gr = NULL;
434
+	
435
+	gr = sr_geoip2_get_record(name);
436
+
437
+	if(gr==NULL)
438
+		return;
439
+	memset(gr, 0, sizeof(struct _sr_geoip2_record));
440
+}
441
+
442
+int geoip2_update_pv(str *tomatch, str *name)
443
+{
444
+	sr_geoip2_record_t *gr = NULL;
445
+	int gai_error, mmdb_error;
446
+	
447
+	if(tomatch->len>255)
448
+	{
449
+		LM_DBG("target too long (max 255): %s\n", tomatch->s);
450
+		return -3;
451
+	}
452
+	
453
+	gr = sr_geoip2_get_record(name);
454
+	if(gr==NULL)
455
+	{
456
+		LM_DBG("container not found: %s\n", tomatch->s);
457
+		return - 4;
458
+	}
459
+
460
+	strncpy(gr->tomatch, tomatch->s, tomatch->len);
461
+	tomatch->s[tomatch->len] = '\0';
462
+	gr->record = MMDB_lookup_string(&_handle_GeoIP,
463
+			(const char*)gr->tomatch,
464
+			&gai_error, &mmdb_error
465
+			);
466
+	LM_DBG("attempt to match: %s\n", gr->tomatch);
467
+	if (gai_error || MMDB_SUCCESS != mmdb_error || !gr->record.found_entry)
468
+	{
469
+		LM_DBG("no match for: %s\n", gr->tomatch);
470
+		return -2;
471
+	}
472
+	LM_DBG("geoip2 PV updated for: %s\n", gr->tomatch);
473
+
474
+	return 1;
475
+}
476
+
0 477
new file mode 100644
... ...
@@ -0,0 +1,40 @@
1
+/**
2
+ * $Id$
3
+ *
4
+ * This file is part of Kamailio, a free SIP server.
5
+ *
6
+ * This file is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 2 of the License, or
9
+ * (at your option) any later version
10
+ *
11
+ *
12
+ * This file is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20
+ *
21
+ */
22
+
23
+#ifndef _GEOIP_PV_H_
24
+#define _GEOIP_PV_H_
25
+
26
+#include <maxminddb.h>
27
+
28
+#include "../../pvar.h"
29
+
30
+int pv_parse_geoip2_name(pv_spec_p sp, str *in);
31
+int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
32
+		pv_value_t *res);
33
+
34
+int geoip2_init_pv(char *path);
35
+void geoip2_destroy_pv(void);
36
+void geoip2_pv_reset(str *pvclass);
37
+int geoip2_update_pv(str *tomatch, str *pvclass);
38
+
39
+#endif
40
+