TOX-DNS V1 name resolution.
Added Tox DNS resolution via libldns. No DNSSEC yet. Only Tox DNS version 1 resolution. Added new development command /dns to test name resolution.
This commit is contained in:
parent
5e30b18d50
commit
d5135c00bc
@ -26,11 +26,16 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
|
||||
find_package(WeeChat REQUIRED)
|
||||
find_package(Tox REQUIRED
|
||||
COMPONENTS CORE
|
||||
OPTIONAL_COMPONENTS AV ENCRYPTSAVE)
|
||||
OPTIONAL_COMPONENTS AV ENCRYPTSAVE DNS)
|
||||
find_package(Ldns)
|
||||
|
||||
set(PLUGIN_PATH "lib/weechat/plugins" CACHE PATH
|
||||
"Path to install the plugin binary to.")
|
||||
|
||||
if(Ldns_FOUND AND Tox_DNS_FOUND)
|
||||
list(APPEND DNS_SRCS src/twc-dns.c)
|
||||
endif()
|
||||
|
||||
add_library(tox MODULE
|
||||
src/twc.c
|
||||
src/twc-bootstrap.c
|
||||
@ -38,6 +43,7 @@ add_library(tox MODULE
|
||||
src/twc-commands.c
|
||||
src/twc-completion.c
|
||||
src/twc-config.c
|
||||
${DNS_SRCS}
|
||||
src/twc-friend-request.c
|
||||
src/twc-gui.c
|
||||
src/twc-group-invite.c
|
||||
@ -53,8 +59,9 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -Wextra -Wno-unused-paramet
|
||||
|
||||
include_directories(${Tox_INCLUDE_DIRS})
|
||||
include_directories(${WeeChat_INCLUDE_DIRS})
|
||||
include_directories(${Ldns_INCLUDE_DIRS})
|
||||
|
||||
target_link_libraries(tox ${Tox_LIBRARIES})
|
||||
target_link_libraries(tox ${Tox_LIBRARIES} ${Ldns_LIBRARIES})
|
||||
|
||||
if(Tox_AV_FOUND)
|
||||
add_definitions(-DTOXAV_ENABLED)
|
||||
@ -64,8 +71,11 @@ if(Tox_ENCRYPTSAVE_FOUND)
|
||||
add_definitions(-DTOXENCRYPTSAVE_ENABLED)
|
||||
endif()
|
||||
|
||||
if(Ldns_FOUND AND Tox_DNS_FOUND)
|
||||
add_definitions(-DLDNS_ENABLED)
|
||||
endif()
|
||||
|
||||
# remove lib prefix (libtox.so -> tox.so)
|
||||
set_target_properties(tox PROPERTIES PREFIX "")
|
||||
|
||||
install(TARGETS tox DESTINATION "${PLUGIN_PATH}")
|
||||
|
||||
|
14
cmake/FindLdns.cmake
Normal file
14
cmake/FindLdns.cmake
Normal file
@ -0,0 +1,14 @@
|
||||
set(Ldns_INCLUDE_DIRS)
|
||||
set(Ldns_LIBRARIES)
|
||||
|
||||
find_path(Ldns_INCLUDE_DIR ldns/ldns.h)
|
||||
find_library(Ldns_LIBRARY ldns)
|
||||
|
||||
if (Ldns_INCLUDE_DIR AND Ldns_LIBRARY)
|
||||
set(Ldns_FOUND TRUE)
|
||||
list(APPEND Ldns_LIBRARIES ldns)
|
||||
list(APPEND Ldns_INCLUDE_DIRS ${Ldns_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Ldns FOUND_VAR Ldns_FOUND REQUIRED_VARS Ldns_INCLUDE_DIRS Ldns_LIBRARIES)
|
@ -27,6 +27,7 @@
|
||||
#include "twc-list.h"
|
||||
#include "twc-profile.h"
|
||||
#include "twc-chat.h"
|
||||
#include "twc-dns.h"
|
||||
#include "twc-friend-request.h"
|
||||
#include "twc-group-invite.h"
|
||||
#include "twc-bootstrap.h"
|
||||
@ -41,6 +42,15 @@ enum TWC_FRIEND_MATCH
|
||||
TWC_FRIEND_MATCH_NOMATCH = -2,
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const bool force;
|
||||
struct t_twc_profile *profile;
|
||||
char *dns_name;
|
||||
const char *message;
|
||||
} t_twc_friend_add_data;
|
||||
|
||||
/**
|
||||
* Make sure a command is executed on a Tox profile buffer. If not, warn user
|
||||
* and abort.
|
||||
@ -215,6 +225,165 @@ twc_cmd_bootstrap(void *data, struct t_gui_buffer *buffer,
|
||||
return WEECHAT_RC_ERROR;
|
||||
}
|
||||
|
||||
#ifdef LDNS_ENABLED
|
||||
void
|
||||
twc_cmd_dns_cb(void *data, enum t_twc_dns_rc rc, const uint8_t *tox_id)
|
||||
{
|
||||
if (!rc == TWC_DNS_RC_OK)
|
||||
{
|
||||
weechat_printf(weechat_current_buffer(), "%s Error resolving Tox DNS ID (%d).",
|
||||
weechat_prefix("error"), rc);
|
||||
return;
|
||||
}
|
||||
char toxid[TOX_ADDRESS_SIZE * 2 + 1];
|
||||
twc_bin2hex(tox_id, TOX_ADDRESS_SIZE, toxid);
|
||||
toxid[TOX_ADDRESS_SIZE * 2] = 0;
|
||||
weechat_printf(weechat_current_buffer(), "Resolved Tox DNS ID to %s", toxid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Command /dns callback.
|
||||
*/
|
||||
int
|
||||
twc_cmd_dns(void *data, struct t_gui_buffer *buffer,
|
||||
int argc, char **argv, char**argv_eol)
|
||||
{
|
||||
if (argc == 1)
|
||||
return WEECHAT_RC_ERROR;
|
||||
|
||||
struct t_twc_profile *profile = twc_profile_search_buffer(buffer);
|
||||
TWC_CHECK_PROFILE(profile);
|
||||
TWC_CHECK_PROFILE_LOADED(profile);
|
||||
|
||||
char dns_id[TWC_DNS_ID_MAXLEN + 1];
|
||||
snprintf(dns_id, TWC_DNS_ID_MAXLEN, "%s", argv_eol[1]);
|
||||
enum t_twc_dns_rc dns_rc;
|
||||
dns_rc = twc_dns_query(dns_id, &twc_cmd_dns_cb, NULL);
|
||||
if (dns_rc)
|
||||
{
|
||||
weechat_printf(buffer, "%sResolving TOX-DNS ID. Error code %d",
|
||||
weechat_prefix("error"), dns_rc);
|
||||
return WEECHAT_RC_ERROR;
|
||||
}
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
#endif // LDNS_ENABLED
|
||||
|
||||
/**
|
||||
* Sub-command '/friend add' callback.
|
||||
*/
|
||||
static void
|
||||
twc_cmd_friend_add_cb(void *data, enum t_twc_dns_rc rc, const uint8_t *tox_id)
|
||||
{
|
||||
const t_twc_friend_add_data *d = data;
|
||||
const bool force = d->force;
|
||||
char *name = d->dns_name;
|
||||
struct t_twc_profile *profile = d->profile;
|
||||
const char *message = d->message;
|
||||
char toxid[TOX_ADDRESS_SIZE * 2 + 1];
|
||||
|
||||
switch (rc)
|
||||
{
|
||||
case TWC_DNS_RC_OK:
|
||||
break;
|
||||
case TWC_DNS_RC_VERSION:
|
||||
weechat_printf(profile->buffer,
|
||||
"%sUnsupported Tox DNS version in reply.",
|
||||
weechat_prefix("error"));
|
||||
return;
|
||||
case TWC_DNS_RC_ERROR:
|
||||
weechat_printf(profile->buffer, "%sCould not resolve Tox ID.",
|
||||
weechat_prefix("error"));
|
||||
return;
|
||||
case TWC_DNS_RC_EINVAL:
|
||||
weechat_printf(profile->buffer, "%sInvalid Tox DNS ID.",
|
||||
weechat_prefix("error"));
|
||||
return;
|
||||
default:
|
||||
weechat_printf(profile->buffer,
|
||||
"%sUnknown error resolving Tox ID (%d).",
|
||||
weechat_prefix("error"), rc);
|
||||
return;
|
||||
}
|
||||
twc_bin2hex(tox_id, TOX_ADDRESS_SIZE, toxid);
|
||||
toxid[TOX_ADDRESS_SIZE * 2] = 0;
|
||||
weechat_printf(profile->buffer, "Resolved tox dns id '%s' to %s", name, toxid);
|
||||
free(name);
|
||||
|
||||
/* -force to delete friend before sending a new friend request */
|
||||
if (force)
|
||||
{
|
||||
bool fail = false;
|
||||
char *hex_key = strndup(toxid, TOX_PUBLIC_KEY_SIZE * 2);
|
||||
int32_t friend_number = twc_match_friend(profile, hex_key);
|
||||
free(hex_key);
|
||||
|
||||
if (friend_number == TWC_FRIEND_MATCH_AMBIGUOUS)
|
||||
fail = true;
|
||||
else if (friend_number != TWC_FRIEND_MATCH_NOMATCH)
|
||||
fail = !tox_friend_delete(profile->tox, friend_number, NULL);
|
||||
|
||||
if (fail)
|
||||
{
|
||||
weechat_printf(profile->buffer,
|
||||
"%scould not remove friend; please remove "
|
||||
"manually before resending friend request",
|
||||
weechat_prefix("error"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TOX_ERR_FRIEND_ADD err;
|
||||
(void)tox_friend_add(profile->tox,
|
||||
(uint8_t *)tox_id,
|
||||
(uint8_t *)message,
|
||||
strlen(message), &err);
|
||||
|
||||
switch (err)
|
||||
{
|
||||
case TOX_ERR_FRIEND_ADD_OK:
|
||||
weechat_printf(profile->buffer,
|
||||
"%sFriend request sent!",
|
||||
weechat_prefix("network"));
|
||||
break;
|
||||
case TOX_ERR_FRIEND_ADD_TOO_LONG:
|
||||
weechat_printf(profile->buffer,
|
||||
"%sFriend request message too long! Try again.",
|
||||
weechat_prefix("error"));
|
||||
break;
|
||||
case TOX_ERR_FRIEND_ADD_ALREADY_SENT:
|
||||
case TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM:
|
||||
weechat_printf(profile->buffer,
|
||||
"%sYou have already sent a friend request to "
|
||||
"that address (use -force to circumvent)",
|
||||
weechat_prefix("error"));
|
||||
break;
|
||||
case TOX_ERR_FRIEND_ADD_OWN_KEY:
|
||||
weechat_printf(profile->buffer,
|
||||
"%sYou can't add yourself as a friend.",
|
||||
weechat_prefix("error"));
|
||||
break;
|
||||
case TOX_ERR_FRIEND_ADD_BAD_CHECKSUM:
|
||||
weechat_printf(profile->buffer,
|
||||
"%sInvalid friend address - try again.",
|
||||
weechat_prefix("error"));
|
||||
break;
|
||||
case TOX_ERR_FRIEND_ADD_MALLOC:
|
||||
weechat_printf(profile->buffer,
|
||||
"%sCould not add friend (out of memory).",
|
||||
weechat_prefix("error"));
|
||||
break;
|
||||
case TOX_ERR_FRIEND_ADD_NULL:
|
||||
case TOX_ERR_FRIEND_ADD_NO_MESSAGE: /* this should not happen as we
|
||||
validate the message */
|
||||
default:
|
||||
weechat_printf(profile->buffer,
|
||||
"%sCould not add friend (unknown error %d).",
|
||||
weechat_prefix("error"), err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Command /friend callback.
|
||||
*/
|
||||
@ -286,89 +455,48 @@ twc_cmd_friend(void *data, struct t_gui_buffer *buffer,
|
||||
if (!message)
|
||||
message = weechat_config_string(twc_config_friend_request_message);
|
||||
|
||||
/* strip "tox:" URI prefix */
|
||||
char *l = weechat_strcasestr(hex_id, "tox:");
|
||||
if (l && (l == hex_id))
|
||||
hex_id = &hex_id[4];
|
||||
|
||||
char *dns_name = strdup(hex_id);
|
||||
if (!dns_name)
|
||||
{
|
||||
weechat_printf(profile->buffer,
|
||||
"%sMemory allocation error.",
|
||||
weechat_prefix("error"));
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
t_twc_friend_add_data data = { force, profile, dns_name, message };
|
||||
uint8_t address[TOX_ADDRESS_SIZE];
|
||||
|
||||
if (strlen(hex_id) != TOX_ADDRESS_SIZE * 2)
|
||||
{
|
||||
#ifdef LDNS_ENABLED
|
||||
/* resolve toxid */
|
||||
enum t_twc_dns_rc dns_rc;
|
||||
dns_rc = twc_dns_query(hex_id, &twc_cmd_friend_add_cb, &data);
|
||||
if (dns_rc)
|
||||
{
|
||||
weechat_printf(profile->buffer,
|
||||
"%sTox ID length invalid. Please try again.",
|
||||
"%sError calling Tox DNS resolver (%d).",
|
||||
weechat_prefix("error"), dns_rc);
|
||||
}
|
||||
#else
|
||||
/* immediately fail */
|
||||
weechat_printf(profile->buffer,
|
||||
"%sTox ID length invalid and Tox DNS resolution not implemented."
|
||||
" Please try again.",
|
||||
weechat_prefix("error"));
|
||||
|
||||
#endif // LDNS_ENABLED
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
|
||||
uint8_t address[TOX_ADDRESS_SIZE];
|
||||
twc_hex2bin(hex_id, TOX_ADDRESS_SIZE, address);
|
||||
/* call the callback by hand and finish the /friend add command */
|
||||
twc_cmd_friend_add_cb(&data, TWC_DNS_RC_OK, address);
|
||||
|
||||
if (force)
|
||||
{
|
||||
bool fail = false;
|
||||
char *hex_key = strndup(hex_id, TOX_PUBLIC_KEY_SIZE * 2);
|
||||
int32_t friend_number = twc_match_friend(profile, hex_key);
|
||||
free(hex_key);
|
||||
|
||||
if (friend_number == TWC_FRIEND_MATCH_AMBIGUOUS)
|
||||
fail = true;
|
||||
else if (friend_number != TWC_FRIEND_MATCH_NOMATCH)
|
||||
fail = !tox_friend_delete(profile->tox, friend_number, NULL);
|
||||
|
||||
if (fail)
|
||||
{
|
||||
weechat_printf(profile->buffer,
|
||||
"%scould not remove friend; please remove "
|
||||
"manually before resending friend request",
|
||||
weechat_prefix("error"));
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
}
|
||||
|
||||
TOX_ERR_FRIEND_ADD err;
|
||||
(void)tox_friend_add(profile->tox,
|
||||
(uint8_t *)address,
|
||||
(uint8_t *)message,
|
||||
strlen(message), &err);
|
||||
|
||||
switch (err)
|
||||
{
|
||||
case TOX_ERR_FRIEND_ADD_OK:
|
||||
weechat_printf(profile->buffer,
|
||||
"%sFriend request sent!",
|
||||
weechat_prefix("network"));
|
||||
break;
|
||||
case TOX_ERR_FRIEND_ADD_TOO_LONG:
|
||||
weechat_printf(profile->buffer,
|
||||
"%sFriend request message too long! Try again.",
|
||||
weechat_prefix("error"));
|
||||
break;
|
||||
case TOX_ERR_FRIEND_ADD_ALREADY_SENT:
|
||||
case TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM:
|
||||
weechat_printf(profile->buffer,
|
||||
"%sYou have already sent a friend request to "
|
||||
"that address (use -force to circumvent)",
|
||||
weechat_prefix("error"));
|
||||
break;
|
||||
case TOX_ERR_FRIEND_ADD_OWN_KEY:
|
||||
weechat_printf(profile->buffer,
|
||||
"%sYou can't add yourself as a friend.",
|
||||
weechat_prefix("error"));
|
||||
break;
|
||||
case TOX_ERR_FRIEND_ADD_BAD_CHECKSUM:
|
||||
weechat_printf(profile->buffer,
|
||||
"%sInvalid friend address - try again.",
|
||||
weechat_prefix("error"));
|
||||
break;
|
||||
case TOX_ERR_FRIEND_ADD_MALLOC:
|
||||
weechat_printf(profile->buffer,
|
||||
"%sCould not add friend (out of memory).",
|
||||
weechat_prefix("error"));
|
||||
break;
|
||||
case TOX_ERR_FRIEND_ADD_NULL:
|
||||
case TOX_ERR_FRIEND_ADD_NO_MESSAGE: /* this should not happen as we
|
||||
validate the message */
|
||||
default:
|
||||
weechat_printf(profile->buffer,
|
||||
"%sCould not add friend (unknown error %d).",
|
||||
weechat_prefix("error"), err);
|
||||
break;
|
||||
}
|
||||
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
@ -668,6 +796,7 @@ twc_cmd_me(void *data, struct t_gui_buffer *buffer,
|
||||
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command /msg callback.
|
||||
*/
|
||||
@ -1208,6 +1337,13 @@ twc_commands_init()
|
||||
"<message>",
|
||||
"message: message to send",
|
||||
NULL, twc_cmd_me, NULL);
|
||||
#ifdef LDNS_ENABLED
|
||||
weechat_hook_command("dns",
|
||||
"test toxdns",
|
||||
"<toxdnsid>",
|
||||
"[tox:]<name>[@|._tox.]<domain>\n",
|
||||
NULL, twc_cmd_dns, NULL);
|
||||
#endif // LDNS_ENABLED
|
||||
|
||||
weechat_hook_command("msg",
|
||||
"send a message to a Tox friend",
|
||||
|
343
src/twc-dns.c
343
src/twc-dns.c
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Håvard Pettersson <mail@haavard.me>
|
||||
* Copyright (c) 2015 Håvard Pettersson <mail@haavard.me>,
|
||||
* Michael Raitza <spacefrogg-devel@meterriblecrew.net>
|
||||
*
|
||||
* This file is part of Tox-WeeChat.
|
||||
*
|
||||
@ -21,10 +22,14 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <weechat/weechat-plugin.h>
|
||||
#include <tox/tox.h>
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
#undef dprintf /* well, yeah, well... */
|
||||
|
||||
#include "twc.h"
|
||||
#include "twc-utils.h"
|
||||
|
||||
@ -43,6 +48,312 @@ struct t_twc_dns_callback_info
|
||||
struct t_hook *hook;
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct holding the split dns_id.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
char *domain;
|
||||
} t_twc_toxdns_data;
|
||||
|
||||
/**
|
||||
* Struct holding a list of DNS responses.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
size_t count;
|
||||
uint8_t **data;
|
||||
} t_resolve_response_list;
|
||||
|
||||
static t_twc_toxdns_data *
|
||||
toxdns_data_new(size_t namelen, size_t domlen)
|
||||
{
|
||||
t_twc_toxdns_data *d;
|
||||
d = (t_twc_toxdns_data *)malloc(sizeof(t_twc_toxdns_data)
|
||||
+ namelen + domlen + 2);
|
||||
if (!d)
|
||||
return NULL;
|
||||
d->name = (char *)malloc(namelen + 1);
|
||||
if (!d->name)
|
||||
{
|
||||
free(d);
|
||||
return NULL;
|
||||
}
|
||||
d->domain = (char *)malloc(domlen + 1);
|
||||
if (!d->domain)
|
||||
{
|
||||
free(d);
|
||||
free(d->name);
|
||||
return NULL;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
static void
|
||||
toxdns_data_deep_free(t_twc_toxdns_data *d)
|
||||
{
|
||||
if (d)
|
||||
{
|
||||
if (d->name)
|
||||
free(d->name);
|
||||
if (d->domain)
|
||||
free(d->domain);
|
||||
free(d);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits [tox:]<name>[@|._tox.]<domain> into a struct S with two
|
||||
* fields S.name = "<name>" and S.domain = "_tox.<domain>.". Note the
|
||||
* ending dot that finalises the DNS domain for later query!
|
||||
*
|
||||
* name: a string that is shorter than or equal to RESOLVE_ID_MAXLEN
|
||||
* and must be in the form mentioned above.
|
||||
*/
|
||||
static t_twc_toxdns_data *
|
||||
split_name(const char *name, enum t_twc_dns_rc *error)
|
||||
{
|
||||
enum t_twc_dns_rc err = TWC_DNS_RC_OK;
|
||||
t_twc_toxdns_data *data = NULL;
|
||||
uint32_t name_len = strlen(name);
|
||||
char n[name_len + 1];
|
||||
char d[name_len + 6];
|
||||
char *domain;
|
||||
char *d_pos = d;
|
||||
char *n_pos = n;
|
||||
|
||||
strcpy(n, name);
|
||||
domain = strstr(n, "tox:"); /* ignore a "tox:" uri prefix */
|
||||
if (domain && (domain == n))
|
||||
n_pos = &n[4];
|
||||
|
||||
domain = strstr(n_pos, "._tox.");
|
||||
if ((!domain) || (domain == n_pos) || (strlen(domain) <= 6))
|
||||
{
|
||||
domain = strstr(n_pos, "@");
|
||||
if ((!domain) || (domain == n_pos) || (strlen(domain) <= 1))
|
||||
{
|
||||
err = TWC_DNS_RC_EINVAL;
|
||||
goto err;
|
||||
}
|
||||
d_pos = stpcpy(d_pos, "_tox.");
|
||||
}
|
||||
d_pos = stpcpy(d_pos, &domain[1]);
|
||||
strcpy(d_pos, ".");
|
||||
domain[0] = 0;
|
||||
|
||||
data = toxdns_data_new(strlen(n_pos), strlen(d));
|
||||
if (!data)
|
||||
{
|
||||
err = TWC_DNS_RC_ERROR;
|
||||
goto err;
|
||||
}
|
||||
strcpy(data->name, n_pos);
|
||||
strcpy(data->domain, d);
|
||||
|
||||
err:
|
||||
*error = err;
|
||||
return data;
|
||||
}
|
||||
|
||||
static size_t
|
||||
resolve_response_count(const t_resolve_response_list *resp)
|
||||
{
|
||||
if (resp)
|
||||
return resp->count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t *
|
||||
resolve_response_data(const t_resolve_response_list *resp, const size_t nr)
|
||||
{
|
||||
if (nr < resolve_response_count(resp))
|
||||
return resp->data[nr];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static t_resolve_response_list *
|
||||
resolve_response_list_new(size_t size)
|
||||
{
|
||||
t_resolve_response_list *resps;
|
||||
resps = (t_resolve_response_list *)malloc(sizeof(t_resolve_response_list)
|
||||
+ sizeof(char*) * size);
|
||||
if (!resps)
|
||||
return NULL;
|
||||
resps->count = 0;
|
||||
resps->data = (uint8_t **)&resps->data + 1;
|
||||
return resps;
|
||||
}
|
||||
|
||||
static void
|
||||
resolve_response_list_deep_free(t_resolve_response_list *resp)
|
||||
{
|
||||
if (!resp)
|
||||
return;
|
||||
for (size_t i = 0; i < resolve_response_count(resp); ++i)
|
||||
if (resp->data[i])
|
||||
free(resp->data[i]);
|
||||
free(resp);
|
||||
}
|
||||
|
||||
static ldns_rr_list *
|
||||
twc_ldns_query(ldns_resolver* res, const char *name, const ldns_rr_type t,
|
||||
enum t_twc_dns_rc *err)
|
||||
{
|
||||
ldns_rdf *domain = ldns_dname_new_frm_str(name);
|
||||
ldns_pkt *pkt;
|
||||
ldns_rr_list *txt = NULL;
|
||||
|
||||
*err = TWC_DNS_RC_ERROR;
|
||||
|
||||
if (!domain)
|
||||
goto err_dom;
|
||||
|
||||
for (size_t i = 0; i < ldns_resolver_nameserver_count(res); ++i)
|
||||
{
|
||||
pkt = ldns_resolver_query(res, domain, t, LDNS_RR_CLASS_IN, LDNS_RD);
|
||||
if (!pkt)
|
||||
goto fin;
|
||||
switch (ldns_pkt_get_rcode(pkt))
|
||||
{
|
||||
case LDNS_RCODE_NOERROR:
|
||||
*err = TWC_DNS_RC_OK;
|
||||
txt = ldns_pkt_rr_list_by_type(pkt, t, LDNS_SECTION_ANSWER);
|
||||
goto fin;
|
||||
case LDNS_RCODE_REFUSED:
|
||||
case LDNS_RCODE_NXDOMAIN:
|
||||
case LDNS_RCODE_SERVFAIL:
|
||||
for (size_t i = 0; i < ldns_resolver_nameserver_count(res); ++i)
|
||||
if (!ldns_rdf_compare(ldns_pkt_answerfrom(pkt),
|
||||
ldns_resolver_nameservers(res)[i]))
|
||||
{
|
||||
/* mark faulty nameserver as unreachable */
|
||||
ldns_resolver_set_nameserver_rtt(res, i, LDNS_RESOLV_RTT_INF);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto fin;
|
||||
}
|
||||
}
|
||||
fin:
|
||||
ldns_rdf_deep_free(domain);
|
||||
if (pkt)
|
||||
ldns_pkt_free(pkt);
|
||||
err_dom:
|
||||
return txt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the TXT records for NAME and return all responses. Outer
|
||||
* quotes are stripped from TXT records. All fields of a TXT record
|
||||
* are stiched together to a long string stripping white space as
|
||||
* requested by protocol.
|
||||
*/
|
||||
static t_resolve_response_list *
|
||||
twc_ldns_resolve(char *name, enum t_twc_dns_rc *err) {
|
||||
ldns_resolver *res;
|
||||
ldns_status s;
|
||||
ldns_rr_list *txt = NULL;
|
||||
t_resolve_response_list *txts = NULL;
|
||||
|
||||
*err= TWC_DNS_RC_OK;
|
||||
|
||||
s = ldns_resolver_new_frm_file(&res, NULL);
|
||||
if (s != LDNS_STATUS_OK)
|
||||
{
|
||||
*err = TWC_DNS_RC_ERROR;
|
||||
goto err;
|
||||
}
|
||||
txt = twc_ldns_query(res, name, LDNS_RR_TYPE_TXT, err);
|
||||
if (!txt)
|
||||
goto err_pkt;
|
||||
txts = resolve_response_list_new(ldns_rr_list_rr_count(txt));
|
||||
if (!txts)
|
||||
{
|
||||
*err = TWC_DNS_RC_ERROR;
|
||||
goto err_txt;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ldns_rr_list_rr_count(txt); ++i)
|
||||
{
|
||||
ldns_rr *rr = ldns_rr_list_rr(txt, i);
|
||||
char txt_field[256] = {0}; /* TXT RR RDATA can be 255 bytes long */
|
||||
char *cur_pos = txt_field;
|
||||
|
||||
/* stich together all TXT RR RDATA fields, stripping quotes */
|
||||
for (size_t j = 0; j < ldns_rr_rd_count(rr); ++j)
|
||||
{
|
||||
char *rdata = ldns_rdf2str(ldns_rr_rdf(rr, j));
|
||||
size_t len = strlen(rdata);
|
||||
|
||||
if (rdata[0] == '"')
|
||||
{
|
||||
rdata[len - 1] = 0;
|
||||
cur_pos = stpcpy(cur_pos, &rdata[1]);
|
||||
} else
|
||||
cur_pos = stpcpy(cur_pos, rdata);
|
||||
free(rdata);
|
||||
}
|
||||
txts->data[i] = (uint8_t *)strdup(txt_field);
|
||||
if (!txts->data[i])
|
||||
{
|
||||
*err = TWC_DNS_RC_ERROR;
|
||||
goto err_resp;
|
||||
}
|
||||
++txts->count;
|
||||
}
|
||||
goto err_txt; // Normal return
|
||||
|
||||
err_resp:
|
||||
resolve_response_list_deep_free(txts);
|
||||
txts = NULL;
|
||||
err_txt:
|
||||
ldns_rr_list_deep_free(txt);
|
||||
err_pkt:
|
||||
ldns_resolver_deep_free(res);
|
||||
err:
|
||||
return txts;
|
||||
}
|
||||
|
||||
static uint8_t *
|
||||
resolve_toxdns1(const t_twc_toxdns_data *data, enum t_twc_dns_rc *error)
|
||||
{
|
||||
char buf[TWC_DNS_ID_MAXLEN + 2];
|
||||
t_resolve_response_list *id_rrs;
|
||||
uint8_t *toxid = NULL;
|
||||
*error = TWC_DNS_RC_OK;
|
||||
|
||||
sprintf(buf, "%s.%s", data->name, data->domain);
|
||||
id_rrs = twc_ldns_resolve(buf, error);
|
||||
if (!id_rrs)
|
||||
goto err;
|
||||
|
||||
for (size_t j = 0; j < id_rrs->count; ++j)
|
||||
{
|
||||
uint8_t *id_rr = resolve_response_data(id_rrs, j);
|
||||
if (strncmp("v=tox1;id=", (char *)id_rr, 10))
|
||||
{
|
||||
*error = TWC_DNS_RC_VERSION;
|
||||
continue;
|
||||
}
|
||||
toxid = (uint8_t *)strndup((char *)&id_rr[10], TOX_ADDRESS_SIZE * 2);
|
||||
if (!toxid)
|
||||
{
|
||||
*error = TWC_DNS_RC_ERROR;
|
||||
goto err_id;
|
||||
}
|
||||
*error = TWC_DNS_RC_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
err_id:
|
||||
resolve_response_list_deep_free(id_rrs);
|
||||
err:
|
||||
return toxid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback when the DNS resolver child process has written to our file
|
||||
* descriptor. Process the data a bit and pass it on to the original callback.
|
||||
@ -87,7 +398,35 @@ twc_dns_fd_callback(void *data, int fd)
|
||||
void
|
||||
twc_perform_dns_lookup(const char *dns_id, int out_fd)
|
||||
{
|
||||
dprintf(out_fd, "%d", TWC_DNS_RC_ERROR);
|
||||
enum t_twc_dns_rc err = TWC_DNS_RC_OK;
|
||||
t_twc_toxdns_data *d;
|
||||
uint8_t *toxid;
|
||||
|
||||
if (!dns_id || weechat_strlen_screen(dns_id) > TWC_DNS_ID_MAXLEN)
|
||||
{
|
||||
err = TWC_DNS_RC_EINVAL;
|
||||
goto err;
|
||||
}
|
||||
/* Split name from domain in preparation for tox3dns protocol. */
|
||||
d = split_name(dns_id, &err);
|
||||
|
||||
if (!d)
|
||||
{
|
||||
err = TWC_DNS_RC_EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* For now only resolve Tox DNS version 1 addresses */
|
||||
toxid = resolve_toxdns1(d, &err);
|
||||
if (!toxid)
|
||||
goto err;
|
||||
|
||||
err:
|
||||
if (err)
|
||||
dprintf(out_fd, "%d", err);
|
||||
else
|
||||
dprintf(out_fd, "%s", toxid);
|
||||
toxdns_data_deep_free(d);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,10 +22,19 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef LDNS_ENABLED
|
||||
#include <tox/toxdns.h>
|
||||
|
||||
#define TWC_DNS_ID_MAXLEN TOXDNS_MAX_RECOMMENDED_NAME_LENGTH
|
||||
|
||||
#endif // LDNS_ENABLED
|
||||
|
||||
enum t_twc_dns_rc
|
||||
{
|
||||
TWC_DNS_RC_OK = 0,
|
||||
TWC_DNS_RC_ERROR = -1,
|
||||
TWC_DNS_RC_EINVAL = -2,
|
||||
TWC_DNS_RC_VERSION = -4,
|
||||
};
|
||||
|
||||
enum t_twc_dns_rc
|
||||
|
Loading…
Reference in New Issue
Block a user