ipops: new function dns_query(hostname, pvid)
[sip-router] / modules / ipops / ipops_mod.c
1 /*
2  * ipops module - IPv4 and Ipv6 operations
3  *
4  * Copyright (C) 2011 Iñaki Baz Castillo
5  *
6  * This file is part of SIP Router, a free SIP server.
7  *
8  * SIP Router is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * SIP Router is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  * History:
23  * -------
24  *  2011-07-29: Added a function to detect RFC1918 private IPv4 addresses (ibc)
25  *  2011-04-27: Initial version (ibc)
26  */
27 /*!
28  * \file
29  * \brief SIP-router ipops :: Module interface
30  * \ingroup ipops
31  * Copyright (C) 2011 Iñaki Baz Castillo
32  * Module: \ref ipops
33  */
34
35 /*! \defgroup ipops SIP-router ipops Module
36  *
37  * The ipops module provide IPv4 and IPv6 operations.
38  */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <netdb.h>
46 #include <arpa/inet.h>
47 #include "../../sr_module.h"
48 #include "../../dprint.h"
49 #include "../../str.h"
50 #include "../../mod_fix.h"
51 #include "../../pvar.h"
52 #include "../../resolve.h"
53 #include "api.h"
54 #include "ipops_pv.h"
55 #include "ip_parser.h"
56 #include "rfc1918_parser.h"
57
58 MODULE_VERSION
59
60
61 /*
62  * Module parameter variables
63  */
64
65
66 /*
67  * Module core functions
68  */
69
70
71 /*
72  * Module internal functions
73  */
74 int _compare_ips(char*, size_t, enum enum_ip_type, char*, size_t, enum enum_ip_type);
75 int _ip_is_in_subnet(char *ip1, size_t len1, enum enum_ip_type ip1_type, char *ip2, size_t len2, enum enum_ip_type ip2_type, int netmask);
76
77
78 /*
79  * Script functions
80  */
81 static int w_is_ip(struct sip_msg*, char*);
82 static int w_is_pure_ip(struct sip_msg*, char*);
83 static int w_is_ipv4(struct sip_msg*, char*);
84 static int w_is_ipv6(struct sip_msg*, char*);
85 static int w_is_ipv6_reference(struct sip_msg*, char*);
86 static int w_ip_type(struct sip_msg*, char*);
87 static int w_compare_ips(struct sip_msg*, char*, char*);
88 static int w_compare_pure_ips(struct sip_msg*, char*, char*);
89 static int w_is_ip_rfc1918(struct sip_msg*, char*);
90 static int w_ip_is_in_subnet(struct sip_msg*, char*, char*);
91 static int w_dns_sys_match_ip(sip_msg_t*, char*, char*);
92 static int w_dns_int_match_ip(sip_msg_t*, char*, char*);
93
94 static int w_dns_query(struct sip_msg* msg, char* str1, char* str2);
95
96 static pv_export_t mod_pvs[] = {
97         { {"dns", sizeof("dns")-1}, PVT_OTHER, pv_get_dns, 0,
98                 pv_parse_dns_name, 0, 0, 0 },
99         { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
100 };
101
102 /*
103  * Exported functions
104  */
105 static cmd_export_t cmds[] =
106 {
107   { "is_ip", (cmd_function)w_is_ip, 1, fixup_spve_null, 0,
108   REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
109   { "is_pure_ip", (cmd_function)w_is_pure_ip, 1, fixup_spve_null, 0,
110   REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
111   { "is_ipv4", (cmd_function)w_is_ipv4, 1, fixup_spve_null, 0,
112   REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
113   { "is_ipv6", (cmd_function)w_is_ipv6, 1, fixup_spve_null, 0,
114   REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
115   { "is_ipv6_reference", (cmd_function)w_is_ipv6_reference, 1, fixup_spve_null, 0,
116   REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
117   { "ip_type", (cmd_function)w_ip_type, 1, fixup_spve_null, 0,
118   REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
119   { "compare_ips", (cmd_function)w_compare_ips, 2, fixup_spve_spve, 0,
120   REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
121   { "compare_pure_ips", (cmd_function)w_compare_pure_ips, 2, fixup_spve_spve, 0,
122   REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
123   { "is_ip_rfc1918", (cmd_function)w_is_ip_rfc1918, 1, fixup_spve_null, 0,
124   REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
125   { "is_in_subnet", (cmd_function)w_ip_is_in_subnet, 2, fixup_spve_spve, 0,
126   REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
127   { "dns_sys_match_ip", (cmd_function)w_dns_sys_match_ip, 2, fixup_spve_spve, 0,
128   ANY_ROUTE },
129   { "dns_int_match_ip", (cmd_function)w_dns_int_match_ip, 2, fixup_spve_spve, 0,
130   ANY_ROUTE },
131   { "dns_query", (cmd_function)w_dns_query, 2, fixup_spve_spve, 0,
132   ANY_ROUTE },
133   { "bind_ipops", (cmd_function)bind_ipops, 0, 0, 0, 0},
134   { 0, 0, 0, 0, 0, 0 }
135 };
136
137
138 /*
139  * Module interface
140  */
141 struct module_exports exports = {
142   "ipops",                   /*!< module name */
143   DEFAULT_DLFLAGS,           /*!< dlopen flags */
144   cmds,                      /*!< exported functions */
145   0,                         /*!< exported parameters */
146   0,                         /*!< exported statistics */
147   0,                         /*!< exported MI functions */
148   mod_pvs,                   /*!< exported pseudo-variables */
149   0,                         /*!< extra processes */
150   0,                         /*!< module initialization function */
151   (response_function) 0,     /*!< response handling function */
152   0,                         /*!< destroy function */
153   0                          /*!< per-child init function */
154 };
155
156
157 /*
158  * Module internal functions
159  */
160
161 /*! \brief Return 1 if both pure IP's are equal, 0 otherwise. */
162 int _compare_ips(char *ip1, size_t len1, enum enum_ip_type ip1_type, char *ip2, size_t len2, enum enum_ip_type ip2_type)
163 {
164   struct in_addr in_addr1, in_addr2;
165   struct in6_addr in6_addr1, in6_addr2;
166   char _ip1[INET6_ADDRSTRLEN], _ip2[INET6_ADDRSTRLEN];
167   
168   // Not same IP type, return false.
169   if (ip1_type != ip2_type)
170     return 0;
171
172   memcpy(_ip1, ip1, len1);
173   _ip1[len1] = '\0';
174   memcpy(_ip2, ip2, len2);
175   _ip2[len2] = '\0';
176
177   switch(ip1_type) {
178     // Comparing IPv4 with IPv4.
179     case(ip_type_ipv4):
180       if (inet_pton(AF_INET, _ip1, &in_addr1) == 0)  return 0;
181       if (inet_pton(AF_INET, _ip2, &in_addr2) == 0)  return 0;
182       if (in_addr1.s_addr == in_addr2.s_addr)
183         return 1;
184       else
185         return 0;
186       break;
187     // Comparing IPv6 with IPv6.
188     case(ip_type_ipv6):
189       if (inet_pton(AF_INET6, _ip1, &in6_addr1) != 1)  return 0;
190       if (inet_pton(AF_INET6, _ip2, &in6_addr2) != 1)  return 0;
191       if (memcmp(in6_addr1.s6_addr, in6_addr2.s6_addr, sizeof(in6_addr1.s6_addr)) == 0)
192         return 1;
193       else
194         return 0;
195       break;
196     default:
197       return 0;
198       break;
199   }
200 }
201
202 /*! \brief Return 1 if IP1 is in the subnet given by IP2 and the netmask, 0 otherwise. */
203 int _ip_is_in_subnet(char *ip1, size_t len1, enum enum_ip_type ip1_type, char *ip2, size_t len2, enum enum_ip_type ip2_type, int netmask)
204 {
205   struct in_addr in_addr1, in_addr2;
206   struct in6_addr in6_addr1, in6_addr2;
207   char _ip1[INET6_ADDRSTRLEN], _ip2[INET6_ADDRSTRLEN];
208   uint32_t ipv4_mask;
209   uint8_t ipv6_mask[16];
210   int i;
211   
212   // Not same IP type, return false.
213   if (ip1_type != ip2_type)
214     return 0;
215
216   memcpy(_ip1, ip1, len1);
217   _ip1[len1] = '\0';
218   memcpy(_ip2, ip2, len2);
219   _ip2[len2] = '\0';
220
221   switch(ip1_type) {
222     // Comparing IPv4 with IPv4.
223     case(ip_type_ipv4):
224       if (inet_pton(AF_INET, _ip1, &in_addr1) == 0)  return 0;
225       if (inet_pton(AF_INET, _ip2, &in_addr2) == 0)  return 0;
226       if (netmask <0 || netmask > 32)  return 0;
227       if (netmask == 32) ipv4_mask = 0xFFFFFFFF;
228       else ipv4_mask = htonl(~(0xFFFFFFFF >> netmask));
229       if ((in_addr1.s_addr & ipv4_mask) == in_addr2.s_addr)
230         return 1;
231       else
232         return 0;
233       break;
234     // Comparing IPv6 with IPv6.
235     case(ip_type_ipv6):
236       if (inet_pton(AF_INET6, _ip1, &in6_addr1) != 1)  return 0;
237       if (inet_pton(AF_INET6, _ip2, &in6_addr2) != 1)  return 0;
238       if (netmask <0 || netmask > 128)  return 0;
239       for (i=0; i<16; i++)
240       {
241         if (netmask > ((i+1)*8)) ipv6_mask[i] = 0xFF;
242         else if (netmask > (i*8))  ipv6_mask[i] = ~(0xFF >> (netmask-(i*8)));
243         else ipv6_mask[i] = 0x00;
244       }
245       for (i=0; i<16; i++)  in6_addr1.s6_addr[i] &= ipv6_mask[i];
246       if (memcmp(in6_addr1.s6_addr, in6_addr2.s6_addr, sizeof(in6_addr1.s6_addr)) == 0)
247         return 1;
248       else
249         return 0;
250       break;
251     default:
252       return 0;
253       break;
254   }
255 }
256
257
258
259 /*
260  * Script functions
261  */
262
263 /*! \brief Return true if the given argument (string or pv) is a valid IPv4, IPv6 or IPv6 reference. */
264 static int w_is_ip(struct sip_msg* _msg, char* _s)
265 {
266   str string;
267   
268   if (_s == NULL) {
269     LM_ERR("bad parameter\n");
270     return -2;
271   }
272   
273   if (fixup_get_svalue(_msg, (gparam_p)_s, &string))
274   {
275     LM_ERR("cannot print the format for string\n");
276     return -3;
277   }
278   
279   if (ip_parser_execute(string.s, string.len) != ip_type_error)
280     return 1;
281   else
282     return -1;
283 }
284
285
286 /*! \brief Return true if the given argument (string or pv) is a valid IPv4 or IPv6. */
287 static int w_is_pure_ip(struct sip_msg* _msg, char* _s)
288 {
289   str string;
290   
291   if (_s == NULL) {
292     LM_ERR("bad parameter\n");
293     return -2;
294   }
295   
296   if (fixup_get_svalue(_msg, (gparam_p)_s, &string))
297   {
298     LM_ERR("cannot print the format for string\n");
299     return -3;
300   }
301
302   switch(ip_parser_execute(string.s, string.len)) {
303     case(ip_type_ipv4):
304       return 1;
305       break;
306     case(ip_type_ipv6):
307       return 1;
308       break;
309     default:
310       return -1;
311       break;
312   }
313 }
314
315
316 /*! \brief Return true if the given argument (string or pv) is a valid IPv4. */
317 static int w_is_ipv4(struct sip_msg* _msg, char* _s)
318 {
319   str string;
320   
321   if (_s == NULL) {
322     LM_ERR("bad parameter\n");
323     return -2;
324   }
325   
326   if (fixup_get_svalue(_msg, (gparam_p)_s, &string))
327   {
328     LM_ERR("cannot print the format for string\n");
329     return -3;
330   }
331
332   if (ip_parser_execute(string.s, string.len) == ip_type_ipv4)
333     return 1;
334   else
335     return -1;
336 }
337
338
339 /*! \brief Return true if the given argument (string or pv) is a valid IPv6. */
340 static int w_is_ipv6(struct sip_msg* _msg, char* _s)
341 {
342   str string;
343   
344   if (_s == NULL) {
345     LM_ERR("bad parameter\n");
346     return -2;
347   }
348   
349   if (fixup_get_svalue(_msg, (gparam_p)_s, &string))
350   {
351     LM_ERR("cannot print the format for string\n");
352     return -3;
353   }
354   
355   if (ip_parser_execute(string.s, string.len) == ip_type_ipv6)
356     return 1;
357   else
358     return -1;
359 }
360
361
362 /*! \brief Return true if the given argument (string or pv) is a valid IPv6 reference. */
363 static int w_is_ipv6_reference(struct sip_msg* _msg, char* _s)
364 {
365   str string;
366   
367   if (_s == NULL) {
368     LM_ERR("bad parameter\n");
369     return -2;
370   }
371   
372   if (fixup_get_svalue(_msg, (gparam_p)_s, &string))
373   {
374     LM_ERR("cannot print the format for string\n");
375     return -3;
376   }
377   
378   if (ip_parser_execute(string.s, string.len) == ip_type_ipv6_reference)
379     return 1;
380   else
381     return -1;
382 }
383
384
385 /*! \brief Return the IP type of the given argument (string or pv): 1 = IPv4, 2 = IPv6, 3 = IPv6 refenrece, -1 = invalid IP. */
386 static int w_ip_type(struct sip_msg* _msg, char* _s)
387 {
388   str string;
389   
390   if (_s == NULL) {
391     LM_ERR("bad parameter\n");
392     return -2;
393   }
394   
395   if (fixup_get_svalue(_msg, (gparam_p)_s, &string))
396   {
397     LM_ERR("cannot print the format for string\n");
398     return -3;
399   }
400   
401   switch (ip_parser_execute(string.s, string.len)) {
402     case(ip_type_ipv4):
403       return 1;
404       break;
405     case(ip_type_ipv6):
406       return 2;
407       break;
408     case(ip_type_ipv6_reference):
409       return 3;
410       break;
411     default:
412       return -1;
413       break;
414   }
415 }
416
417
418 /*! \brief Return true if both IP's (string or pv) are equal. This function also allows comparing an IPv6 with an IPv6 reference. */
419 static int w_compare_ips(struct sip_msg* _msg, char* _s1, char* _s2)
420 {
421   str string1, string2;
422   enum enum_ip_type ip1_type, ip2_type;
423   
424   if (_s1 == NULL || _s2 == NULL ) {
425     LM_ERR("bad parameters\n");
426     return -2;
427   }
428   
429   if (fixup_get_svalue(_msg, (gparam_p)_s1, &string1))
430   {
431     LM_ERR("cannot print the format for first string\n");
432     return -3;
433   }
434
435   if (fixup_get_svalue(_msg, (gparam_p)_s2, &string2))
436   {
437     LM_ERR("cannot print the format for second string\n");
438     return -3;
439   }
440
441   switch(ip1_type = ip_parser_execute(string1.s, string1.len)) {
442     case(ip_type_error):
443       return -1;
444       break;
445     case(ip_type_ipv6_reference):
446       string1.s += 1;
447       string1.len -= 2;
448       ip1_type = ip_type_ipv6;
449       break;
450     default:
451       break;
452   }
453   switch(ip2_type = ip_parser_execute(string2.s, string2.len)) {
454     case(ip_type_error):
455       return -1;
456       break;
457     case(ip_type_ipv6_reference):
458       string2.s += 1;
459       string2.len -= 2;
460       ip2_type = ip_type_ipv6;
461       break;
462     default:
463       break;
464   }
465
466   if (_compare_ips(string1.s, string1.len, ip1_type, string2.s, string2.len, ip2_type))
467     return 1;
468   else
469     return -1;
470 }
471
472
473 /*! \brief Return true if both pure IP's (string or pv) are equal. IPv6 references not allowed. */
474 static int w_compare_pure_ips(struct sip_msg* _msg, char* _s1, char* _s2)
475 {
476   str string1, string2;
477   enum enum_ip_type ip1_type, ip2_type;
478   
479   if (_s1 == NULL || _s2 == NULL ) {
480     LM_ERR("bad parameters\n");
481     return -2;
482   }
483   
484   if (fixup_get_svalue(_msg, (gparam_p)_s1, &string1))
485   {
486     LM_ERR("cannot print the format for first string\n");
487     return -3;
488   }
489   
490   if (fixup_get_svalue(_msg, (gparam_p)_s2, &string2))
491   {
492     LM_ERR("cannot print the format for second string\n");
493     return -3;
494   }
495
496   switch(ip1_type = ip_parser_execute(string1.s, string1.len)) {
497     case(ip_type_error):
498       return -1;
499       break;
500     case(ip_type_ipv6_reference):
501       return -1;
502       break;
503     default:
504       break;
505   }
506   switch(ip2_type = ip_parser_execute(string2.s, string2.len)) {
507     case(ip_type_error):
508       return -1;
509       break;
510     case(ip_type_ipv6_reference):
511       return -1;
512       break;
513     default:
514       break;
515   }
516   
517   if (_compare_ips(string1.s, string1.len, ip1_type, string2.s, string2.len, ip2_type))
518     return 1;
519   else
520     return -1;
521 }
522
523
524 /*! \brief Return true if the first IP (string or pv) is within the subnet defined by the second IP in CIDR notation. IPv6 references not allowed. */
525 static int w_ip_is_in_subnet(struct sip_msg* _msg, char* _s1, char* _s2)
526 {
527   str string1, string2;
528   enum enum_ip_type ip1_type, ip2_type;
529   char *cidr_pos = NULL;
530   int netmask = 0;
531   
532   if (_s1 == NULL || _s2 == NULL ) {
533     LM_ERR("bad parameters\n");
534     return -2;
535   }
536   
537   if (fixup_get_svalue(_msg, (gparam_p)_s1, &string1))
538   {
539     LM_ERR("cannot print the format for first string\n");
540     return -3;
541   }
542   
543   if (fixup_get_svalue(_msg, (gparam_p)_s2, &string2))
544   {
545     LM_ERR("cannot print the format for second string\n");
546     return -3;
547   }
548
549   switch(ip1_type = ip_parser_execute(string1.s, string1.len)) {
550     case(ip_type_error):
551       return -1;
552       break;
553     case(ip_type_ipv6_reference):
554       return -1;
555       break;
556     default:
557       break;
558   }
559   cidr_pos = string2.s + string2.len - 1;
560   while (cidr_pos > string2.s)
561   {
562     if (*cidr_pos == '/')
563     {
564       string2.len = (cidr_pos - string2.s);
565       netmask = atoi(cidr_pos+1);
566       break;
567     }
568     cidr_pos--;
569   }
570   switch(ip2_type = ip_parser_execute(string2.s, string2.len)) {
571     case(ip_type_error):
572       return -1;
573       break;
574     case(ip_type_ipv6_reference):
575       return -1;
576       break;
577     default:
578       break;
579   }
580
581   if (netmask == 0)
582   {
583     if (_compare_ips(string1.s, string1.len, ip1_type, string2.s, string2.len, ip2_type))
584       return 1;
585     else
586       return -1;
587   }
588   else
589   {
590     if (_ip_is_in_subnet(string1.s, string1.len, ip1_type, string2.s, string2.len, ip2_type, netmask))
591       return 1;
592     else
593       return -1;
594   }
595 }
596
597
598 /*! \brief Return true if the given argument (string or pv) is a valid RFC 1918 IPv4 (private address). */
599 static int w_is_ip_rfc1918(struct sip_msg* _msg, char* _s)
600 {
601   str string;
602   
603   if (_s == NULL) {
604     LM_ERR("bad parameter\n");
605     return -2;
606   }
607   
608   if (fixup_get_svalue(_msg, (gparam_p)_s, &string))
609   {
610     LM_ERR("cannot print the format for string\n");
611     return -3;
612   }
613   
614   if (rfc1918_parser_execute(string.s, string.len) == 1)
615     return 1;
616   else
617     return -1;
618 }
619
620 static inline ip_addr_t *strtoipX(str *ips)
621 {
622         /* try to figure out INET class */
623         if(ips->s[0] == '[' || memchr(ips->s, ':', ips->len)!=NULL)
624         {
625                 /* IPv6 */
626                 return str2ip6(ips);
627         } else {
628                 /* IPv4 */
629                 return str2ip(ips);
630         }
631 }
632
633 static int w_dns_sys_match_ip(sip_msg_t *msg, char *hnp, char *ipp)
634 {
635         struct addrinfo hints, *res, *p;
636         int status;
637         ip_addr_t *ipa;
638         void *addr;
639         str hns;
640         str ips;
641         struct sockaddr_in *ipv4;
642         struct sockaddr_in6 *ipv6;
643
644         if (fixup_get_svalue(msg, (gparam_p)hnp, &hns))
645         {
646                 LM_ERR("cannot evaluate hostname parameter\n");
647                 return -2;
648         }
649
650         if (fixup_get_svalue(msg, (gparam_p)ipp, &ips))
651         {
652                 LM_ERR("cannot evaluate ip address parameter\n");
653                 return -2;
654         }
655
656         ipa = strtoipX(&ips);
657         if(ipa==NULL)
658         {
659                 LM_ERR("invalid ip address: %.*s\n", ips.len, ips.s);
660                 return -3;
661         }
662
663         memset(&hints, 0, sizeof(hints));
664         hints.ai_family = AF_UNSPEC; /* allow any of AF_INET or AF_INET6 */
665         // hints.ai_socktype = SOCK_STREAM;
666         hints.ai_socktype = SOCK_DGRAM;
667
668         if ((status = getaddrinfo(hns.s, NULL, &hints, &res)) != 0)
669         {
670         LM_ERR("getaddrinfo: %s\n", gai_strerror(status));
671         return -4;
672     }
673
674         for(p = res;p != NULL; p = p->ai_next)
675         {
676                 if(p->ai_family==ipa->af)
677                 {
678                         if (p->ai_family==AF_INET)
679                         {
680                                 ipv4 = (struct sockaddr_in *)p->ai_addr;
681                                 addr = &(ipv4->sin_addr);
682                         } else {
683                                 ipv6 = (struct sockaddr_in6 *)p->ai_addr;
684                                 addr = &(ipv6->sin6_addr);
685                         }
686                         if(memcmp(ipa->u.addr, addr, ipa->len)==0)
687                         {
688                                 /* matched IP */
689                                 freeaddrinfo(res);
690                                 return 1;
691                         }
692                 }
693     }
694         freeaddrinfo(res);
695
696         return -1;
697 }
698
699 static int w_dns_int_match_ip(sip_msg_t *msg, char *hnp, char *ipp)
700 {
701         ip_addr_t *ipa;
702         str hns;
703         str ips;
704         struct hostent* he;
705         char ** h;
706         int ret;
707
708         if (fixup_get_svalue(msg, (gparam_p)hnp, &hns))
709         {
710                 LM_ERR("cannot evaluate hostname parameter\n");
711                 return -2;
712         }
713
714         if (fixup_get_svalue(msg, (gparam_p)ipp, &ips))
715         {
716                 LM_ERR("cannot evaluate ip address parameter\n");
717                 return -2;
718         }
719
720         ipa = strtoipX(&ips);
721         if(ipa==NULL)
722         {
723                 LM_ERR("invalid ip address: %.*s\n", ips.len, ips.s);
724                 return -3;
725         }
726
727         he=resolvehost(hns.s);
728         if (he==0) {
729                 DBG("could not resolve %s\n", hns.s);
730                 return -4;
731         }
732         ret = 0;
733         if (he->h_addrtype==ipa->af)
734         {
735                 for(h=he->h_addr_list; (*h); h++)
736                 {
737                         if(memcmp(ipa->u.addr, *h, ipa->len)==0)
738                         {
739                                 /* match */
740                                 return 1;
741                         }
742                 }
743         }
744         /* no match */
745         return -1;
746 }
747
748 /**
749  *
750  */
751 static int w_dns_query(struct sip_msg* msg, char* str1, char* str2)
752 {
753         str hostname;
754         str name;
755
756         if(msg==NULL)
757         {
758                 LM_ERR("received null msg\n");
759                 return -1;
760         }
761
762         if(fixup_get_svalue(msg, (gparam_t*)str1, &hostname)<0)
763         {
764                 LM_ERR("cannot get the hostname\n");
765                 return -1;
766         }
767         if(fixup_get_svalue(msg, (gparam_t*)str2, &name)<0)
768         {
769                 LM_ERR("cannot get the pv container name\n");
770                 return -1;
771         }
772
773         return dns_update_pv(&hostname, &name);
774 }