Browse code

geoip2: add reload RCP command fuctionality (related to GH #2029)

Henning Westerholt authored on 13/04/2022 06:34:02
Showing 5 changed files
... ...
@@ -23,6 +23,11 @@
23 23
 		<surname>Mierla</surname>
24 24
 		    <email>miconda@gmail.com</email>
25 25
 	    </editor>
26
+	    <editor>
27
+		<firstname>Henning</firstname>
28
+		<surname>Westerholt</surname>
29
+			<affiliation><orgname>gilawa.com</orgname></affiliation>
30
+	    </editor>
26 31
 	</authorgroup>
27 32
 	<copyright>
28 33
 	    <year>2010</year>
... ...
@@ -121,6 +121,27 @@ if(geoip2_match("$si", "src"))
121 121
 	    </example>
122 122
 	</section>
123 123
 	
124
+    </section>
125
+
126
+    <section>
127
+	<title>RPC Commands</title>
128
+	<section id="userblocklist.r.reload_blocklist">
129
+	   <title>
130
+		<function moreinfo="none">userblocklist.reload_blocklist</function>
131
+	   </title>
132
+	   <para>
133
+			Reload the internal GeoIP database. This is necessary after
134
+			the database file has been changed on the disk.
135
+	   </para>
136
+		<example>
137
+		<title><function>geoip2.reload</function> usage</title>
138
+		<programlisting format="linespecific">
139
+...
140
+&kamcmd; geoip2.reload
141
+...
142
+		</programlisting>
143
+		</example>
144
+	</section>
124 145
     </section>
125 146
 	
126 147
 	<section>
... ...
@@ -30,6 +30,7 @@
30 30
 #include "../../core/pvar.h"
31 31
 #include "../../core/kemi.h"
32 32
 #include "../../core/mod_fix.h"
33
+#include "../../core/rpc_lookup.h"
33 34
 
34 35
 #include "geoip2_pv.h"
35 36
 
... ...
@@ -39,6 +40,7 @@ static char *geoip2_path = NULL;
39 40
 
40 41
 static int  mod_init(void);
41 42
 static void mod_destroy(void);
43
+static int geoip2_rpc_init(void);
42 44
 
43 45
 static int w_geoip2_match(struct sip_msg* msg, char* str1, char* str2);
44 46
 static int geoip2_match(sip_msg_t *msg, str *tomatch, str *pvclass);
... ...
@@ -93,6 +95,13 @@ static int mod_init(void)
93 95
 		LM_ERR("cannot init for database file at: %s\n", geoip2_path);
94 96
 		return -1;
95 97
 	}
98
+
99
+	if (geoip2_rpc_init() < 0)
100
+	{
101
+		LM_ERR("error during RPC initialization\n");
102
+		return -1;
103
+	}
104
+
96 105
 	return 0;
97 106
 }
98 107
 
... ...
@@ -133,6 +142,38 @@ static int w_geoip2_match(sip_msg_t* msg, char* target, char* pvname)
133 142
 	return geoip2_match(msg, &tomatch, &pvclass);
134 143
 }
135 144
 
145
+static void geoip2_rpc_reload(rpc_t* rpc, void* ctx)
146
+{
147
+	if(geoip2_reload_pv(geoip2_path) != 0)
148
+	{
149
+		rpc->fault(ctx, 500, "Reload failed");
150
+		return;
151
+	}
152
+}
153
+
154
+static const char* geoip2_rpc_reload_doc[2] =
155
+{
156
+	"Reload GeoIP2 database file.",
157
+	0
158
+};
159
+
160
+rpc_export_t ubl_rpc[] =
161
+{
162
+	{"geoip2.reload", geoip2_rpc_reload,
163
+		geoip2_rpc_reload_doc, 0},
164
+	{0, 0, 0, 0}
165
+};
166
+
167
+static int geoip2_rpc_init(void)
168
+{
169
+        if (rpc_register_array(ubl_rpc)!=0)
170
+        {
171
+                LM_ERR("failed to register RPC commands\n");
172
+                return -1;
173
+        }
174
+        return 0;
175
+}
176
+
136 177
 /**
137 178
  *
138 179
  */
... ...
@@ -29,6 +29,7 @@
29 29
 #include "../../core/dprint.h"
30 30
 #include "../../core/hashes.h"
31 31
 #include "../../core/pvar.h"
32
+#include "../../core/locking.h"
32 33
 
33 34
 #include "geoip2_pv.h"
34 35
 
... ...
@@ -61,7 +62,8 @@ typedef struct _geoip2_pv {
61 62
 	int type;
62 63
 } geoip2_pv_t;
63 64
 
64
-static MMDB_s _handle_GeoIP;
65
+static MMDB_s *_handle_GeoIP;
66
+static gen_lock_t *lock = NULL;
65 67
 
66 68
 static sr_geoip2_item_t *_sr_geoip2_list = NULL;
67 69
 
... ...
@@ -239,6 +241,44 @@ int pv_geoip2_get_strzval(struct sip_msg *msg, pv_param_t *param,
239 241
 	return pv_get_strval(msg, param, res, &s);
240 242
 }
241 243
 
244
+static int get_mmdb_value2(MMDB_entry_s *entry, MMDB_entry_data_s *data,
245
+		const char *first, const char *second)
246
+{
247
+	int status = 0;
248
+
249
+	lock_get(lock);
250
+	status = MMDB_get_value(entry, data, first, second, NULL);
251
+	lock_release(lock);
252
+
253
+	return status;
254
+}
255
+
256
+static int get_mmdb_value3(MMDB_entry_s *entry, MMDB_entry_data_s *data,
257
+		const char *first, const char *second, const char *third)
258
+{
259
+	int status = 0;
260
+
261
+	lock_get(lock);
262
+	status = MMDB_get_value(entry, data, first, second, third, NULL);
263
+	lock_release(lock);
264
+
265
+	return status;
266
+}
267
+
268
+static int get_mmdb_value4(MMDB_entry_s *entry, MMDB_entry_data_s *data,
269
+		const char *first, const char *second, const char *third,
270
+		const char *fourth)
271
+{
272
+	int status = 0;
273
+
274
+	lock_get(lock);
275
+	status = MMDB_get_value(entry, data, first, second, third, fourth, NULL);
276
+	lock_release(lock);
277
+
278
+	return status;
279
+}
280
+
281
+
242 282
 int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
243 283
 		pv_value_t *res)
244 284
 {
... ...
@@ -261,9 +301,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
261 301
 			{
262 302
 				if(gpv->item->r.flags&1)
263 303
 					return pv_get_null(msg, param, res);
264
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
265
-					"location","time_zone", NULL
266
-					) != MMDB_SUCCESS)
304
+				if(get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
305
+					"location","time_zone") != MMDB_SUCCESS)
267 306
 					return pv_get_null(msg, param, res);
268 307
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
269 308
 					gpv->item->r.time_zone.s = (char *)entry_data.utf8_string;
... ...
@@ -277,8 +316,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
277 316
 			{
278 317
 				if(gpv->item->r.flags&32)
279 318
 					return pv_get_null(msg, param, res);
280
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
281
-					"postal","code", NULL) != MMDB_SUCCESS)
319
+				if(get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
320
+					"postal","code") != MMDB_SUCCESS)
282 321
 					return pv_get_null(msg, param, res);
283 322
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
284 323
 					gpv->item->r.zip.s = (char *)entry_data.utf8_string;
... ...
@@ -291,8 +330,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
291 330
 			if((gpv->item->r.flags&2)==0)
292 331
 			{
293 332
 				gpv->item->r.latitude[0] = '\0';
294
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
295
-					"location","latitude", NULL) != MMDB_SUCCESS)
333
+				if(get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
334
+					"location","latitude") != MMDB_SUCCESS)
296 335
 					return pv_get_null(msg, param, res);
297 336
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_DOUBLE)
298 337
 					snprintf(gpv->item->r.latitude, 15, "%f", entry_data.double_value);
... ...
@@ -304,8 +343,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
304 343
 			if((gpv->item->r.flags&4)==0)
305 344
 			{
306 345
 				gpv->item->r.latitude[0] = '\0';
307
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
308
-					"location","longitude", NULL) != MMDB_SUCCESS)
346
+				if(get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
347
+					"location","longitude") != MMDB_SUCCESS)
309 348
 					return pv_get_null(msg, param, res);
310 349
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_DOUBLE)
311 350
 					snprintf(gpv->item->r.longitude, 15, "%f", entry_data.double_value);
... ...
@@ -318,9 +357,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
318 357
 			{
319 358
 				if(gpv->item->r.flags&16)
320 359
 					return pv_get_null(msg, param, res);
321
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
322
-					"continent","code", NULL
323
-					) != MMDB_SUCCESS)
360
+				if(get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
361
+					"continent","code") != MMDB_SUCCESS)
324 362
 					return pv_get_null(msg, param, res);
325 363
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
326 364
 					gpv->item->r.cont_code.s = (char *)entry_data.utf8_string;
... ...
@@ -334,9 +372,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
334 372
 			{
335 373
 				if(gpv->item->r.flags&64)
336 374
 					return pv_get_null(msg, param, res);
337
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
338
-					"city","names","en", NULL
339
-					) != MMDB_SUCCESS)
375
+				if(get_mmdb_value3(&gpv->item->r.record.entry, &entry_data,
376
+					"city","names","en") != MMDB_SUCCESS)
340 377
 					return pv_get_null(msg, param, res);
341 378
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
342 379
 					gpv->item->r.city.s = (char *)entry_data.utf8_string;
... ...
@@ -350,9 +387,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
350 387
 			{
351 388
 				if(gpv->item->r.flags&128)
352 389
 					return pv_get_null(msg, param, res);
353
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
354
-					"subdivisions","0","iso_code", NULL
355
-					) != MMDB_SUCCESS)
390
+				if(get_mmdb_value3(&gpv->item->r.record.entry, &entry_data,
391
+					"subdivisions","0","iso_code") != MMDB_SUCCESS)
356 392
 					return pv_get_null(msg, param, res);
357 393
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
358 394
 					gpv->item->r.region_code.s = (char *)entry_data.utf8_string;
... ...
@@ -366,9 +402,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
366 402
 			{
367 403
 				if(gpv->item->r.flags&16)
368 404
 					return pv_get_null(msg, param, res);
369
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
370
-					"subdivisions","0","names","en", NULL
371
-					) != MMDB_SUCCESS)
405
+				if(get_mmdb_value4(&gpv->item->r.record.entry, &entry_data,
406
+					"subdivisions","0","names","en") != MMDB_SUCCESS)
372 407
 					return pv_get_null(msg, param, res);
373 408
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
374 409
 					gpv->item->r.region_name.s = (char *)entry_data.utf8_string;
... ...
@@ -381,8 +416,8 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
381 416
 			if((gpv->item->r.flags&256)==0)
382 417
 			{
383 418
 				gpv->item->r.metro[0] = '\0';
384
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
385
-					"location","metro_code", NULL) != MMDB_SUCCESS)
419
+				if(get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
420
+					"location","metro_code") != MMDB_SUCCESS)
386 421
 					return pv_get_null(msg, param, res);
387 422
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UINT16)
388 423
 					snprintf(gpv->item->r.metro, 15, "%hd", entry_data.uint16);
... ...
@@ -404,20 +439,18 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
404 439
 			{
405 440
 				if(gpv->item->r.flags&512)
406 441
 					return pv_get_null(msg, param, res);
407
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
408
-					"country","iso_code", NULL
409
-					) != MMDB_SUCCESS
410
-					&& MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
411
-						"registered_country","iso_code", NULL
412
-						) != MMDB_SUCCESS
442
+				if(get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
443
+					"country","iso_code") != MMDB_SUCCESS
444
+					&& get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
445
+						"registered_country","iso_code") != MMDB_SUCCESS
413 446
 					)
414 447
 					return pv_get_null(msg, param, res);
415 448
 				if(entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
416 449
 					gpv->item->r.country.s = (char *)entry_data.utf8_string;
417 450
 					gpv->item->r.country.len = entry_data.data_size;
418 451
 				}
419
-				if(MMDB_get_value(&gpv->item->r.record.entry, &entry_data,
420
-					"traits","is_anonymous_proxy", NULL) == MMDB_SUCCESS
452
+				if(get_mmdb_value2(&gpv->item->r.record.entry, &entry_data,
453
+					"traits","is_anonymous_proxy") == MMDB_SUCCESS
421 454
 					&& entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_BOOLEAN
422 455
 					&& entry_data.boolean) {
423 456
 					gpv->item->r.country.s = "A1";
... ...
@@ -429,25 +462,83 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
429 462
 	}
430 463
 }
431 464
 
465
+static int init_shmlock(void)
466
+{
467
+	lock = lock_alloc();
468
+	if (!lock) {
469
+		LM_CRIT("cannot allocate memory for lock\n");
470
+		return -1;
471
+	}
472
+	if (lock_init(lock) == 0) {
473
+		LM_CRIT("cannot initialize lock\n");
474
+		return -1;
475
+	}
476
+
477
+	return 0;
478
+}
479
+
480
+static void destroy_shmlock(void)
481
+{
482
+	if (lock) {
483
+		lock_destroy(lock);
484
+		lock_dealloc((void *)lock);
485
+		lock = NULL;
486
+	}
487
+}
488
+
432 489
 int geoip2_init_pv(char *path)
433 490
 {
434
-	int status = MMDB_open(path, MMDB_MODE_MMAP, &_handle_GeoIP);
491
+	int status;
492
+	_handle_GeoIP = shm_malloc(sizeof(struct MMDB_s));
493
+	if (_handle_GeoIP == NULL)
494
+	{
495
+		SHM_MEM_ERROR;
496
+		return -1;
497
+	}
498
+
499
+	status = MMDB_open(path, MMDB_MODE_MMAP, _handle_GeoIP);
435 500
 
436 501
 	if(MMDB_SUCCESS != status)
437 502
 	{
438 503
 		LM_ERR("cannot open GeoIP database file at: %s\n", path);
439 504
 		return -1;
440 505
 	}
506
+
507
+	if (init_shmlock() != 0)
508
+	{
509
+		LM_ERR("cannot create GeoIP database lock\n");
510
+		return -1;
511
+	}
441 512
 	return 0;
442 513
 }
443 514
 
515
+int geoip2_reload_pv(char *path)
516
+{
517
+	int status = 0;
518
+
519
+	lock_get(lock);
520
+	MMDB_close(_handle_GeoIP);
521
+	status = MMDB_open(path, MMDB_MODE_MMAP, _handle_GeoIP);
522
+	if(MMDB_SUCCESS != status)
523
+	{
524
+		LM_ERR("cannot reload GeoIP database file at: %s\n", path);
525
+	}
526
+	lock_release(lock);
527
+	LM_INFO("reloaded GeoIP database file at: %s\n", path);
528
+
529
+	return status;
530
+}
531
+
444 532
 void geoip2_destroy_list(void)
445 533
 {
446 534
 }
447 535
 
448 536
 void geoip2_destroy_pv(void)
449 537
 {
450
-	MMDB_close(&_handle_GeoIP);
538
+	MMDB_close(_handle_GeoIP);
539
+	shm_free(_handle_GeoIP);
540
+	_handle_GeoIP = NULL;
541
+	destroy_shmlock();
451 542
 }
452 543
 
453 544
 void geoip2_pv_reset(str *name)
... ...
@@ -481,10 +572,12 @@ int geoip2_update_pv(str *tomatch, str *name)
481 572
 
482 573
 	strncpy(gr->tomatch, tomatch->s, tomatch->len);
483 574
 	tomatch->s[tomatch->len] = '\0';
484
-	gr->record = MMDB_lookup_string(&_handle_GeoIP,
575
+	lock_get(lock);
576
+	gr->record = MMDB_lookup_string(_handle_GeoIP,
485 577
 			(const char*)gr->tomatch,
486 578
 			&gai_error, &mmdb_error
487 579
 			);
580
+	lock_release(lock);
488 581
 	LM_DBG("attempt to match: %s\n", gr->tomatch);
489 582
 	if (gai_error || MMDB_SUCCESS != mmdb_error || !gr->record.found_entry)
490 583
 	{
... ...
@@ -32,6 +32,7 @@ int pv_get_geoip2(struct sip_msg *msg, pv_param_t *param,
32 32
 
33 33
 int geoip2_init_pv(char *path);
34 34
 void geoip2_destroy_pv(void);
35
+int geoip2_reload_pv(char *path);
35 36
 void geoip2_pv_reset(str *pvclass);
36 37
 int geoip2_update_pv(str *tomatch, str *pvclass);
37 38