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(WeeChat REQUIRED)
|
||||||
find_package(Tox REQUIRED
|
find_package(Tox REQUIRED
|
||||||
COMPONENTS CORE
|
COMPONENTS CORE
|
||||||
OPTIONAL_COMPONENTS AV ENCRYPTSAVE)
|
OPTIONAL_COMPONENTS AV ENCRYPTSAVE DNS)
|
||||||
|
find_package(Ldns)
|
||||||
|
|
||||||
set(PLUGIN_PATH "lib/weechat/plugins" CACHE PATH
|
set(PLUGIN_PATH "lib/weechat/plugins" CACHE PATH
|
||||||
"Path to install the plugin binary to.")
|
"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
|
add_library(tox MODULE
|
||||||
src/twc.c
|
src/twc.c
|
||||||
src/twc-bootstrap.c
|
src/twc-bootstrap.c
|
||||||
@ -38,6 +43,7 @@ add_library(tox MODULE
|
|||||||
src/twc-commands.c
|
src/twc-commands.c
|
||||||
src/twc-completion.c
|
src/twc-completion.c
|
||||||
src/twc-config.c
|
src/twc-config.c
|
||||||
|
${DNS_SRCS}
|
||||||
src/twc-friend-request.c
|
src/twc-friend-request.c
|
||||||
src/twc-gui.c
|
src/twc-gui.c
|
||||||
src/twc-group-invite.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(${Tox_INCLUDE_DIRS})
|
||||||
include_directories(${WeeChat_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)
|
if(Tox_AV_FOUND)
|
||||||
add_definitions(-DTOXAV_ENABLED)
|
add_definitions(-DTOXAV_ENABLED)
|
||||||
@ -64,8 +71,11 @@ if(Tox_ENCRYPTSAVE_FOUND)
|
|||||||
add_definitions(-DTOXENCRYPTSAVE_ENABLED)
|
add_definitions(-DTOXENCRYPTSAVE_ENABLED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(Ldns_FOUND AND Tox_DNS_FOUND)
|
||||||
|
add_definitions(-DLDNS_ENABLED)
|
||||||
|
endif()
|
||||||
|
|
||||||
# remove lib prefix (libtox.so -> tox.so)
|
# remove lib prefix (libtox.so -> tox.so)
|
||||||
set_target_properties(tox PROPERTIES PREFIX "")
|
set_target_properties(tox PROPERTIES PREFIX "")
|
||||||
|
|
||||||
install(TARGETS tox DESTINATION "${PLUGIN_PATH}")
|
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-list.h"
|
||||||
#include "twc-profile.h"
|
#include "twc-profile.h"
|
||||||
#include "twc-chat.h"
|
#include "twc-chat.h"
|
||||||
|
#include "twc-dns.h"
|
||||||
#include "twc-friend-request.h"
|
#include "twc-friend-request.h"
|
||||||
#include "twc-group-invite.h"
|
#include "twc-group-invite.h"
|
||||||
#include "twc-bootstrap.h"
|
#include "twc-bootstrap.h"
|
||||||
@ -41,6 +42,15 @@ enum TWC_FRIEND_MATCH
|
|||||||
TWC_FRIEND_MATCH_NOMATCH = -2,
|
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
|
* Make sure a command is executed on a Tox profile buffer. If not, warn user
|
||||||
* and abort.
|
* and abort.
|
||||||
@ -215,6 +225,165 @@ twc_cmd_bootstrap(void *data, struct t_gui_buffer *buffer,
|
|||||||
return WEECHAT_RC_ERROR;
|
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.
|
* Command /friend callback.
|
||||||
*/
|
*/
|
||||||
@ -286,89 +455,48 @@ twc_cmd_friend(void *data, struct t_gui_buffer *buffer,
|
|||||||
if (!message)
|
if (!message)
|
||||||
message = weechat_config_string(twc_config_friend_request_message);
|
message = weechat_config_string(twc_config_friend_request_message);
|
||||||
|
|
||||||
if (strlen(hex_id) != TOX_ADDRESS_SIZE * 2)
|
/* 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,
|
weechat_printf(profile->buffer,
|
||||||
"%sTox ID length invalid. Please try again.",
|
"%sMemory allocation error.",
|
||||||
weechat_prefix("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,
|
||||||
|
"%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;
|
return WEECHAT_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t address[TOX_ADDRESS_SIZE];
|
|
||||||
twc_hex2bin(hex_id, TOX_ADDRESS_SIZE, address);
|
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;
|
return WEECHAT_RC_OK;
|
||||||
}
|
}
|
||||||
@ -668,6 +796,7 @@ twc_cmd_me(void *data, struct t_gui_buffer *buffer,
|
|||||||
|
|
||||||
return WEECHAT_RC_OK;
|
return WEECHAT_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command /msg callback.
|
* Command /msg callback.
|
||||||
*/
|
*/
|
||||||
@ -1208,6 +1337,13 @@ twc_commands_init()
|
|||||||
"<message>",
|
"<message>",
|
||||||
"message: message to send",
|
"message: message to send",
|
||||||
NULL, twc_cmd_me, NULL);
|
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",
|
weechat_hook_command("msg",
|
||||||
"send a message to a Tox friend",
|
"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.
|
* This file is part of Tox-WeeChat.
|
||||||
*
|
*
|
||||||
@ -21,10 +22,14 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <weechat/weechat-plugin.h>
|
#include <weechat/weechat-plugin.h>
|
||||||
#include <tox/tox.h>
|
#include <tox/tox.h>
|
||||||
|
|
||||||
|
#include <ldns/ldns.h>
|
||||||
|
#undef dprintf /* well, yeah, well... */
|
||||||
|
|
||||||
#include "twc.h"
|
#include "twc.h"
|
||||||
#include "twc-utils.h"
|
#include "twc-utils.h"
|
||||||
|
|
||||||
@ -43,6 +48,312 @@ struct t_twc_dns_callback_info
|
|||||||
struct t_hook *hook;
|
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
|
* 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.
|
* 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
|
void
|
||||||
twc_perform_dns_lookup(const char *dns_id, int out_fd)
|
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>
|
#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
|
enum t_twc_dns_rc
|
||||||
{
|
{
|
||||||
TWC_DNS_RC_OK = 0,
|
TWC_DNS_RC_OK = 0,
|
||||||
TWC_DNS_RC_ERROR = -1,
|
TWC_DNS_RC_ERROR = -1,
|
||||||
|
TWC_DNS_RC_EINVAL = -2,
|
||||||
|
TWC_DNS_RC_VERSION = -4,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum t_twc_dns_rc
|
enum t_twc_dns_rc
|
||||||
|
Loading…
Reference in New Issue
Block a user