Tue Feb 10 08:11:37 CST 2009 Pekka Pessi <first.last@nokia.com>
* check_nua: use s2dns git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@11937 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
ea9eaeaf44
commit
f4ab414190
|
@ -37,6 +37,7 @@
|
|||
#define TP_MAGIC_T struct tp_magic_s
|
||||
|
||||
#include "test_s2.h"
|
||||
#include "s2dns.h"
|
||||
|
||||
#include <sofia-sip/sip_header.h>
|
||||
#include <sofia-sip/sip_status.h>
|
||||
|
@ -45,6 +46,7 @@
|
|||
#include <sofia-sip/su_tagarg.h>
|
||||
#include <sofia-sip/su_alloc.h>
|
||||
#include <sofia-sip/su_string.h>
|
||||
#include <sofia-sip/sresolv.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -1058,471 +1060,6 @@ s2_setup_tport(char const * const *protocols,
|
|||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* S2 DNS server */
|
||||
|
||||
#include <sofia-resolv/sres_record.h>
|
||||
|
||||
extern uint16_t _sres_default_port;
|
||||
|
||||
static int s2_dns_query(struct tester *s2,
|
||||
su_wait_t *w,
|
||||
su_wakeup_arg_t *arg);
|
||||
|
||||
void s2_setup_dns(void)
|
||||
{
|
||||
int n;
|
||||
su_socket_t socket;
|
||||
su_wait_t *wait;
|
||||
su_sockaddr_t su[1];
|
||||
socklen_t sulen = sizeof su->su_sin;
|
||||
|
||||
assert(s2->nua == NULL); assert(s2->root != NULL);
|
||||
|
||||
memset(su, 0, sulen);
|
||||
su->su_len = sulen;
|
||||
su->su_family = AF_INET;
|
||||
|
||||
/* su->su_port = htons(1053); */
|
||||
|
||||
socket = su_socket(su->su_family, SOCK_DGRAM, 0);
|
||||
|
||||
n = bind(socket, &su->su_sa, sulen); assert(n == 0);
|
||||
n = getsockname(socket, &su->su_sa, &sulen); assert(n == 0);
|
||||
|
||||
_sres_default_port = ntohs(su->su_port);
|
||||
|
||||
wait = s2->dns.wait;
|
||||
n = su_wait_create(wait, socket, SU_WAIT_IN); assert(n == 0);
|
||||
s2->dns.reg = su_root_register(s2->root, wait, s2_dns_query, NULL, 0);
|
||||
assert(s2->dns.reg > 0);
|
||||
s2->dns.socket = socket;
|
||||
}
|
||||
|
||||
static
|
||||
struct s2_dns_response {
|
||||
struct s2_dns_response *next;
|
||||
uint16_t qlen, dlen;
|
||||
struct m_header {
|
||||
/* Header defined in RFC 1035 section 4.1.1 (page 26) */
|
||||
uint16_t mh_id; /* Query ID */
|
||||
uint16_t mh_flags; /* Flags */
|
||||
uint16_t mh_qdcount; /* Question record count */
|
||||
uint16_t mh_ancount; /* Answer record count */
|
||||
uint16_t mh_nscount; /* Authority records count */
|
||||
uint16_t mh_arcount; /* Additional records count */
|
||||
} header[1];
|
||||
uint8_t data[1500];
|
||||
} *zonedata;
|
||||
|
||||
enum {
|
||||
FLAGS_QR = (1 << 15),
|
||||
FLAGS_QUERY = (0 << 11),
|
||||
FLAGS_IQUERY = (1 << 11),
|
||||
FLAGS_STATUS = (2 << 11),
|
||||
FLAGS_OPCODE = (15 << 11), /* mask */
|
||||
FLAGS_AA = (1 << 10), /* */
|
||||
FLAGS_TC = (1 << 9),
|
||||
FLAGS_RD = (1 << 8),
|
||||
FLAGS_RA = (1 << 7),
|
||||
|
||||
FLAGS_RCODE = (15 << 0), /* mask of return code */
|
||||
|
||||
FLAGS_OK = 0, /* No error condition. */
|
||||
FLAGS_FORMAT_ERR = 1, /* Server could not interpret query. */
|
||||
FLAGS_SERVER_ERR = 2, /* Server error. */
|
||||
FLAGS_NAME_ERR = 3, /* No domain name. */
|
||||
FLAGS_UNIMPL_ERR = 4, /* Not implemented. */
|
||||
FLAGS_AUTH_ERR = 5, /* Refused */
|
||||
};
|
||||
|
||||
uint32_t s2_dns_ttl = 3600;
|
||||
|
||||
static int
|
||||
s2_dns_query(struct tester *s2,
|
||||
su_wait_t *w,
|
||||
su_wakeup_arg_t *arg)
|
||||
{
|
||||
union {
|
||||
struct m_header header[1];
|
||||
uint8_t buffer[1500];
|
||||
} request;
|
||||
ssize_t len;
|
||||
|
||||
su_socket_t socket;
|
||||
su_sockaddr_t su[1];
|
||||
socklen_t sulen = sizeof su;
|
||||
uint16_t flags;
|
||||
struct s2_dns_response *r;
|
||||
size_t const hlen = sizeof r->header;
|
||||
|
||||
(void)arg;
|
||||
|
||||
socket = s2->dns.socket;
|
||||
|
||||
len = su_recvfrom(socket, request.buffer, sizeof request.buffer, 0,
|
||||
&su->su_sa, &sulen);
|
||||
|
||||
flags = ntohs(request.header->mh_flags);
|
||||
|
||||
if (len < (ssize_t)hlen)
|
||||
return 0;
|
||||
if ((flags & FLAGS_QR) == FLAGS_QR)
|
||||
return 0;
|
||||
if ((flags & FLAGS_RCODE) != FLAGS_OK)
|
||||
return 0;
|
||||
|
||||
if ((flags & FLAGS_OPCODE) != FLAGS_QUERY
|
||||
|| ntohs(request.header->mh_qdcount) != 1) {
|
||||
flags |= FLAGS_QR | FLAGS_UNIMPL_ERR;
|
||||
request.header->mh_flags = htons(flags);
|
||||
su_sendto(socket, request.buffer, len, 0, &su->su_sa, sulen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (r = zonedata; r; r = r->next) {
|
||||
if (memcmp(r->data, request.buffer + hlen, r->qlen) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (r) {
|
||||
flags |= FLAGS_QR | FLAGS_AA | FLAGS_OK;
|
||||
request.header->mh_flags = htons(flags);
|
||||
request.header->mh_ancount = htons(r->header->mh_ancount);
|
||||
request.header->mh_nscount = htons(r->header->mh_nscount);
|
||||
request.header->mh_arcount = htons(r->header->mh_arcount);
|
||||
memcpy(request.buffer + hlen + r->qlen,
|
||||
r->data + r->qlen,
|
||||
r->dlen - r->qlen);
|
||||
len = hlen + r->dlen;
|
||||
}
|
||||
else {
|
||||
flags |= FLAGS_QR | FLAGS_AA | FLAGS_NAME_ERR;
|
||||
}
|
||||
|
||||
request.header->mh_flags = htons(flags);
|
||||
su_sendto(socket, request.buffer, len, 0, &su->su_sa, sulen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void put_uint16(struct s2_dns_response *m, uint16_t h)
|
||||
{
|
||||
uint8_t *p = m->data + m->dlen;
|
||||
|
||||
assert(m->dlen + (sizeof h) < sizeof m->data);
|
||||
p[0] = h >> 8; p[1] = h;
|
||||
m->dlen += (sizeof h);
|
||||
}
|
||||
|
||||
static void put_uint32(struct s2_dns_response *m, uint32_t w)
|
||||
{
|
||||
uint8_t *p = m->data + m->dlen;
|
||||
|
||||
assert(m->dlen + (sizeof w) < sizeof m->data);
|
||||
p[0] = w >> 24; p[1] = w >> 16; p[2] = w >> 8; p[3] = w;
|
||||
m->dlen += (sizeof w);
|
||||
}
|
||||
|
||||
static void put_domain(struct s2_dns_response *m, char const *domain)
|
||||
{
|
||||
char const *label;
|
||||
size_t llen;
|
||||
|
||||
/* Copy domain into query label at a time */
|
||||
for (label = domain; label && label[0]; label += llen) {
|
||||
assert(!(label[0] == '.' && label[1] != '\0'));
|
||||
llen = strcspn(label, ".");
|
||||
assert(llen < 64);
|
||||
assert(m->dlen + llen + 1 < sizeof m->data);
|
||||
m->data[m->dlen++] = (uint8_t)llen;
|
||||
if (llen == 0)
|
||||
return;
|
||||
|
||||
memcpy(m->data + m->dlen, label, llen);
|
||||
m->dlen += (uint16_t)llen;
|
||||
|
||||
if (label[llen] == '\0')
|
||||
break;
|
||||
if (label[llen + 1])
|
||||
llen++;
|
||||
}
|
||||
|
||||
assert(m->dlen < sizeof m->data);
|
||||
m->data[m->dlen++] = '\0';
|
||||
}
|
||||
|
||||
static void put_string(struct s2_dns_response *m, char const *string)
|
||||
{
|
||||
uint8_t *p = m->data + m->dlen;
|
||||
size_t len = strlen(string);
|
||||
|
||||
assert(len <= 255);
|
||||
assert(m->dlen + len + 1 < sizeof m->data);
|
||||
|
||||
*p++ = (uint8_t)len;
|
||||
memcpy(p, string, len);
|
||||
m->dlen += len + 1;
|
||||
}
|
||||
|
||||
static uint16_t put_len_at(struct s2_dns_response *m)
|
||||
{
|
||||
uint16_t at = m->dlen;
|
||||
assert(m->dlen + sizeof(at) < sizeof m->data);
|
||||
memset(m->data + m->dlen, 0, sizeof(at));
|
||||
m->dlen += sizeof(at);
|
||||
return at;
|
||||
}
|
||||
|
||||
static void put_len(struct s2_dns_response *m, uint16_t start)
|
||||
{
|
||||
uint8_t *p = m->data + start;
|
||||
uint16_t len = m->dlen - (start + 2);
|
||||
p[0] = len >> 8; p[1] = len;
|
||||
}
|
||||
|
||||
static void put_data(struct s2_dns_response *m, void *data, uint16_t len)
|
||||
{
|
||||
assert(m->dlen + len < sizeof m->data);
|
||||
memcpy(m->data + m->dlen, data, len);
|
||||
m->dlen += len;
|
||||
}
|
||||
|
||||
static void put_query(struct s2_dns_response *m, char const *domain,
|
||||
uint16_t qtype)
|
||||
{
|
||||
assert(m->header->mh_qdcount == 0);
|
||||
put_domain(m, domain), put_uint16(m, qtype), put_uint16(m, sres_class_in);
|
||||
m->header->mh_qdcount++;
|
||||
m->qlen = m->dlen;
|
||||
}
|
||||
|
||||
static void put_a_record(struct s2_dns_response *m,
|
||||
char const *domain,
|
||||
struct in_addr addr)
|
||||
{
|
||||
uint16_t start;
|
||||
|
||||
put_domain(m, domain);
|
||||
put_uint16(m, sres_type_a);
|
||||
put_uint16(m, sres_class_in);
|
||||
put_uint32(m, s2_dns_ttl);
|
||||
start = put_len_at(m);
|
||||
|
||||
put_data(m, &addr, sizeof addr);
|
||||
put_len(m, start);
|
||||
}
|
||||
|
||||
static void put_srv_record(struct s2_dns_response *m,
|
||||
char const *domain,
|
||||
uint16_t prio, uint16_t weight,
|
||||
uint16_t port, char const *target)
|
||||
{
|
||||
uint16_t start;
|
||||
put_domain(m, domain);
|
||||
put_uint16(m, sres_type_srv);
|
||||
put_uint16(m, sres_class_in);
|
||||
put_uint32(m, s2_dns_ttl);
|
||||
start = put_len_at(m);
|
||||
|
||||
put_uint16(m, prio);
|
||||
put_uint16(m, weight);
|
||||
put_uint16(m, port);
|
||||
put_domain(m, target);
|
||||
put_len(m, start);
|
||||
}
|
||||
|
||||
static void put_naptr_record(struct s2_dns_response *m,
|
||||
char const *domain,
|
||||
uint16_t order, uint16_t preference,
|
||||
char const *flags,
|
||||
char const *services,
|
||||
char const *regexp,
|
||||
char const *replace)
|
||||
{
|
||||
uint16_t start;
|
||||
put_domain(m, domain);
|
||||
put_uint16(m, sres_type_naptr);
|
||||
put_uint16(m, sres_class_in);
|
||||
put_uint32(m, s2_dns_ttl);
|
||||
start = put_len_at(m);
|
||||
|
||||
put_uint16(m, order);
|
||||
put_uint16(m, preference);
|
||||
put_string(m, flags);
|
||||
put_string(m, services);
|
||||
put_string(m, regexp);
|
||||
put_domain(m, replace);
|
||||
put_len(m, start);
|
||||
}
|
||||
|
||||
static void put_srv_record_from_uri(struct s2_dns_response *m,
|
||||
char const *base,
|
||||
uint16_t prio, uint16_t weight,
|
||||
url_t const *uri, char const *server)
|
||||
{
|
||||
char domain[1024] = "none";
|
||||
char const *service = url_port(uri);
|
||||
uint16_t port;
|
||||
|
||||
if (uri->url_type == url_sips) {
|
||||
strcpy(domain, "_sips._tcp.");
|
||||
}
|
||||
else if (uri->url_type == url_sip) {
|
||||
if (url_has_param(uri, "transport=udp")) {
|
||||
strcpy(domain, "_sip._udp.");
|
||||
}
|
||||
else if (url_has_param(uri, "transport=tcp")) {
|
||||
strcpy(domain, "_sip._tcp.");
|
||||
}
|
||||
}
|
||||
|
||||
assert(strcmp(domain, "none"));
|
||||
|
||||
strcat(domain, base);
|
||||
|
||||
if (m->header->mh_qdcount == 0)
|
||||
put_query(m, domain, sres_type_srv);
|
||||
|
||||
port = (uint16_t)strtoul(service, NULL, 10);
|
||||
|
||||
put_srv_record(m, domain, prio, weight, port, server);
|
||||
}
|
||||
|
||||
static
|
||||
void s2_add_to_zone(struct s2_dns_response *_r)
|
||||
{
|
||||
size_t size = offsetof(struct s2_dns_response, data[_r->dlen]);
|
||||
struct s2_dns_response *r = malloc(size); assert(r);
|
||||
|
||||
memcpy(r, _r, size);
|
||||
r->next = zonedata;
|
||||
zonedata = r;
|
||||
}
|
||||
|
||||
|
||||
static void make_server(char *server, char const *prefix, char const *domain)
|
||||
{
|
||||
strcpy(server, prefix);
|
||||
|
||||
if (strlen(server) == 0 || server[strlen(server) - 1] != '.') {
|
||||
strcat(server, ".");
|
||||
strcat(server, domain);
|
||||
}
|
||||
}
|
||||
|
||||
/** Set up DNS domain */
|
||||
void s2_dns_domain(char const *domain, int use_naptr,
|
||||
/* char *prefix, int priority, url_t const *uri, */
|
||||
...)
|
||||
{
|
||||
struct s2_dns_response m[1];
|
||||
|
||||
char server[1024], target[1024];
|
||||
|
||||
va_list va0, va;
|
||||
char const *prefix; int priority; url_t const *uri;
|
||||
struct in_addr localhost;
|
||||
|
||||
assert(s2->dns.reg != 0);
|
||||
|
||||
su_inet_pton(AF_INET, "127.0.0.1", &localhost);
|
||||
|
||||
va_start(va0, use_naptr);
|
||||
|
||||
if (use_naptr) {
|
||||
memset(m, 0, sizeof m);
|
||||
put_query(m, domain, sres_type_naptr);
|
||||
|
||||
va_copy(va, va0);
|
||||
|
||||
for (;(prefix = va_arg(va, char *));) {
|
||||
char *services = NULL;
|
||||
|
||||
priority = va_arg(va, int);
|
||||
uri = va_arg(va, url_t *); assert(uri);
|
||||
|
||||
if (uri->url_type == url_sips) {
|
||||
services = "SIPS+D2T";
|
||||
strcpy(target, "_sips._tcp.");
|
||||
}
|
||||
else if (uri->url_type == url_sip) {
|
||||
if (url_has_param(uri, "transport=udp")) {
|
||||
services = "SIP+D2U";
|
||||
strcpy(target, "_sip._udp.");
|
||||
}
|
||||
else if (url_has_param(uri, "transport=tcp")) {
|
||||
services = "SIP+D2T";
|
||||
strcpy(target, "_sip._tcp.");
|
||||
}
|
||||
}
|
||||
|
||||
strcat(target, domain);
|
||||
assert(services);
|
||||
put_naptr_record(m, domain, 1, priority, "s", services, "", target);
|
||||
m->header->mh_ancount++;
|
||||
}
|
||||
|
||||
va_end(va);
|
||||
va_copy(va, va0);
|
||||
|
||||
for (;(prefix = va_arg(va, char *));) {
|
||||
priority = va_arg(va, int);
|
||||
uri = va_arg(va, url_t *); assert(uri);
|
||||
|
||||
make_server(server, prefix, domain);
|
||||
|
||||
put_srv_record_from_uri(m, domain, priority, 10, uri, server);
|
||||
m->header->mh_arcount++;
|
||||
|
||||
put_a_record(m, server, localhost);
|
||||
m->header->mh_arcount++;
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
s2_add_to_zone(m);
|
||||
}
|
||||
|
||||
/* Add SRV records */
|
||||
va_copy(va, va0);
|
||||
for (;(prefix = va_arg(va, char *));) {
|
||||
priority = va_arg(va, int);
|
||||
uri = va_arg(va, url_t *); assert(uri);
|
||||
|
||||
make_server(server, prefix, domain);
|
||||
|
||||
memset(m, 0, sizeof m);
|
||||
put_srv_record_from_uri(m, domain, priority, 10, uri, server);
|
||||
m->header->mh_ancount++;
|
||||
|
||||
strcpy(server, prefix); strcat(server, domain);
|
||||
|
||||
put_a_record(m, server, localhost);
|
||||
m->header->mh_arcount++;
|
||||
|
||||
s2_add_to_zone(m);
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
/* Add A records */
|
||||
va_copy(va, va0);
|
||||
for (;(prefix = va_arg(va, char *));) {
|
||||
(void)va_arg(va, int);
|
||||
(void)va_arg(va, url_t *);
|
||||
|
||||
memset(m, 0, sizeof m);
|
||||
make_server(server, prefix, domain);
|
||||
|
||||
put_query(m, server, sres_type_a);
|
||||
put_a_record(m, server, localhost);
|
||||
m->header->mh_ancount++;
|
||||
|
||||
s2_add_to_zone(m);
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
va_end(va0);
|
||||
}
|
||||
|
||||
static char const *s2_teardown_label = NULL;
|
||||
|
||||
void
|
||||
|
@ -1552,28 +1089,25 @@ s2_teardown(void)
|
|||
|
||||
/* ====================================================================== */
|
||||
|
||||
#include <sofia-sip/sresolv.h>
|
||||
|
||||
nua_t *s2_nua_setup(char const *label,
|
||||
tag_type_t tag, tag_value_t value, ...)
|
||||
{
|
||||
ta_list ta;
|
||||
|
||||
s2_setup_base(label, NULL);
|
||||
s2_setup_dns();
|
||||
s2_dns_setup(s2->root);
|
||||
|
||||
s2_setup_logs(0);
|
||||
s2_setup_tport(NULL, TAG_END());
|
||||
assert(s2->contact);
|
||||
|
||||
/* enable/disable multithreading */
|
||||
su_root_threading(s2->root, s2_nua_thread);
|
||||
|
||||
s2_dns_domain("example.org", 1,
|
||||
"s2", 1, s2->udp.contact->m_url,
|
||||
"s2", 1, s2->tcp.contact->m_url,
|
||||
NULL);
|
||||
|
||||
/* enable/disable multithreading */
|
||||
su_root_threading(s2->root, s2_nua_thread);
|
||||
|
||||
ta_start(ta, tag, value);
|
||||
s2->nua =
|
||||
nua_create(s2->root,
|
||||
|
@ -1583,6 +1117,7 @@ nua_t *s2_nua_setup(char const *label,
|
|||
/* NUTAG_PROXY((url_string_t *)s2->contact->m_url), */
|
||||
/* Use internal DNS server */
|
||||
NUTAG_PROXY("sip:example.org"),
|
||||
/* Force sresolv to use localhost and s2dns as DNS server */
|
||||
#if HAVE_WIN32
|
||||
SRESTAG_RESOLV_CONF("NUL"),
|
||||
#else
|
||||
|
@ -1598,6 +1133,7 @@ void s2_nua_teardown(void)
|
|||
{
|
||||
nua_destroy(s2->nua);
|
||||
s2->nua = NULL;
|
||||
s2_dns_teardown();
|
||||
s2_teardown();
|
||||
}
|
||||
|
||||
|
|
|
@ -60,12 +60,6 @@ struct tester
|
|||
su_time_t when;
|
||||
} *received;
|
||||
|
||||
struct {
|
||||
su_socket_t socket;
|
||||
su_wait_t wait[1];
|
||||
int reg;
|
||||
} dns;
|
||||
|
||||
nua_t *nua;
|
||||
|
||||
struct event {
|
||||
|
|
Loading…
Reference in New Issue