Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
David Goulet
Tor
Commits
3cf02a88
Commit
3cf02a88
authored
Feb 14, 2003
by
Roger Dingledine
Browse files
rudimentary dns caching (of both resolves and resolve failures)
serious performance increase over non-caching svn:r158
parent
5273e2b8
Changes
6
Show whitespace changes
Inline
Side-by-side
TODO
View file @
3cf02a88
...
...
@@ -32,11 +32,11 @@ SPEC - Spec not finalized
o Distribute queries onto the farm, get answers
o Preemptively grow a new worker before he's needed
- Prune workers when too many are idle
-
Keep track of which connections are in dns_wait
-
Need to cache positives/negatives on the tor side
-
Keep track of which queries have been asked
-
Better error handling when
-
An address doesn't resolve
o
Keep track of which connections are in dns_wait
o
Need to cache positives/negatives on the tor side
o
Keep track of which queries have been asked
.
Better error handling when
.
An address doesn't resolve
- We have max workers running
. Directory servers
- Automated reputation management
...
...
src/or/connection_exit.c
View file @
3cf02a88
...
...
@@ -150,7 +150,7 @@ int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
circ
->
n_conn
=
n_conn
;
/* send it off to the gethostbyname farm */
if
(
dns_
tor_to_master
(
n_conn
)
<
0
)
{
if
(
dns_
resolve
(
n_conn
)
<
0
)
{
log
(
LOG_DEBUG
,
"connection_exit_begin_conn(): Couldn't queue resolve request."
);
connection_remove
(
n_conn
);
connection_free
(
n_conn
);
...
...
src/or/dns.c
View file @
3cf02a88
...
...
@@ -4,6 +4,8 @@
#include
"or.h"
#define MAX_ADDRESSLEN 256
#define MAX_DNSSLAVES 50
#define MIN_DNSSLAVES 3
/* 1 for the tor process, 3 slaves */
...
...
@@ -11,9 +13,9 @@ struct slave_data_t {
int
fd
;
/* socket to talk on */
int
num_processed
;
/* number of times we've used this slave */
char
busy
;
/* whether this slave currently has a task */
char
question
[
256
];
/* the hostname that we're resolving */
char
question
[
MAX_ADDRESSLEN
];
/* the hostname that we're resolving */
unsigned
char
question_len
;
/* how many bytes in question */
char
answer
[
256
];
/* the answer to the question */
char
answer
[
MAX_ADDRESSLEN
];
/* the answer to the question */
unsigned
char
answer_len
;
/* how many bytes in answer */
};
...
...
@@ -29,6 +31,8 @@ static int dns_find_idle_slave(int max);
static
int
dns_assign_to_slave
(
int
from
,
int
to
);
static
int
dns_master_to_tor
(
int
from
,
int
to
);
static
void
dns_master_main
(
int
fd
);
static
int
dns_tor_to_master
(
connection_t
*
exitconn
);
static
int
dns_found_answer
(
char
*
question
,
uint32_t
answer
,
uint32_t
valid
);
int
connection_dns_finished_flushing
(
connection_t
*
conn
)
{
...
...
@@ -41,9 +45,9 @@ int connection_dns_finished_flushing(connection_t *conn) {
int
connection_dns_process_inbuf
(
connection_t
*
conn
)
{
unsigned
char
length
;
char
buf
[
256
];
char
buf
[
MAX_ADDRESSLEN
];
char
*
question
;
connection_t
*
exitconn
;
uint32_t
answer
;
assert
(
conn
&&
conn
->
type
==
CONN_TYPE_DNSMASTER
);
assert
(
conn
->
state
==
DNSMASTER_STATE_OPEN
);
...
...
@@ -76,24 +80,11 @@ int connection_dns_process_inbuf(connection_t *conn) {
log
(
LOG_DEBUG
,
"connection_dns_process_inbuf(): length %d, question '%s', strlen question %d"
,
length
,
question
,
strlen
(
question
));
assert
(
length
==
4
+
strlen
(
question
)
+
1
);
/* find the conn that question refers to. */
exitconn
=
connection_get_pendingresolve_by_address
(
question
);
if
(
!
exitconn
)
{
log
(
LOG_DEBUG
,
"connection_dns_process_inbuf(): No conn -- question no longer relevant? Dropping."
);
return
connection_process_inbuf
(
conn
);
/* process the remainder of the buffer */
}
memcpy
((
char
*
)
&
exitconn
->
addr
,
buf
+
1
+
length
-
4
,
4
);
exitconn
->
addr
=
ntohl
(
exitconn
->
addr
);
/* get it back to host order */
if
(
connection_exit_connect
(
exitconn
)
<
0
)
{
exitconn
->
marked_for_close
=
1
;
}
answer
=
*
(
uint32_t
*
)(
buf
+
1
+
length
-
4
);
dns_found_answer
(
question
,
answer
,
(
answer
!=
0
));
return
connection_process_inbuf
(
conn
);
/* process the remainder of the buffer */
}
/* return -1 if error, else the fd that can talk to the dns master */
int
dns_master_start
(
void
)
{
connection_t
*
conn
;
...
...
@@ -149,7 +140,7 @@ int dns_master_start(void) {
}
static
void
dns_slave_main
(
int
fd
)
{
char
question
[
256
];
char
question
[
MAX_ADDRESSLEN
];
unsigned
char
question_len
;
struct
hostent
*
rent
;
...
...
@@ -316,7 +307,7 @@ static int dns_assign_to_slave(int from, int to) {
}
static
int
dns_master_to_tor
(
int
from
,
int
to
)
{
char
tmp
[
256
];
char
tmp
[
MAX_ADDRESSLEN
*
2
];
unsigned
char
len
;
len
=
slave_data
[
from
].
question_len
+
1
+
slave_data
[
from
].
answer_len
;
...
...
@@ -339,52 +330,6 @@ static int dns_master_to_tor(int from, int to) {
return
0
;
}
int
dns_tor_to_master
(
connection_t
*
exitconn
)
{
connection_t
*
conn
;
unsigned
char
len
;
#ifdef DO_DNS_DIRECTLY
/* new version which does it all right here */
struct
hostent
*
rent
;
rent
=
gethostbyname
(
exitconn
->
address
);
if
(
!
rent
)
{
return
-
1
;
}
memcpy
((
char
*
)
&
exitconn
->
addr
,
rent
->
h_addr
,
rent
->
h_length
);
exitconn
->
addr
=
ntohl
(
exitconn
->
addr
);
/* get it back to host order */
if
(
connection_exit_connect
(
exitconn
)
<
0
)
{
exitconn
->
marked_for_close
=
1
;
}
return
0
;
#endif
/* old version which actually uses the dns farm */
conn
=
connection_get_by_type
(
CONN_TYPE_DNSMASTER
);
if
(
!
conn
)
{
log
(
LOG_ERR
,
"dns_tor_to_master(): dns master nowhere to be found!"
);
/* XXX should do gethostbyname right here */
return
-
1
;
}
len
=
strlen
(
exitconn
->
address
);
if
(
connection_write_to_buf
(
&
len
,
1
,
conn
)
<
0
)
{
log
(
LOG_DEBUG
,
"dns_tor_to_master(): Couldn't write length."
);
return
-
1
;
}
if
(
connection_write_to_buf
(
exitconn
->
address
,
len
,
conn
)
<
0
)
{
log
(
LOG_DEBUG
,
"dns_tor_to_master(): Couldn't write address."
);
return
-
1
;
}
// log(LOG_DEBUG,"dns_tor_to_master(): submitted '%s'", address);
return
0
;
}
static
void
dns_master_main
(
int
fd
)
{
int
nfds
=
1
;
/* the 0th index is the tor process, the rest are slaves */
int
num_slaves_busy
=
0
;
...
...
@@ -455,3 +400,163 @@ static void dns_master_main(int fd) {
assert
(
0
);
/* should never get here */
}
#include
"tree.h"
struct
pending_connection_t
{
struct
connection_t
*
conn
;
struct
pending_connection_t
*
next
;
};
struct
cached_resolve
{
SPLAY_ENTRY
(
cached_resolve
)
node
;
char
question
[
MAX_ADDRESSLEN
];
/* the hostname to be resolved */
uint32_t
answer
;
/* in host order. I know I'm horrible for assuming ipv4 */
char
state
;
/* 0 is pending; 1 means answer is valid; 2 means resolve failed */
#define CACHE_STATE_PENDING 0
#define CACHE_STATE_VALID 1
#define CACHE_STATE_FAILED 2
uint32_t
expire
;
/* remove untouched items from cache after some time? */
struct
pending_connection_t
*
pending_connections
;
struct
cached_resolve
*
next
;
};
SPLAY_HEAD
(
cache_tree
,
cached_resolve
)
cache_root
;
static
int
compare_cached_resolves
(
struct
cached_resolve
*
a
,
struct
cached_resolve
*
b
)
{
/* make this smarter one day? */
return
strncasecmp
(
a
->
question
,
b
->
question
,
MAX_ADDRESSLEN
);
}
SPLAY_PROTOTYPE
(
cache_tree
,
cached_resolve
,
node
,
compare_cached_resolves
);
SPLAY_GENERATE
(
cache_tree
,
cached_resolve
,
node
,
compare_cached_resolves
);
void
init_cache_tree
(
void
)
{
SPLAY_INIT
(
&
cache_root
);
}
/* see if the question 'exitconn->address' has been answered. if so,
* if resolve valid, put it into exitconn->addr and call
* connection_exit_connect directly. If resolve failed, return -1.
*
* Else, if seen before and pending, add conn to the pending list,
* and return 0.
*
* Else, if not seen before, add conn to pending list, hand to
* dns farm, and return 0.
*/
int
dns_resolve
(
connection_t
*
exitconn
)
{
struct
cached_resolve
*
new_resolve
;
struct
cached_resolve
*
resolve
;
struct
pending_connection_t
*
pending_connection
;
new_resolve
=
malloc
(
sizeof
(
struct
cached_resolve
));
memset
(
new_resolve
,
0
,
sizeof
(
struct
cached_resolve
));
strncpy
(
new_resolve
->
question
,
exitconn
->
address
,
MAX_ADDRESSLEN
);
/* try adding it to the tree. if it's already there it will
* return it. */
resolve
=
SPLAY_INSERT
(
cache_tree
,
&
cache_root
,
new_resolve
);
if
(
resolve
)
{
/* already there. free up new_resolve */
free
(
new_resolve
);
switch
(
resolve
->
state
)
{
case
CACHE_STATE_PENDING
:
/* add us to the pending list */
pending_connection
=
malloc
(
sizeof
(
struct
pending_connection_t
));
pending_connection
->
conn
=
exitconn
;
pending_connection
->
next
=
new_resolve
->
pending_connections
;
new_resolve
->
pending_connections
=
pending_connection
;
return
dns_tor_to_master
(
exitconn
);
case
CACHE_STATE_VALID
:
exitconn
->
addr
=
resolve
->
answer
;
return
connection_exit_connect
(
exitconn
);
case
CACHE_STATE_FAILED
:
return
-
1
;
}
}
else
{
/* this was newly added to the tree. ask the dns farm. */
new_resolve
->
state
=
CACHE_STATE_PENDING
;
/* add us to the pending list */
pending_connection
=
malloc
(
sizeof
(
struct
pending_connection_t
));
pending_connection
->
conn
=
exitconn
;
pending_connection
->
next
=
new_resolve
->
pending_connections
;
new_resolve
->
pending_connections
=
pending_connection
;
return
dns_tor_to_master
(
exitconn
);
}
assert
(
0
);
return
0
;
/* not reached; keep gcc happy */
}
static
int
dns_tor_to_master
(
connection_t
*
exitconn
)
{
connection_t
*
dnsconn
;
unsigned
char
len
;
int
do_dns_directly
=
0
;
dnsconn
=
connection_get_by_type
(
CONN_TYPE_DNSMASTER
);
if
(
!
dnsconn
)
{
log
(
LOG_ERR
,
"dns_tor_to_master(): dns master nowhere to be found!"
);
}
if
(
!
dnsconn
||
do_dns_directly
)
{
/* new version which does it all right here */
struct
hostent
*
rent
;
rent
=
gethostbyname
(
exitconn
->
address
);
if
(
!
rent
)
{
return
dns_found_answer
(
exitconn
->
address
,
0
,
0
);
}
return
dns_found_answer
(
exitconn
->
address
,
*
(
uint32_t
*
)
rent
->
h_addr
,
1
);
}
len
=
strlen
(
exitconn
->
address
);
if
(
connection_write_to_buf
(
&
len
,
1
,
dnsconn
)
<
0
)
{
log
(
LOG_DEBUG
,
"dns_tor_to_master(): Couldn't write length."
);
return
-
1
;
}
if
(
connection_write_to_buf
(
exitconn
->
address
,
len
,
dnsconn
)
<
0
)
{
log
(
LOG_DEBUG
,
"dns_tor_to_master(): Couldn't write address."
);
return
-
1
;
}
// log(LOG_DEBUG,"dns_tor_to_master(): submitted '%s'", address);
return
0
;
}
static
int
dns_found_answer
(
char
*
question
,
uint32_t
answer
,
uint32_t
valid
)
{
struct
pending_connection_t
*
pend
;
struct
cached_resolve
search
;
struct
cached_resolve
*
resolve
;
strncpy
(
search
.
question
,
question
,
MAX_ADDRESSLEN
);
resolve
=
SPLAY_FIND
(
cache_tree
,
&
cache_root
,
&
search
);
if
(
!
resolve
)
{
log
(
LOG_ERR
,
"dns_found_answer(): Answer to unasked question '%s'? Dropping."
,
question
);
return
0
;
}
assert
(
resolve
->
state
==
CACHE_STATE_PENDING
);
if
(
valid
)
resolve
->
state
=
CACHE_STATE_VALID
;
else
resolve
->
state
=
CACHE_STATE_FAILED
;
while
(
resolve
->
pending_connections
)
{
pend
=
resolve
->
pending_connections
;
pend
->
conn
->
addr
=
ntohl
(
answer
);
if
(
resolve
->
state
==
CACHE_STATE_FAILED
||
connection_exit_connect
(
pend
->
conn
)
<
0
)
{
pend
->
conn
->
marked_for_close
=
1
;
}
resolve
->
pending_connections
=
pend
->
next
;
free
(
pend
);
}
return
0
;
}
src/or/main.c
View file @
3cf02a88
...
...
@@ -159,24 +159,6 @@ connection_t *connection_get_by_type(int type) {
return
NULL
;
}
connection_t
*
connection_get_pendingresolve_by_address
(
char
*
address
)
{
int
i
;
connection_t
*
conn
;
for
(
i
=
0
;
i
<
nfds
;
i
++
)
{
conn
=
connection_array
[
i
];
if
(
conn
->
type
==
CONN_TYPE_EXIT
&&
conn
->
state
==
EXIT_CONN_STATE_RESOLVING
&&
!
strcmp
(
conn
->
address
,
address
))
{
return
conn
;
}
}
return
NULL
;
}
void
connection_watch_events
(
connection_t
*
conn
,
short
events
)
{
assert
(
conn
&&
conn
->
poll_index
<
nfds
);
...
...
src/or/onion.c
View file @
3cf02a88
...
...
@@ -9,6 +9,7 @@ extern or_options_t options; /* command-line and config-file options */
static
int
onion_process
(
circuit_t
*
circ
);
static
int
onion_deliver_to_conn
(
aci_t
aci
,
unsigned
char
*
onion
,
uint32_t
onionlen
,
connection_t
*
conn
);
static
int
find_tracked_onion
(
unsigned
char
*
onion
,
uint32_t
onionlen
);
int
decide_aci_type
(
uint32_t
local_addr
,
uint16_t
local_port
,
uint32_t
remote_addr
,
uint16_t
remote_port
)
{
...
...
@@ -756,7 +757,7 @@ void init_tracked_tree(void) {
/* see if this onion has been seen before. if so, return 1, else
* return 0 and add the sha1 of this onion to the tree.
*/
int
find_tracked_onion
(
unsigned
char
*
onion
,
uint32_t
onionlen
)
{
static
int
find_tracked_onion
(
unsigned
char
*
onion
,
uint32_t
onionlen
)
{
static
struct
tracked_onion
*
head_tracked_onions
=
NULL
;
/* linked list of tracked onions */
static
struct
tracked_onion
*
tail_tracked_onions
=
NULL
;
...
...
@@ -764,7 +765,7 @@ int find_tracked_onion(unsigned char *onion, uint32_t onionlen) {
struct
tracked_onion
*
to
;
/* first take this opportunity to see if there are any expired
* onions in the tree. we know this i
n O(1)
because the linked list
* onions in the tree. we know this i
s fast
because the linked list
* 'tracked_onions' is ordered by when they were seen.
*/
while
(
head_tracked_onions
&&
(
head_tracked_onions
->
expire
<
now
))
{
...
...
src/or/or.h
View file @
3cf02a88
...
...
@@ -650,7 +650,7 @@ int connection_dir_handle_listener_read(connection_t *conn);
int
connection_dns_finished_flushing
(
connection_t
*
conn
);
int
connection_dns_process_inbuf
(
connection_t
*
conn
);
int
dns_
tor_to_master
(
connection_t
*
exitconn
);
int
dns_
resolve
(
connection_t
*
exitconn
);
int
dns_master_start
(
void
);
/********************************* main.c ***************************/
...
...
@@ -665,7 +665,6 @@ connection_t *connection_twin_get_by_addr_port(uint32_t addr, uint16_t port);
connection_t
*
connection_exact_get_by_addr_port
(
uint32_t
addr
,
uint16_t
port
);
connection_t
*
connection_get_by_type
(
int
type
);
connection_t
*
connection_get_pendingresolve_by_address
(
char
*
address
);
void
connection_watch_events
(
connection_t
*
conn
,
short
events
);
void
connection_stop_reading
(
connection_t
*
conn
);
...
...
@@ -724,7 +723,6 @@ int decrypt_onion(unsigned char *onion, uint32_t onionlen, crypto_pk_env_t *prke
void
pad_onion
(
unsigned
char
*
onion
,
uint32_t
onionlen
,
int
n
);
void
init_tracked_tree
(
void
);
int
find_tracked_onion
(
unsigned
char
*
onion
,
uint32_t
onionlen
);
/********************************* routers.c ***************************/
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment