#include "../../pvar.h"
#include "../../resolve.h"
#include "api.h"
+#include "ipops_pv.h"
#include "ip_parser.h"
#include "rfc1918_parser.h"
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_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
ANY_ROUTE },
{ "dns_int_match_ip", (cmd_function)w_dns_int_match_ip, 2, fixup_spve_spve, 0,
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},
{ 0, 0, 0, 0, 0, 0 }
};
0, /*!< exported parameters */
0, /*!< exported statistics */
0, /*!< exported MI functions */
- 0, /*!< exported pseudo-variables */
+ mod_pvs, /*!< exported pseudo-variables */
0, /*!< extra processes */
0, /*!< module initialization function */
(response_function) 0, /*!< response handling function */
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(hns.s, NULL, &hints, &res)) != 0)
{
/* no match */
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);
+}
--- /dev/null
+/**
+ * $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;
+}