Implemented resolver to replace sock_srv_lookup()
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -48,6 +48,7 @@ tests/test_hash
|
|||||||
tests/test_jid
|
tests/test_jid
|
||||||
tests/test_md5
|
tests/test_md5
|
||||||
tests/test_rand
|
tests/test_rand
|
||||||
|
tests/test_resolver
|
||||||
tests/test_sasl
|
tests/test_sasl
|
||||||
tests/test_scram
|
tests/test_scram
|
||||||
tests/test_sha1
|
tests/test_sha1
|
||||||
|
|||||||
16
Makefile.am
16
Makefile.am
@@ -22,13 +22,13 @@ libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(DIST_LIBS) -no-undefined
|
|||||||
# Export only public API
|
# Export only public API
|
||||||
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_'
|
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_'
|
||||||
libstrophe_la_SOURCES = src/auth.c src/conn.c src/ctx.c \
|
libstrophe_la_SOURCES = src/auth.c src/conn.c src/ctx.c \
|
||||||
src/event.c src/handler.c src/hash.c \
|
src/event.c src/handler.c src/hash.c src/jid.c src/md5.c \
|
||||||
src/jid.c src/md5.c src/sasl.c src/scram.c src/sha1.c \
|
src/resolver.c src/sasl.c src/scram.c src/sha1.c \
|
||||||
src/snprintf.c src/sock.c src/stanza.c \
|
src/snprintf.c src/sock.c src/stanza.c \
|
||||||
src/tls_openssl.c src/util.c src/rand.c src/uuid.c \
|
src/tls_openssl.c src/util.c src/rand.c src/uuid.c \
|
||||||
src/common.h src/hash.h src/md5.h src/ostypes.h src/parser.h \
|
src/common.h src/hash.h src/md5.h src/ostypes.h src/parser.h \
|
||||||
src/sasl.h src/scram.h src/sha1.h src/snprintf.h src/sock.h \
|
src/resolver.h src/sasl.h src/scram.h src/sha1.h src/snprintf.h \
|
||||||
src/tls.h src/util.h src/rand.h
|
src/sock.h src/tls.h src/util.h src/rand.h
|
||||||
|
|
||||||
if PARSER_EXPAT
|
if PARSER_EXPAT
|
||||||
libstrophe_la_SOURCES += src/parser_expat.c
|
libstrophe_la_SOURCES += src/parser_expat.c
|
||||||
@@ -68,7 +68,8 @@ examples_uuid_LDADD = $(STROPHE_LIBS)
|
|||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
TESTS = tests/check_parser tests/test_sha1 tests/test_md5 tests/test_rand \
|
TESTS = tests/check_parser tests/test_sha1 tests/test_md5 tests/test_rand \
|
||||||
tests/test_scram tests/test_base64 tests/test_snprintf
|
tests/test_scram tests/test_base64 tests/test_snprintf \
|
||||||
|
tests/test_resolver
|
||||||
check_PROGRAMS = $(TESTS)
|
check_PROGRAMS = $(TESTS)
|
||||||
|
|
||||||
tests_check_parser_SOURCES = tests/check_parser.c tests/test.h
|
tests_check_parser_SOURCES = tests/check_parser.c tests/test.h
|
||||||
@@ -82,6 +83,11 @@ tests_test_base64_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
|||||||
tests_test_base64_LDADD = $(STROPHE_LIBS)
|
tests_test_base64_LDADD = $(STROPHE_LIBS)
|
||||||
tests_test_base64_LDFLAGS = -static
|
tests_test_base64_LDFLAGS = -static
|
||||||
|
|
||||||
|
tests_test_resolver_SOURCES = tests/test_resolver.c tests/test.h
|
||||||
|
tests_test_resolver_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
||||||
|
tests_test_resolver_LDADD = $(STROPHE_LIBS)
|
||||||
|
tests_test_resolver_LDFLAGS = -static
|
||||||
|
|
||||||
tests_test_rand_SOURCES = tests/test_rand.c tests/test.c src/sha1.c
|
tests_test_rand_SOURCES = tests/test_rand.c tests/test.c src/sha1.c
|
||||||
tests_test_rand_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
tests_test_rand_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
||||||
|
|
||||||
|
|||||||
@@ -103,9 +103,6 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([
|
|||||||
LIBS="${LIBS_TMP}"
|
LIBS="${LIBS_TMP}"
|
||||||
PC_LIBS="${DIST_LIBS} ${PC_LIBS}"
|
PC_LIBS="${DIST_LIBS} ${PC_LIBS}"
|
||||||
|
|
||||||
AC_CHECK_HEADERS([arpa/nameser_compat.h])
|
|
||||||
|
|
||||||
|
|
||||||
m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
|
m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
|
||||||
[AC_ARG_WITH([pkgconfigdir],
|
[AC_ARG_WITH([pkgconfigdir],
|
||||||
[AS_HELP_STRING([--with-pkgconfigdir],
|
[AS_HELP_STRING([--with-pkgconfigdir],
|
||||||
|
|||||||
17
src/conn.c
17
src/conn.c
@@ -25,6 +25,7 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "resolver.h"
|
||||||
|
|
||||||
#ifndef DEFAULT_SEND_QUEUE_MAX
|
#ifndef DEFAULT_SEND_QUEUE_MAX
|
||||||
/** @def DEFAULT_SEND_QUEUE_MAX
|
/** @def DEFAULT_SEND_QUEUE_MAX
|
||||||
@@ -56,7 +57,7 @@ static void _handle_stream_end(char *name,
|
|||||||
void * const userdata);
|
void * const userdata);
|
||||||
static void _handle_stream_stanza(xmpp_stanza_t *stanza,
|
static void _handle_stream_stanza(xmpp_stanza_t *stanza,
|
||||||
void * const userdata);
|
void * const userdata);
|
||||||
static int _conn_default_port(xmpp_conn_t * const conn);
|
static unsigned short _conn_default_port(xmpp_conn_t * const conn);
|
||||||
|
|
||||||
/** Create a new Strophe connection object.
|
/** Create a new Strophe connection object.
|
||||||
*
|
*
|
||||||
@@ -407,7 +408,7 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
|
|||||||
void * const userdata)
|
void * const userdata)
|
||||||
{
|
{
|
||||||
char domain[2048];
|
char domain[2048];
|
||||||
int port;
|
unsigned short port;
|
||||||
const char *prefdomain = NULL;
|
const char *prefdomain = NULL;
|
||||||
int found;
|
int found;
|
||||||
|
|
||||||
@@ -427,8 +428,8 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
|
|||||||
prefdomain = altdomain;
|
prefdomain = altdomain;
|
||||||
port = altport ? altport : _conn_default_port(conn);
|
port = altport ? altport : _conn_default_port(conn);
|
||||||
} else {
|
} else {
|
||||||
found = sock_srv_lookup("xmpp-client", "tcp", conn->domain,
|
found = resolver_srv_lookup("xmpp-client", "tcp", conn->domain,
|
||||||
domain, sizeof(domain), &port);
|
domain, sizeof(domain), &port);
|
||||||
if (!found) {
|
if (!found) {
|
||||||
xmpp_debug(conn->ctx, "xmpp", "SRV lookup failed, "
|
xmpp_debug(conn->ctx, "xmpp", "SRV lookup failed, "
|
||||||
"connecting via domain.");
|
"connecting via domain.");
|
||||||
@@ -448,7 +449,7 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
|
|||||||
domain[sizeof(domain) - 1] = '\0';
|
domain[sizeof(domain) - 1] = '\0';
|
||||||
}
|
}
|
||||||
conn->sock = sock_connect(domain, port);
|
conn->sock = sock_connect(domain, port);
|
||||||
xmpp_debug(conn->ctx, "xmpp", "sock_connect to %s:%d returned %d",
|
xmpp_debug(conn->ctx, "xmpp", "sock_connect to %s:%u returned %d",
|
||||||
domain, port, conn->sock);
|
domain, port, conn->sock);
|
||||||
if (conn->sock == -1) return -1;
|
if (conn->sock == -1) return -1;
|
||||||
|
|
||||||
@@ -495,7 +496,7 @@ int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server,
|
|||||||
unsigned short port, xmpp_conn_handler callback,
|
unsigned short port, xmpp_conn_handler callback,
|
||||||
void * const userdata)
|
void * const userdata)
|
||||||
{
|
{
|
||||||
int connectport;
|
unsigned short connectport;
|
||||||
|
|
||||||
if (conn->state != XMPP_STATE_DISCONNECTED)
|
if (conn->state != XMPP_STATE_DISCONNECTED)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -516,7 +517,7 @@ int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server,
|
|||||||
|
|
||||||
xmpp_debug(conn->ctx, "xmpp", "Connecting via %s", server);
|
xmpp_debug(conn->ctx, "xmpp", "Connecting via %s", server);
|
||||||
conn->sock = sock_connect(server, connectport);
|
conn->sock = sock_connect(server, connectport);
|
||||||
xmpp_debug(conn->ctx, "xmpp", "sock_connect to %s:%d returned %d",
|
xmpp_debug(conn->ctx, "xmpp", "sock_connect to %s:%u returned %d",
|
||||||
server, connectport, conn->sock);
|
server, connectport, conn->sock);
|
||||||
if (conn->sock == -1) return -1;
|
if (conn->sock == -1) return -1;
|
||||||
|
|
||||||
@@ -969,7 +970,7 @@ static void _handle_stream_stanza(xmpp_stanza_t *stanza,
|
|||||||
handler_fire_stanza(conn, stanza);
|
handler_fire_stanza(conn, stanza);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _conn_default_port(xmpp_conn_t * const conn)
|
static unsigned short _conn_default_port(xmpp_conn_t * const conn)
|
||||||
{
|
{
|
||||||
switch (conn->type) {
|
switch (conn->type) {
|
||||||
case XMPP_CLIENT:
|
case XMPP_CLIENT:
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
#ifndef __LIBSTROPHE_OSTYPES_H__
|
#ifndef __LIBSTROPHE_OSTYPES_H__
|
||||||
#define __LIBSTROPHE_OSTYPES_H__
|
#define __LIBSTROPHE_OSTYPES_H__
|
||||||
|
|
||||||
|
#include <stddef.h> /* size_t */
|
||||||
|
|
||||||
#if defined (_MSC_VER) && _MSC_VER < 1600
|
#if defined (_MSC_VER) && _MSC_VER < 1600
|
||||||
typedef signed char int8_t;
|
typedef signed char int8_t;
|
||||||
typedef short int int16_t;
|
typedef short int int16_t;
|
||||||
@@ -27,6 +29,14 @@ typedef unsigned char uint8_t;
|
|||||||
typedef unsigned short int uint16_t;
|
typedef unsigned short int uint16_t;
|
||||||
typedef unsigned int uint32_t;
|
typedef unsigned int uint32_t;
|
||||||
typedef unsigned __int64 uint64_t;
|
typedef unsigned __int64 uint64_t;
|
||||||
|
|
||||||
|
#ifndef UINT32_MAX
|
||||||
|
#define UINT32_MAX 0xffffffff
|
||||||
|
#endif /* UINT32_MAX */
|
||||||
|
#ifndef SIZE_MAX
|
||||||
|
#define SIZE_MAX UINT32_MAX
|
||||||
|
#endif /* SIZE_MAX */
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
641
src/resolver.c
Normal file
641
src/resolver.c
Normal file
@@ -0,0 +1,641 @@
|
|||||||
|
/* resolver.h
|
||||||
|
* strophe XMPP client library -- DNS resolver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Dmitry Podgorny <pasis.ua@gmail.com>
|
||||||
|
*
|
||||||
|
* This software is provided AS-IS with no warranty, either express
|
||||||
|
* or implied.
|
||||||
|
*
|
||||||
|
* This program is dual licensed under the MIT and GPLv3 licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
* DNS resolver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/nameser.h>
|
||||||
|
#include <resolv.h> /* res_query */
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
#include <string.h> /* strncpy */
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "resolver.h"
|
||||||
|
#include "ostypes.h"
|
||||||
|
|
||||||
|
#define MESSAGE_HEADER_LEN 12
|
||||||
|
#define MESSAGE_RESPONSE 1
|
||||||
|
#define MESSAGE_T_SRV 33
|
||||||
|
#define MESSAGE_C_IN 1
|
||||||
|
|
||||||
|
struct message_header {
|
||||||
|
uint16_t id;
|
||||||
|
uint8_t octet2;
|
||||||
|
uint8_t octet3;
|
||||||
|
uint16_t qdcount;
|
||||||
|
uint16_t ancount;
|
||||||
|
uint16_t nscount;
|
||||||
|
uint16_t arcount;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static int resolver_win32_srv_lookup(const char *fulldomain,
|
||||||
|
char *target, size_t target_len,
|
||||||
|
unsigned short *port);
|
||||||
|
static int resolver_win32_srv_query(const char *fulldomain,
|
||||||
|
unsigned char *buf, size_t len);
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
/* the same as ntohs(), but receives pointer to the value */
|
||||||
|
static uint16_t xmpp_ntohs_ptr(const void *ptr)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)ptr;
|
||||||
|
|
||||||
|
return (uint16_t)((p[0] << 8U) + p[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t message_header_qr(const struct message_header *header)
|
||||||
|
{
|
||||||
|
return (header->octet2 >> 7) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t message_header_rcode(const struct message_header *header)
|
||||||
|
{
|
||||||
|
return header->octet3 & 0x0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned message_name_get(const unsigned char *buf, size_t buf_len,
|
||||||
|
unsigned buf_offset,
|
||||||
|
char *name, size_t name_max)
|
||||||
|
{
|
||||||
|
size_t name_len = 0;
|
||||||
|
unsigned i = buf_offset;
|
||||||
|
unsigned pointer;
|
||||||
|
unsigned char label_len;
|
||||||
|
|
||||||
|
while ((label_len = buf[i++]) != 0) {
|
||||||
|
/* label */
|
||||||
|
if ((label_len & 0xc0) == 0) {
|
||||||
|
if (name != NULL) {
|
||||||
|
if (name_len != 0)
|
||||||
|
name[name_len++] = '.';
|
||||||
|
strncpy(&name[name_len], (char *)&buf[i], label_len);
|
||||||
|
}
|
||||||
|
i += label_len;
|
||||||
|
name_len += label_len;
|
||||||
|
|
||||||
|
/* pointer */
|
||||||
|
} else if ((label_len & 0xc0) == 0xc0) {
|
||||||
|
pointer = (label_len & 0x3f) << 8 | buf[i++];
|
||||||
|
(void)message_name_get(buf, buf_len, pointer, &name[name_len],
|
||||||
|
name_max - name_len);
|
||||||
|
/* pointer is always the last */
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* The 10 and 01 combinations are reserved for future use. */
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (label_len == 0 && name != NULL)
|
||||||
|
name[name_len] = '\0';
|
||||||
|
|
||||||
|
return i - buf_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned message_name_len(const unsigned char *buf, size_t buf_len,
|
||||||
|
unsigned buf_offset)
|
||||||
|
{
|
||||||
|
return message_name_get(buf, buf_len, buf_offset, NULL, SIZE_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
int resolver_srv_lookup_buf(const unsigned char *buf, size_t len,
|
||||||
|
char *target, size_t target_len,
|
||||||
|
unsigned short *port)
|
||||||
|
{
|
||||||
|
int set = 0;
|
||||||
|
unsigned i;
|
||||||
|
unsigned j;
|
||||||
|
unsigned name_len;
|
||||||
|
unsigned rdlength;
|
||||||
|
uint16_t type;
|
||||||
|
uint16_t class;
|
||||||
|
uint16_t priority;
|
||||||
|
uint16_t priority_min;
|
||||||
|
struct message_header header;
|
||||||
|
|
||||||
|
if (len < MESSAGE_HEADER_LEN)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
header.id = xmpp_ntohs_ptr(&buf[0]);
|
||||||
|
header.octet2 = buf[2];
|
||||||
|
header.octet3 = buf[3];
|
||||||
|
header.qdcount = xmpp_ntohs_ptr(&buf[4]);
|
||||||
|
header.ancount = xmpp_ntohs_ptr(&buf[6]);
|
||||||
|
header.nscount = xmpp_ntohs_ptr(&buf[8]);
|
||||||
|
header.arcount = xmpp_ntohs_ptr(&buf[10]);
|
||||||
|
if (message_header_qr(&header) != MESSAGE_RESPONSE ||
|
||||||
|
message_header_rcode(&header) != 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
j = MESSAGE_HEADER_LEN;
|
||||||
|
|
||||||
|
/* skip question section */
|
||||||
|
for (i = 0; i < header.qdcount; ++i) {
|
||||||
|
name_len = message_name_len(buf, len, j);
|
||||||
|
if (name_len == 0) {
|
||||||
|
/* error in name format */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
j += name_len + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RFC2052: A client MUST attempt to contact the target host
|
||||||
|
* with the lowest-numbered priority it can reach.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < header.ancount; ++i) {
|
||||||
|
name_len = message_name_len(buf, len, j);
|
||||||
|
j += name_len;
|
||||||
|
type = xmpp_ntohs_ptr(&buf[j]);
|
||||||
|
class = xmpp_ntohs_ptr(&buf[j + 2]);
|
||||||
|
rdlength = xmpp_ntohs_ptr(&buf[j + 8]);
|
||||||
|
j += 10;
|
||||||
|
if (type == MESSAGE_T_SRV && class == MESSAGE_C_IN) {
|
||||||
|
priority = xmpp_ntohs_ptr(&buf[j]);
|
||||||
|
if (!set || priority < priority_min) {
|
||||||
|
*port = xmpp_ntohs_ptr(&buf[j + 4]);
|
||||||
|
name_len = message_name_get(buf, len, j + 6, target, target_len);
|
||||||
|
set = name_len > 0 ? 1 : 0;
|
||||||
|
priority_min = priority;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
j += rdlength;
|
||||||
|
}
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
int resolver_srv_lookup(const char *service, const char *proto,
|
||||||
|
const char *domain, char *target,
|
||||||
|
size_t target_len, unsigned short *port)
|
||||||
|
{
|
||||||
|
char fulldomain[2048];
|
||||||
|
unsigned char buf[65535];
|
||||||
|
int len;
|
||||||
|
int set = 0;
|
||||||
|
|
||||||
|
xmpp_snprintf(fulldomain, sizeof(fulldomain),
|
||||||
|
"_%s._%s.%s", service, proto, domain);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
set = resolver_win32_srv_lookup(fulldomain, target, target_len, port);
|
||||||
|
if (set)
|
||||||
|
return set;
|
||||||
|
len = resolver_win32_srv_query(fulldomain, buf, sizeof(buf));
|
||||||
|
#else /* _WIN32 */
|
||||||
|
len = res_query(fulldomain, MESSAGE_C_IN, MESSAGE_T_SRV, buf, sizeof(buf));
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
set = resolver_srv_lookup_buf(buf, (size_t)len, target, target_len, port);
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: interface that returns array of results, maybe sorted by priority */
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Next part was copied from sock.c and contains old win32 code.
|
||||||
|
*
|
||||||
|
* The idea is to get raw response from a name server and pass it to
|
||||||
|
* resolver_srv_lookup_buf(). In fact, resolver_win32_srv_query() replaces
|
||||||
|
* the call of res_query().
|
||||||
|
* Dnsapi code is left unchanged and moved to a separated function
|
||||||
|
* resolver_srv_win32_lookup().
|
||||||
|
*
|
||||||
|
* XXX If the code is compiled it should work like before.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#include <windns.h>
|
||||||
|
#include <Iphlpapi.h>
|
||||||
|
|
||||||
|
struct dnsquery_header
|
||||||
|
{
|
||||||
|
unsigned short id;
|
||||||
|
unsigned char qr;
|
||||||
|
unsigned char opcode;
|
||||||
|
unsigned char aa;
|
||||||
|
unsigned char tc;
|
||||||
|
unsigned char rd;
|
||||||
|
unsigned char ra;
|
||||||
|
unsigned char z;
|
||||||
|
unsigned char rcode;
|
||||||
|
unsigned short qdcount;
|
||||||
|
unsigned short ancount;
|
||||||
|
unsigned short nscount;
|
||||||
|
unsigned short arcount;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dnsquery_question
|
||||||
|
{
|
||||||
|
char qname[1024];
|
||||||
|
unsigned short qtype;
|
||||||
|
unsigned short qclass;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void netbuf_add_16bitnum(unsigned char *buf, int buflen, int *offset, unsigned short num)
|
||||||
|
{
|
||||||
|
unsigned char *start = buf + *offset;
|
||||||
|
unsigned char *p = start;
|
||||||
|
|
||||||
|
/* assuming big endian */
|
||||||
|
*p++ = (num >> 8) & 0xff;
|
||||||
|
*p++ = (num) & 0xff;
|
||||||
|
|
||||||
|
*offset += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset,
|
||||||
|
char *name)
|
||||||
|
{
|
||||||
|
unsigned char *start = buf + *offset;
|
||||||
|
unsigned char *p = start;
|
||||||
|
unsigned char *wordstart, *wordend;
|
||||||
|
|
||||||
|
wordstart = (unsigned char *)name;
|
||||||
|
|
||||||
|
while (*wordstart)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
wordend = wordstart;
|
||||||
|
while (*wordend && *wordend != '.')
|
||||||
|
{
|
||||||
|
wordend++;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = (int)(wordend - wordstart);
|
||||||
|
|
||||||
|
if (len > 0x3F)
|
||||||
|
{
|
||||||
|
len = 0x3F;
|
||||||
|
}
|
||||||
|
|
||||||
|
*p++ = len;
|
||||||
|
|
||||||
|
while (wordstart != wordend)
|
||||||
|
{
|
||||||
|
*p++ = *wordstart++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*wordstart == '.')
|
||||||
|
{
|
||||||
|
wordstart++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*p++ = '\0';
|
||||||
|
|
||||||
|
*offset += p - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void netbuf_add_dnsquery_header(unsigned char *buf, int buflen, int *offset, struct dnsquery_header *header)
|
||||||
|
{
|
||||||
|
unsigned char *p;
|
||||||
|
|
||||||
|
netbuf_add_16bitnum(buf, buflen, offset, header->id);
|
||||||
|
|
||||||
|
p = buf + *offset;
|
||||||
|
*p++ = ((header->qr & 0x01) << 7)
|
||||||
|
| ((header->opcode & 0x0F) << 3)
|
||||||
|
| ((header->aa & 0x01) << 2)
|
||||||
|
| ((header->tc & 0x01) << 1)
|
||||||
|
| ((header->rd & 0x01));
|
||||||
|
*p++ = ((header->ra & 0x01) << 7)
|
||||||
|
| ((header->z & 0x07) << 4)
|
||||||
|
| ((header->rcode & 0x0F));
|
||||||
|
*offset += 2;
|
||||||
|
|
||||||
|
netbuf_add_16bitnum(buf, buflen, offset, header->qdcount);
|
||||||
|
netbuf_add_16bitnum(buf, buflen, offset, header->ancount);
|
||||||
|
netbuf_add_16bitnum(buf, buflen, offset, header->nscount);
|
||||||
|
netbuf_add_16bitnum(buf, buflen, offset, header->arcount);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void netbuf_add_dnsquery_question(unsigned char *buf, int buflen, int *offset, struct dnsquery_question *question)
|
||||||
|
{
|
||||||
|
netbuf_add_domain_name(buf, buflen, offset, question->qname);
|
||||||
|
netbuf_add_16bitnum(buf, buflen, offset, question->qtype);
|
||||||
|
netbuf_add_16bitnum(buf, buflen, offset, question->qclass);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int resolver_win32_srv_lookup(const char *fulldomain,
|
||||||
|
char *target, size_t target_len,
|
||||||
|
unsigned short *port)
|
||||||
|
{
|
||||||
|
int set = 0;
|
||||||
|
|
||||||
|
/* try using dnsapi first */
|
||||||
|
if (!set)
|
||||||
|
{
|
||||||
|
HINSTANCE hdnsapi = NULL;
|
||||||
|
|
||||||
|
DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, PDNS_RECORD*, PVOID*);
|
||||||
|
void (WINAPI * pDnsRecordListFree)(PDNS_RECORD, DNS_FREE_TYPE);
|
||||||
|
|
||||||
|
if (hdnsapi = LoadLibrary("dnsapi.dll")) {
|
||||||
|
|
||||||
|
pDnsQuery_A = (void *)GetProcAddress(hdnsapi, "DnsQuery_A");
|
||||||
|
pDnsRecordListFree = (void *)GetProcAddress(hdnsapi, "DnsRecordListFree");
|
||||||
|
|
||||||
|
if (pDnsQuery_A && pDnsRecordListFree) {
|
||||||
|
PDNS_RECORD dnsrecords = NULL;
|
||||||
|
DNS_STATUS error;
|
||||||
|
|
||||||
|
error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, NULL);
|
||||||
|
|
||||||
|
if (error == 0) {
|
||||||
|
PDNS_RECORD current = dnsrecords;
|
||||||
|
|
||||||
|
while (current) {
|
||||||
|
if (current->wType == DNS_TYPE_SRV) {
|
||||||
|
xmpp_snprintf(target, target_len, "%s", current->Data.Srv.pNameTarget);
|
||||||
|
*port = current->Data.Srv.wPort;
|
||||||
|
set = 1;
|
||||||
|
|
||||||
|
current = NULL;
|
||||||
|
} else {
|
||||||
|
current = current->pNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pDnsRecordListFree(dnsrecords, DnsFreeRecordList);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeLibrary(hdnsapi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int resolver_win32_srv_query(const char *fulldomain,
|
||||||
|
unsigned char *buf, size_t len)
|
||||||
|
{
|
||||||
|
int set = 0;
|
||||||
|
int insize;
|
||||||
|
|
||||||
|
/* if dnsapi didn't work/isn't there, try querying the dns server manually */
|
||||||
|
if (!set)
|
||||||
|
{
|
||||||
|
struct dnsquery_header header;
|
||||||
|
struct dnsquery_question question;
|
||||||
|
int offset = 0;
|
||||||
|
int addrlen;
|
||||||
|
sock_t sock;
|
||||||
|
struct sockaddr_in dnsaddr;
|
||||||
|
char dnsserverips[16][256];
|
||||||
|
int numdnsservers = 0;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
/* Try getting the DNS server ips from GetNetworkParams() in iphlpapi first */
|
||||||
|
if (!numdnsservers)
|
||||||
|
{
|
||||||
|
HINSTANCE hiphlpapi = NULL;
|
||||||
|
DWORD (WINAPI * pGetNetworkParams)(PFIXED_INFO, PULONG);
|
||||||
|
|
||||||
|
if (hiphlpapi = LoadLibrary("Iphlpapi.dll"))
|
||||||
|
{
|
||||||
|
pGetNetworkParams = (void *)GetProcAddress(hiphlpapi, "GetNetworkParams");
|
||||||
|
|
||||||
|
if (pGetNetworkParams)
|
||||||
|
{
|
||||||
|
FIXED_INFO *fi;
|
||||||
|
ULONG len;
|
||||||
|
DWORD error;
|
||||||
|
char buffer[65535];
|
||||||
|
|
||||||
|
len = 65535;
|
||||||
|
fi = buffer;
|
||||||
|
|
||||||
|
if ((error = pGetNetworkParams(fi, &len)) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
IP_ADDR_STRING *pias = &(fi->DnsServerList);
|
||||||
|
|
||||||
|
while (pias && numdnsservers < 16)
|
||||||
|
{
|
||||||
|
strcpy(dnsserverips[numdnsservers++], pias->IpAddress.String);
|
||||||
|
pias = pias->Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FreeLibrary(hiphlpapi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next, try getting the DNS server ips from the registry */
|
||||||
|
if (!numdnsservers)
|
||||||
|
{
|
||||||
|
HKEY search;
|
||||||
|
LONG error;
|
||||||
|
|
||||||
|
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ, &search);
|
||||||
|
|
||||||
|
if (error != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &search);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
char name[512];
|
||||||
|
DWORD len = 512;
|
||||||
|
|
||||||
|
error = RegQueryValueEx(search, "NameServer", NULL, NULL, (LPBYTE)name, &len);
|
||||||
|
|
||||||
|
if (error != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
error = RegQueryValueEx(search, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
char *parse = "0123456789.", *start, *end;
|
||||||
|
start = name;
|
||||||
|
end = name;
|
||||||
|
name[len] = '\0';
|
||||||
|
|
||||||
|
while (*start && numdnsservers < 16)
|
||||||
|
{
|
||||||
|
while (strchr(parse, *end))
|
||||||
|
{
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(dnsserverips[numdnsservers++], start, end - start);
|
||||||
|
|
||||||
|
while (*end && !strchr(parse, *end))
|
||||||
|
{
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RegCloseKey(search);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!numdnsservers)
|
||||||
|
{
|
||||||
|
HKEY searchlist;
|
||||||
|
LONG error;
|
||||||
|
|
||||||
|
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", 0, KEY_READ, &searchlist);
|
||||||
|
|
||||||
|
if (error == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
DWORD numinterfaces = 0;
|
||||||
|
|
||||||
|
RegQueryInfoKey(searchlist, NULL, NULL, NULL, &numinterfaces, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
for (i = 0; i < numinterfaces; i++)
|
||||||
|
{
|
||||||
|
char name[512];
|
||||||
|
DWORD len = 512;
|
||||||
|
HKEY searchentry;
|
||||||
|
|
||||||
|
RegEnumKeyEx(searchlist, i, (LPTSTR)name, &len, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
if (RegOpenKeyEx(searchlist, name, 0, KEY_READ, &searchentry) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
if (RegQueryValueEx(searchentry, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
char *parse = "0123456789.", *start, *end;
|
||||||
|
start = name;
|
||||||
|
end = name;
|
||||||
|
name[len] = '\0';
|
||||||
|
|
||||||
|
while (*start && numdnsservers < 16)
|
||||||
|
{
|
||||||
|
while (strchr(parse, *end))
|
||||||
|
{
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(dnsserverips[numdnsservers++], start, end - start);
|
||||||
|
|
||||||
|
while (*end && !strchr(parse, *end))
|
||||||
|
{
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (RegQueryValueEx(searchentry, "NameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
char *parse = "0123456789.", *start, *end;
|
||||||
|
start = name;
|
||||||
|
end = name;
|
||||||
|
name[len] = '\0';
|
||||||
|
|
||||||
|
while (*start && numdnsservers < 16)
|
||||||
|
{
|
||||||
|
while (strchr(parse, *end))
|
||||||
|
{
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(dnsserverips[numdnsservers++], start, end - start);
|
||||||
|
|
||||||
|
while (*end && !strchr(parse, *end))
|
||||||
|
{
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RegCloseKey(searchentry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RegCloseKey(searchlist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we have a DNS server, use it */
|
||||||
|
if (numdnsservers)
|
||||||
|
{
|
||||||
|
ULONG nonblocking = 1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(&header, 0, sizeof(header));
|
||||||
|
header.id = 12345; /* FIXME: Get a better id here */
|
||||||
|
header.rd = 1;
|
||||||
|
header.qdcount = 1;
|
||||||
|
|
||||||
|
netbuf_add_dnsquery_header(buf, len, &offset, &header);
|
||||||
|
|
||||||
|
memset(&question, 0, sizeof(question));
|
||||||
|
strncpy(question.qname, fulldomain, 1024);
|
||||||
|
question.qtype = 33; /* SRV */
|
||||||
|
question.qclass = 1; /* INTERNET! */
|
||||||
|
|
||||||
|
netbuf_add_dnsquery_question(buf, len, &offset, &question);
|
||||||
|
|
||||||
|
insize = 0;
|
||||||
|
for (i = 0; i < numdnsservers && insize <= 0; i++)
|
||||||
|
{
|
||||||
|
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
ioctlsocket(sock, FIONBIO, &nonblocking);
|
||||||
|
|
||||||
|
memset(&dnsaddr, 0, sizeof(dnsaddr));
|
||||||
|
|
||||||
|
dnsaddr.sin_family = AF_INET;
|
||||||
|
dnsaddr.sin_port = htons(53);
|
||||||
|
dnsaddr.sin_addr.s_addr = inet_addr(dnsserverips[i]);
|
||||||
|
|
||||||
|
addrlen = sizeof(dnsaddr);
|
||||||
|
sendto(sock, (char *)buf, offset, 0, (struct sockaddr *)&dnsaddr, addrlen);
|
||||||
|
for (j = 0; j < 50; j++)
|
||||||
|
{
|
||||||
|
insize = recvfrom(sock, (char *)buf, len, 0, (struct sockaddr *)&dnsaddr, &addrlen);
|
||||||
|
if (insize == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
if (sock_error() == WSAEWOULDBLOCK)
|
||||||
|
{
|
||||||
|
Sleep(100);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closesocket(sock);
|
||||||
|
}
|
||||||
|
set = insize > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return set ? insize : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _WIN32 */
|
||||||
41
src/resolver.h
Normal file
41
src/resolver.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/* resolver.h
|
||||||
|
* strophe XMPP client library -- DNS resolver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Dmitry Podgorny <pasis.ua@gmail.com>
|
||||||
|
*
|
||||||
|
* This software is provided AS-IS with no warranty, either express
|
||||||
|
* or implied.
|
||||||
|
*
|
||||||
|
* This program is dual licensed under the MIT and GPLv3 licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
* DNS resolver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBSTROPHE_RESOLVER_H__
|
||||||
|
#define __LIBSTROPHE_RESOLVER_H__
|
||||||
|
|
||||||
|
#include "ostypes.h"
|
||||||
|
|
||||||
|
/** Perform lookup for RFC1035 message format. */
|
||||||
|
int resolver_srv_lookup_buf(const unsigned char *buf, size_t len,
|
||||||
|
char *target, size_t target_len,
|
||||||
|
unsigned short *port);
|
||||||
|
|
||||||
|
/** Resolve SRV record.
|
||||||
|
*
|
||||||
|
* @param service service of the SRV record
|
||||||
|
* @param proto protocol of the SRV record
|
||||||
|
* @param domain resolving domain
|
||||||
|
* @param target pre-allocated string where result is stored
|
||||||
|
* @param target_len maximum size of the target
|
||||||
|
* @param port pointer where resulting port is stored
|
||||||
|
*
|
||||||
|
* @return 1 on success or 0 on fail
|
||||||
|
*/
|
||||||
|
int resolver_srv_lookup(const char *service, const char *proto,
|
||||||
|
const char *domain, char *target,
|
||||||
|
size_t target_len, unsigned short *port);
|
||||||
|
|
||||||
|
#endif /* __LIBSTROPHE_RESOLVER_H__ */
|
||||||
679
src/sock.c
679
src/sock.c
@@ -21,7 +21,6 @@
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
#include <windns.h>
|
|
||||||
#include <Iphlpapi.h>
|
#include <Iphlpapi.h>
|
||||||
#else
|
#else
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -30,11 +29,6 @@
|
|||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <arpa/nameser.h>
|
|
||||||
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
|
|
||||||
#include <arpa/nameser_compat.h>
|
|
||||||
#endif
|
|
||||||
#include <resolv.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "sock.h"
|
#include "sock.h"
|
||||||
@@ -73,7 +67,7 @@ static int _in_progress(int error)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
sock_t sock_connect(const char * const host, const unsigned int port)
|
sock_t sock_connect(const char * const host, const unsigned short port)
|
||||||
{
|
{
|
||||||
sock_t sock;
|
sock_t sock;
|
||||||
char service[6];
|
char service[6];
|
||||||
@@ -205,674 +199,3 @@ int sock_connect_error(const sock_t sock)
|
|||||||
|
|
||||||
return sock_error();
|
return sock_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dnsquery_header
|
|
||||||
{
|
|
||||||
unsigned short id;
|
|
||||||
unsigned char qr;
|
|
||||||
unsigned char opcode;
|
|
||||||
unsigned char aa;
|
|
||||||
unsigned char tc;
|
|
||||||
unsigned char rd;
|
|
||||||
unsigned char ra;
|
|
||||||
unsigned char z;
|
|
||||||
unsigned char rcode;
|
|
||||||
unsigned short qdcount;
|
|
||||||
unsigned short ancount;
|
|
||||||
unsigned short nscount;
|
|
||||||
unsigned short arcount;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dnsquery_question
|
|
||||||
{
|
|
||||||
char qname[1024];
|
|
||||||
unsigned short qtype;
|
|
||||||
unsigned short qclass;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dnsquery_srvrdata
|
|
||||||
{
|
|
||||||
unsigned short priority;
|
|
||||||
unsigned short weight;
|
|
||||||
unsigned short port;
|
|
||||||
char target[1024];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dnsquery_resourcerecord
|
|
||||||
{
|
|
||||||
char name[1024];
|
|
||||||
unsigned short type;
|
|
||||||
unsigned short _class;
|
|
||||||
unsigned int ttl;
|
|
||||||
unsigned short rdlength;
|
|
||||||
struct dnsquery_srvrdata rdata;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void netbuf_get_32bitnum(unsigned char *buf, int buflen, int *offset, unsigned int *num)
|
|
||||||
{
|
|
||||||
unsigned char *start = buf + *offset;
|
|
||||||
unsigned char *p = start;
|
|
||||||
*num = 0;
|
|
||||||
|
|
||||||
/* assuming big endian */
|
|
||||||
*num |= (*p++) << 24;
|
|
||||||
*num |= (*p++) << 16;
|
|
||||||
*num |= (*p++) << 8;
|
|
||||||
*num |= (*p++);
|
|
||||||
|
|
||||||
*offset += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void netbuf_get_16bitnum(unsigned char *buf, int buflen, int *offset, unsigned short *num)
|
|
||||||
{
|
|
||||||
unsigned char *start = buf + *offset;
|
|
||||||
unsigned char *p = start;
|
|
||||||
*num = 0;
|
|
||||||
|
|
||||||
/* assuming big endian */
|
|
||||||
*num |= (*p++) << 8;
|
|
||||||
*num |= (*p++);
|
|
||||||
|
|
||||||
*offset += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int netbuf_get_domain_name(unsigned char *buf, int buflen, int *offset, char *namebuf, int namebuflen)
|
|
||||||
{
|
|
||||||
unsigned char *start = buf + *offset;
|
|
||||||
unsigned char *p, *p2;
|
|
||||||
int *curroffset = offset;
|
|
||||||
int len = 0;
|
|
||||||
|
|
||||||
*namebuf = '\0';
|
|
||||||
|
|
||||||
/* measure length */
|
|
||||||
p = start;
|
|
||||||
while (*p)
|
|
||||||
{
|
|
||||||
if ((*p & 0xC0) == 0xC0)
|
|
||||||
{
|
|
||||||
int newoffset = 0;
|
|
||||||
newoffset |= (*p++ & 0x3F) << 8;
|
|
||||||
newoffset |= *p++;
|
|
||||||
|
|
||||||
p = buf + newoffset;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
len += *p;
|
|
||||||
p += *p + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (namebuflen < len)
|
|
||||||
{
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* actually copy in name */
|
|
||||||
p = start;
|
|
||||||
p2 = (unsigned char *)namebuf;
|
|
||||||
while (*p)
|
|
||||||
{
|
|
||||||
if ((*p & 0xC0) == 0xC0)
|
|
||||||
{
|
|
||||||
int newoffset = 0;
|
|
||||||
newoffset |= (*p++ & 0x3F) << 8;
|
|
||||||
newoffset |= *p++;
|
|
||||||
|
|
||||||
if (curroffset)
|
|
||||||
{
|
|
||||||
*curroffset += (int)(p - start);
|
|
||||||
curroffset = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
p = buf + newoffset;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int i, partlen;
|
|
||||||
|
|
||||||
if (*namebuf != '\0')
|
|
||||||
{
|
|
||||||
*p2++ = '.';
|
|
||||||
}
|
|
||||||
|
|
||||||
partlen = *p++;
|
|
||||||
|
|
||||||
for (i=0; i < partlen; i++)
|
|
||||||
{
|
|
||||||
*p2++ = *p++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (curroffset)
|
|
||||||
{
|
|
||||||
p++;
|
|
||||||
*curroffset += (int)(p - start);
|
|
||||||
curroffset = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*p2 = '\0';
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void netbuf_get_dnsquery_header(unsigned char *buf, int buflen, int *offset, struct dnsquery_header *header)
|
|
||||||
{
|
|
||||||
unsigned char *p;
|
|
||||||
|
|
||||||
netbuf_get_16bitnum(buf, buflen, offset, &(header->id));
|
|
||||||
|
|
||||||
p = buf + *offset;
|
|
||||||
header->qr = (*p >> 7) & 0x01;
|
|
||||||
header->opcode = (*p >> 3) & 0x0F;
|
|
||||||
header->aa = (*p >> 2) & 0x01;
|
|
||||||
header->tc = (*p >> 1) & 0x01;
|
|
||||||
header->rd = (*p) & 0x01;
|
|
||||||
p++;
|
|
||||||
header->ra = (*p >> 7) & 0x01;
|
|
||||||
header->z = (*p >> 4) & 0x07;
|
|
||||||
header->rcode = (*p) & 0x0F;
|
|
||||||
p++;
|
|
||||||
*offset += 2;
|
|
||||||
|
|
||||||
netbuf_get_16bitnum(buf, buflen, offset, &(header->qdcount));
|
|
||||||
netbuf_get_16bitnum(buf, buflen, offset, &(header->ancount));
|
|
||||||
netbuf_get_16bitnum(buf, buflen, offset, &(header->nscount));
|
|
||||||
netbuf_get_16bitnum(buf, buflen, offset, &(header->arcount));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void netbuf_get_dnsquery_question(unsigned char *buf, int buflen, int *offset, struct dnsquery_question *question)
|
|
||||||
{
|
|
||||||
netbuf_get_domain_name(buf, buflen, offset, question->qname, 1024);
|
|
||||||
netbuf_get_16bitnum(buf, buflen, offset, &(question->qtype));
|
|
||||||
netbuf_get_16bitnum(buf, buflen, offset, &(question->qclass));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void netbuf_get_dnsquery_srvrdata(unsigned char *buf, int buflen, int *offset, struct dnsquery_srvrdata *srvrdata)
|
|
||||||
{
|
|
||||||
netbuf_get_16bitnum(buf, buflen, offset, &(srvrdata->priority));
|
|
||||||
netbuf_get_16bitnum(buf, buflen, offset, &(srvrdata->weight));
|
|
||||||
netbuf_get_16bitnum(buf, buflen, offset, &(srvrdata->port));
|
|
||||||
netbuf_get_domain_name(buf, buflen, offset, srvrdata->target, 1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void netbuf_get_dnsquery_resourcerecord(unsigned char *buf, int buflen, int *offset, struct dnsquery_resourcerecord *rr)
|
|
||||||
{
|
|
||||||
netbuf_get_domain_name(buf, buflen, offset, rr->name, 1024);
|
|
||||||
netbuf_get_16bitnum(buf, buflen, offset, &(rr->type));
|
|
||||||
netbuf_get_16bitnum(buf, buflen, offset, &(rr->_class));
|
|
||||||
netbuf_get_32bitnum(buf, buflen, offset, &(rr->ttl));
|
|
||||||
netbuf_get_16bitnum(buf, buflen, offset, &(rr->rdlength));
|
|
||||||
if (rr->type == 33) /* SRV */
|
|
||||||
{
|
|
||||||
int newoffset = *offset;
|
|
||||||
netbuf_get_dnsquery_srvrdata(buf, buflen, &newoffset, &(rr->rdata));
|
|
||||||
}
|
|
||||||
*offset += rr->rdlength;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
static void netbuf_add_16bitnum(unsigned char *buf, int buflen, int *offset, unsigned short num)
|
|
||||||
{
|
|
||||||
unsigned char *start = buf + *offset;
|
|
||||||
unsigned char *p = start;
|
|
||||||
|
|
||||||
/* assuming big endian */
|
|
||||||
*p++ = (num >> 8) & 0xff;
|
|
||||||
*p++ = (num) & 0xff;
|
|
||||||
|
|
||||||
*offset += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset,
|
|
||||||
char *name)
|
|
||||||
{
|
|
||||||
unsigned char *start = buf + *offset;
|
|
||||||
unsigned char *p = start;
|
|
||||||
unsigned char *wordstart, *wordend;
|
|
||||||
|
|
||||||
wordstart = (unsigned char *)name;
|
|
||||||
|
|
||||||
while (*wordstart)
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
wordend = wordstart;
|
|
||||||
while (*wordend && *wordend != '.')
|
|
||||||
{
|
|
||||||
wordend++;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = (int)(wordend - wordstart);
|
|
||||||
|
|
||||||
if (len > 0x3F)
|
|
||||||
{
|
|
||||||
len = 0x3F;
|
|
||||||
}
|
|
||||||
|
|
||||||
*p++ = len;
|
|
||||||
|
|
||||||
while (wordstart != wordend)
|
|
||||||
{
|
|
||||||
*p++ = *wordstart++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*wordstart == '.')
|
|
||||||
{
|
|
||||||
wordstart++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*p++ = '\0';
|
|
||||||
|
|
||||||
*offset += p - start;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void netbuf_add_dnsquery_header(unsigned char *buf, int buflen, int *offset, struct dnsquery_header *header)
|
|
||||||
{
|
|
||||||
unsigned char *p;
|
|
||||||
|
|
||||||
netbuf_add_16bitnum(buf, buflen, offset, header->id);
|
|
||||||
|
|
||||||
p = buf + *offset;
|
|
||||||
*p++ = ((header->qr & 0x01) << 7)
|
|
||||||
| ((header->opcode & 0x0F) << 3)
|
|
||||||
| ((header->aa & 0x01) << 2)
|
|
||||||
| ((header->tc & 0x01) << 1)
|
|
||||||
| ((header->rd & 0x01));
|
|
||||||
*p++ = ((header->ra & 0x01) << 7)
|
|
||||||
| ((header->z & 0x07) << 4)
|
|
||||||
| ((header->rcode & 0x0F));
|
|
||||||
*offset += 2;
|
|
||||||
|
|
||||||
netbuf_add_16bitnum(buf, buflen, offset, header->qdcount);
|
|
||||||
netbuf_add_16bitnum(buf, buflen, offset, header->ancount);
|
|
||||||
netbuf_add_16bitnum(buf, buflen, offset, header->nscount);
|
|
||||||
netbuf_add_16bitnum(buf, buflen, offset, header->arcount);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void netbuf_add_dnsquery_question(unsigned char *buf, int buflen, int *offset, struct dnsquery_question *question)
|
|
||||||
{
|
|
||||||
netbuf_add_domain_name(buf, buflen, offset, question->qname);
|
|
||||||
netbuf_add_16bitnum(buf, buflen, offset, question->qtype);
|
|
||||||
netbuf_add_16bitnum(buf, buflen, offset, question->qclass);
|
|
||||||
}
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
|
|
||||||
int sock_srv_lookup(const char *service, const char *proto,
|
|
||||||
const char *domain, char *resulttarget,
|
|
||||||
int resulttargetlength, int *resultport)
|
|
||||||
{
|
|
||||||
int set = 0;
|
|
||||||
char fulldomain[2048];
|
|
||||||
|
|
||||||
xmpp_snprintf(fulldomain, sizeof(fulldomain),
|
|
||||||
"_%s._%s.%s", service, proto, domain);
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
/* try using dnsapi first */
|
|
||||||
if (!set)
|
|
||||||
{
|
|
||||||
HINSTANCE hdnsapi = NULL;
|
|
||||||
|
|
||||||
DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, PDNS_RECORD*, PVOID*);
|
|
||||||
void (WINAPI * pDnsRecordListFree)(PDNS_RECORD, DNS_FREE_TYPE);
|
|
||||||
|
|
||||||
if (hdnsapi = LoadLibrary("dnsapi.dll")) {
|
|
||||||
|
|
||||||
pDnsQuery_A = (void *)GetProcAddress(hdnsapi, "DnsQuery_A");
|
|
||||||
pDnsRecordListFree = (void *)GetProcAddress(hdnsapi, "DnsRecordListFree");
|
|
||||||
|
|
||||||
if (pDnsQuery_A && pDnsRecordListFree) {
|
|
||||||
PDNS_RECORD dnsrecords = NULL;
|
|
||||||
DNS_STATUS error;
|
|
||||||
|
|
||||||
error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, NULL);
|
|
||||||
|
|
||||||
if (error == 0) {
|
|
||||||
PDNS_RECORD current = dnsrecords;
|
|
||||||
|
|
||||||
while (current) {
|
|
||||||
if (current->wType == DNS_TYPE_SRV) {
|
|
||||||
xmpp_snprintf(resulttarget, resulttargetlength, "%s", current->Data.Srv.pNameTarget);
|
|
||||||
*resultport = current->Data.Srv.wPort;
|
|
||||||
set = 1;
|
|
||||||
|
|
||||||
current = NULL;
|
|
||||||
} else {
|
|
||||||
current = current->pNext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pDnsRecordListFree(dnsrecords, DnsFreeRecordList);
|
|
||||||
}
|
|
||||||
|
|
||||||
FreeLibrary(hdnsapi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if dnsapi didn't work/isn't there, try querying the dns server manually */
|
|
||||||
if (!set)
|
|
||||||
{
|
|
||||||
unsigned char buf[65536];
|
|
||||||
struct dnsquery_header header;
|
|
||||||
struct dnsquery_question question;
|
|
||||||
int offset = 0;
|
|
||||||
int addrlen;
|
|
||||||
sock_t sock;
|
|
||||||
struct sockaddr_in dnsaddr;
|
|
||||||
char dnsserverips[16][256];
|
|
||||||
int numdnsservers = 0;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
/* Try getting the DNS server ips from GetNetworkParams() in iphlpapi first */
|
|
||||||
if (!numdnsservers)
|
|
||||||
{
|
|
||||||
HINSTANCE hiphlpapi = NULL;
|
|
||||||
DWORD (WINAPI * pGetNetworkParams)(PFIXED_INFO, PULONG);
|
|
||||||
|
|
||||||
if (hiphlpapi = LoadLibrary("Iphlpapi.dll"))
|
|
||||||
{
|
|
||||||
pGetNetworkParams = (void *)GetProcAddress(hiphlpapi, "GetNetworkParams");
|
|
||||||
|
|
||||||
if (pGetNetworkParams)
|
|
||||||
{
|
|
||||||
FIXED_INFO *fi;
|
|
||||||
ULONG len;
|
|
||||||
DWORD error;
|
|
||||||
char buffer[65535];
|
|
||||||
|
|
||||||
len = 65535;
|
|
||||||
fi = buffer;
|
|
||||||
|
|
||||||
if ((error = pGetNetworkParams(fi, &len)) == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
IP_ADDR_STRING *pias = &(fi->DnsServerList);
|
|
||||||
|
|
||||||
while (pias && numdnsservers < 16)
|
|
||||||
{
|
|
||||||
strcpy(dnsserverips[numdnsservers++], pias->IpAddress.String);
|
|
||||||
pias = pias->Next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FreeLibrary(hiphlpapi);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Next, try getting the DNS server ips from the registry */
|
|
||||||
if (!numdnsservers)
|
|
||||||
{
|
|
||||||
HKEY search;
|
|
||||||
LONG error;
|
|
||||||
|
|
||||||
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ, &search);
|
|
||||||
|
|
||||||
if (error != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &search);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
char name[512];
|
|
||||||
DWORD len = 512;
|
|
||||||
|
|
||||||
error = RegQueryValueEx(search, "NameServer", NULL, NULL, (LPBYTE)name, &len);
|
|
||||||
|
|
||||||
if (error != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
error = RegQueryValueEx(search, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
char *parse = "0123456789.", *start, *end;
|
|
||||||
start = name;
|
|
||||||
end = name;
|
|
||||||
name[len] = '\0';
|
|
||||||
|
|
||||||
while (*start && numdnsservers < 16)
|
|
||||||
{
|
|
||||||
while (strchr(parse, *end))
|
|
||||||
{
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(dnsserverips[numdnsservers++], start, end - start);
|
|
||||||
|
|
||||||
while (*end && !strchr(parse, *end))
|
|
||||||
{
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
|
|
||||||
start = end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RegCloseKey(search);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!numdnsservers)
|
|
||||||
{
|
|
||||||
HKEY searchlist;
|
|
||||||
LONG error;
|
|
||||||
|
|
||||||
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", 0, KEY_READ, &searchlist);
|
|
||||||
|
|
||||||
if (error == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
DWORD numinterfaces = 0;
|
|
||||||
|
|
||||||
RegQueryInfoKey(searchlist, NULL, NULL, NULL, &numinterfaces, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
for (i = 0; i < numinterfaces; i++)
|
|
||||||
{
|
|
||||||
char name[512];
|
|
||||||
DWORD len = 512;
|
|
||||||
HKEY searchentry;
|
|
||||||
|
|
||||||
RegEnumKeyEx(searchlist, i, (LPTSTR)name, &len, NULL, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
if (RegOpenKeyEx(searchlist, name, 0, KEY_READ, &searchentry) == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
if (RegQueryValueEx(searchentry, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
char *parse = "0123456789.", *start, *end;
|
|
||||||
start = name;
|
|
||||||
end = name;
|
|
||||||
name[len] = '\0';
|
|
||||||
|
|
||||||
while (*start && numdnsservers < 16)
|
|
||||||
{
|
|
||||||
while (strchr(parse, *end))
|
|
||||||
{
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(dnsserverips[numdnsservers++], start, end - start);
|
|
||||||
|
|
||||||
while (*end && !strchr(parse, *end))
|
|
||||||
{
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
|
|
||||||
start = end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (RegQueryValueEx(searchentry, "NameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
char *parse = "0123456789.", *start, *end;
|
|
||||||
start = name;
|
|
||||||
end = name;
|
|
||||||
name[len] = '\0';
|
|
||||||
|
|
||||||
while (*start && numdnsservers < 16)
|
|
||||||
{
|
|
||||||
while (strchr(parse, *end))
|
|
||||||
{
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(dnsserverips[numdnsservers++], start, end - start);
|
|
||||||
|
|
||||||
while (*end && !strchr(parse, *end))
|
|
||||||
{
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
|
|
||||||
start = end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RegCloseKey(searchentry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RegCloseKey(searchlist);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we have a DNS server, use it */
|
|
||||||
if (numdnsservers)
|
|
||||||
{
|
|
||||||
ULONG nonblocking = 1;
|
|
||||||
int i;
|
|
||||||
int insize;
|
|
||||||
|
|
||||||
memset(&header, 0, sizeof(header));
|
|
||||||
header.id = 12345; /* FIXME: Get a better id here */
|
|
||||||
header.rd = 1;
|
|
||||||
header.qdcount = 1;
|
|
||||||
|
|
||||||
netbuf_add_dnsquery_header(buf, 65536, &offset, &header);
|
|
||||||
|
|
||||||
memset(&question, 0, sizeof(question));
|
|
||||||
strncpy(question.qname, fulldomain, 1024);
|
|
||||||
question.qtype = 33; /* SRV */
|
|
||||||
question.qclass = 1; /* INTERNET! */
|
|
||||||
|
|
||||||
netbuf_add_dnsquery_question(buf, 65536, &offset, &question);
|
|
||||||
|
|
||||||
insize = 0;
|
|
||||||
for (i = 0; i < numdnsservers && insize <= 0; i++)
|
|
||||||
{
|
|
||||||
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
||||||
ioctlsocket(sock, FIONBIO, &nonblocking);
|
|
||||||
|
|
||||||
memset(&dnsaddr, 0, sizeof(dnsaddr));
|
|
||||||
|
|
||||||
dnsaddr.sin_family = AF_INET;
|
|
||||||
dnsaddr.sin_port = htons(53);
|
|
||||||
dnsaddr.sin_addr.s_addr = inet_addr(dnsserverips[i]);
|
|
||||||
|
|
||||||
addrlen = sizeof(dnsaddr);
|
|
||||||
sendto(sock, (char *)buf, offset, 0, (struct sockaddr *)&dnsaddr, addrlen);
|
|
||||||
for (j = 0; j < 50; j++)
|
|
||||||
{
|
|
||||||
insize = recvfrom(sock, (char *)buf, 65536, 0, (struct sockaddr *)&dnsaddr, &addrlen);
|
|
||||||
if (insize == SOCKET_ERROR)
|
|
||||||
{
|
|
||||||
if (sock_error() == WSAEWOULDBLOCK)
|
|
||||||
{
|
|
||||||
Sleep(100);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closesocket(sock);
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = insize;
|
|
||||||
|
|
||||||
if (offset > 0)
|
|
||||||
{
|
|
||||||
int len = offset;
|
|
||||||
int i;
|
|
||||||
struct dnsquery_header header;
|
|
||||||
struct dnsquery_question question;
|
|
||||||
struct dnsquery_resourcerecord rr;
|
|
||||||
|
|
||||||
offset = 0;
|
|
||||||
netbuf_get_dnsquery_header(buf, 65536, &offset, &header);
|
|
||||||
|
|
||||||
for (i = 0; i < header.qdcount; i++)
|
|
||||||
{
|
|
||||||
netbuf_get_dnsquery_question(buf, 65536, &offset, &question);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < header.ancount; i++)
|
|
||||||
{
|
|
||||||
netbuf_get_dnsquery_resourcerecord(buf, 65536, &offset, &rr);
|
|
||||||
|
|
||||||
if (rr.type == 33)
|
|
||||||
{
|
|
||||||
struct dnsquery_srvrdata *srvrdata = &(rr.rdata);
|
|
||||||
|
|
||||||
xmpp_snprintf(resulttarget, resulttargetlength, "%s", srvrdata->target);
|
|
||||||
*resultport = srvrdata->port;
|
|
||||||
set = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < header.ancount; i++)
|
|
||||||
{
|
|
||||||
netbuf_get_dnsquery_resourcerecord(buf, 65536, &offset, &rr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
if (!set) {
|
|
||||||
unsigned char buf[65535];
|
|
||||||
unsigned short min;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
if ((len = res_query(fulldomain, C_IN, T_SRV, buf, 65535)) > 0) {
|
|
||||||
int offset;
|
|
||||||
int i;
|
|
||||||
struct dnsquery_header header;
|
|
||||||
struct dnsquery_question question;
|
|
||||||
struct dnsquery_resourcerecord rr;
|
|
||||||
|
|
||||||
offset = 0;
|
|
||||||
netbuf_get_dnsquery_header(buf, 65536, &offset, &header);
|
|
||||||
|
|
||||||
for (i = 0; i < header.qdcount; i++) {
|
|
||||||
netbuf_get_dnsquery_question(buf, 65536, &offset, &question);
|
|
||||||
}
|
|
||||||
|
|
||||||
min = 65535;
|
|
||||||
for (i = 0; i < header.ancount; i++) {
|
|
||||||
netbuf_get_dnsquery_resourcerecord(buf, 65536, &offset, &rr);
|
|
||||||
|
|
||||||
if (rr.type == 33) {
|
|
||||||
struct dnsquery_srvrdata *srvrdata = &(rr.rdata);
|
|
||||||
|
|
||||||
if (srvrdata->priority < min || !set) {
|
|
||||||
xmpp_snprintf(resulttarget, resulttargetlength, "%s",
|
|
||||||
srvrdata->target);
|
|
||||||
*resultport = srvrdata->port;
|
|
||||||
set = 1;
|
|
||||||
min = srvrdata->priority;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return set;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ void sock_shutdown(void);
|
|||||||
|
|
||||||
int sock_error(void);
|
int sock_error(void);
|
||||||
|
|
||||||
sock_t sock_connect(const char * const host, const unsigned int port);
|
sock_t sock_connect(const char * const host, const unsigned short port);
|
||||||
int sock_close(const sock_t sock);
|
int sock_close(const sock_t sock);
|
||||||
|
|
||||||
int sock_set_blocking(const sock_t sock);
|
int sock_set_blocking(const sock_t sock);
|
||||||
@@ -41,8 +41,4 @@ int sock_is_recoverable(const int error);
|
|||||||
/* checks for an error after connect, return 0 if connect successful */
|
/* checks for an error after connect, return 0 if connect successful */
|
||||||
int sock_connect_error(const sock_t sock);
|
int sock_connect_error(const sock_t sock);
|
||||||
|
|
||||||
int sock_srv_lookup(const char *service, const char *proto,
|
|
||||||
const char *domain, char *resulttarget,
|
|
||||||
int resulttargetlength, int *resultport);
|
|
||||||
|
|
||||||
#endif /* __LIBSTROPHE_SOCK_H__ */
|
#endif /* __LIBSTROPHE_SOCK_H__ */
|
||||||
|
|||||||
56
tests/res_query_dump.c
Normal file
56
tests/res_query_dump.c
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/* Simple program to dump res_query(3) response. */
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/nameser.h>
|
||||||
|
#include <resolv.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define STEP 8
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
unsigned char buf[65536];
|
||||||
|
char fulldomain[2048];
|
||||||
|
char *service = "xmpp-client";
|
||||||
|
char *proto = "tcp";
|
||||||
|
char *domain = NULL;
|
||||||
|
int len;
|
||||||
|
int i;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "%s: argument missed\n", argc > 0 ? argv[0] : "$0");
|
||||||
|
fprintf(stderr, "Usage: %s <domain>\n", argc > 0 ? argv[0] : "$0");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
domain = argv[1];
|
||||||
|
snprintf(fulldomain, sizeof(fulldomain), "_%s._%s.%s",
|
||||||
|
service, proto, domain);
|
||||||
|
errno = 0;
|
||||||
|
len = res_query(fulldomain, C_IN, T_SRV, buf, sizeof(buf));
|
||||||
|
|
||||||
|
if (len < 0) {
|
||||||
|
fprintf(stderr, "res_query(): Error occured (errno=%d)\n", errno);
|
||||||
|
}
|
||||||
|
if (len == 0) {
|
||||||
|
fprintf(stderr, "res_query(): Empty result\n");
|
||||||
|
}
|
||||||
|
if (len > 0) {
|
||||||
|
printf("/* res_query(\"%s\", C_IN, T_SRV, ...) */\n", fulldomain);
|
||||||
|
printf("static const unsigned char data[] = {\n");
|
||||||
|
for (i = 0; i < len; i += STEP) {
|
||||||
|
printf(" ");
|
||||||
|
for (j = i; j < len && j < i + STEP; ++j) {
|
||||||
|
printf(" 0x%02x,", buf[j]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
printf("};\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return len <= 0;
|
||||||
|
}
|
||||||
139
tests/test_resolver.c
Normal file
139
tests/test_resolver.c
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
/* test_resolver.c
|
||||||
|
* strophe XMPP client library -- tests for resolver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Dmitry Podgorny <pasis.ua@gmail.com>
|
||||||
|
*
|
||||||
|
* This software is provided AS-IS with no warranty, either express
|
||||||
|
* or implied.
|
||||||
|
*
|
||||||
|
* This program is dual licensed under the MIT and GPLv3 licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* gcc -o test_resolver -I. -I./src tests/test_resolver.c -static -lstrophe */
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "resolver.h"
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
/* res_query("_xmpp-client._tcp.jabber.kiev.ua", C_IN, T_SRV, ...) */
|
||||||
|
static const unsigned char data1[] = {
|
||||||
|
0x95, 0xf3, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
|
||||||
|
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||||
|
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a,
|
||||||
|
0x61, 0x62, 0x62, 0x65, 0x72, 0x04, 0x6b, 0x69,
|
||||||
|
0x65, 0x76, 0x02, 0x75, 0x61, 0x00, 0x00, 0x21,
|
||||||
|
0x00, 0x01, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01,
|
||||||
|
0x00, 0x00, 0x00, 0x3b, 0x00, 0x16, 0x00, 0x01,
|
||||||
|
0x00, 0x00, 0x14, 0x66, 0x06, 0x6a, 0x61, 0x62,
|
||||||
|
0x62, 0x65, 0x72, 0x04, 0x6b, 0x69, 0x65, 0x76,
|
||||||
|
0x02, 0x75, 0x61, 0x00,
|
||||||
|
};
|
||||||
|
/* res_query("_xmpp-client._tcp.jabber.org", C_IN, T_SRV, ...) */
|
||||||
|
static const unsigned char data2[] = {
|
||||||
|
0xf2, 0x98, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
|
||||||
|
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||||
|
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a,
|
||||||
|
0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72,
|
||||||
|
0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c,
|
||||||
|
0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83,
|
||||||
|
0x00, 0x1a, 0x00, 0x1e, 0x00, 0x1e, 0x14, 0x66,
|
||||||
|
0x07, 0x68, 0x65, 0x72, 0x6d, 0x65, 0x73, 0x32,
|
||||||
|
0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03,
|
||||||
|
0x6f, 0x72, 0x67, 0x00, 0xc0, 0x0c, 0x00, 0x21,
|
||||||
|
0x00, 0x01, 0x00, 0x00, 0x03, 0x83, 0x00, 0x1c,
|
||||||
|
0x00, 0x1f, 0x00, 0x1e, 0x14, 0x66, 0x09, 0x68,
|
||||||
|
0x65, 0x72, 0x6d, 0x65, 0x73, 0x32, 0x76, 0x36,
|
||||||
|
0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03,
|
||||||
|
0x6f, 0x72, 0x67, 0x00,
|
||||||
|
};
|
||||||
|
/* res_query("_xmpp-client._tcp.gmail.com", C_IN, T_SRV, ...) */
|
||||||
|
static const unsigned char data3[] = {
|
||||||
|
0xda, 0xa8, 0x81, 0x80, 0x00, 0x01, 0x00, 0x05,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
|
||||||
|
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
|
||||||
|
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x67,
|
||||||
|
0x6d, 0x61, 0x69, 0x6c, 0x03, 0x63, 0x6f, 0x6d,
|
||||||
|
0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00,
|
||||||
|
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00,
|
||||||
|
0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04,
|
||||||
|
0x61, 0x6c, 0x74, 0x31, 0x04, 0x78, 0x6d, 0x70,
|
||||||
|
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67,
|
||||||
|
0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0xc0,
|
||||||
|
0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02,
|
||||||
|
0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14,
|
||||||
|
0x66, 0x04, 0x61, 0x6c, 0x74, 0x34, 0x04, 0x78,
|
||||||
|
0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f,
|
||||||
|
0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d,
|
||||||
|
0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00,
|
||||||
|
0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00,
|
||||||
|
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x32,
|
||||||
|
0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06,
|
||||||
|
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
|
||||||
|
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00,
|
||||||
|
0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x19, 0x00,
|
||||||
|
0x05, 0x00, 0x00, 0x14, 0x66, 0x04, 0x78, 0x6d,
|
||||||
|
0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f,
|
||||||
|
0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
|
||||||
|
0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00,
|
||||||
|
0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00,
|
||||||
|
0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x33, 0x04,
|
||||||
|
0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67,
|
||||||
|
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f,
|
||||||
|
0x6d, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
const unsigned char *data;
|
||||||
|
size_t len;
|
||||||
|
char *target;
|
||||||
|
unsigned short port;
|
||||||
|
} tests[] = {
|
||||||
|
{
|
||||||
|
.data = data1,
|
||||||
|
.len = sizeof(data1),
|
||||||
|
.target = "jabber.kiev.ua",
|
||||||
|
.port = 5222,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.data = data2,
|
||||||
|
.len = sizeof(data2),
|
||||||
|
.target = "hermes2.jabber.org",
|
||||||
|
.port = 5222,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.data = data3,
|
||||||
|
.len = sizeof(data3),
|
||||||
|
.target = "xmpp.l.google.com",
|
||||||
|
.port = 5222,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char domain[2048];
|
||||||
|
unsigned short port;
|
||||||
|
size_t i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
printf("resolver_srv_lookup_buf() tests.\n");
|
||||||
|
for (i = 0; i < ARRAY_SIZE(tests); ++i) {
|
||||||
|
printf("Test #%zu: ", i + 1);
|
||||||
|
memset(domain, 'x', sizeof(domain));
|
||||||
|
ret = resolver_srv_lookup_buf(tests[i].data, tests[i].len,
|
||||||
|
domain, sizeof(domain), &port);
|
||||||
|
assert(ret == 1);
|
||||||
|
COMPARE(tests[i].target, domain);
|
||||||
|
if (tests[i].port != port) {
|
||||||
|
printf("fail! got port=%u, but should be %u\n",
|
||||||
|
(unsigned)port, (unsigned)tests[i].port);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("ok\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user