Forráskód Böngészése

ipops: new function dns_query(hostname, pvid)

- store the result of dns query in a variable $dns(pvid=>key)
- dns query is using getaddrinfo()
- $dns(pvid=>key) - new pv allowing to navigate through the result of a dns query
- key can be:
	- count - number of addresses
	- ipv4 - set to 1 if at least one ipv4 address (otherwise 0)
	- ipv6 - set to 1 if at least one ipv6 address (otherwise 0)
	- addr[index] - the address as string from position index in the list (0 based indexing)
	- type[index] - the type of address from position index in the list (0 based indexing), the value is 4 for ipv4 and 6 for ipv6
- example:

	if(dns_query("test.com", "xyz"))
	{
		xlog("===== number of addresses: $dns(xyz=>count)\n");
		xlog("===== ipv4 address found: $dns(xyz=>ipv4)\n");
		xlog("===== ipv6 address found: $dns(xyz=>ipv6)\n");
		$var(i) = 0;
		while($var(i)<$dns(xyz=>count)) {
			xlog("===== #[$var(i)] type ($dns(xyz=>addr[$var(i)])) addr [$dns(xyz=>addr[$var(i)])]\n");
			$var(i) = $var(i) + 1;
		}
	}
Daniel-Constantin Mierla 12 éve
szülő
commit
20f3846d6d
3 módosított fájl, 508 hozzáadás és 1 törlés
  1. 41 1
      modules/ipops/ipops_mod.c
  2. 428 0
      modules/ipops/ipops_pv.c
  3. 39 0
      modules/ipops/ipops_pv.h

+ 41 - 1
modules/ipops/ipops_mod.c

@@ -51,6 +51,7 @@
 #include "../../pvar.h"
 #include "../../pvar.h"
 #include "../../resolve.h"
 #include "../../resolve.h"
 #include "api.h"
 #include "api.h"
+#include "ipops_pv.h"
 #include "ip_parser.h"
 #include "ip_parser.h"
 #include "rfc1918_parser.h"
 #include "rfc1918_parser.h"
 
 
@@ -90,6 +91,13 @@ 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_sys_match_ip(sip_msg_t*, char*, char*);
 static int w_dns_int_match_ip(sip_msg_t*, char*, char*);
 static int w_dns_int_match_ip(sip_msg_t*, char*, char*);
 
 
+static int w_dns_query(struct sip_msg* msg, char* str1, char* str2);
+
+static pv_export_t mod_pvs[] = {
+	{ {"dns", sizeof("dns")-1}, PVT_OTHER, pv_get_dns, 0,
+		pv_parse_dns_name, 0, 0, 0 },
+	{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
+};
 
 
 /*
 /*
  * Exported functions
  * Exported functions
@@ -120,6 +128,8 @@ static cmd_export_t cmds[] =
   ANY_ROUTE },
   ANY_ROUTE },
   { "dns_int_match_ip", (cmd_function)w_dns_int_match_ip, 2, fixup_spve_spve, 0,
   { "dns_int_match_ip", (cmd_function)w_dns_int_match_ip, 2, fixup_spve_spve, 0,
   ANY_ROUTE },
   ANY_ROUTE },
+  { "dns_query", (cmd_function)w_dns_query, 2, fixup_spve_spve, 0,
+  ANY_ROUTE },
   { "bind_ipops", (cmd_function)bind_ipops, 0, 0, 0, 0},
   { "bind_ipops", (cmd_function)bind_ipops, 0, 0, 0, 0},
   { 0, 0, 0, 0, 0, 0 }
   { 0, 0, 0, 0, 0, 0 }
 };
 };
@@ -135,7 +145,7 @@ struct module_exports exports = {
   0,                         /*!< exported parameters */
   0,                         /*!< exported parameters */
   0,                         /*!< exported statistics */
   0,                         /*!< exported statistics */
   0,                         /*!< exported MI functions */
   0,                         /*!< exported MI functions */
-  0,                         /*!< exported pseudo-variables */
+  mod_pvs,                   /*!< exported pseudo-variables */
   0,                         /*!< extra processes */
   0,                         /*!< extra processes */
   0,                         /*!< module initialization function */
   0,                         /*!< module initialization function */
   (response_function) 0,     /*!< response handling function */
   (response_function) 0,     /*!< response handling function */
@@ -652,6 +662,8 @@ static int w_dns_sys_match_ip(sip_msg_t *msg, char *hnp, char *ipp)
 
 
 	memset(&hints, 0, sizeof(hints));
 	memset(&hints, 0, sizeof(hints));
 	hints.ai_family = AF_UNSPEC; /* allow any of AF_INET or AF_INET6 */
 	hints.ai_family = AF_UNSPEC; /* allow any of AF_INET or AF_INET6 */
+	// hints.ai_socktype = SOCK_STREAM;
+	hints.ai_socktype = SOCK_DGRAM;
 
 
 	if ((status = getaddrinfo(hns.s, NULL, &hints, &res)) != 0)
 	if ((status = getaddrinfo(hns.s, NULL, &hints, &res)) != 0)
 	{
 	{
@@ -732,3 +744,31 @@ static int w_dns_int_match_ip(sip_msg_t *msg, char *hnp, char *ipp)
 	/* no match */
 	/* no match */
 	return -1;
 	return -1;
 }
 }
+
+/**
+ *
+ */
+static int w_dns_query(struct sip_msg* msg, char* str1, char* str2)
+{
+	str hostname;
+	str name;
+
+	if(msg==NULL)
+	{
+		LM_ERR("received null msg\n");
+		return -1;
+	}
+
+	if(fixup_get_svalue(msg, (gparam_t*)str1, &hostname)<0)
+	{
+		LM_ERR("cannot get the hostname\n");
+		return -1;
+	}
+	if(fixup_get_svalue(msg, (gparam_t*)str2, &name)<0)
+	{
+		LM_ERR("cannot get the pv container name\n");
+		return -1;
+	}
+
+	return dns_update_pv(&hostname, &name);
+}

+ 428 - 0
modules/ipops/ipops_pv.c

@@ -0,0 +1,428 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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
+ *
+ *
+ * This file 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 <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "../../dprint.h"
+#include "../../hashes.h"
+#include "../../pvar.h"
+
+
+#define PV_DNS_ADDR 64
+#define PV_DNS_RECS 32
+
+typedef struct _sr_dns_record {
+	int type;
+	char addr[PV_DNS_ADDR];
+} sr_dns_record_t;
+
+typedef struct _sr_dns_item {
+	str name;
+	unsigned int hashid;
+	char hostname[256];
+	int count;
+	int ipv4;
+	int ipv6;
+	sr_dns_record_t r[PV_DNS_RECS];
+	struct _sr_dns_item *next;
+} sr_dns_item_t;
+
+#define SR_DNS_PVIDX	1
+
+typedef struct _dns_pv {
+	sr_dns_item_t *item;
+	int type;
+	int flags;
+	pv_spec_t *pidx;
+	int nidx;
+} dns_pv_t;
+
+
+static sr_dns_item_t *_sr_dns_list = NULL;
+
+/**
+ *
+ */
+sr_dns_item_t *sr_dns_get_item(str *name)
+{
+	sr_dns_item_t *it = NULL;
+	unsigned int hashid = 0;
+
+	hashid =  get_hash1_raw(name->s, name->len);
+
+	it = _sr_dns_list;
+	while(it!=NULL)
+	{
+		if(it->hashid==hashid && it->name.len == name->len
+				&& strncmp(it->name.s, name->s, name->len)==0)
+			return it;
+		it = it->next;
+	}
+	return NULL;
+}
+
+/**
+ *
+ */
+sr_dns_item_t *sr_dns_add_item(str *name)
+{
+	sr_dns_item_t *it = NULL;
+	unsigned int hashid = 0;
+
+	hashid =  get_hash1_raw(name->s, name->len);
+
+	it = _sr_dns_list;
+	while(it!=NULL)
+	{
+		if(it->hashid==hashid && it->name.len == name->len
+				&& strncmp(it->name.s, name->s, name->len)==0)
+			return it;
+		it = it->next;
+	}
+	/* add new */
+	it = (sr_dns_item_t*)pkg_malloc(sizeof(sr_dns_item_t));
+	if(it==NULL)
+	{
+		LM_ERR("no more pkg\n");
+		return NULL;
+	}
+	memset(it, 0, sizeof(sr_dns_item_t));
+	it->name.s = (char*)pkg_malloc(name->len+1);
+	if(it->name.s==NULL)
+	{
+		LM_ERR("no more pkg.\n");
+		pkg_free(it);
+		return NULL;
+	}
+	memcpy(it->name.s, name->s, name->len);
+	it->name.s[name->len] = '\0';
+	it->name.len = name->len;
+	it->hashid = hashid;
+	it->next = _sr_dns_list;
+	_sr_dns_list = it;
+	return it;
+}
+
+
+/**
+ *
+ */
+int pv_parse_dns_name(pv_spec_t *sp, str *in)
+{
+	dns_pv_t *dpv=NULL;
+	char *p;
+	str pvc;
+	str pvs;
+	str pvi;
+	int sign;
+
+	if(sp==NULL || in==NULL || in->len<=0)
+		return -1;
+
+	dpv = (dns_pv_t*)pkg_malloc(sizeof(dns_pv_t));
+	if(dpv==NULL)
+		return -1;
+
+	memset(dpv, 0, sizeof(dns_pv_t));
+
+	p = in->s;
+
+	while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
+		p++;
+	if(p>in->s+in->len || *p=='\0')
+		goto error;
+	pvc.s = p;
+	while(p < in->s + in->len)
+	{
+		if(*p=='=' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r')
+			break;
+		p++;
+	}
+	if(p>in->s+in->len || *p=='\0')
+		goto error;
+	pvc.len = p - pvc.s;
+	if(*p!='=')
+	{
+		while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
+			p++;
+		if(p>in->s+in->len || *p=='\0' || *p!='=')
+			goto error;
+	}
+	p++;
+	if(*p!='>')
+		goto error;
+	p++;
+
+	pvs.len = in->len - (int)(p - in->s);
+	pvs.s = p;
+	pvi.s = 0;
+	pvi.len = 0;
+	if(pvs.s[pvs.len-1]==']') {
+		/* index */
+		p = memchr(pvs.s, '[', pvs.len-1);
+		if(p==NULL) {
+			goto error;
+		}
+		pvi.s = p + 1;
+		pvi.len = pvs.s + pvs.len - pvi.s;
+		pvs.len = p - pvs.s;
+	}
+	LM_DBG("dns [%.*s] - key [%.*s] index [%.*s]\n", pvc.len, pvc.s,
+			pvs.len, pvs.s, (pvi.len>0)?pvi.len:0, (pvi.s!=NULL)?pvi.s:0);
+
+	dpv->item = sr_dns_add_item(&pvc);
+	if(dpv->item==NULL)
+		goto error;
+
+	switch(pvs.len)
+	{
+		case 4: 
+			if(strncmp(pvs.s, "addr", 4)==0)
+				dpv->type = 0;
+			else if(strncmp(pvs.s, "type", 4)==0)
+				dpv->type = 1;
+			else if(strncmp(pvs.s, "ipv4", 4)==0)
+				dpv->type = 2;
+			else if(strncmp(pvs.s, "ipv6", 4)==0)
+				dpv->type = 3;
+			else goto error;
+		break;
+		case 5: 
+			if(strncmp(pvs.s, "count", 5)==0)
+				dpv->type = 4;
+			else goto error;
+		break;
+		default:
+			goto error;
+	}
+
+	if(pvi.len>0)
+	{
+		if(pvi.s[0]==PV_MARKER)
+		{
+			dpv->pidx = pv_cache_get(&pvi);
+			if(dpv->pidx==NULL)
+				goto error;
+			dpv->flags |= SR_DNS_PVIDX;
+		} else {
+			sign = 1;
+			p = pvi.s;
+			if(*p=='-')
+			{
+				sign = -1;
+				p++;
+			}
+			dpv->nidx = 0;
+			while(p<pvi.s+pvi.len && *p>='0' && *p<='9')
+			{
+				dpv->nidx = dpv->nidx * 10 + *p - '0';
+				p++;
+			}
+			if(p!=pvi.s+pvi.len)
+			{
+				LM_ERR("invalid index [%.*s]\n", in->len, in->s);
+				return -1;
+			}
+			dpv->nidx *= sign;
+		}
+	}
+	sp->pvp.pvn.u.dname = (void*)dpv;
+	sp->pvp.pvn.type = PV_NAME_OTHER;
+
+	return 0;
+
+error:
+	LM_ERR("error at PV dns name: %.*s\n", in->len, in->s);
+	return -1;
+}
+
+/**
+ *
+ */
+int pv_get_dns(sip_msg_t *msg, pv_param_t *param,
+		pv_value_t *res)
+{
+	dns_pv_t *dpv;
+	pv_value_t val;
+
+	if(msg==NULL || param==NULL)
+		return -1;
+
+	dpv = (dns_pv_t*)param->pvn.u.dname;
+	if(dpv==NULL || dpv->item==NULL)
+		return -1;
+
+	if(dpv->pidx!=NULL)
+	{
+		if(pv_get_spec_value(msg, dpv->pidx, &val)<0
+				|| (!(val.flags&PV_VAL_INT)))
+		{
+			LM_ERR("failed to evaluate index variable\n");
+			return pv_get_null(msg, param, res);
+		}
+	} else {
+		val.ri = dpv->nidx;
+	}
+	if(val.ri<0)
+	{
+		if(dpv->item->count+val.ri<0) {
+			return pv_get_null(msg, param, res);
+		}
+		val.ri = dpv->item->count+val.ri;
+	}
+	if(val.ri>=dpv->item->count) {
+		return pv_get_null(msg, param, res);
+	}
+	switch(dpv->type)
+	{
+		case 0: /* address */
+			return pv_get_strzval(msg, param, res,
+					dpv->item->r[val.ri].addr);
+		case 1: /* type */
+			return pv_get_sintval(msg, param, res,
+					dpv->item->r[val.ri].type);
+		case 2: /* ipv4 */
+			return pv_get_sintval(msg, param, res,
+					dpv->item->ipv4);
+		case 3: /* ipv6 */
+			return pv_get_sintval(msg, param, res,
+					dpv->item->ipv6);
+		case 4: /* count */
+			return pv_get_sintval(msg, param, res,
+					dpv->item->count);
+		default: /* else */
+			return pv_get_null(msg, param, res);
+	}
+}
+
+/**
+ *
+ */
+int dns_init_pv(char *path)
+{
+	return 0;
+}
+
+/**
+ *
+ */
+void dns_destroy_list(void)
+{
+	return;
+}
+
+/**
+ *
+ */
+void dns_destroy_pv(void)
+{
+	return;
+}
+
+/**
+ *
+ */
+int dns_update_pv(str *hostname, str *name)
+{
+	sr_dns_item_t *dr = NULL;
+	struct addrinfo hints, *res, *p;
+	struct sockaddr_in *ipv4;
+	struct sockaddr_in6 *ipv6;
+	void *addr;
+	int status;
+	int i;
+	
+	if(hostname->len>255)
+	{
+		LM_DBG("target hostname too long (max 255): %s\n", hostname->s);
+		return -2;
+	}
+	
+	dr = sr_dns_get_item(name);
+	if(dr==NULL)
+	{
+		LM_DBG("container not found: %s\n", name->s);
+		return -3;
+	}
+
+	/* reset the counter */
+	dr->count = 0;
+
+	strncpy(dr->hostname, hostname->s, hostname->len);
+	dr->hostname[hostname->len] = '\0';
+	LM_DBG("attempting to resolve: %s\n", dr->hostname);
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_UNSPEC; /* allow any of AF_INET or AF_INET6 */
+	// hints.ai_socktype = SOCK_STREAM;
+	hints.ai_socktype = SOCK_DGRAM;
+
+	if ((status = getaddrinfo(dr->hostname, NULL, &hints, &res)) != 0)
+	{
+        LM_ERR("unable to resolve %s - getaddrinfo: %s\n",
+				dr->hostname, gai_strerror(status));
+        return -4;
+    }
+
+	i=0;
+	for(p=res; p!=NULL; p=p->ai_next)
+	{
+		if (p->ai_family==AF_INET)
+		{
+			dr->ipv4 = 1;
+			dr->r[i].type = 4;
+			ipv4 = (struct sockaddr_in *)p->ai_addr;
+			addr = &(ipv4->sin_addr);
+		} else {
+			dr->ipv6 = 1;
+			dr->r[i].type = 6;
+			ipv6 = (struct sockaddr_in6 *)p->ai_addr;
+			addr = &(ipv6->sin6_addr);
+		}
+		inet_ntop(p->ai_family, addr, dr->r[i].addr,
+				PV_DNS_ADDR);
+		LM_DBG("#%d - type %d addr: %s (%d)\n", i, dr->r[i].type,
+				dr->r[i].addr, p->ai_socktype);
+		i++;
+		if(i==PV_DNS_RECS) {
+			LM_WARN("more than %d addresses for %s - truncating\n",
+					PV_DNS_RECS, dr->hostname);
+			break;
+		}
+    }
+	freeaddrinfo(res);
+
+	dr->count = i;
+
+	LM_DBG("dns PV updated for: %s (%d)\n", dr->hostname, i);
+
+	return 1;
+}

+ 39 - 0
modules/ipops/ipops_pv.h

@@ -0,0 +1,39 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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
+ *
+ *
+ * This file 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_PV_H_
+#define _IPOPS_PV_H_
+
+#include "../../pvar.h"
+
+int pv_parse_dns_name(pv_spec_t *sp, str *in);
+int pv_get_dns(sip_msg_t *msg, pv_param_t *param,
+		pv_value_t *res);
+
+int dns_init_pv(char *path);
+void dns_destroy_pv(void);
+int dns_update_pv(str *tomatch, str *name);
+
+#endif
+