1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-11-15 08:03:01 +01:00
toxic/src/dns.c

316 lines
8.7 KiB
C
Raw Normal View History

2014-06-17 03:22:26 +02:00
/* dns.c
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <resolv.h>
2014-06-24 19:20:12 +02:00
#ifdef __APPLE__
#include <arpa/nameser_compat.h>
2014-06-24 19:20:12 +02:00
#else
#include <arpa/nameser.h>
2014-06-24 19:20:12 +02:00
#endif /* ifdef __APPLE__ */
2014-06-17 03:22:26 +02:00
#include <tox/toxdns.h>
#include "toxic.h"
#include "windows.h"
#include "line_info.h"
#include "dns.h"
2014-06-18 01:10:25 +02:00
#include "global_commands.h"
#include "misc_tools.h"
2014-06-17 03:22:26 +02:00
#define MAX_DNS_REQST_SIZE 256
2014-06-19 02:22:26 +02:00
#define NUM_DNS3_SERVERS 2 /* must correspond to number of items in dns3_servers array */
2014-06-17 03:22:26 +02:00
#define TOX_DNS3_TXT_PREFIX "v=tox3;id="
#define DNS3_KEY_SZ 32
2014-07-09 06:05:13 +02:00
extern struct _Winthread Winthread;
2014-06-19 02:22:26 +02:00
/* TODO: process keys from key file instead of hard-coding like a noob */
2014-06-17 03:22:26 +02:00
static struct dns3_server {
const char *name;
char key[DNS3_KEY_SZ];
2014-06-17 03:22:26 +02:00
} dns3_servers[] = {
{
2014-06-19 19:50:41 +02:00
"utox.org",
{
2014-06-17 03:22:26 +02:00
0xD3, 0x15, 0x4F, 0x65, 0xD2, 0x8A, 0x5B, 0x41, 0xA0, 0x5D, 0x4A, 0xC7, 0xE4, 0xB3, 0x9C, 0x6B,
0x1C, 0x23, 0x3C, 0xC8, 0x57, 0xFB, 0x36, 0x5C, 0x56, 0xE8, 0x39, 0x27, 0x37, 0x46, 0x2A, 0x12
}
},
2014-06-19 02:22:26 +02:00
{
"toxme.se",
{
0x5D, 0x72, 0xC5, 0x17, 0xDF, 0x6A, 0xEC, 0x54, 0xF1, 0xE9, 0x77, 0xA6, 0xB6, 0xF2, 0x59, 0x14,
0xEA, 0x4C, 0xF7, 0x27, 0x7A, 0x85, 0x02, 0x7C, 0xD9, 0xF5, 0x19, 0x6D, 0xF1, 0x7E, 0x0B, 0x13
}
},
2014-06-17 03:22:26 +02:00
};
2014-06-18 21:54:05 +02:00
static struct _thread_data {
2014-06-18 01:10:25 +02:00
ToxWindow *self;
char id_bin[TOX_FRIEND_ADDRESS_SIZE];
char addr[MAX_STR_SIZE];
char msg[MAX_STR_SIZE];
2014-06-18 01:10:25 +02:00
uint8_t busy;
Tox *m;
} t_data;
static struct _dns_thread {
pthread_t tid;
pthread_attr_t attr;
2014-06-18 01:10:25 +02:00
} dns_thread;
2014-06-19 19:50:41 +02:00
static int dns_error(ToxWindow *self, const char *errmsg)
2014-06-17 03:22:26 +02:00
{
const char *msg = "User lookup failed: %s";
2014-06-18 01:10:25 +02:00
2014-07-09 06:05:13 +02:00
pthread_mutex_lock(&Winthread.lock);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg, errmsg);
2014-07-09 06:05:13 +02:00
pthread_mutex_unlock(&Winthread.lock);
2014-06-18 01:10:25 +02:00
return -1;
}
2014-06-17 03:22:26 +02:00
2014-06-18 01:32:02 +02:00
static void kill_dns_thread(void *dns_obj)
2014-06-18 01:10:25 +02:00
{
2014-06-17 03:22:26 +02:00
if (dns_obj)
tox_dns3_kill(dns_obj);
2014-06-18 01:10:25 +02:00
memset(&t_data, 0, sizeof(struct _thread_data));
pthread_attr_destroy(&dns_thread.attr);
pthread_exit(NULL);
2014-06-17 03:22:26 +02:00
}
2014-06-18 01:10:25 +02:00
/* puts TXT from dns response in buf. Returns length of TXT on success, -1 on fail.*/
static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char *buf)
2014-06-17 03:22:26 +02:00
{
uint8_t *ans_pt = answer + sizeof(HEADER);
uint8_t *ans_end = answer + ans_len;
char exp_ans[PACKETSZ];
2014-06-17 03:22:26 +02:00
int len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
if (len == -1)
2014-06-18 01:10:25 +02:00
return dns_error(self, "dn_expand failed.");
2014-06-17 03:22:26 +02:00
ans_pt += len;
if (ans_pt > ans_end - 4)
2014-06-24 00:54:23 +02:00
return dns_error(self, "DNS reply was too short.");
2014-06-17 03:22:26 +02:00
int type;
GETSHORT(type, ans_pt);
if (type != T_TXT)
2014-06-24 00:54:23 +02:00
return dns_error(self, "Broken DNS reply.");
2014-06-17 03:22:26 +02:00
ans_pt += INT16SZ; /* class */
uint32_t size = 0;
/* recurse through CNAME rr's */
do {
ans_pt += size;
len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
if (len == -1)
2014-06-18 01:10:25 +02:00
return dns_error(self, "Second dn_expand failed.");
2014-06-17 03:22:26 +02:00
ans_pt += len;
if (ans_pt > ans_end - 10)
2014-06-24 00:54:23 +02:00
return dns_error(self, "DNS reply was too short.");
2014-06-17 03:22:26 +02:00
GETSHORT(type, ans_pt);
ans_pt += INT16SZ;
ans_pt += 4;
GETSHORT(size, ans_pt);
if (ans_pt + size < answer || ans_pt + size > ans_end)
2014-06-18 01:10:25 +02:00
return dns_error(self, "RR overflow.");
2014-06-17 03:22:26 +02:00
} while (type == T_CNAME);
if (type != T_TXT)
2014-06-24 00:54:23 +02:00
return dns_error(self, "DNS response failed.");
2014-06-17 03:22:26 +02:00
uint32_t txt_len = *ans_pt;
2014-06-18 01:10:25 +02:00
if (!size || txt_len >= size || !txt_len)
return dns_error(self, "No record found.");
2014-06-17 03:22:26 +02:00
ans_pt++;
ans_pt[txt_len] = '\0';
memcpy(buf, ans_pt, txt_len + 1);
2014-06-18 01:10:25 +02:00
return txt_len;
2014-06-17 03:22:26 +02:00
}
/* Takes address addr in the form "username@domain", puts the username in namebuf,
and the domain in dombuf.
return length of username on success, -1 on failure */
static int parse_addr(const char *addr, char *namebuf, char *dombuf)
2014-06-17 03:22:26 +02:00
{
char tmpaddr[MAX_STR_SIZE];
char *tmpname, *tmpdom;
2014-06-17 03:22:26 +02:00
strcpy(tmpaddr, addr);
tmpname = strtok(tmpaddr, "@");
tmpdom = strtok(NULL, "");
if (tmpname == NULL || tmpdom == NULL)
return -1;
str_to_lower(tmpdom);
2014-06-17 03:22:26 +02:00
strcpy(namebuf, tmpname);
strcpy(dombuf, tmpdom);
return strlen(namebuf);
}
2014-06-18 01:10:25 +02:00
/* Does DNS lookup for addr and puts resulting tox id in id_bin. */
void *dns3_lookup_thread(void *data)
2014-06-17 03:22:26 +02:00
{
2014-06-18 01:10:25 +02:00
ToxWindow *self = t_data.self;
2014-06-17 03:22:26 +02:00
char domain[MAX_STR_SIZE];
char name[MAX_STR_SIZE];
2014-06-17 03:22:26 +02:00
2014-06-18 01:10:25 +02:00
int namelen = parse_addr(t_data.addr, name, domain);
2014-06-17 03:22:26 +02:00
2014-06-18 01:10:25 +02:00
if (namelen == -1) {
dns_error(self, "Must be a Tox ID or an address in the form username@domain");
2014-06-18 01:32:02 +02:00
kill_dns_thread(NULL);
2014-06-18 01:10:25 +02:00
}
2014-06-17 03:22:26 +02:00
/* get domain name/pub key */
const char *DNS_pubkey = NULL;
const char *domname = NULL;
2014-06-17 03:22:26 +02:00
int i;
for (i = 0; i < NUM_DNS3_SERVERS; ++i) {
if (strcmp(dns3_servers[i].name, domain) == 0) {
DNS_pubkey = dns3_servers[i].key;
domname = dns3_servers[i].name;
break;
}
}
2014-06-18 01:10:25 +02:00
if (domname == NULL) {
dns_error(self, "Domain not found.");
2014-06-18 01:32:02 +02:00
kill_dns_thread(NULL);
2014-06-18 01:10:25 +02:00
}
2014-06-17 03:22:26 +02:00
void *dns_obj = tox_dns3_new((uint8_t *) DNS_pubkey);
2014-06-17 03:22:26 +02:00
2014-06-18 01:10:25 +02:00
if (dns_obj == NULL) {
dns_error(self, "Core failed to create DNS object.");
2014-06-18 01:32:02 +02:00
kill_dns_thread(NULL);
2014-06-18 01:10:25 +02:00
}
2014-06-17 03:22:26 +02:00
char string[MAX_DNS_REQST_SIZE];
2014-06-17 03:22:26 +02:00
uint32_t request_id;
int str_len = tox_generate_dns3_string(dns_obj, (uint8_t *) string, sizeof(string), &request_id,
(uint8_t *) name, namelen);
2014-06-17 03:22:26 +02:00
2014-06-18 01:10:25 +02:00
if (str_len == -1) {
2014-06-24 00:54:23 +02:00
dns_error(self, "Core failed to generate DNS3 string.");
2014-06-18 01:32:02 +02:00
kill_dns_thread(dns_obj);
2014-06-18 01:10:25 +02:00
}
2014-06-17 03:22:26 +02:00
string[str_len] = '\0';
u_char answer[PACKETSZ];
char d_string[MAX_DNS_REQST_SIZE];
2014-06-17 03:22:26 +02:00
/* format string and create dns query */
snprintf(d_string, sizeof(d_string), "_%s._tox.%s", string, domname);
int ans_len = res_query(d_string, C_IN, T_TXT, answer, sizeof(answer));
2014-06-18 01:10:25 +02:00
if (ans_len <= 0) {
2014-06-24 00:54:23 +02:00
dns_error(self, "DNS query failed.");
2014-06-18 01:32:02 +02:00
kill_dns_thread(dns_obj);
2014-06-18 01:10:25 +02:00
}
2014-06-17 03:22:26 +02:00
char ans_id[MAX_DNS_REQST_SIZE];
2014-06-17 03:22:26 +02:00
/* extract TXT from DNS response */
if (parse_dns_response(self, answer, ans_len, ans_id) == -1)
2014-06-18 01:32:02 +02:00
kill_dns_thread(dns_obj);
2014-06-17 03:22:26 +02:00
char encrypted_id[MAX_DNS_REQST_SIZE];
2014-06-17 03:22:26 +02:00
int prfx_len = strlen(TOX_DNS3_TXT_PREFIX);
/* extract the encrypted ID from TXT response */
2014-06-18 01:10:25 +02:00
if (strncmp(ans_id, TOX_DNS3_TXT_PREFIX, prfx_len) != 0) {
2014-06-24 00:54:23 +02:00
dns_error(self, "Bad DNS3 TXT response.");
2014-06-18 01:32:02 +02:00
kill_dns_thread(dns_obj);
2014-06-18 01:10:25 +02:00
}
2014-06-17 03:22:26 +02:00
memcpy(encrypted_id, ans_id + prfx_len, ans_len - prfx_len);
2014-07-09 06:05:13 +02:00
if (tox_decrypt_dns3_TXT(dns_obj, (uint8_t *) t_data.id_bin, (uint8_t *) encrypted_id,
strlen(encrypted_id), request_id) == -1) {
2014-06-24 00:54:23 +02:00
dns_error(self, "Core failed to decrypt DNS response.");
2014-06-18 01:32:02 +02:00
kill_dns_thread(dns_obj);
2014-06-18 01:10:25 +02:00
}
2014-07-09 06:05:13 +02:00
pthread_mutex_lock(&Winthread.lock);
2014-06-18 01:10:25 +02:00
cmd_add_helper(self, t_data.m, t_data.id_bin, t_data.msg);
2014-07-09 06:05:13 +02:00
pthread_mutex_unlock(&Winthread.lock);
2014-06-18 01:10:25 +02:00
2014-06-18 01:32:02 +02:00
kill_dns_thread(dns_obj);
return 0;
2014-06-18 01:10:25 +02:00
}
/* creates new thread for dns3 lookup. Only allows one lookup at a time. */
void dns3_lookup(ToxWindow *self, Tox *m, char *id_bin, char *addr, char *msg)
2014-06-18 01:10:25 +02:00
{
if (t_data.busy) {
const char *err = "Please wait for previous user lookup to finish.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, err);
2014-06-18 01:10:25 +02:00
return;
}
2014-06-17 03:22:26 +02:00
2014-06-18 01:10:25 +02:00
snprintf(t_data.id_bin, sizeof(t_data.id_bin), "%s", id_bin);
snprintf(t_data.addr, sizeof(t_data.addr), "%s", addr);
snprintf(t_data.msg, sizeof(t_data.msg), "%s", msg);
2014-06-19 19:50:41 +02:00
t_data.self = self;
2014-06-18 01:10:25 +02:00
t_data.m = m;
t_data.busy = 1;
if (pthread_attr_init(&dns_thread.attr) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_ATTR);
2014-07-09 06:05:13 +02:00
if (pthread_attr_setdetachstate(&dns_thread.attr, PTHREAD_CREATE_DETACHED) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_ATTR);
2014-06-18 01:10:25 +02:00
if (pthread_create(&dns_thread.tid, &dns_thread.attr, dns3_lookup_thread, NULL) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_CREATE);
2014-06-17 03:22:26 +02:00
}