summaryrefslogtreecommitdiff
path: root/src/or/eventdns.h
blob: e3d43cee53e1d1cef118790b6f66063c88f0dbe1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/* This software is Public Domain. To view a copy of the public domain dedication,
 * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
 * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
 *
 * I ask and expect, but do not require, that all derivative works contain an
 * attribution similar to:
 * 	Parts developed by Adam Langley <agl@imperialviolet.org>
 *
 * You may wish to replace the word "Parts" with something else depending on
 * the amount of original code.
 *
 * (Derivative works does not include programs which link against, run or include
 * the source verbatim in their source distributions)
 */

#ifndef EVENTDNS_H
#define EVENTDNS_H

/* Error codes 0-5 are as described in RFC 1035. */
#define DNS_ERR_NONE 0
/* The name server was unable to interpret the query */
#define DNS_ERR_FORMAT 1
/* The name server was unable to process this query due to a problem with the
 * name server */
#define DNS_ERR_SERVERFAILED 2
/* The domain name does not exist */
#define DNS_ERR_NOTEXIST 3
/* The name server does not support the requested kind of query */
#define DNS_ERR_NOTIMPL 4
/* The name server refuses to reform the specified operation for policy
 * reasons */
#define DNS_ERR_REFUSED 5
/* The reply was truncated or ill-formated */
#define DNS_ERR_TRUNCATED 65
/* An unknown error occurred */
#define DNS_ERR_UNKNOWN 66
/* Communication with the server timed out */
#define DNS_ERR_TIMEOUT 67
/* The request was canceled because the DNS subsystem was shut down. */
#define DNS_ERR_SHUTDOWN 68

#define DNS_IPv4_A 1
#define DNS_PTR 2
#define DNS_IPv6_AAAA 3

#define DNS_QUERY_NO_SEARCH 1

#define DNS_OPTION_SEARCH 1
#define DNS_OPTION_NAMESERVERS 2
#define DNS_OPTION_MISC 4
#define DNS_OPTIONS_ALL 7

/*
 * The callback that contains the results from a lookup.
 * - type is either DNS_IPv4_A or DNS_IPv6_AAAA or DNS_PTR
 * - count contains the number of addresses of form type
 * - ttl is the number of seconds the resolution may be cached for.
 * - addresses needs to be cast according to type
 */
typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg);

int evdns_init(void);
void evdns_shutdown(int fail_requests);
const char *evdns_err_to_string(int err);
int evdns_nameserver_add(unsigned long int address);
int evdns_count_nameservers(void);
int evdns_clear_nameservers_and_suspend(void);
int evdns_resume(void);
int evdns_nameserver_ip_add(const char *ip_as_string);
int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr);
int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr);
struct in_addr;
struct in6_addr;
int evdns_resolve_reverse(struct in_addr *in, int flags, evdns_callback_type callback, void *ptr);
int evdns_resolve_reverse_ipv6(struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr);
int evdns_resolv_conf_parse(int flags, const char *);
#ifdef MS_WINDOWS
int evdns_config_windows_nameservers(void);
#endif
void evdns_search_clear(void);
void evdns_search_add(const char *domain);
void evdns_search_ndots_set(const int ndots);

typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg);
void evdns_set_log_fn(evdns_debug_log_fn_type fn);

#define DNS_NO_SEARCH 1

/* Structures and functions used to implement a DNS server. */

struct evdns_server_request {
	int flags;
	int nquestions;
	struct evdns_server_question **questions;
};
struct evdns_server_question {
	int type;
	int class;
	char name[1];
};
typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *);
#define EVDNS_ANSWER_SECTION 0
#define EVDNS_AUTHORITY_SECTION 1
#define EVDNS_ADDITIONAL_SECTION 2

#define EVDNS_TYPE_A	   1
#define EVDNS_TYPE_NS	   2
#define EVDNS_TYPE_CNAME   5
#define EVDNS_TYPE_SOA     6
#define EVDNS_TYPE_PTR	  12
#define EVDNS_TYPE_MX	  15
#define EVDNS_TYPE_TXT	  16
#define EVDNS_TYPE_AAAA	  28

#define EVDNS_QTYPE_AXFR 252
#define EVDNS_QTYPE_ALL  255

#define EVDNS_CLASS_INET   1

struct evdns_server_port *evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type callback, void *user_data);
void evdns_close_server_port(struct evdns_server_port *port);

int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data);
int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl);
int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl);
int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl);
int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl);

int evdns_server_request_respond(struct evdns_server_request *req, int err);
int evdns_server_request_drop(struct evdns_server_request *req);

#endif  // !EVENTDNS_H
,"CMETHOD trebuchet socks5 127.0.0.1:1999",sizeof(line)); tt_assert(parse_cmethod_line(line, mp) == 0); tt_assert(smartlist_len(mp->transports) == 1); transport = smartlist_get(mp->transports, 0); /* test registered address of transport */ tor_addr_parse(&test_addr, "127.0.0.1"); tt_assert(tor_addr_eq(&test_addr, &transport->addr)); /* test registered port of transport */ tt_assert(transport->port == 1999); /* test registered SOCKS version of transport */ tt_assert(transport->socks_version == PROXY_SOCKS5); /* test registered name of transport */ tt_str_op(transport->name,OP_EQ, "trebuchet"); reset_mp(mp); /* incomplete smethod */ strlcpy(line,"SMETHOD trebuchet",sizeof(line)); tt_assert(parse_smethod_line(line, mp) < 0); reset_mp(mp); /* wrong addr type */ strlcpy(line,"SMETHOD trebuchet abcd",sizeof(line)); tt_assert(parse_smethod_line(line, mp) < 0); reset_mp(mp); /* cowwect */ strlcpy(line,"SMETHOD trebuchy 127.0.0.2:2999",sizeof(line)); tt_assert(parse_smethod_line(line, mp) == 0); tt_assert(smartlist_len(mp->transports) == 1); transport = smartlist_get(mp->transports, 0); /* test registered address of transport */ tor_addr_parse(&test_addr, "127.0.0.2"); tt_assert(tor_addr_eq(&test_addr, &transport->addr)); /* test registered port of transport */ tt_assert(transport->port == 2999); /* test registered name of transport */ tt_str_op(transport->name,OP_EQ, "trebuchy"); reset_mp(mp); /* Include some arguments. Good ones. */ strlcpy(line,"SMETHOD trebuchet 127.0.0.1:9999 " "ARGS:counterweight=3,sling=snappy", sizeof(line)); tt_assert(parse_smethod_line(line, mp) == 0); tt_int_op(1, OP_EQ, smartlist_len(mp->transports)); { const transport_t *transport = smartlist_get(mp->transports, 0); tt_assert(transport); tt_str_op(transport->name, OP_EQ, "trebuchet"); tt_int_op(transport->port, OP_EQ, 9999); tt_str_op(fmt_addr(&transport->addr), OP_EQ, "127.0.0.1"); tt_str_op(transport->extra_info_args, OP_EQ, "counterweight=3,sling=snappy"); } reset_mp(mp); /* unsupported version */ strlcpy(line,"VERSION 666",sizeof(line)); tt_assert(parse_version(line, mp) < 0); /* incomplete VERSION */ strlcpy(line,"VERSION ",sizeof(line)); tt_assert(parse_version(line, mp) < 0); /* correct VERSION */ strlcpy(line,"VERSION 1",sizeof(line)); tt_assert(parse_version(line, mp) == 0); done: reset_mp(mp); smartlist_free(mp->transports); tor_free(mp); } static void test_pt_get_transport_options(void *arg) { char **execve_args; smartlist_t *transport_list = smartlist_new(); managed_proxy_t *mp; or_options_t *options = get_options_mutable(); char *opt_str = NULL; config_line_t *cl = NULL; (void)arg; execve_args = tor_malloc(sizeof(char*)*2); execve_args[0] = tor_strdup("cheeseshop"); execve_args[1] = NULL; mp = managed_proxy_create(transport_list, execve_args, 1); tt_ptr_op(mp, OP_NE, NULL); opt_str = get_transport_options_for_server_proxy(mp); tt_ptr_op(opt_str, OP_EQ, NULL); smartlist_add(mp->transports_to_launch, tor_strdup("gruyere")); smartlist_add(mp->transports_to_launch, tor_strdup("roquefort")); smartlist_add(mp->transports_to_launch, tor_strdup("stnectaire")); tt_assert(options); cl = tor_malloc_zero(sizeof(config_line_t)); cl->value = tor_strdup("gruyere melty=10 hardness=se;ven"); options->ServerTransportOptions = cl; cl = tor_malloc_zero(sizeof(config_line_t)); cl->value = tor_strdup("stnectaire melty=4 hardness=three"); cl->next = options->ServerTransportOptions; options->ServerTransportOptions = cl; cl = tor_malloc_zero(sizeof(config_line_t)); cl->value = tor_strdup("pepperjack melty=12 hardness=five"); cl->next = options->ServerTransportOptions; options->ServerTransportOptions = cl; opt_str = get_transport_options_for_server_proxy(mp); tt_str_op(opt_str, OP_EQ, "gruyere:melty=10;gruyere:hardness=se\\;ven;" "stnectaire:melty=4;stnectaire:hardness=three"); done: tor_free(opt_str); config_free_lines(cl); managed_proxy_destroy(mp, 0); smartlist_free(transport_list); } static void test_pt_protocol(void *arg) { char line[200]; managed_proxy_t *mp = tor_malloc_zero(sizeof(managed_proxy_t)); (void)arg; mp->conf_state = PT_PROTO_LAUNCHED; mp->transports = smartlist_new(); mp->argv = tor_calloc(2, sizeof(char *)); mp->argv[0] = tor_strdup("<testcase>"); /* various wrong protocol runs: */ strlcpy(line,"VERSION 1",sizeof(line)); handle_proxy_line(line, mp); tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); strlcpy(line,"VERSION 1",sizeof(line)); handle_proxy_line(line, mp); tt_assert(mp->conf_state == PT_PROTO_BROKEN); reset_mp(mp); strlcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999",sizeof(line)); handle_proxy_line(line, mp); tt_assert(mp->conf_state == PT_PROTO_BROKEN); reset_mp(mp); /* correct protocol run: */ strlcpy(line,"VERSION 1",sizeof(line)); handle_proxy_line(line, mp); tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); strlcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999",sizeof(line)); handle_proxy_line(line, mp); tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); strlcpy(line,"CMETHODS DONE",sizeof(line)); handle_proxy_line(line, mp); tt_assert(mp->conf_state == PT_PROTO_CONFIGURED); done: reset_mp(mp); smartlist_free(mp->transports); tor_free(mp->argv[0]); tor_free(mp->argv); tor_free(mp); } static void test_pt_get_extrainfo_string(void *arg) { managed_proxy_t *mp1 = NULL, *mp2 = NULL; char **argv1, **argv2; smartlist_t *t1 = smartlist_new(), *t2 = smartlist_new(); int r; char *s = NULL; (void) arg; argv1 = tor_malloc_zero(sizeof(char*)*3); argv1[0] = tor_strdup("ewige"); argv1[1] = tor_strdup("Blumenkraft"); argv1[2] = NULL; argv2 = tor_malloc_zero(sizeof(char*)*4); argv2[0] = tor_strdup("und"); argv2[1] = tor_strdup("ewige"); argv2[2] = tor_strdup("Schlangenkraft"); argv2[3] = NULL; mp1 = managed_proxy_create(t1, argv1, 1); mp2 = managed_proxy_create(t2, argv2, 1); r = parse_smethod_line("SMETHOD hagbard 127.0.0.1:5555", mp1); tt_int_op(r, OP_EQ, 0); r = parse_smethod_line("SMETHOD celine 127.0.0.1:1723 ARGS:card=no-enemy", mp2); tt_int_op(r, OP_EQ, 0); /* Force these proxies to look "completed" or they won't generate output. */ mp1->conf_state = mp2->conf_state = PT_PROTO_COMPLETED; s = pt_get_extra_info_descriptor_string(); tt_assert(s); tt_str_op(s, OP_EQ, "transport hagbard 127.0.0.1:5555\n" "transport celine 127.0.0.1:1723 card=no-enemy\n"); done: /* XXXX clean up better */ smartlist_free(t1); smartlist_free(t2); tor_free(s); } #ifdef _WIN32 #define STDIN_HANDLE HANDLE #else #define STDIN_HANDLE FILE #endif static smartlist_t * tor_get_lines_from_handle_replacement(STDIN_HANDLE *handle, enum stream_status *stream_status_out) { static int times_called = 0; smartlist_t *retval_sl = smartlist_new(); (void) handle; (void) stream_status_out; /* Generate some dummy CMETHOD lines the first 5 times. The 6th time, send 'CMETHODS DONE' to finish configuring the proxy. */ if (times_called++ != 5) { smartlist_add_asprintf(retval_sl, "SMETHOD mock%d 127.0.0.1:555%d", times_called, times_called); } else { smartlist_add(retval_sl, tor_strdup("SMETHODS DONE")); } return retval_sl; } /* NOP mock */ static void tor_process_handle_destroy_replacement(process_handle_t *process_handle, int also_terminate_process) { (void) process_handle; (void) also_terminate_process; } static or_state_t *dummy_state = NULL; static or_state_t * get_or_state_replacement(void) { return dummy_state; } static int controlevent_n = 0; static uint16_t controlevent_event = 0; static smartlist_t *controlevent_msgs = NULL; static void queue_control_event_string_replacement(uint16_t event, char *msg) { ++controlevent_n; controlevent_event = event; if (!controlevent_msgs) controlevent_msgs = smartlist_new(); smartlist_add(controlevent_msgs, msg); } /* Test the configure_proxy() function. */ static void test_pt_configure_proxy(void *arg) { int i, retval; managed_proxy_t *mp = NULL; (void) arg; dummy_state = tor_malloc_zero(sizeof(or_state_t)); MOCK(tor_get_lines_from_handle, tor_get_lines_from_handle_replacement); MOCK(tor_process_handle_destroy, tor_process_handle_destroy_replacement); MOCK(get_or_state, get_or_state_replacement); MOCK(queue_control_event_string, queue_control_event_string_replacement); control_testing_set_global_event_mask(EVENT_TRANSPORT_LAUNCHED); mp = tor_malloc_zero(sizeof(managed_proxy_t)); mp->conf_state = PT_PROTO_ACCEPTING_METHODS; mp->transports = smartlist_new(); mp->transports_to_launch = smartlist_new(); mp->process_handle = tor_malloc_zero(sizeof(process_handle_t)); mp->argv = tor_malloc_zero(sizeof(char*)*2); mp->argv[0] = tor_strdup("<testcase>"); mp->is_server = 1; /* Test the return value of configure_proxy() by calling it some times while it is uninitialized and then finally finalizing its configuration. */ for (i = 0 ; i < 5 ; i++) { retval = configure_proxy(mp); /* retval should be zero because proxy hasn't finished configuring yet */ tt_int_op(retval, OP_EQ, 0); /* check the number of registered transports */ tt_assert(smartlist_len(mp->transports) == i+1); /* check that the mp is still waiting for transports */ tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); } /* this last configure_proxy() should finalize the proxy configuration. */ retval = configure_proxy(mp); /* retval should be 1 since the proxy finished configuring */ tt_int_op(retval, OP_EQ, 1); /* check the mp state */ tt_assert(mp->conf_state == PT_PROTO_COMPLETED); tt_int_op(controlevent_n, OP_EQ, 5); tt_int_op(controlevent_event, OP_EQ, EVENT_TRANSPORT_LAUNCHED); tt_int_op(smartlist_len(controlevent_msgs), OP_EQ, 5); smartlist_sort_strings(controlevent_msgs); tt_str_op(smartlist_get(controlevent_msgs, 0), OP_EQ, "650 TRANSPORT_LAUNCHED server mock1 127.0.0.1 5551\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 1), OP_EQ, "650 TRANSPORT_LAUNCHED server mock2 127.0.0.1 5552\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 2), OP_EQ, "650 TRANSPORT_LAUNCHED server mock3 127.0.0.1 5553\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 3), OP_EQ, "650 TRANSPORT_LAUNCHED server mock4 127.0.0.1 5554\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 4), OP_EQ, "650 TRANSPORT_LAUNCHED server mock5 127.0.0.1 5555\r\n"); { /* check that the transport info were saved properly in the tor state */ config_line_t *transport_in_state = NULL; smartlist_t *transport_info_sl = smartlist_new(); char *name_of_transport = NULL; char *bindaddr = NULL; /* Get the bindaddr for "mock1" and check it against the bindaddr that the mocked tor_get_lines_from_handle() generated. */ transport_in_state = get_transport_in_state_by_name("mock1"); tt_assert(transport_in_state); smartlist_split_string(transport_info_sl, transport_in_state->value, NULL, 0, 0); name_of_transport = smartlist_get(transport_info_sl, 0); bindaddr = smartlist_get(transport_info_sl, 1); tt_str_op(name_of_transport, OP_EQ, "mock1"); tt_str_op(bindaddr, OP_EQ, "127.0.0.1:5551"); SMARTLIST_FOREACH(transport_info_sl, char *, cp, tor_free(cp)); smartlist_free(transport_info_sl); } done: or_state_free(dummy_state); UNMOCK(tor_get_lines_from_handle); UNMOCK(tor_process_handle_destroy); UNMOCK(get_or_state); UNMOCK(queue_control_event_string); if (controlevent_msgs) { SMARTLIST_FOREACH(controlevent_msgs, char *, cp, tor_free(cp)); smartlist_free(controlevent_msgs); controlevent_msgs = NULL; } if (mp->transports) { SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t)); smartlist_free(mp->transports); } smartlist_free(mp->transports_to_launch); tor_free(mp->process_handle); tor_free(mp->argv[0]); tor_free(mp->argv); tor_free(mp); } /* Test the get_pt_proxy_uri() function. */ static void test_get_pt_proxy_uri(void *arg) { or_options_t *options = get_options_mutable(); char *uri = NULL; int ret; (void) arg; /* Test with no proxy. */ uri = get_pt_proxy_uri(); tt_assert(uri == NULL); /* Test with a SOCKS4 proxy. */ options->Socks4Proxy = tor_strdup("192.0.2.1:1080"); ret = tor_addr_port_lookup(options->Socks4Proxy, &options->Socks4ProxyAddr, &options->Socks4ProxyPort); tt_int_op(ret, OP_EQ, 0); uri = get_pt_proxy_uri(); tt_str_op(uri, OP_EQ, "socks4a://192.0.2.1:1080"); tor_free(uri); tor_free(options->Socks4Proxy); /* Test with a SOCKS5 proxy, no username/password. */ options->Socks5Proxy = tor_strdup("192.0.2.1:1080"); ret = tor_addr_port_lookup(options->Socks5Proxy, &options->Socks5ProxyAddr, &options->Socks5ProxyPort); tt_int_op(ret, OP_EQ, 0); uri = get_pt_proxy_uri(); tt_str_op(uri, OP_EQ, "socks5://192.0.2.1:1080"); tor_free(uri); /* Test with a SOCKS5 proxy, with username/password. */ options->Socks5ProxyUsername = tor_strdup("hwest"); options->Socks5ProxyPassword = tor_strdup("r34n1m470r"); uri = get_pt_proxy_uri(); tt_str_op(uri, OP_EQ, "socks5://hwest:r34n1m470r@192.0.2.1:1080"); tor_free(uri); tor_free(options->Socks5Proxy); tor_free(options->Socks5ProxyUsername); tor_free(options->Socks5ProxyPassword); /* Test with a HTTPS proxy, no authenticator. */ options->HTTPSProxy = tor_strdup("192.0.2.1:80"); ret = tor_addr_port_lookup(options->HTTPSProxy, &options->HTTPSProxyAddr, &options->HTTPSProxyPort); tt_int_op(ret, OP_EQ, 0); uri = get_pt_proxy_uri(); tt_str_op(uri, OP_EQ, "http://192.0.2.1:80"); tor_free(uri); /* Test with a HTTPS proxy, with authenticator. */ options->HTTPSProxyAuthenticator = tor_strdup("hwest:r34n1m470r"); uri = get_pt_proxy_uri(); tt_str_op(uri, OP_EQ, "http://hwest:r34n1m470r@192.0.2.1:80"); tor_free(uri); tor_free(options->HTTPSProxy); tor_free(options->HTTPSProxyAuthenticator); /* Token nod to the fact that IPv6 exists. */ options->Socks4Proxy = tor_strdup("[2001:db8::1]:1080"); ret = tor_addr_port_lookup(options->Socks4Proxy, &options->Socks4ProxyAddr, &options->Socks4ProxyPort); tt_int_op(ret, OP_EQ, 0); uri = get_pt_proxy_uri(); tt_str_op(uri, OP_EQ, "socks4a://[2001:db8::1]:1080"); tor_free(uri); tor_free(options->Socks4Proxy); done: if (uri) tor_free(uri); } #define PT_LEGACY(name) \ { #name, test_pt_ ## name , 0, NULL, NULL } struct testcase_t pt_tests[] = { PT_LEGACY(parsing), PT_LEGACY(protocol), { "get_transport_options", test_pt_get_transport_options, TT_FORK, NULL, NULL }, { "get_extrainfo_string", test_pt_get_extrainfo_string, TT_FORK, NULL, NULL }, { "configure_proxy",test_pt_configure_proxy, TT_FORK, NULL, NULL }, { "get_pt_proxy_uri", test_get_pt_proxy_uri, TT_FORK, NULL, NULL }, END_OF_TESTCASES };