mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
Refactor buffers; implement descriptors.
'buf_t' is now an opaque type defined in buffers.c . Router descriptors now include all keys; routers generate keys as needed on startup (in a newly defined "data directory"), and generate their own descriptors. Descriptors are now self-signed. Implementation is not complete: descriptors are never published; and upon receiving a descriptor, the directory doesn't do anything with it. At least "routers.or" and orkeygen are now obsolete, BTW. svn:r483
This commit is contained in:
+1
-1
@@ -48,7 +48,7 @@ NICK - instruments ORs to report stats
|
||||
. integrate rep_ok functions, see what breaks
|
||||
ARMA - configure log files. separate log file, separate severities.
|
||||
ARMA - what assumptions break if we fclose(0) when we daemonize?
|
||||
NICK - make buffer struct elements opaque outside buffers.c
|
||||
NICK o make buffer struct elements opaque outside buffers.c
|
||||
ARMA - Go through log messages, reduce confusing error messages.
|
||||
ARMA - make the logs include more info (fd, etc)
|
||||
ARMA - add log convention to the HACKING file
|
||||
|
||||
@@ -439,12 +439,16 @@ which reveals the downstream node.
|
||||
|
||||
(Unless otherwise noted, tokens on the same line are space-separated.)
|
||||
|
||||
Router ::= Router-Line Public-Key Signing-Key? Exit-Policy NL
|
||||
Router ::= Router-Line Onion-Key Link-Key Signing-Key Exit-Policy Router-Signature NL
|
||||
Router-Line ::= "router" address ORPort APPort DirPort bandwidth NL
|
||||
Public-key ::= a public key in PEM format NL
|
||||
Signing-Key ::= "signing-key" NL signing key in PEM format NL
|
||||
Onion-key ::= "onion-key" NL a public key in PEM format NL
|
||||
Link-key ::= "link-key" NL a public key in PEM format NL
|
||||
Signing-Key ::= "signing-key" NL a public key in PEM format NL
|
||||
Exit-Policy ::= Exit-Line*
|
||||
Exit-Line ::= ("accept"|"reject") string NL
|
||||
Router-Signature ::= "router-signature" NL Signature
|
||||
Signature ::= "-----BEGIN SIGNATURE-----" NL
|
||||
Base-64-encoded-signature NL "-----END SIGNATURE-----" NL
|
||||
|
||||
ORport ::= port where the router listens for routers/proxies (speaking cells)
|
||||
APPort ::= where the router listens for applications (speaking socks)
|
||||
@@ -475,7 +479,8 @@ Directory ::= Directory-Header Directory-Router Router* Signature
|
||||
Directory-Header ::= "signed-directory" NL Software-Line NL
|
||||
Software-Line: "recommended-software" comma-separated-version-list
|
||||
Directory-Router ::= Router
|
||||
Signature ::= "directory-signature" NL "-----BEGIN SIGNATURE-----" NL
|
||||
Directory-Signature ::= "directory-signature" NL Signature
|
||||
Signature ::= "-----BEGIN SIGNATURE-----" NL
|
||||
Base-64-encoded-signature NL "-----END SIGNATURE-----" NL
|
||||
|
||||
Note: The router block for the directory server must appear first.
|
||||
|
||||
@@ -349,7 +349,7 @@ int crypto_pk_read_private_key_from_file(crypto_pk_env_t *env, FILE *src)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env, unsigned char *keyfile)
|
||||
int crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env, const char *keyfile)
|
||||
{
|
||||
FILE *f_pr;
|
||||
int retval = 0;
|
||||
@@ -618,6 +618,43 @@ int crypto_pk_private_sign(crypto_pk_env_t *env, unsigned char *from, int fromle
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
crypto_pk_get_fingerprint(crypto_pk_env_t *pk, char *fp_out)
|
||||
{
|
||||
unsigned char *buf, *bufp;
|
||||
unsigned char digest[20];
|
||||
int len;
|
||||
int i;
|
||||
assert(pk->type == CRYPTO_PK_RSA);
|
||||
len = i2d_RSAPublicKey((RSA*)pk->key, NULL);
|
||||
if (len < 0)
|
||||
return -1;
|
||||
if (len<FINGERPRINT_LEN+1) len = FINGERPRINT_LEN+1;
|
||||
buf = bufp = tor_malloc(len+1);
|
||||
len = i2d_RSAPublicKey((RSA*)pk->key, &bufp);
|
||||
if (len < 0) {
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
if (crypto_SHA_digest(buf, len, digest) < 0) {
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
bufp = buf;
|
||||
for (i = 0; i < 20; ++i) {
|
||||
sprintf(bufp,"%02X",digest[i]);
|
||||
bufp += 2;
|
||||
if (i%2 && i != 19) {
|
||||
*bufp++ = ' ';
|
||||
}
|
||||
}
|
||||
*bufp = '\0';
|
||||
assert(strlen(buf) == FINGERPRINT_LEN);
|
||||
strcpy(fp_out, buf);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* symmetric crypto */
|
||||
int crypto_cipher_generate_key(crypto_cipher_env_t *env)
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@ int crypto_pk_read_public_key_from_string(crypto_pk_env_t *env, char *src, int l
|
||||
int crypto_pk_write_private_key_to_file(crypto_pk_env_t *env, FILE *dest);
|
||||
int crypto_pk_write_public_key_to_file(crypto_pk_env_t *env, FILE *dest);
|
||||
int crypto_pk_check_key(crypto_pk_env_t *env);
|
||||
int crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env, unsigned char *keyfile);
|
||||
int crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env, const char *keyfile);
|
||||
|
||||
int crypto_pk_set_key(crypto_pk_env_t *env, unsigned char *key);
|
||||
int crypto_pk_cmp_keys(crypto_pk_env_t *a, crypto_pk_env_t *b);
|
||||
@@ -53,6 +53,8 @@ int crypto_pk_public_encrypt(crypto_pk_env_t *env, unsigned char *from, int from
|
||||
int crypto_pk_private_decrypt(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to, int padding);
|
||||
int crypto_pk_private_sign(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to);
|
||||
int crypto_pk_public_checksig(crypto_pk_env_t *env, unsigned char *from, int fromlen, unsigned char *to);
|
||||
#define FINGERPRINT_LEN 49
|
||||
int crypto_pk_get_fingerprint(crypto_pk_env_t *pk, char *fp_out);
|
||||
|
||||
int base64_encode(char *dest, int destlen, char *src, int srclen);
|
||||
int base64_decode(char *dest, int destlen, char *src, int srclen);
|
||||
|
||||
+28
-21
@@ -33,6 +33,9 @@ struct tor_tls_st {
|
||||
int isServer;
|
||||
};
|
||||
|
||||
static X509* tor_tls_create_certificate(crypto_pk_env_t *rsa,
|
||||
const char *nickname);
|
||||
|
||||
/* global tls context, keep it here because nobody else needs to touch it */
|
||||
static tor_tls_context *global_tls_context=NULL;
|
||||
static int tls_library_is_initialized = 0;
|
||||
@@ -111,8 +114,9 @@ static int always_accept_verify_cb(int preverify_ok,
|
||||
* commonName 'nickname', and write it, PEM-encoded, to the file named
|
||||
* by 'certfile'. Return 0 on success, -1 for failure.
|
||||
*/
|
||||
int
|
||||
tor_tls_write_certificate(char *certfile, crypto_pk_env_t *rsa, char *nickname)
|
||||
X509 *
|
||||
tor_tls_create_certificate(crypto_pk_env_t *rsa,
|
||||
const char *nickname)
|
||||
{
|
||||
time_t start_time, end_time;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
@@ -120,15 +124,15 @@ tor_tls_write_certificate(char *certfile, crypto_pk_env_t *rsa, char *nickname)
|
||||
X509_NAME *name = NULL;
|
||||
BIO *out = NULL;
|
||||
int nid;
|
||||
int r;
|
||||
int err;
|
||||
|
||||
tor_tls_init();
|
||||
|
||||
start_time = time(NULL);
|
||||
|
||||
assert(rsa);
|
||||
assert(rsa && nickname);
|
||||
if (!(pkey = _crypto_pk_env_get_evp_pkey(rsa)))
|
||||
return -1;
|
||||
return NULL;
|
||||
if (!(x509 = X509_new()))
|
||||
goto error;
|
||||
if (!(X509_set_version(x509, 2)))
|
||||
@@ -143,7 +147,7 @@ tor_tls_write_certificate(char *certfile, crypto_pk_env_t *rsa, char *nickname)
|
||||
"TOR", -1, -1, 0))) goto error;
|
||||
if ((nid = OBJ_txt2nid("commonName")) == NID_undef) goto error;
|
||||
if (!(X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC,
|
||||
nickname, -1, -1, 0))) goto error;
|
||||
(char*)nickname, -1, -1, 0))) goto error;
|
||||
|
||||
if (!(X509_set_issuer_name(x509, name)))
|
||||
goto error;
|
||||
@@ -158,25 +162,21 @@ tor_tls_write_certificate(char *certfile, crypto_pk_env_t *rsa, char *nickname)
|
||||
goto error;
|
||||
if (!X509_sign(x509, pkey, EVP_sha1()))
|
||||
goto error;
|
||||
if (!(out = BIO_new_file(certfile, "w")))
|
||||
goto error;
|
||||
if (!(PEM_write_bio_X509(out, x509)))
|
||||
goto error;
|
||||
|
||||
r = 0;
|
||||
err = 0;
|
||||
goto done;
|
||||
error:
|
||||
r = -1;
|
||||
err = 1;
|
||||
done:
|
||||
if (out)
|
||||
BIO_free(out);
|
||||
if (x509)
|
||||
if (x509 && err)
|
||||
X509_free(x509);
|
||||
if (pkey)
|
||||
EVP_PKEY_free(pkey);
|
||||
if (name)
|
||||
X509_NAME_free(name);
|
||||
return r;
|
||||
return x509;
|
||||
}
|
||||
|
||||
|
||||
@@ -201,16 +201,24 @@ tor_tls_write_certificate(char *certfile, crypto_pk_env_t *rsa, char *nickname)
|
||||
* used for that certificate. Return -1 if failure, else 0.
|
||||
*/
|
||||
int
|
||||
tor_tls_context_new(char *certfile, crypto_pk_env_t *rsa, int isServer)
|
||||
tor_tls_context_new(crypto_pk_env_t *rsa,
|
||||
int isServer, const char *nickname)
|
||||
{
|
||||
crypto_dh_env_t *dh = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
tor_tls_context *result;
|
||||
|
||||
assert((certfile && rsa) || (!certfile && !rsa));
|
||||
|
||||
X509 *cert = NULL;
|
||||
|
||||
tor_tls_init();
|
||||
|
||||
if (rsa) {
|
||||
cert = tor_tls_create_certificate(rsa, nickname);
|
||||
if (!cert) {
|
||||
log(LOG_ERR, "Error creating certificate");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
result = tor_malloc(sizeof(tor_tls_context));
|
||||
result->ctx = NULL;
|
||||
#ifdef EVERYONE_HAS_AES
|
||||
@@ -225,8 +233,7 @@ tor_tls_context_new(char *certfile, crypto_pk_env_t *rsa, int isServer)
|
||||
#endif
|
||||
if (!SSL_CTX_set_cipher_list(result->ctx, CIPHER_LIST))
|
||||
goto error;
|
||||
if (certfile && !SSL_CTX_use_certificate_file(result->ctx,certfile,
|
||||
SSL_FILETYPE_PEM))
|
||||
if (cert && !SSL_CTX_use_certificate(result->ctx,cert))
|
||||
goto error;
|
||||
SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF);
|
||||
if (rsa) {
|
||||
@@ -236,7 +243,7 @@ tor_tls_context_new(char *certfile, crypto_pk_env_t *rsa, int isServer)
|
||||
goto error;
|
||||
EVP_PKEY_free(pkey);
|
||||
pkey = NULL;
|
||||
if (certfile) {
|
||||
if (cert) {
|
||||
if (!SSL_CTX_check_private_key(result->ctx))
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ typedef struct tor_tls_st tor_tls;
|
||||
#define TOR_TLS_WANTWRITE -1
|
||||
#define TOR_TLS_DONE 0
|
||||
|
||||
int tor_tls_write_certificate(char *certfile, crypto_pk_env_t *rsa, char *nickname);
|
||||
int tor_tls_context_new(char *certfile, crypto_pk_env_t *rsa, int isServer);
|
||||
/* X509* tor_tls_write_certificate(char *certfile, crypto_pk_env_t *rsa, char *nickname); */
|
||||
int tor_tls_context_new(crypto_pk_env_t *rsa, int isServer, const char *nickname);
|
||||
tor_tls *tor_tls_new(int sock, int isServer);
|
||||
void tor_tls_free(tor_tls *tls);
|
||||
int tor_tls_peer_has_cert(tor_tls *tls);
|
||||
|
||||
+132
-92
@@ -8,50 +8,103 @@
|
||||
|
||||
extern or_options_t options; /* command-line and config-file options */
|
||||
|
||||
/* Create a new buf of size MAX_BUF_SIZE. Write a pointer to it
|
||||
* into *buf, write MAX_BUF_SIZE into *buflen, and initialize
|
||||
* *buf_datalen to 0. Return 0.
|
||||
struct buf_t {
|
||||
char *buf;
|
||||
size_t len;
|
||||
size_t datalen;
|
||||
};
|
||||
|
||||
#define BUF_OK(b) ((b) && (b)->buf && (b)->datalen <= (b)->len)
|
||||
|
||||
/* Find the first instance of str on buf. If none exists, return -1.
|
||||
* Otherwise, return index of the first character in buf _after_ the
|
||||
* first instance of str.
|
||||
*/
|
||||
int buf_new(char **buf, int *buflen, int *buf_datalen) {
|
||||
static int find_str_in_str(const char *str, int str_len,
|
||||
const char *buf, int buf_len)
|
||||
{
|
||||
const char *location;
|
||||
const char *last_possible = buf + buf_len - str_len;
|
||||
|
||||
assert(buf && buflen && buf_datalen);
|
||||
assert(str && str_len > 0 && buf);
|
||||
|
||||
*buf = (char *)tor_malloc(MAX_BUF_SIZE);
|
||||
// memset(*buf,0,MAX_BUF_SIZE);
|
||||
*buflen = MAX_BUF_SIZE;
|
||||
*buf_datalen = 0;
|
||||
if(buf_len < str_len)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
for(location = buf; location <= last_possible; location++)
|
||||
if((*location == *str) && !memcmp(location+1, str+1, str_len-1))
|
||||
return location-buf+str_len;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void buf_free(char *buf) {
|
||||
/* Create and return a new buf of size 'size'
|
||||
*/
|
||||
buf_t *buf_new_with_capacity(size_t size) {
|
||||
buf_t *buf;
|
||||
buf = (buf_t*)tor_malloc(sizeof(buf_t));
|
||||
buf->buf = (char *)tor_malloc(size);
|
||||
buf->len = size;
|
||||
buf->datalen = 0;
|
||||
// memset(buf->buf,0,size);
|
||||
|
||||
assert(BUF_OK(buf));
|
||||
return buf;
|
||||
}
|
||||
|
||||
buf_t *buf_new()
|
||||
{
|
||||
return buf_new_with_capacity(MAX_BUF_SIZE);
|
||||
}
|
||||
|
||||
|
||||
size_t buf_datalen(const buf_t *buf)
|
||||
{
|
||||
return buf->datalen;
|
||||
}
|
||||
|
||||
size_t buf_capacity(const buf_t *buf)
|
||||
{
|
||||
return buf->len;
|
||||
}
|
||||
|
||||
const char *_buf_peek_raw_buffer(const buf_t *buf)
|
||||
{
|
||||
return buf->buf;
|
||||
}
|
||||
|
||||
void buf_free(buf_t *buf) {
|
||||
assert(buf && buf->buf);
|
||||
free(buf->buf);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/* read from socket s, writing onto buf+buf_datalen.
|
||||
|
||||
|
||||
/* read from socket s, writing onto end of buf.
|
||||
* read at most 'at_most' bytes, and in any case don't read more than will fit based on buflen.
|
||||
* If read() returns 0, set *reached_eof to 1 and return 0. If you want to tear
|
||||
* down the connection return -1, else return the number of bytes read.
|
||||
*/
|
||||
int read_to_buf(int s, int at_most, char **buf, int *buflen, int *buf_datalen, int *reached_eof) {
|
||||
int read_to_buf(int s, int at_most, buf_t *buf, int *reached_eof) {
|
||||
|
||||
int read_result;
|
||||
#ifdef MS_WINDOWS
|
||||
int e;
|
||||
#endif
|
||||
|
||||
assert(buf && *buf && buflen && buf_datalen && reached_eof && (s>=0));
|
||||
assert(BUF_OK(buf) && reached_eof && (s>=0));
|
||||
|
||||
/* this is the point where you would grow the buffer, if you want to */
|
||||
|
||||
if(at_most > *buflen - *buf_datalen)
|
||||
at_most = *buflen - *buf_datalen; /* take the min of the two */
|
||||
if(at_most > buf->len - buf->datalen)
|
||||
at_most = buf->len - buf->datalen; /* take the min of the two */
|
||||
|
||||
if(at_most == 0)
|
||||
return 0; /* we shouldn't read anything */
|
||||
|
||||
// log_fn(LOG_DEBUG,"reading at most %d bytes.",at_most);
|
||||
read_result = read(s, *buf+*buf_datalen, at_most);
|
||||
read_result = read(s, buf->buf+buf->datalen, at_most);
|
||||
if (read_result < 0) {
|
||||
if(!ERRNO_EAGAIN(errno)) { /* it's a real error */
|
||||
return -1;
|
||||
@@ -68,31 +121,33 @@ int read_to_buf(int s, int at_most, char **buf, int *buflen, int *buf_datalen, i
|
||||
*reached_eof = 1;
|
||||
return 0;
|
||||
} else { /* we read some bytes */
|
||||
*buf_datalen += read_result;
|
||||
log_fn(LOG_DEBUG,"Read %d bytes. %d on inbuf.",read_result, *buf_datalen);
|
||||
buf->datalen += read_result;
|
||||
log_fn(LOG_DEBUG,"Read %d bytes. %d on inbuf.",read_result,
|
||||
(int)buf->datalen);
|
||||
return read_result;
|
||||
}
|
||||
}
|
||||
|
||||
int read_to_buf_tls(tor_tls *tls, int at_most, char **buf, int *buflen, int *buf_datalen) {
|
||||
int read_to_buf_tls(tor_tls *tls, int at_most, buf_t *buf) {
|
||||
int r;
|
||||
assert(tls && *buf && buflen && buf_datalen);
|
||||
assert(tls && BUF_OK(buf));
|
||||
|
||||
if (at_most > *buflen - *buf_datalen)
|
||||
at_most = *buflen - *buf_datalen;
|
||||
if (at_most > buf->len - buf->datalen)
|
||||
at_most = buf->len - buf->datalen;
|
||||
|
||||
if (at_most == 0)
|
||||
return 0;
|
||||
|
||||
r = tor_tls_read(tls, *buf+*buf_datalen, at_most);
|
||||
r = tor_tls_read(tls, buf->buf+buf->datalen, at_most);
|
||||
if (r<0)
|
||||
return r;
|
||||
*buf_datalen += r;
|
||||
log_fn(LOG_DEBUG,"Read %d bytes. %d on inbuf.",r, *buf_datalen);
|
||||
buf->datalen += r;
|
||||
log_fn(LOG_DEBUG,"Read %d bytes. %d on inbuf.",r, (int)buf->datalen);
|
||||
return r;
|
||||
}
|
||||
|
||||
int flush_buf(int s, char **buf, int *buflen, int *buf_flushlen, int *buf_datalen) {
|
||||
int flush_buf(int s, buf_t *buf, int *buf_flushlen)
|
||||
{
|
||||
|
||||
/* push from buf onto s
|
||||
* then memmove to front of buf
|
||||
@@ -103,14 +158,12 @@ int flush_buf(int s, char **buf, int *buflen, int *buf_flushlen, int *buf_datale
|
||||
int e;
|
||||
#endif
|
||||
|
||||
assert(buf && *buf && buflen && buf_flushlen && buf_datalen && (s>=0) && (*buf_flushlen <= *buf_datalen));
|
||||
assert(BUF_OK(buf) && buf_flushlen && (s>=0) && (*buf_flushlen <= buf->datalen));
|
||||
|
||||
if(*buf_flushlen == 0) /* nothing to flush */
|
||||
return 0;
|
||||
|
||||
/* this is the point where you would grow the buffer, if you want to */
|
||||
|
||||
write_result = write(s, *buf, *buf_flushlen);
|
||||
write_result = write(s, buf->buf, *buf_flushlen);
|
||||
if (write_result < 0) {
|
||||
if(!ERRNO_EAGAIN(errno)) { /* it's a real error */
|
||||
return -1;
|
||||
@@ -124,72 +177,70 @@ int flush_buf(int s, char **buf, int *buflen, int *buf_flushlen, int *buf_datale
|
||||
log_fn(LOG_DEBUG,"write() would block, returning.");
|
||||
return 0;
|
||||
} else {
|
||||
*buf_datalen -= write_result;
|
||||
buf->datalen -= write_result;
|
||||
*buf_flushlen -= write_result;
|
||||
memmove(*buf, *buf+write_result, *buf_datalen);
|
||||
memmove(buf->buf, buf->buf+write_result, buf->datalen);
|
||||
log_fn(LOG_DEBUG,"%d: flushed %d bytes, %d ready to flush, %d remain.",
|
||||
s,write_result,*buf_flushlen,*buf_datalen);
|
||||
s,write_result,*buf_flushlen,(int)buf->datalen);
|
||||
return *buf_flushlen;
|
||||
/* XXX USE_TLS should change to return write_result like any sane function would */
|
||||
}
|
||||
}
|
||||
|
||||
int flush_buf_tls(tor_tls *tls, char **buf, int *buflen, int *buf_flushlen, int *buf_datalen)
|
||||
int flush_buf_tls(tor_tls *tls, buf_t *buf, int *buf_flushlen)
|
||||
{
|
||||
int r;
|
||||
assert(tls && *buf && buflen && buf_datalen);
|
||||
assert(tls && BUF_OK(buf) && buf_flushlen);
|
||||
|
||||
/* we want to let tls write even if flushlen is zero, because it might
|
||||
* have a partial record pending */
|
||||
r = tor_tls_write(tls, *buf, *buf_flushlen);
|
||||
r = tor_tls_write(tls, buf->buf, *buf_flushlen);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
*buf_datalen -= r;
|
||||
buf->datalen -= r;
|
||||
*buf_flushlen -= r;
|
||||
memmove(*buf, *buf+r, *buf_datalen);
|
||||
memmove(buf->buf, buf->buf+r, buf->datalen);
|
||||
log_fn(LOG_DEBUG,"flushed %d bytes, %d ready to flush, %d remain.",
|
||||
r,*buf_flushlen,*buf_datalen);
|
||||
r,*buf_flushlen,(int)buf->datalen);
|
||||
return r;
|
||||
}
|
||||
|
||||
int write_to_buf(char *string, int string_len,
|
||||
char **buf, int *buflen, int *buf_datalen) {
|
||||
int write_to_buf(char *string, int string_len, buf_t *buf) {
|
||||
|
||||
/* append string to buf (growing as needed, return -1 if "too big")
|
||||
* return total number of bytes on the buf
|
||||
*/
|
||||
|
||||
assert(string && buf && *buf && buflen && buf_datalen);
|
||||
assert(string && BUF_OK(buf));
|
||||
|
||||
/* this is the point where you would grow the buffer, if you want to */
|
||||
|
||||
if (string_len + *buf_datalen > *buflen) { /* we're out of luck */
|
||||
if (string_len + buf->datalen > buf->len) { /* we're out of luck */
|
||||
log_fn(LOG_DEBUG, "buflen too small. Time to implement growing dynamic bufs.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(*buf+*buf_datalen, string, string_len);
|
||||
*buf_datalen += string_len;
|
||||
log_fn(LOG_DEBUG,"added %d bytes to buf (now %d total).",string_len, *buf_datalen);
|
||||
return *buf_datalen;
|
||||
memcpy(buf->buf+buf->datalen, string, string_len);
|
||||
buf->datalen += string_len;
|
||||
log_fn(LOG_DEBUG,"added %d bytes to buf (now %d total).",string_len, (int)buf->datalen);
|
||||
return buf->datalen;
|
||||
}
|
||||
|
||||
int fetch_from_buf(char *string, int string_len,
|
||||
char **buf, int *buflen, int *buf_datalen) {
|
||||
int fetch_from_buf(char *string, int string_len, buf_t *buf) {
|
||||
|
||||
/* There must be string_len bytes in buf; write them onto string,
|
||||
* then memmove buf back (that is, remove them from buf).
|
||||
*
|
||||
* Return the number of bytes still on the buffer. */
|
||||
|
||||
assert(string && buf && *buf && buflen && buf_datalen);
|
||||
assert(string_len <= *buf_datalen); /* make sure we don't ask for too much */
|
||||
assert(string && BUF_OK(buf));
|
||||
assert(string_len <= buf->datalen); /* make sure we don't ask for too much */
|
||||
|
||||
memcpy(string,*buf,string_len);
|
||||
*buf_datalen -= string_len;
|
||||
memmove(*buf, *buf+string_len, *buf_datalen);
|
||||
return *buf_datalen;
|
||||
memcpy(string,buf->buf,string_len);
|
||||
buf->datalen -= string_len;
|
||||
memmove(buf->buf, buf->buf+string_len, buf->datalen);
|
||||
return buf->datalen;
|
||||
}
|
||||
|
||||
/* There is a (possibly incomplete) http statement on *buf, of the
|
||||
@@ -204,24 +255,24 @@ int fetch_from_buf(char *string, int string_len,
|
||||
*
|
||||
* Else, change nothing and return 0.
|
||||
*/
|
||||
int fetch_from_buf_http(char *buf, int *buf_datalen,
|
||||
int fetch_from_buf_http(buf_t *buf,
|
||||
char *headers_out, int max_headerlen,
|
||||
char *body_out, int max_bodylen) {
|
||||
char *headers, *body;
|
||||
int i;
|
||||
int headerlen, bodylen, contentlen;
|
||||
|
||||
assert(buf && buf_datalen);
|
||||
assert(BUF_OK(buf));
|
||||
|
||||
headers = buf;
|
||||
i = find_on_inbuf("\r\n\r\n", 4, buf, *buf_datalen);
|
||||
headers = buf->buf;
|
||||
i = find_on_inbuf("\r\n\r\n", 4, buf);
|
||||
if(i < 0) {
|
||||
log_fn(LOG_DEBUG,"headers not all here yet.");
|
||||
return 0;
|
||||
}
|
||||
body = buf+i;
|
||||
body = buf->buf+i;
|
||||
headerlen = body-headers; /* includes the CRLFCRLF */
|
||||
bodylen = *buf_datalen - headerlen;
|
||||
bodylen = buf->datalen - headerlen;
|
||||
log_fn(LOG_DEBUG,"headerlen %d, bodylen %d.",headerlen,bodylen);
|
||||
|
||||
if(headers_out && max_headerlen <= headerlen) {
|
||||
@@ -234,9 +285,11 @@ int fetch_from_buf_http(char *buf, int *buf_datalen,
|
||||
}
|
||||
|
||||
#define CONTENT_LENGTH "\r\nContent-Length: "
|
||||
i = find_on_inbuf(CONTENT_LENGTH, strlen(CONTENT_LENGTH), headers, headerlen);
|
||||
i = find_str_in_str(CONTENT_LENGTH, sizeof(CONTENT_LENGTH),
|
||||
headers, headerlen);
|
||||
if(i > 0) {
|
||||
contentlen = atoi(headers+i);
|
||||
/* XXX What if content-length is malformed? */
|
||||
if(bodylen < contentlen) {
|
||||
log_fn(LOG_DEBUG,"body not all here yet.");
|
||||
return 0; /* not all there yet */
|
||||
@@ -246,15 +299,15 @@ int fetch_from_buf_http(char *buf, int *buf_datalen,
|
||||
}
|
||||
/* all happy. copy into the appropriate places, and return 1 */
|
||||
if(headers_out) {
|
||||
memcpy(headers_out,buf,headerlen);
|
||||
memcpy(headers_out,buf->buf,headerlen);
|
||||
headers_out[headerlen] = 0; /* null terminate it */
|
||||
}
|
||||
if(body_out) {
|
||||
memcpy(body_out,buf+headerlen,bodylen);
|
||||
memcpy(body_out,buf->buf+headerlen,bodylen);
|
||||
body_out[bodylen] = 0; /* null terminate it */
|
||||
}
|
||||
*buf_datalen -= (headerlen+bodylen);
|
||||
memmove(buf, buf+headerlen+bodylen, *buf_datalen);
|
||||
buf->datalen -= (headerlen+bodylen);
|
||||
memmove(buf, buf->buf+headerlen+bodylen, buf->datalen);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -269,7 +322,7 @@ int fetch_from_buf_http(char *buf, int *buf_datalen,
|
||||
* If it's invalid or too big, return -1.
|
||||
* Else it's not all there yet, change nothing and return 0.
|
||||
*/
|
||||
int fetch_from_buf_socks(char *buf, int *buf_datalen,
|
||||
int fetch_from_buf_socks(buf_t *buf,
|
||||
char *addr_out, int max_addrlen,
|
||||
uint16_t *port_out) {
|
||||
socks4_t socks4_info;
|
||||
@@ -278,14 +331,14 @@ int fetch_from_buf_socks(char *buf, int *buf_datalen,
|
||||
enum {socks4, socks4a } socks_prot = socks4a;
|
||||
char *next, *startaddr;
|
||||
|
||||
if(*buf_datalen < sizeof(socks4_t)) /* basic info available? */
|
||||
if(buf->datalen < sizeof(socks4_t)) /* basic info available? */
|
||||
return 0; /* not yet */
|
||||
|
||||
/* an inlined socks4_unpack() */
|
||||
socks4_info.version = *buf;
|
||||
socks4_info.command = *(buf+1);
|
||||
socks4_info.destport = ntohs(*(uint16_t*)(buf+2));
|
||||
socks4_info.destip = ntohl(*(uint32_t*)(buf+4));
|
||||
socks4_info.version = (unsigned char) *(buf->buf);
|
||||
socks4_info.command = (unsigned char) *(buf->buf+1);
|
||||
socks4_info.destport = ntohs(*(uint16_t*)(buf->buf+2));
|
||||
socks4_info.destip = ntohl(*(uint32_t*)(buf->buf+4));
|
||||
|
||||
if(socks4_info.version != 4) {
|
||||
log_fn(LOG_NOTICE,"Unrecognized version %d.",socks4_info.version);
|
||||
@@ -321,7 +374,7 @@ int fetch_from_buf_socks(char *buf, int *buf_datalen,
|
||||
socks_prot = socks4;
|
||||
}
|
||||
|
||||
next = memchr(buf+SOCKS4_NETWORK_LEN, 0, *buf_datalen);
|
||||
next = memchr(buf->buf+SOCKS4_NETWORK_LEN, 0, buf->datalen);
|
||||
if(!next) {
|
||||
log_fn(LOG_DEBUG,"Username not here yet.");
|
||||
return 0;
|
||||
@@ -329,7 +382,7 @@ int fetch_from_buf_socks(char *buf, int *buf_datalen,
|
||||
|
||||
startaddr = next+1;
|
||||
if(socks_prot == socks4a) {
|
||||
next = memchr(startaddr, 0, buf+*buf_datalen-startaddr);
|
||||
next = memchr(startaddr, 0, buf->buf+buf->datalen-startaddr);
|
||||
if(!next) {
|
||||
log_fn(LOG_DEBUG,"Destaddr not here yet.");
|
||||
return 0;
|
||||
@@ -342,32 +395,19 @@ int fetch_from_buf_socks(char *buf, int *buf_datalen,
|
||||
log_fn(LOG_DEBUG,"Everything is here. Success.");
|
||||
*port_out = port;
|
||||
strcpy(addr_out, socks_prot == socks4 ? tmpbuf : startaddr);
|
||||
*buf_datalen -= (next-buf+1); /* next points to the final \0 on inbuf */
|
||||
memmove(buf, next+1, *buf_datalen);
|
||||
buf->datalen -= (next-buf->buf+1); /* next points to the final \0 on inbuf */
|
||||
memmove(buf->buf, next+1, buf->datalen);
|
||||
// log_fn(LOG_DEBUG,"buf_datalen is now %d:'%s'",*buf_datalen,buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int find_on_inbuf(char *string, int string_len,
|
||||
char *buf, int buf_datalen) {
|
||||
int find_on_inbuf(char *string, int string_len, buf_t *buf) {
|
||||
/* find first instance of needle 'string' on haystack 'buf'. return how
|
||||
* many bytes from the beginning of buf to the end of string.
|
||||
* If it's not there, return -1.
|
||||
*/
|
||||
|
||||
char *location;
|
||||
char *last_possible = buf + buf_datalen - string_len;
|
||||
|
||||
assert(string && string_len > 0 && buf);
|
||||
|
||||
if(buf_datalen < string_len)
|
||||
return -1;
|
||||
|
||||
for(location = buf; location <= last_possible; location++)
|
||||
if((*location == *string) && !memcmp(location+1, string+1, string_len-1))
|
||||
return location-buf+string_len;
|
||||
|
||||
return -1;
|
||||
return find_str_in_str(string, string_len, buf->buf, buf->datalen);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -751,7 +751,7 @@ int circuit_send_next_onion_skin(circuit_t *circ) {
|
||||
cell.aci = circ->n_aci;
|
||||
cell.length = DH_ONIONSKIN_LEN;
|
||||
|
||||
if(onion_skin_create(circ->n_conn->pkey, &(circ->cpath->handshake_state), cell.payload) < 0) {
|
||||
if(onion_skin_create(circ->n_conn->onion_pkey, &(circ->cpath->handshake_state), cell.payload) < 0) {
|
||||
log_fn(LOG_INFO,"onion_skin_create (first hop) failed.");
|
||||
return -1;
|
||||
}
|
||||
@@ -791,7 +791,7 @@ int circuit_send_next_onion_skin(circuit_t *circ) {
|
||||
cell.length = RELAY_HEADER_SIZE + 6 + DH_ONIONSKIN_LEN;
|
||||
*(uint32_t*)(cell.payload+RELAY_HEADER_SIZE) = htonl(hop->addr);
|
||||
*(uint16_t*)(cell.payload+RELAY_HEADER_SIZE+4) = htons(hop->port);
|
||||
if(onion_skin_create(router->pkey, &(hop->handshake_state), cell.payload+RELAY_HEADER_SIZE+6) < 0) {
|
||||
if(onion_skin_create(router->onion_pkey, &(hop->handshake_state), cell.payload+RELAY_HEADER_SIZE+6) < 0) {
|
||||
log_fn(LOG_INFO,"onion_skin_create failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
+4
-11
@@ -189,10 +189,8 @@ static void config_assign(or_options_t *options, struct config_line *list) {
|
||||
|
||||
/* string options */
|
||||
config_compare(list, "LogLevel", CONFIG_TYPE_STRING, &options->LogLevel) ||
|
||||
config_compare(list, "PrivateKeyFile", CONFIG_TYPE_STRING, &options->PrivateKeyFile) ||
|
||||
config_compare(list, "SigningPrivateKeyFile", CONFIG_TYPE_STRING, &options->SigningPrivateKeyFile) ||
|
||||
config_compare(list, "DataDirectory", CONFIG_TYPE_STRING, &options->DataDirectory) ||
|
||||
config_compare(list, "RouterFile", CONFIG_TYPE_STRING, &options->RouterFile) ||
|
||||
config_compare(list, "CertFile", CONFIG_TYPE_STRING, &options->CertFile) ||
|
||||
config_compare(list, "Nickname", CONFIG_TYPE_STRING, &options->Nickname) ||
|
||||
|
||||
/* int options */
|
||||
@@ -238,6 +236,7 @@ int getconfig(int argc, char **argv, or_options_t *options) {
|
||||
memset(options,0,sizeof(or_options_t));
|
||||
options->LogLevel = "debug";
|
||||
options->loglevel = LOG_DEBUG;
|
||||
options->DataDirectory = NULL;
|
||||
options->CoinWeight = 0.8;
|
||||
options->MaxConn = 900;
|
||||
options->DirFetchPeriod = 600;
|
||||
@@ -246,7 +245,6 @@ int getconfig(int argc, char **argv, or_options_t *options) {
|
||||
options->NewCircuitPeriod = 60; /* once a minute */
|
||||
options->TotalBandwidth = 800000; /* at most 800kB/s total sustained incoming */
|
||||
options->NumCpus = 1;
|
||||
options->CertFile = "default.cert";
|
||||
|
||||
/* learn config file name, get config lines, assign them */
|
||||
i = 1;
|
||||
@@ -316,8 +314,8 @@ int getconfig(int argc, char **argv, or_options_t *options) {
|
||||
result = -1;
|
||||
}
|
||||
|
||||
if(options->OnionRouter && options->PrivateKeyFile == NULL) {
|
||||
log(LOG_ERR,"PrivateKeyFile option required for OnionRouter, but not found.");
|
||||
if(options->OnionRouter && options->DataDirectory == NULL) {
|
||||
log(LOG_ERR,"DataDirectory option required for OnionRouter, but not found.");
|
||||
result = -1;
|
||||
}
|
||||
|
||||
@@ -326,11 +324,6 @@ int getconfig(int argc, char **argv, or_options_t *options) {
|
||||
result = -1;
|
||||
}
|
||||
|
||||
if(options->DirPort > 0 && options->SigningPrivateKeyFile == NULL) {
|
||||
log(LOG_ERR,"SigningPrivateKeyFile option required for DirServer, but not found.");
|
||||
result = -1;
|
||||
}
|
||||
|
||||
if(options->APPort < 0) {
|
||||
log(LOG_ERR,"APPort option can't be negative.");
|
||||
result = -1;
|
||||
|
||||
+27
-30
@@ -80,8 +80,8 @@ connection_t *connection_new(int type) {
|
||||
memset(conn,0,sizeof(connection_t)); /* zero it out to start */
|
||||
|
||||
conn->type = type;
|
||||
if(buf_new(&conn->inbuf, &conn->inbuflen, &conn->inbuf_datalen) < 0 ||
|
||||
buf_new(&conn->outbuf, &conn->outbuflen, &conn->outbuf_datalen) < 0)
|
||||
if(!(conn->inbuf = buf_new()) ||
|
||||
!(conn->outbuf = buf_new()))
|
||||
return NULL;
|
||||
|
||||
conn->receiver_bucket = 50000; /* should be enough to do the handshake */
|
||||
@@ -108,8 +108,12 @@ void connection_free(connection_t *conn) {
|
||||
tor_tls_free(conn->tls);
|
||||
}
|
||||
|
||||
if (conn->pkey)
|
||||
crypto_free_pk_env(conn->pkey);
|
||||
if (conn->onion_pkey)
|
||||
crypto_free_pk_env(conn->onion_pkey);
|
||||
if (conn->link_pkey)
|
||||
crypto_free_pk_env(conn->link_pkey);
|
||||
if (conn->identity_pkey)
|
||||
crypto_free_pk_env(conn->identity_pkey);
|
||||
|
||||
if(conn->s > 0) {
|
||||
log_fn(LOG_INFO,"closing fd %d.",conn->s);
|
||||
@@ -287,14 +291,14 @@ static int connection_tls_finish_handshake(connection_t *conn) {
|
||||
log_fn(LOG_INFO,"Other side has a cert but it's bad. Closing.");
|
||||
return -1;
|
||||
}
|
||||
router = router_get_by_pk(pk);
|
||||
router = router_get_by_link_pk(pk);
|
||||
if (!router) {
|
||||
log_fn(LOG_INFO,"Unrecognized public key from peer. Closing.");
|
||||
crypto_free_pk_env(pk);
|
||||
return -1;
|
||||
}
|
||||
if(conn->pkey) { /* I initiated this connection. */
|
||||
if(crypto_pk_cmp_keys(conn->pkey, pk)) {
|
||||
if(conn->link_pkey) { /* I initiated this connection. */
|
||||
if(crypto_pk_cmp_keys(conn->link_pkey, pk)) {
|
||||
log_fn(LOG_INFO,"We connected to '%s' but he gave us a different key. Closing.", router->nickname);
|
||||
crypto_free_pk_env(pk);
|
||||
return -1;
|
||||
@@ -306,7 +310,7 @@ static int connection_tls_finish_handshake(connection_t *conn) {
|
||||
log_fn(LOG_INFO,"That router is already connected. Dropping.");
|
||||
return -1;
|
||||
}
|
||||
conn->pkey = pk;
|
||||
conn->link_pkey = pk;
|
||||
conn->bandwidth = router->bandwidth;
|
||||
conn->addr = router->addr, conn->port = router->or_port;
|
||||
if(conn->address)
|
||||
@@ -326,13 +330,13 @@ static int connection_tls_finish_handshake(connection_t *conn) {
|
||||
log_fn(LOG_INFO,"Other side has a cert but it's bad. Closing.");
|
||||
return -1;
|
||||
}
|
||||
router = router_get_by_pk(pk);
|
||||
router = router_get_by_link_pk(pk);
|
||||
if (!router) {
|
||||
log_fn(LOG_INFO,"Unrecognized public key from peer. Closing.");
|
||||
crypto_free_pk_env(pk);
|
||||
return -1;
|
||||
}
|
||||
if(crypto_pk_cmp_keys(conn->pkey, pk)) {
|
||||
if(crypto_pk_cmp_keys(conn->link_pkey, pk)) {
|
||||
log_fn(LOG_INFO,"We connected to '%s' but he gave us a different key. Closing.", router->nickname);
|
||||
crypto_free_pk_env(pk);
|
||||
return -1;
|
||||
@@ -494,8 +498,7 @@ int connection_read_to_buf(connection_t *conn) {
|
||||
return connection_tls_continue_handshake(conn);
|
||||
|
||||
/* else open, or closing */
|
||||
result = read_to_buf_tls(conn->tls, at_most, &conn->inbuf,
|
||||
&conn->inbuflen, &conn->inbuf_datalen);
|
||||
result = read_to_buf_tls(conn->tls, at_most, conn->inbuf);
|
||||
|
||||
switch(result) {
|
||||
case TOR_TLS_ERROR:
|
||||
@@ -510,8 +513,9 @@ int connection_read_to_buf(connection_t *conn) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
result = read_to_buf(conn->s, at_most, &conn->inbuf, &conn->inbuflen,
|
||||
&conn->inbuf_datalen, &conn->inbuf_reached_eof);
|
||||
result = read_to_buf(conn->s, at_most, conn->inbuf,
|
||||
&conn->inbuf_reached_eof);
|
||||
|
||||
// log(LOG_DEBUG,"connection_read_to_buf(): read_to_buf returned %d.",read_result);
|
||||
|
||||
if(result < 0)
|
||||
@@ -534,11 +538,11 @@ int connection_read_to_buf(connection_t *conn) {
|
||||
}
|
||||
|
||||
int connection_fetch_from_buf(char *string, int len, connection_t *conn) {
|
||||
return fetch_from_buf(string, len, &conn->inbuf, &conn->inbuflen, &conn->inbuf_datalen);
|
||||
return fetch_from_buf(string, len, conn->inbuf);
|
||||
}
|
||||
|
||||
int connection_find_on_inbuf(char *string, int len, connection_t *conn) {
|
||||
return find_on_inbuf(string, len, conn->inbuf, conn->inbuf_datalen);
|
||||
return find_on_inbuf(string, len, conn->inbuf);
|
||||
}
|
||||
|
||||
int connection_wants_to_flush(connection_t *conn) {
|
||||
@@ -550,8 +554,7 @@ int connection_outbuf_too_full(connection_t *conn) {
|
||||
}
|
||||
|
||||
int connection_flush_buf(connection_t *conn) {
|
||||
return flush_buf(conn->s, &conn->outbuf, &conn->outbuflen,
|
||||
&conn->outbuf_flushlen, &conn->outbuf_datalen);
|
||||
return flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen);
|
||||
}
|
||||
|
||||
/* return -1 if you want to break the conn, else return 0 */
|
||||
@@ -573,8 +576,7 @@ int connection_handle_write(connection_t *conn) {
|
||||
}
|
||||
|
||||
/* else open, or closing */
|
||||
switch(flush_buf_tls(conn->tls, &conn->outbuf, &conn->outbuflen,
|
||||
&conn->outbuf_flushlen, &conn->outbuf_datalen)) {
|
||||
switch(flush_buf_tls(conn->tls, conn->outbuf, &conn->outbuf_flushlen)) {
|
||||
case TOR_TLS_ERROR:
|
||||
case TOR_TLS_CLOSE:
|
||||
log_fn(LOG_DEBUG,"tls error. breaking.");
|
||||
@@ -601,8 +603,7 @@ int connection_handle_write(connection_t *conn) {
|
||||
*/
|
||||
}
|
||||
} else {
|
||||
if(flush_buf(conn->s, &conn->outbuf, &conn->outbuflen,
|
||||
&conn->outbuf_flushlen, &conn->outbuf_datalen) < 0)
|
||||
if(flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen) < 0)
|
||||
return -1;
|
||||
/* conns in CONNECTING state will fall through... */
|
||||
}
|
||||
@@ -631,7 +632,7 @@ int connection_write_to_buf(char *string, int len, connection_t *conn) {
|
||||
conn->outbuf_flushlen += len;
|
||||
}
|
||||
|
||||
return write_to_buf(string, len, &conn->outbuf, &conn->outbuflen, &conn->outbuf_datalen);
|
||||
return write_to_buf(string, len, conn->outbuf);
|
||||
}
|
||||
|
||||
int connection_receiver_bucket_should_increase(connection_t *conn) {
|
||||
@@ -741,29 +742,25 @@ void assert_connection_ok(connection_t *conn, time_t now)
|
||||
|
||||
/* buffers */
|
||||
assert(conn->inbuf);
|
||||
assert(conn->inbuflen >= conn->inbuf_datalen);
|
||||
assert(conn->inbuflen >= 0);
|
||||
assert(conn->inbuf_datalen >= 0);
|
||||
assert(conn->outbuf);
|
||||
assert(conn->outbuflen >= conn->outbuf_datalen);
|
||||
assert(conn->outbuflen >= 0);
|
||||
assert(conn->outbuf_datalen >= 0);
|
||||
|
||||
assert(!now || conn->timestamp_lastread <= now);
|
||||
assert(!now || conn->timestamp_lastwritten <= now);
|
||||
assert(conn->timestamp_created <= conn->timestamp_lastread);
|
||||
assert(conn->timestamp_created <= conn->timestamp_lastwritten);
|
||||
|
||||
/* XXX Fix this; no longer so.*/
|
||||
#if 0
|
||||
if(conn->type != CONN_TYPE_OR && conn->type != CONN_TYPE_DIR)
|
||||
assert(!conn->pkey);
|
||||
/* pkey is set if we're a dir client, or if we're an OR in state OPEN
|
||||
* connected to another OR.
|
||||
*/
|
||||
#endif
|
||||
|
||||
if (conn->type != CONN_TYPE_OR) {
|
||||
assert(conn->bandwidth == -1);
|
||||
assert(conn->receiver_bucket == -1);
|
||||
/* Addr, port, address XXX */
|
||||
assert(!conn->tls);
|
||||
} else {
|
||||
assert(conn->bandwidth);
|
||||
|
||||
@@ -336,7 +336,7 @@ repeat_connection_package_raw_inbuf:
|
||||
return 0;
|
||||
}
|
||||
|
||||
amount_to_process = conn->inbuf_datalen;
|
||||
amount_to_process = buf_datalen(conn->inbuf);
|
||||
|
||||
if(!amount_to_process)
|
||||
return 0;
|
||||
@@ -352,7 +352,8 @@ repeat_connection_package_raw_inbuf:
|
||||
|
||||
connection_fetch_from_buf(cell.payload+RELAY_HEADER_SIZE, cell.length, conn);
|
||||
|
||||
log_fn(LOG_DEBUG,"(%d) Packaging %d bytes (%d waiting).",conn->s,cell.length, conn->inbuf_datalen);
|
||||
log_fn(LOG_DEBUG,"(%d) Packaging %d bytes (%d waiting).",conn->s,cell.length,
|
||||
(int)buf_datalen(conn->inbuf));
|
||||
|
||||
cell.command = CELL_RELAY;
|
||||
SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_DATA);
|
||||
@@ -440,7 +441,7 @@ static int connection_ap_handshake_process_socks(connection_t *conn) {
|
||||
|
||||
log_fn(LOG_DEBUG,"entered.");
|
||||
|
||||
switch(fetch_from_buf_socks(conn->inbuf,&conn->inbuf_datalen,
|
||||
switch(fetch_from_buf_socks(conn->inbuf,
|
||||
destaddr, sizeof(destaddr), &destport)) {
|
||||
case -1:
|
||||
log_fn(LOG_DEBUG,"Fetching socks handshake failed. Closing.");
|
||||
|
||||
@@ -99,7 +99,8 @@ connection_t *connection_or_connect(routerinfo_t *router) {
|
||||
conn->addr = router->addr;
|
||||
conn->port = router->or_port;
|
||||
conn->bandwidth = router->bandwidth;
|
||||
conn->pkey = crypto_pk_dup_key(router->pkey);
|
||||
conn->onion_pkey = crypto_pk_dup_key(router->onion_pkey);
|
||||
conn->link_pkey = crypto_pk_dup_key(router->link_pkey);
|
||||
conn->address = strdup(router->address);
|
||||
|
||||
if(connection_add(conn) < 0) { /* no space, forget it */
|
||||
@@ -148,9 +149,9 @@ int connection_write_cell_to_buf(const cell_t *cellp, connection_t *conn) {
|
||||
int connection_process_cell_from_inbuf(connection_t *conn) {
|
||||
char buf[CELL_NETWORK_SIZE];
|
||||
cell_t cell;
|
||||
|
||||
log_fn(LOG_DEBUG,"%d: starting, inbuf_datalen %d.",conn->s,conn->inbuf_datalen);
|
||||
if(conn->inbuf_datalen < CELL_NETWORK_SIZE) /* entire response available? */
|
||||
|
||||
log_fn(LOG_DEBUG,"%d: starting, inbuf_datalen %d.",conn->s,buf_datalen(conn->inbuf));
|
||||
if(buf_datalen(conn->inbuf) < CELL_NETWORK_SIZE) /* entire response available? */
|
||||
return 0; /* not yet */
|
||||
|
||||
connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, conn);
|
||||
|
||||
@@ -73,9 +73,9 @@ int connection_cpu_process_inbuf(connection_t *conn) {
|
||||
}
|
||||
|
||||
if(conn->state == CPUWORKER_STATE_BUSY_ONION) {
|
||||
if(conn->inbuf_datalen < LEN_ONION_RESPONSE) /* entire answer available? */
|
||||
if(buf_datalen(conn->inbuf) < LEN_ONION_RESPONSE) /* entire answer available? */
|
||||
return 0; /* not yet */
|
||||
assert(conn->inbuf_datalen == LEN_ONION_RESPONSE);
|
||||
assert(buf_datalen(conn->inbuf) == LEN_ONION_RESPONSE);
|
||||
|
||||
connection_fetch_from_buf(buf,LEN_ONION_RESPONSE,conn);
|
||||
|
||||
@@ -147,7 +147,7 @@ int cpuworker_main(void *data) {
|
||||
}
|
||||
|
||||
if(question_type == CPUWORKER_TASK_ONION) {
|
||||
if(onion_skin_server_handshake(question, get_privatekey(),
|
||||
if(onion_skin_server_handshake(question, get_onion_key(),
|
||||
reply_to_proxy, keys, 32) < 0) {
|
||||
/* failure */
|
||||
log_fn(LOG_ERR,"onion_skin_server_handshake failed.");
|
||||
|
||||
@@ -53,11 +53,11 @@ void directory_initiate_command(routerinfo_t *router, int command) {
|
||||
conn->address = strdup(router->address);
|
||||
conn->receiver_bucket = -1; /* edge connections don't do receiver buckets */
|
||||
conn->bandwidth = -1;
|
||||
if (router->signing_pkey)
|
||||
conn->pkey = crypto_pk_dup_key(router->signing_pkey);
|
||||
if (router->identity_pkey)
|
||||
conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey);
|
||||
else {
|
||||
log_fn(LOG_ERR, "No signing key known for dirserver %s; signature won't be checked", conn->address);
|
||||
conn->pkey = NULL;
|
||||
conn->identity_pkey = NULL;
|
||||
}
|
||||
|
||||
if(connection_add(conn) < 0) { /* no space, forget it */
|
||||
@@ -124,7 +124,7 @@ void directory_set_dirty(void) {
|
||||
static void directory_rebuild(void) {
|
||||
if(directory_dirty) {
|
||||
if (dump_signed_directory_to_string(the_directory, MAX_DIR_SIZE,
|
||||
get_signing_privatekey())) {
|
||||
get_identity_key())) {
|
||||
log(LOG_ERR, "Error writing directory");
|
||||
return;
|
||||
}
|
||||
@@ -144,7 +144,7 @@ int connection_dir_process_inbuf(connection_t *conn) {
|
||||
switch(conn->state) {
|
||||
case DIR_CONN_STATE_CLIENT_READING_FETCH:
|
||||
/* kill it, but first process the_directory and learn about new routers. */
|
||||
switch(fetch_from_buf_http(conn->inbuf,&conn->inbuf_datalen,
|
||||
switch(fetch_from_buf_http(conn->inbuf,
|
||||
NULL, 0, the_directory, MAX_DIR_SIZE)) {
|
||||
case -1: /* overflow */
|
||||
log_fn(LOG_DEBUG,"'fetch' response too large. Failing.");
|
||||
@@ -161,11 +161,11 @@ int connection_dir_process_inbuf(connection_t *conn) {
|
||||
log_fn(LOG_DEBUG,"Empty directory. Ignoring.");
|
||||
return -1;
|
||||
}
|
||||
if(router_get_dir_from_string(the_directory, conn->pkey) < 0) {
|
||||
if(router_get_dir_from_string(the_directory, conn->identity_pkey) < 0){
|
||||
log_fn(LOG_DEBUG,"...but parsing failed. Ignoring.");
|
||||
} else {
|
||||
log_fn(LOG_DEBUG,"and got an %s directory; updated routers.",
|
||||
conn->pkey ? "authenticated" : "unauthenticated");
|
||||
conn->identity_pkey ? "authenticated" : "unauthenticated");
|
||||
}
|
||||
if(options.OnionRouter) { /* connect to them all */
|
||||
router_retry_connections();
|
||||
@@ -196,7 +196,7 @@ static int directory_handle_command(connection_t *conn) {
|
||||
|
||||
assert(conn && conn->type == CONN_TYPE_DIR);
|
||||
|
||||
switch(fetch_from_buf_http(conn->inbuf,&conn->inbuf_datalen,
|
||||
switch(fetch_from_buf_http(conn->inbuf,
|
||||
headers, sizeof(headers), body, sizeof(body))) {
|
||||
case -1: /* overflow */
|
||||
log_fn(LOG_DEBUG,"input too large. Failing.");
|
||||
|
||||
+2
-2
@@ -309,9 +309,9 @@ int connection_dns_process_inbuf(connection_t *conn) {
|
||||
}
|
||||
|
||||
assert(conn->state == DNSWORKER_STATE_BUSY);
|
||||
if(conn->inbuf_datalen < 4) /* entire answer available? */
|
||||
if(buf_datalen(conn->inbuf) < 4) /* entire answer available? */
|
||||
return 0; /* not yet */
|
||||
assert(conn->inbuf_datalen == 4);
|
||||
assert(buf_datalen(conn->inbuf) == 4);
|
||||
|
||||
connection_fetch_from_buf((char*)&answer,sizeof(answer),conn);
|
||||
|
||||
|
||||
+322
-107
@@ -7,6 +7,7 @@
|
||||
/********* START PROTOTYPES **********/
|
||||
|
||||
static void dumpstats(void); /* dump stats to stdout */
|
||||
static int init_descriptor(void);
|
||||
|
||||
/********* START VARIABLES **********/
|
||||
|
||||
@@ -29,30 +30,42 @@ static int please_reset =0; /* whether we just got a sighup */
|
||||
static int please_reap_children=0; /* whether we should waitpid for exited children*/
|
||||
#endif /* signal stuff */
|
||||
|
||||
/* private key */
|
||||
static crypto_pk_env_t *privatekey=NULL;
|
||||
static crypto_pk_env_t *signing_privatekey=NULL;
|
||||
/* private keys */
|
||||
static crypto_pk_env_t *onionkey=NULL;
|
||||
static crypto_pk_env_t *linkkey=NULL;
|
||||
static crypto_pk_env_t *identitykey=NULL;
|
||||
|
||||
routerinfo_t *my_routerinfo=NULL;
|
||||
|
||||
/********* END VARIABLES ************/
|
||||
|
||||
void set_privatekey(crypto_pk_env_t *k) {
|
||||
privatekey = k;
|
||||
void set_onion_key(crypto_pk_env_t *k) {
|
||||
onionkey = k;
|
||||
}
|
||||
|
||||
crypto_pk_env_t *get_privatekey(void) {
|
||||
assert(privatekey);
|
||||
return privatekey;
|
||||
crypto_pk_env_t *get_onion_key(void) {
|
||||
assert(onionkey);
|
||||
return onionkey;
|
||||
}
|
||||
|
||||
void set_signing_privatekey(crypto_pk_env_t *k) {
|
||||
signing_privatekey = k;
|
||||
void set_link_key(crypto_pk_env_t *k)
|
||||
{
|
||||
linkkey = k;
|
||||
}
|
||||
|
||||
crypto_pk_env_t *get_signing_privatekey(void) {
|
||||
assert(signing_privatekey);
|
||||
return signing_privatekey;
|
||||
crypto_pk_env_t *get_link_key(void)
|
||||
{
|
||||
assert(linkkey);
|
||||
return linkkey;
|
||||
}
|
||||
|
||||
void set_identity_key(crypto_pk_env_t *k) {
|
||||
identitykey = k;
|
||||
}
|
||||
|
||||
crypto_pk_env_t *get_identity_key(void) {
|
||||
assert(identitykey);
|
||||
return identitykey;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -69,7 +82,7 @@ int connection_add(connection_t *conn) {
|
||||
log(LOG_INFO,"connection_add(): failing because nfds is too high.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
conn->poll_index = nfds;
|
||||
connection_set_poll_socket(conn);
|
||||
connection_array[nfds] = conn;
|
||||
@@ -146,7 +159,7 @@ connection_t *connection_twin_get_by_addr_port(uint32_t addr, uint16_t port) {
|
||||
assert(conn);
|
||||
if(connection_state_is_open(conn) &&
|
||||
!conn->marked_for_close &&
|
||||
!crypto_pk_cmp_keys(conn->pkey, router->pkey)) {
|
||||
!crypto_pk_cmp_keys(conn->onion_pkey, router->onion_pkey)) {
|
||||
log(LOG_INFO,"connection_twin_get_by_addr_port(): Found twin (%s).",conn->address);
|
||||
return conn;
|
||||
}
|
||||
@@ -308,13 +321,11 @@ static void check_conn_marked(int i) {
|
||||
if(conn->s >= 0) { /* might be an incomplete edge connection */
|
||||
/* FIXME there's got to be a better way to check for this -- and make other checks? */
|
||||
if(connection_speaks_cells(conn) && conn->state != OR_CONN_STATE_CONNECTING)
|
||||
flush_buf_tls(conn->tls, &conn->outbuf, &conn->outbuflen,
|
||||
&conn->outbuf_flushlen, &conn->outbuf_datalen);
|
||||
flush_buf_tls(conn->tls, conn->outbuf, &conn->outbuf_flushlen);
|
||||
else
|
||||
flush_buf(conn->s, &conn->outbuf, &conn->outbuflen,
|
||||
&conn->outbuf_flushlen, &conn->outbuf_datalen);
|
||||
flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen);
|
||||
if(connection_wants_to_flush(conn)) /* not done flushing */
|
||||
log_fn(LOG_WARNING,"Conn (socket %d) still wants to flush. Losing %d bytes!",conn->s, conn->inbuf_datalen);
|
||||
log_fn(LOG_WARNING,"Conn (socket %d) still wants to flush. Losing %d bytes!",conn->s, (int)buf_datalen(conn->inbuf));
|
||||
}
|
||||
connection_remove(conn);
|
||||
connection_free(conn);
|
||||
@@ -420,70 +431,220 @@ static int prepare_for_poll(void) {
|
||||
return (1000 - (now.tv_usec / 1000)); /* how many milliseconds til the next second? */
|
||||
}
|
||||
|
||||
#define FN_ERROR -1
|
||||
#define FN_NOENT 0
|
||||
#define FN_FILE 1
|
||||
#define FN_DIR 2
|
||||
static int fn_exists(const char *fname)
|
||||
{
|
||||
struct stat st;
|
||||
if (stat(fname, &st)) {
|
||||
if (errno == ENOENT) {
|
||||
return FN_NOENT;
|
||||
}
|
||||
return FN_ERROR;
|
||||
}
|
||||
if (st.st_mode & S_IFDIR)
|
||||
return FN_DIR;
|
||||
else
|
||||
return FN_FILE;
|
||||
}
|
||||
|
||||
static crypto_pk_env_t *init_key_from_file(const char *fname)
|
||||
{
|
||||
crypto_pk_env_t *prkey = NULL;
|
||||
int fd = -1;
|
||||
FILE *file = NULL;
|
||||
|
||||
if (!(prkey = crypto_new_pk_env(CRYPTO_PK_RSA))) {
|
||||
log(LOG_ERR, "Error creating crypto environment.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch(fn_exists(fname)) {
|
||||
case FN_DIR:
|
||||
case FN_ERROR:
|
||||
log(LOG_ERR, "Can't read key from %s", fname);
|
||||
goto error;
|
||||
case FN_NOENT:
|
||||
log(LOG_INFO, "No key found in %s; generating fresh key.", fname);
|
||||
if (crypto_pk_generate_key(prkey)) {
|
||||
log(LOG_ERR, "Error generating key: %s", crypto_perror());
|
||||
goto error;
|
||||
}
|
||||
if (crypto_pk_check_key(prkey) <= 0) {
|
||||
log(LOG_ERR, "Generated key seems invalid");
|
||||
goto error;
|
||||
}
|
||||
log(LOG_INFO, "Generated key seems valid");
|
||||
fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0400);
|
||||
if (fd == -1) {
|
||||
log(LOG_ERR, "Can't open %s for writing", fname);
|
||||
goto error;
|
||||
}
|
||||
file = fdopen(fd, "w");
|
||||
if (!file) {
|
||||
log(LOG_ERR, "Can't fdopen %s for writing", fname);
|
||||
goto error;
|
||||
}
|
||||
if (crypto_pk_write_private_key_to_file(prkey, file) < 0) {
|
||||
log(LOG_ERR, "Can't write private key to %s", fname);
|
||||
goto error;
|
||||
}
|
||||
fclose(file);
|
||||
/* XXX fingerprint */
|
||||
return prkey;
|
||||
case FN_FILE:
|
||||
if (crypto_pk_read_private_key_from_filename(prkey, fname)) {
|
||||
log(LOG_ERR, "Error loading private key.");
|
||||
goto error;
|
||||
}
|
||||
return prkey;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
error:
|
||||
if (prkey)
|
||||
crypto_free_pk_env(prkey);
|
||||
if (fd >= 0 && !file)
|
||||
close(fd);
|
||||
if (file)
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int init_keys(void)
|
||||
{
|
||||
char keydir[512];
|
||||
char fingerprint[FINGERPRINT_LEN+1];
|
||||
char *cp;
|
||||
crypto_pk_env_t *prkey;
|
||||
FILE *file;
|
||||
|
||||
/* OP's don't need keys. Just initialize the TLS context.*/
|
||||
if (!options.OnionRouter && !options.DirPort) {
|
||||
if (tor_tls_context_new(NULL, 0, NULL)<0) {
|
||||
log_fn(LOG_ERR, "Error creating TLS context for OP.");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
assert(options.DataDirectory);
|
||||
if (strlen(options.DataDirectory) > (512-128)) {
|
||||
log_fn(LOG_ERR, "DataDirectory is too long.");
|
||||
return -1;
|
||||
}
|
||||
strcpy(keydir, options.DataDirectory);
|
||||
switch (fn_exists(keydir)) {
|
||||
case FN_NOENT:
|
||||
log_fn(LOG_ERR, "DataDirectory does not exist");
|
||||
return -1;
|
||||
case FN_ERROR:
|
||||
log_fn(LOG_ERR, "DataDirectory can't be read");
|
||||
return -1;
|
||||
case FN_FILE:
|
||||
log_fn(LOG_ERR, "DataDirectory is not a directory.");
|
||||
return -1;
|
||||
}
|
||||
strcat(keydir, "/keys");
|
||||
switch (fn_exists(keydir)) {
|
||||
case FN_NOENT:
|
||||
if (mkdir(keydir, 0700)) {
|
||||
log_fn(LOG_ERR, "Error making key directory.");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case FN_ERROR:
|
||||
log_fn(LOG_ERR, "Error reading key directory.");
|
||||
return -1;
|
||||
case FN_FILE:
|
||||
log_fn(LOG_ERR, "Key directory is not a directory.");
|
||||
return -1;
|
||||
case FN_DIR:
|
||||
chmod(keydir, 0700);
|
||||
break;
|
||||
}
|
||||
cp = keydir + strlen(keydir); /* End of string. */
|
||||
assert(!*cp);
|
||||
|
||||
/* 1. Read identity key. Make it if none is found. */
|
||||
strcat(keydir, "/identity.key");
|
||||
prkey = init_key_from_file(keydir);
|
||||
if (!prkey) return -1;
|
||||
set_identity_key(prkey);
|
||||
/* 2. Read onion key. Make it if none is found. */
|
||||
*cp = '\0';
|
||||
strcat(keydir, "/onion.key");
|
||||
prkey = init_key_from_file(keydir);
|
||||
if (!prkey) return -1;
|
||||
set_onion_key(prkey);
|
||||
|
||||
/* 3. Initialize link key and TLS context. */
|
||||
*cp = '\0';
|
||||
strcat(keydir, "/link.key");
|
||||
prkey = init_key_from_file(keydir);
|
||||
if (!prkey) return -1;
|
||||
set_link_key(prkey);
|
||||
if (tor_tls_context_new(prkey, 1, options.Nickname) < 0) {
|
||||
log_fn(LOG_ERR, "Error initializing TLS context");
|
||||
return -1;
|
||||
}
|
||||
/* 4. Dump router descriptor to 'router.desc' */
|
||||
/* Must be called after keys are initialized. */
|
||||
if (init_descriptor()<0) {
|
||||
log_fn(LOG_ERR, "Error initializing descriptor.");
|
||||
return -1;
|
||||
}
|
||||
strcpy(keydir, options.DataDirectory);
|
||||
strcat(keydir, "/router.desc");
|
||||
file = fopen(keydir, "w");
|
||||
if (!file) {
|
||||
log_fn(LOG_ERR, "Error opening %s for writing", keydir);
|
||||
return -1;
|
||||
}
|
||||
fputs(router_get_my_descriptor(), file);
|
||||
fclose(file);
|
||||
/* 5. Dump fingerprint to 'fingerprint' */
|
||||
strcpy(keydir, options.DataDirectory);
|
||||
strcat(keydir, "/fingerprint");
|
||||
file = fopen(keydir, "w");
|
||||
if (!file) {
|
||||
log_fn(LOG_ERR, "Error opening %s for writing", keydir);
|
||||
return -1;
|
||||
}
|
||||
if (crypto_pk_get_fingerprint(get_identity_key(), fingerprint)<0) {
|
||||
log_fn(LOG_ERR, "Error computing fingerprint");
|
||||
return -1;
|
||||
}
|
||||
fprintf(file, "%s %s\n", options.Nickname, fingerprint);
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_main_loop(void) {
|
||||
int i;
|
||||
int timeout;
|
||||
int poll_result;
|
||||
crypto_pk_env_t *prkey;
|
||||
|
||||
|
||||
/* load the routers file */
|
||||
if(router_get_list_from_file(options.RouterFile) < 0) {
|
||||
log(LOG_ERR,"Error loading router list.");
|
||||
log_fn(LOG_ERR,"Error loading router list.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* load the private keys, if we're supposed to have them, and set up the
|
||||
* TLS context. */
|
||||
if (init_keys() < 0) {
|
||||
log_fn(LOG_ERR,"Error initializing keys; exiting");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* load the private key, if we're supposed to have one */
|
||||
if(options.OnionRouter) {
|
||||
prkey = crypto_new_pk_env(CRYPTO_PK_RSA);
|
||||
if (!prkey) {
|
||||
log(LOG_ERR,"Error creating a crypto environment.");
|
||||
return -1;
|
||||
}
|
||||
if (crypto_pk_read_private_key_from_filename(prkey, options.PrivateKeyFile)) {
|
||||
log(LOG_ERR,"Error loading private key.");
|
||||
return -1;
|
||||
}
|
||||
set_privatekey(prkey);
|
||||
cpu_init(); /* launch cpuworkers. Need to do this *after* we've read the private key. */
|
||||
}
|
||||
|
||||
/* load the directory private key, if we're supposed to have one */
|
||||
if(options.DirPort) {
|
||||
prkey = crypto_new_pk_env(CRYPTO_PK_RSA);
|
||||
if (!prkey) {
|
||||
log(LOG_ERR,"Error creating a crypto environment.");
|
||||
return -1;
|
||||
}
|
||||
if (crypto_pk_read_private_key_from_filename(prkey, options.SigningPrivateKeyFile)) {
|
||||
log(LOG_ERR,"Error loading private key.");
|
||||
return -1;
|
||||
}
|
||||
set_signing_privatekey(prkey);
|
||||
}
|
||||
|
||||
if(options.OnionRouter) {
|
||||
struct stat statbuf;
|
||||
if(stat(options.CertFile, &statbuf) < 0) {
|
||||
log_fn(LOG_INFO,"CertFile %s is missing. Generating.", options.CertFile);
|
||||
if(tor_tls_write_certificate(options.CertFile,
|
||||
get_privatekey(),
|
||||
options.Nickname) < 0) {
|
||||
log_fn(LOG_ERR,"Couldn't write CertFile %s. Dying.", options.CertFile);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(tor_tls_context_new(options.CertFile, get_privatekey(), 1) < 0) {
|
||||
log_fn(LOG_ERR,"Error creating tls context.");
|
||||
return -1;
|
||||
}
|
||||
} else { /* just a proxy, the context is easy */
|
||||
if(tor_tls_context_new(NULL, NULL, 0) < 0) {
|
||||
log_fn(LOG_ERR,"Error creating tls context.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* start up the necessary connections based on which ports are
|
||||
* non-zero. This is where we try to connect to all the other ORs,
|
||||
* and start the listeners.
|
||||
@@ -590,9 +751,10 @@ static void dumpstats(void) { /* dump stats to stdout */
|
||||
conn->state, conn_state_to_string[conn->type][conn->state], now.tv_sec - conn->timestamp_created);
|
||||
if(!connection_is_listener(conn)) {
|
||||
printf("Conn %d is to '%s:%d'.\n",i,conn->address, conn->port);
|
||||
printf("Conn %d: %d bytes waiting on inbuf (last read %ld secs ago)\n",i,conn->inbuf_datalen,
|
||||
now.tv_sec - conn->timestamp_lastread);
|
||||
printf("Conn %d: %d bytes waiting on outbuf (last written %ld secs ago)\n",i,conn->outbuf_datalen,
|
||||
printf("Conn %d: %d bytes waiting on inbuf (last read %ld secs ago)\n",i,
|
||||
(int)buf_datalen(conn->inbuf),
|
||||
now.tv_sec - conn->timestamp_lastread);
|
||||
printf("Conn %d: %d bytes waiting on outbuf (last written %ld secs ago)\n",i,(int)buf_datalen(conn->outbuf),
|
||||
now.tv_sec - conn->timestamp_lastwritten);
|
||||
}
|
||||
circuit_dump_by_conn(conn); /* dump info about all the circuits using this conn */
|
||||
@@ -601,42 +763,50 @@ static void dumpstats(void) { /* dump stats to stdout */
|
||||
|
||||
}
|
||||
|
||||
int dump_router_to_string(char *s, int maxlen, routerinfo_t *router) {
|
||||
char *pkey;
|
||||
char *signing_pkey, *signing_pkey_tag;
|
||||
int pkeylen, signing_pkeylen;
|
||||
int dump_router_to_string(char *s, int maxlen, routerinfo_t *router,
|
||||
crypto_pk_env_t *ident_key) {
|
||||
char *onion_pkey;
|
||||
char *link_pkey;
|
||||
char *identity_pkey;
|
||||
char digest[20];
|
||||
char signature[128];
|
||||
int onion_pkeylen, link_pkeylen, identity_pkeylen;
|
||||
int written;
|
||||
int result=0;
|
||||
struct exit_policy_t *tmpe;
|
||||
|
||||
if(crypto_pk_write_public_key_to_string(router->pkey,&pkey,&pkeylen)<0) {
|
||||
log(LOG_ERR,"dump_router_to_string(): write pkey to string failed!");
|
||||
return 0;
|
||||
if(crypto_pk_write_public_key_to_string(router->onion_pkey,
|
||||
&onion_pkey,&onion_pkeylen)<0) {
|
||||
log_fn(LOG_ERR,"write onion_pkey to string failed!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
signing_pkey = "";
|
||||
signing_pkey_tag = "";
|
||||
if (router->signing_pkey) {
|
||||
if(crypto_pk_write_public_key_to_string(router->signing_pkey,
|
||||
&signing_pkey,&signing_pkeylen)<0) {
|
||||
log(LOG_ERR,"dump_router_to_string(): write signing_pkey to string failed!");
|
||||
return 0;
|
||||
}
|
||||
signing_pkey_tag = "signing-key\n";
|
||||
if(crypto_pk_write_public_key_to_string(router->identity_pkey,
|
||||
&identity_pkey,&identity_pkeylen)<0) {
|
||||
log_fn(LOG_ERR,"write identity_pkey to string failed!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(crypto_pk_write_public_key_to_string(router->link_pkey,
|
||||
&link_pkey,&link_pkeylen)<0) {
|
||||
log_fn(LOG_ERR,"write link_pkey to string failed!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = snprintf(s, maxlen, "router %s %d %d %d %d\n%s%s%s",
|
||||
result = snprintf(s, maxlen,
|
||||
"router %s %d %d %d %d\nonion-key\n%s"
|
||||
"link-key\n%s"
|
||||
"signing-key\n%s",
|
||||
router->address,
|
||||
router->or_port,
|
||||
router->ap_port,
|
||||
router->dir_port,
|
||||
router->bandwidth,
|
||||
pkey,
|
||||
signing_pkey_tag, signing_pkey);
|
||||
onion_pkey, link_pkey, identity_pkey);
|
||||
|
||||
free(pkey);
|
||||
if (*signing_pkey)
|
||||
free(signing_pkey);
|
||||
free(onion_pkey);
|
||||
free(link_pkey);
|
||||
free(identity_pkey);
|
||||
|
||||
if(result < 0 || result > maxlen) {
|
||||
/* apparently different glibcs do different things on snprintf error.. so check both */
|
||||
@@ -654,19 +824,34 @@ int dump_router_to_string(char *s, int maxlen, routerinfo_t *router) {
|
||||
}
|
||||
written += result;
|
||||
}
|
||||
if (written > maxlen-256) /* Not enough room for signature. */
|
||||
return -1;
|
||||
|
||||
if(written > maxlen-2) {
|
||||
return -1; /* not enough space for \n\0 */
|
||||
strcat(s+written, "router-signature\n");
|
||||
written += strlen(s+written);
|
||||
s[written] = '\0';
|
||||
if (router_get_router_hash(s, digest) < 0)
|
||||
return -1;
|
||||
|
||||
if (crypto_pk_private_sign(ident_key, digest, 20, signature) < 0) {
|
||||
log_fn(LOG_ERR, "Error signing digest");
|
||||
return -1;
|
||||
}
|
||||
/* XXX count fenceposts here. They're probably wrong. In general,
|
||||
* we need a better way to handle overruns in building the directory
|
||||
* string, and a better way to handle directory string size in general. */
|
||||
|
||||
strcat(s+written, "-----BEGIN SIGNATURE-----\n");
|
||||
written += strlen(s+written);
|
||||
if (base64_encode(s+written, maxlen-written, signature, 128) < 0) {
|
||||
log_fn(LOG_ERR, "Couldn't base64-encode signature");
|
||||
}
|
||||
written += strlen(s+written);
|
||||
strcat(s+written, "-----END SIGNATURE-----\n");
|
||||
written += strlen(s+written);
|
||||
|
||||
if (written > maxlen-2)
|
||||
return -1;
|
||||
/* include a last '\n' */
|
||||
s[written] = '\n';
|
||||
s[written+1] = 0;
|
||||
return written+1;
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -738,7 +923,10 @@ dump_signed_directory_to_string_impl(char *s, int maxlen, directory_t *dir,
|
||||
cp = s+i;
|
||||
for (i = 0; i < dir->n_routers; ++i) {
|
||||
router = dir->routers[i];
|
||||
written = dump_router_to_string(cp, eos-cp, router);
|
||||
/* XXX This is wrong; we shouldn't sign routers, but rather propagate
|
||||
* XXX the original router blocks, unaltered.
|
||||
*/
|
||||
written = dump_router_to_string(cp, eos-cp, router, private_key);
|
||||
|
||||
if(written < 0) {
|
||||
log(LOG_ERR,"dump_signed_directory_to_string(): tried to exceed string length.");
|
||||
@@ -789,8 +977,35 @@ dump_signed_directory_to_string_impl(char *s, int maxlen, directory_t *dir,
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *router_get_my_descriptor(void) {
|
||||
return "this is bob's descriptor";
|
||||
static char descriptor[8192];
|
||||
/* XXX should this replace my_routerinfo? */
|
||||
static routerinfo_t *desc_routerinfo;
|
||||
const char *router_get_my_descriptor(void) {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
static int init_descriptor(void) {
|
||||
routerinfo_t *ri;
|
||||
ri = tor_malloc(sizeof(routerinfo_t));
|
||||
ri->address = strdup("XXXXXXX"); /*XXX*/
|
||||
ri->nickname = strdup(options.Nickname);
|
||||
/* No need to set addr. ???? */
|
||||
ri->or_port = options.ORPort;
|
||||
ri->ap_port = options.APPort;
|
||||
ri->dir_port = options.DirPort;
|
||||
ri->onion_pkey = crypto_pk_dup_key(get_onion_key());
|
||||
ri->link_pkey = crypto_pk_dup_key(get_link_key());
|
||||
ri->identity_pkey = crypto_pk_dup_key(get_identity_key());
|
||||
ri->bandwidth = options.TotalBandwidth;
|
||||
ri->exit_policy = NULL; /* XXX implement this. */
|
||||
if (desc_routerinfo)
|
||||
routerinfo_free(desc_routerinfo);
|
||||
desc_routerinfo = ri;
|
||||
if (dump_router_to_string(descriptor, 8192, ri, get_identity_key())<0) {
|
||||
log_fn(LOG_ERR, "Couldn't dump router to string.");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void daemonize(void) {
|
||||
@@ -840,7 +1055,7 @@ int tor_main(int argc, char *argv[]) {
|
||||
crypto_seed_rng();
|
||||
retval = do_main_loop();
|
||||
crypto_global_cleanup();
|
||||
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@@ -231,7 +231,7 @@ static unsigned int *new_route(double cw, routerinfo_t **rarray, int rarray_len,
|
||||
choice = choice % rarray_len;
|
||||
log(LOG_DEBUG,"new_route(): Contemplating router %u.",choice);
|
||||
if(choice == oldchoice ||
|
||||
(oldchoice < rarray_len && !crypto_pk_cmp_keys(rarray[choice]->pkey, rarray[oldchoice]->pkey)) ||
|
||||
(oldchoice < rarray_len && !crypto_pk_cmp_keys(rarray[choice]->onion_pkey, rarray[oldchoice]->onion_pkey)) ||
|
||||
(options.OnionRouter && !connection_twin_get_by_addr_port(rarray[choice]->addr, rarray[choice]->or_port))) {
|
||||
/* Same router as last choice, or router twin,
|
||||
* or no routers with that key are connected to us.
|
||||
@@ -263,7 +263,7 @@ static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len) {
|
||||
}
|
||||
}
|
||||
for(j=0;j<i;j++) {
|
||||
if(!crypto_pk_cmp_keys(rarray[i]->pkey, rarray[j]->pkey)) {
|
||||
if(!crypto_pk_cmp_keys(rarray[i]->onion_pkey, rarray[j]->onion_pkey)) {
|
||||
/* these guys are twins. so we've already counted him. */
|
||||
log(LOG_DEBUG,"Nope, %d is a twin of %d.",i,j);
|
||||
goto next_i_loop;
|
||||
@@ -311,8 +311,8 @@ crypt_path_t *onion_generate_cpath(routerinfo_t **firsthop) {
|
||||
log(LOG_DEBUG,"onion_generate_cpath(): %u : %s:%u, %u/%u",routelen-i,
|
||||
inet_ntoa(netaddr),
|
||||
(rarray[route[i]])->or_port,
|
||||
(int) (rarray[route[i]])->pkey,
|
||||
crypto_pk_keysize((rarray[route[i]])->pkey));
|
||||
(int) (rarray[route[i]])->onion_pkey,
|
||||
crypto_pk_keysize((rarray[route[i]])->onion_pkey));
|
||||
}
|
||||
|
||||
/* create the cpath layer by layer, starting at the last hop */
|
||||
|
||||
+38
-30
@@ -245,6 +245,8 @@ typedef struct {
|
||||
|
||||
#define ZERO_STREAM "\0\0\0\0\0\0\0\0"
|
||||
|
||||
typedef struct buf_t buf_t;
|
||||
|
||||
struct connection_t {
|
||||
|
||||
uint8_t type;
|
||||
@@ -261,16 +263,12 @@ struct connection_t {
|
||||
* iteration of the main loop?
|
||||
*/
|
||||
|
||||
char *inbuf;
|
||||
int inbuflen; /* how many bytes are alloc'ed for inbuf? */
|
||||
int inbuf_datalen; /* how many bytes of data are on inbuf? */
|
||||
buf_t *inbuf;
|
||||
int inbuf_reached_eof; /* did read() return 0 on this conn? */
|
||||
long timestamp_lastread; /* when was the last time poll() said we could read? */
|
||||
|
||||
char *outbuf;
|
||||
int outbuflen; /* how many bytes are allocated for the outbuf? */
|
||||
buf_t *outbuf;
|
||||
int outbuf_flushlen; /* how much data should we try to flush from the outbuf? */
|
||||
int outbuf_datalen; /* how much data is there total on the outbuf? */
|
||||
long timestamp_lastwritten; /* when was the last time poll() said we could write? */
|
||||
|
||||
long timestamp_created; /* when was this connection_t created? */
|
||||
@@ -287,7 +285,9 @@ struct connection_t {
|
||||
char *address; /* FQDN (or IP) of the guy on the other end.
|
||||
* strdup into this, because free_connection frees it
|
||||
*/
|
||||
crypto_pk_env_t *pkey; /* public RSA key for the other side */
|
||||
crypto_pk_env_t *onion_pkey; /* public RSA key for the other side's onions */
|
||||
crypto_pk_env_t *link_pkey; /* public RSA key for the other side's TLS */
|
||||
crypto_pk_env_t *identity_pkey; /* public RSA key for the other side's signing */
|
||||
|
||||
/* Used only by OR connections: */
|
||||
tor_tls *tls;
|
||||
@@ -331,8 +331,9 @@ typedef struct {
|
||||
uint16_t ap_port;
|
||||
uint16_t dir_port;
|
||||
|
||||
crypto_pk_env_t *pkey; /* public RSA key */
|
||||
crypto_pk_env_t *signing_pkey; /* May be null */
|
||||
crypto_pk_env_t *onion_pkey; /* public RSA key for onions */
|
||||
crypto_pk_env_t *link_pkey; /* public RSA key for TLS */
|
||||
crypto_pk_env_t *identity_pkey; /* public RSA key for signing */
|
||||
|
||||
/* link info */
|
||||
uint32_t bandwidth;
|
||||
@@ -405,10 +406,8 @@ typedef struct circuit_t circuit_t;
|
||||
|
||||
typedef struct {
|
||||
char *LogLevel;
|
||||
char *DataDirectory;
|
||||
char *RouterFile;
|
||||
char *SigningPrivateKeyFile;
|
||||
char *PrivateKeyFile;
|
||||
char *CertFile;
|
||||
char *Nickname;
|
||||
double CoinWeight;
|
||||
int Daemon;
|
||||
@@ -435,24 +434,29 @@ typedef struct {
|
||||
|
||||
/********************************* buffers.c ***************************/
|
||||
|
||||
int buf_new(char **buf, int *buflen, int *buf_datalen);
|
||||
void buf_free(char *buf);
|
||||
buf_t *buf_new();
|
||||
buf_t *buf_new_with_capacity(size_t size);
|
||||
void buf_free(buf_t *buf);
|
||||
|
||||
int read_to_buf(int s, int at_most, char **buf, int *buflen, int *buf_datalen, int *reached_eof);
|
||||
int read_to_buf_tls(tor_tls *tls, int at_most, char **buf, int *buflen, int *buf_datalen);
|
||||
size_t buf_datalen(const buf_t *buf);
|
||||
size_t buf_capacity(const buf_t *buf);
|
||||
const char *_buf_peek_raw_buffer(const buf_t *buf);
|
||||
|
||||
int flush_buf(int s, char **buf, int *buflen, int *buf_flushlen, int *buf_datalen);
|
||||
int flush_buf_tls(tor_tls *tls, char **buf, int *buflen, int *buf_flushlen, int *buf_datalen);
|
||||
int read_to_buf(int s, int at_most, buf_t *buf, int *reached_eof);
|
||||
int read_to_buf_tls(tor_tls *tls, int at_most, buf_t *buf);
|
||||
|
||||
int write_to_buf(char *string, int string_len, char **buf, int *buflen, int *buf_datalen);
|
||||
int fetch_from_buf(char *string, int string_len, char **buf, int *buflen, int *buf_datalen);
|
||||
int fetch_from_buf_http(char *buf, int *buf_datalen,
|
||||
int flush_buf(int s, buf_t *buf, int *buf_flushlen);
|
||||
int flush_buf_tls(tor_tls *tls, buf_t *buf, int *buf_flushlen);
|
||||
|
||||
int write_to_buf(char *string, int string_len, buf_t *buf);
|
||||
int fetch_from_buf(char *string, int string_len, buf_t *buf);
|
||||
int fetch_from_buf_http(buf_t *buf,
|
||||
char *headers_out, int max_headerlen,
|
||||
char *body_out, int max_bodylen);
|
||||
int fetch_from_buf_socks(char *buf, int *buf_datalen,
|
||||
int fetch_from_buf_socks(buf_t *buf,
|
||||
char *addr_out, int max_addrlen,
|
||||
uint16_t *port_out);
|
||||
int find_on_inbuf(char *string, int string_len, char *buf, int buf_datalen);
|
||||
int find_on_inbuf(char *string, int string_len, buf_t *buf);
|
||||
|
||||
/********************************* circuit.c ***************************/
|
||||
|
||||
@@ -589,10 +593,10 @@ int dns_resolve(connection_t *exitconn);
|
||||
|
||||
/********************************* main.c ***************************/
|
||||
|
||||
void set_privatekey(crypto_pk_env_t *k);
|
||||
crypto_pk_env_t *get_privatekey(void);
|
||||
void set_signing_privatekey(crypto_pk_env_t *k);
|
||||
crypto_pk_env_t *get_signing_privatekey(void);
|
||||
void set_onion_key(crypto_pk_env_t *k);
|
||||
crypto_pk_env_t *get_onion_key(void);
|
||||
void set_identity_key(crypto_pk_env_t *k);
|
||||
crypto_pk_env_t *get_identity_key(void);
|
||||
int connection_add(connection_t *conn);
|
||||
int connection_remove(connection_t *conn);
|
||||
void connection_set_poll_socket(connection_t *conn);
|
||||
@@ -617,7 +621,7 @@ int dump_signed_directory_to_string(char *s, int maxlen,
|
||||
int dump_signed_directory_to_string_impl(char *s, int maxlen,
|
||||
directory_t *dir,
|
||||
crypto_pk_env_t *private_key);
|
||||
char *router_get_my_descriptor(void);
|
||||
const char *router_get_my_descriptor(void);
|
||||
|
||||
int main(int argc, char *argv[]);
|
||||
|
||||
@@ -655,16 +659,20 @@ int learn_my_address(struct sockaddr_in *me);
|
||||
void router_retry_connections(void);
|
||||
routerinfo_t *router_pick_directory_server(void);
|
||||
routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port);
|
||||
routerinfo_t *router_get_by_pk(crypto_pk_env_t *pk);
|
||||
routerinfo_t *router_get_by_link_pk(crypto_pk_env_t *pk);
|
||||
#if 0
|
||||
routerinfo_t *router_get_by_identity_pk(crypto_pk_env_t *pk);
|
||||
#endif
|
||||
void router_get_directory(directory_t **pdirectory);
|
||||
int router_is_me(uint32_t addr, uint16_t port);
|
||||
void router_forget_router(uint32_t addr, uint16_t port);
|
||||
int router_get_list_from_file(char *routerfile);
|
||||
int router_get_router_hash(char *s, char *digest);
|
||||
|
||||
/* Reads a list of known routers, unsigned. */
|
||||
int router_get_list_from_string(char *s);
|
||||
/* Exported for debugging */
|
||||
int router_get_list_from_string_impl(char *s, directory_t **dest);
|
||||
int router_get_list_from_string_impl(char **s, directory_t **dest);
|
||||
/* Reads a signed directory. */
|
||||
int router_get_dir_from_string(char *s, crypto_pk_env_t *pkey);
|
||||
/* Exported or debugging */
|
||||
|
||||
+151
-80
@@ -28,10 +28,6 @@ static char *eat_whitespace(char *s);
|
||||
static char *eat_whitespace_no_nl(char *s);
|
||||
static char *find_whitespace(char *s);
|
||||
static void router_free_exit_policy(routerinfo_t *router);
|
||||
static routerinfo_t *router_get_entry_from_string_tok(char**s,
|
||||
directory_token_t *tok);
|
||||
static int router_get_list_from_string_tok(char **s, directory_t **dest,
|
||||
directory_token_t *tok);
|
||||
static int router_add_exit_policy(routerinfo_t *router,
|
||||
directory_token_t *tok);
|
||||
static int
|
||||
@@ -119,7 +115,24 @@ routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
routerinfo_t *router_get_by_pk(crypto_pk_env_t *pk)
|
||||
routerinfo_t *router_get_by_link_pk(crypto_pk_env_t *pk)
|
||||
{
|
||||
int i;
|
||||
routerinfo_t *router;
|
||||
|
||||
assert(directory);
|
||||
|
||||
for(i=0;i<directory->n_routers;i++) {
|
||||
router = directory->routers[i];
|
||||
if (0 == crypto_pk_cmp_keys(router->link_pkey, pk))
|
||||
return router;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
routerinfo_t *router_get_by_identity_pk(crypto_pk_env_t *pk)
|
||||
{
|
||||
int i;
|
||||
routerinfo_t *router;
|
||||
@@ -129,13 +142,14 @@ routerinfo_t *router_get_by_pk(crypto_pk_env_t *pk)
|
||||
for(i=0;i<directory->n_routers;i++) {
|
||||
router = directory->routers[i];
|
||||
/* XXX Should this really be a separate link key? */
|
||||
if (0 == crypto_pk_cmp_keys(router->pkey, pk))
|
||||
if (0 == crypto_pk_cmp_keys(router->identity_pkey, pk))
|
||||
return router;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void router_get_directory(directory_t **pdirectory) {
|
||||
*pdirectory = directory;
|
||||
@@ -174,10 +188,12 @@ void routerinfo_free(routerinfo_t *router)
|
||||
|
||||
if (router->address)
|
||||
free(router->address);
|
||||
if (router->pkey)
|
||||
crypto_free_pk_env(router->pkey);
|
||||
if (router->signing_pkey)
|
||||
crypto_free_pk_env(router->signing_pkey);
|
||||
if (router->onion_pkey)
|
||||
crypto_free_pk_env(router->onion_pkey);
|
||||
if (router->link_pkey)
|
||||
crypto_free_pk_env(router->link_pkey);
|
||||
if (router->identity_pkey)
|
||||
crypto_free_pk_env(router->identity_pkey);
|
||||
e = router->exit_policy;
|
||||
while (e) {
|
||||
etmp = e->next;
|
||||
@@ -195,7 +211,8 @@ void directory_free(directory_t *directory)
|
||||
int i;
|
||||
for (i = 0; i < directory->n_routers; ++i)
|
||||
routerinfo_free(directory->routers[i]);
|
||||
free(directory->routers);
|
||||
if (directory->routers)
|
||||
free(directory->routers);
|
||||
if(directory->software_versions)
|
||||
free(directory->software_versions);
|
||||
free(directory);
|
||||
@@ -282,6 +299,9 @@ typedef enum {
|
||||
K_ROUTER,
|
||||
K_SIGNED_DIRECTORY,
|
||||
K_SIGNING_KEY,
|
||||
K_ONION_KEY,
|
||||
K_LINK_KEY,
|
||||
K_ROUTER_SIGNATURE,
|
||||
_SIGNATURE,
|
||||
_PUBLIC_KEY,
|
||||
_ERR,
|
||||
@@ -298,6 +318,9 @@ static struct token_table_ent token_table[] = {
|
||||
{ "recommended-software", K_RECOMMENDED_SOFTWARE },
|
||||
{ "signed-directory", K_SIGNED_DIRECTORY },
|
||||
{ "signing-key", K_SIGNING_KEY },
|
||||
{ "onion-key", K_ONION_KEY },
|
||||
{ "link-key", K_LINK_KEY },
|
||||
{ "router-signature", K_ROUTER_SIGNATURE },
|
||||
{ NULL, -1 }
|
||||
};
|
||||
|
||||
@@ -450,6 +473,9 @@ router_dump_token(directory_token_t *tok) {
|
||||
case K_ROUTER: printf("Router"); break;
|
||||
case K_SIGNED_DIRECTORY: printf("Signed-Directory"); break;
|
||||
case K_SIGNING_KEY: printf("Signing-Key"); break;
|
||||
case K_ONION_KEY: printf("Onion-key"); break;
|
||||
case K_LINK_KEY: printf("Link-key"); break;
|
||||
case K_ROUTER_SIGNATURE: printf("Router-signature"); break;
|
||||
default:
|
||||
printf("?????? %d\n", tok->tp); return;
|
||||
}
|
||||
@@ -459,7 +485,6 @@ router_dump_token(directory_token_t *tok) {
|
||||
printf("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
router_get_next_token(char **s, directory_token_t *tok) {
|
||||
int i;
|
||||
@@ -508,7 +533,7 @@ static char *find_whitespace(char *s) {
|
||||
|
||||
int router_get_list_from_string(char *s)
|
||||
{
|
||||
if (router_get_list_from_string_impl(s, &directory)) {
|
||||
if (router_get_list_from_string_impl(&s, &directory)) {
|
||||
log(LOG_ERR, "Error parsing router file");
|
||||
return -1;
|
||||
}
|
||||
@@ -519,43 +544,46 @@ int router_get_list_from_string(char *s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int router_get_list_from_string_impl(char *s, directory_t **dest) {
|
||||
directory_token_t tok;
|
||||
if (router_get_next_token(&s, &tok)) {
|
||||
log(LOG_ERR, "Error reading routers: %s", tok.val.error);
|
||||
return -1;
|
||||
}
|
||||
return router_get_list_from_string_tok(&s, dest, &tok);
|
||||
}
|
||||
|
||||
static int router_get_dir_hash(char *s, char *digest)
|
||||
static int router_get_hash_impl(char *s, char *digest, const char *start_str,
|
||||
const char *end_str)
|
||||
{
|
||||
char *start, *end;
|
||||
start = strstr(s, "signed-directory");
|
||||
start = strstr(s, start_str);
|
||||
if (!start) {
|
||||
log(LOG_ERR,"router_get_dir_hash(): couldn't find \"signed-directory\"");
|
||||
log_fn(LOG_ERR,"couldn't find \"%s\"",start_str);
|
||||
return -1;
|
||||
}
|
||||
end = strstr(start, "directory-signature");
|
||||
end = strstr(start+strlen(start_str), end_str);
|
||||
if (!end) {
|
||||
log(LOG_ERR,"router_get_dir_hash(): couldn't find \"directory-signature\"");
|
||||
log_fn(LOG_ERR,"couldn't find \"%s\"",end_str);
|
||||
return -1;
|
||||
}
|
||||
end = strchr(end, '\n');
|
||||
if (!end) {
|
||||
log(LOG_ERR,"router_get_dir_hash(): couldn't find EOL");
|
||||
log_fn(LOG_ERR,"couldn't find EOL");
|
||||
return -1;
|
||||
}
|
||||
++end;
|
||||
|
||||
if (crypto_SHA_digest(start, end-start, digest)) {
|
||||
log(LOG_ERR,"router_get_dir_hash(): couldn't compute digest");
|
||||
log_fn(LOG_ERR,"couldn't compute digest");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int router_get_dir_hash(char *s, char *digest)
|
||||
{
|
||||
return router_get_hash_impl(s,digest,
|
||||
"signed-directory","directory-signature");
|
||||
}
|
||||
int router_get_router_hash(char *s, char *digest)
|
||||
{
|
||||
return router_get_hash_impl(s,digest,
|
||||
"router ","router-signature");
|
||||
}
|
||||
|
||||
/* return 0 if myversion is in start. Else return -1. */
|
||||
int compare_recommended_versions(char *myversion, char *start) {
|
||||
int len_myversion = strlen(myversion);
|
||||
@@ -621,12 +649,11 @@ int router_get_dir_from_string_impl(char *s, directory_t **dest,
|
||||
log(LOG_ERR, "Error reading directory: expected %s", name); \
|
||||
return -1; \
|
||||
} } while(0)
|
||||
|
||||
|
||||
if (router_get_dir_hash(s, digest)) {
|
||||
log(LOG_ERR, "Unable to compute digest of directory");
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
NEXT_TOK();
|
||||
TOK_IS(K_SIGNED_DIRECTORY, "signed-directory");
|
||||
|
||||
@@ -634,17 +661,17 @@ int router_get_dir_from_string_impl(char *s, directory_t **dest,
|
||||
TOK_IS(K_RECOMMENDED_SOFTWARE, "recommended-software");
|
||||
if (tok.val.cmd.n_args != 1) {
|
||||
log(LOG_ERR, "Invalid recommded-software line");
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
versions = strdup(tok.val.cmd.args[0]);
|
||||
|
||||
NEXT_TOK();
|
||||
if (router_get_list_from_string_tok(&s, &new_dir, &tok)) {
|
||||
if (router_get_list_from_string_impl(&s, &new_dir)) {
|
||||
log(LOG_ERR, "Error reading routers from directory");
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
new_dir->software_versions = versions;
|
||||
|
||||
|
||||
NEXT_TOK();
|
||||
TOK_IS(K_DIRECTORY_SIGNATURE, "directory-signature");
|
||||
NEXT_TOK();
|
||||
TOK_IS(_SIGNATURE, "signature");
|
||||
@@ -653,12 +680,12 @@ int router_get_dir_from_string_impl(char *s, directory_t **dest,
|
||||
!= 20) {
|
||||
log(LOG_ERR, "Error reading directory: invalid signature.");
|
||||
free(tok.val.signature);
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
if (memcmp(digest, signed_digest, 20)) {
|
||||
log(LOG_ERR, "Error reading directory: signature does not match.");
|
||||
free(tok.val.signature);
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
free(tok.val.signature);
|
||||
@@ -671,12 +698,16 @@ int router_get_dir_from_string_impl(char *s, directory_t **dest,
|
||||
*dest = new_dir;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (new_dir)
|
||||
directory_free(new_dir);
|
||||
return -1;
|
||||
#undef NEXT_TOK
|
||||
#undef TOK_IS
|
||||
}
|
||||
|
||||
static int router_get_list_from_string_tok(char **s, directory_t **dest,
|
||||
directory_token_t *tok)
|
||||
int router_get_list_from_string_impl(char **s, directory_t **dest)
|
||||
{
|
||||
routerinfo_t *router;
|
||||
routerinfo_t **rarray;
|
||||
@@ -686,8 +717,11 @@ static int router_get_list_from_string_tok(char **s, directory_t **dest,
|
||||
|
||||
rarray = (routerinfo_t **)tor_malloc((sizeof(routerinfo_t *))*MAX_ROUTERS_IN_DIR);
|
||||
|
||||
while (tok->tp == K_ROUTER) {
|
||||
router = router_get_entry_from_string_tok(s, tok);
|
||||
while (1) {
|
||||
*s = eat_whitespace(*s);
|
||||
if (strncmp(*s, "router ", 7)!=0)
|
||||
break;
|
||||
router = router_get_entry_from_string(s);
|
||||
if (!router) {
|
||||
log(LOG_ERR, "Error reading router");
|
||||
return -1;
|
||||
@@ -755,34 +789,32 @@ router_resolve_directory(directory_t *dir)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
routerinfo_t *router_get_entry_from_string(char **s) {
|
||||
directory_token_t tok;
|
||||
routerinfo_t *router;
|
||||
if (router_get_next_token(s, &tok)) return NULL;
|
||||
router = router_get_entry_from_string_tok(s, &tok);
|
||||
if (tok.tp != _EOF) {
|
||||
router_release_token(&tok);
|
||||
return NULL;
|
||||
}
|
||||
return router;
|
||||
}
|
||||
|
||||
/* reads a single router entry from s.
|
||||
* updates s so it points to after the router it just read.
|
||||
* mallocs a new router, returns it if all goes well, else returns NULL.
|
||||
*/
|
||||
static routerinfo_t *router_get_entry_from_string_tok(char**s, directory_token_t *tok) {
|
||||
routerinfo_t *router_get_entry_from_string(char**s) {
|
||||
routerinfo_t *router = NULL;
|
||||
#if 0
|
||||
char signed_digest[128];
|
||||
#endif
|
||||
char digest[128];
|
||||
directory_token_t _tok;
|
||||
directory_token_t *tok = &_tok;
|
||||
|
||||
#define NEXT_TOKEN() \
|
||||
do { if (router_get_next_token(s, tok)) { \
|
||||
log(LOG_ERR, "Error reading directory: %s", tok->val.error); \
|
||||
goto err; \
|
||||
#define NEXT_TOKEN() \
|
||||
do { if (router_get_next_token(s, tok)) { \
|
||||
log(LOG_ERR, "Error reading directory: %s", tok->val.error); \
|
||||
goto err; \
|
||||
} } while(0)
|
||||
|
||||
#define ARGS tok->val.cmd.args
|
||||
|
||||
if (router_get_router_hash(*s, digest) < 0)
|
||||
return NULL;
|
||||
|
||||
NEXT_TOKEN();
|
||||
|
||||
if (tok->tp != K_ROUTER) {
|
||||
router_release_token(tok);
|
||||
log(LOG_ERR,"router_get_entry_from_string(): Entry does not start with \"router\"");
|
||||
@@ -793,7 +825,7 @@ static routerinfo_t *router_get_entry_from_string_tok(char**s, directory_token_t
|
||||
memset(router,0,sizeof(routerinfo_t)); /* zero it out first */
|
||||
/* C doesn't guarantee that NULL is represented by 0 bytes. You'll
|
||||
thank me for this someday. */
|
||||
router->pkey = router->signing_pkey = NULL;
|
||||
router->onion_pkey = router->identity_pkey = router->link_pkey = NULL;
|
||||
|
||||
if (tok->val.cmd.n_args != 5) {
|
||||
log(LOG_ERR,"router_get_entry_from_string(): Wrong # of arguments to \"router\"");
|
||||
@@ -827,39 +859,78 @@ static routerinfo_t *router_get_entry_from_string_tok(char**s, directory_token_t
|
||||
log(LOG_DEBUG,"or_port %d, ap_port %d, dir_port %d, bandwidth %d.",
|
||||
router->or_port, router->ap_port, router->dir_port, router->bandwidth);
|
||||
|
||||
NEXT_TOKEN();
|
||||
if (tok->tp != K_ONION_KEY) {
|
||||
log_fn(LOG_ERR, "Missing onion-key"); goto err;
|
||||
}
|
||||
NEXT_TOKEN();
|
||||
if (tok->tp != _PUBLIC_KEY) {
|
||||
log(LOG_ERR,"router_get_entry_from_string(): Missing public key");
|
||||
goto err;
|
||||
} /* Check key length */
|
||||
router->pkey = tok->val.public_key;
|
||||
log_fn(LOG_ERR, "Missing onion key"); goto err;
|
||||
} /* XXX Check key length */
|
||||
router->onion_pkey = tok->val.public_key;
|
||||
|
||||
NEXT_TOKEN();
|
||||
if (tok->tp == K_SIGNING_KEY) {
|
||||
NEXT_TOKEN();
|
||||
if (tok->tp != _PUBLIC_KEY) {
|
||||
log(LOG_ERR,"router_get_entry_from_string(): Missing signing key");
|
||||
goto err;
|
||||
}
|
||||
router->signing_pkey = tok->val.public_key;
|
||||
NEXT_TOKEN();
|
||||
}
|
||||
if (tok->tp != K_LINK_KEY) {
|
||||
log_fn(LOG_ERR, "Missing link-key"); goto err;
|
||||
}
|
||||
NEXT_TOKEN();
|
||||
if (tok->tp != _PUBLIC_KEY) {
|
||||
log_fn(LOG_ERR, "Missing link key"); goto err;
|
||||
} /* XXX Check key length */
|
||||
router->link_pkey = tok->val.public_key;
|
||||
|
||||
NEXT_TOKEN();
|
||||
if (tok->tp != K_SIGNING_KEY) {
|
||||
log_fn(LOG_ERR, "Missing signing-key"); goto err;
|
||||
}
|
||||
NEXT_TOKEN();
|
||||
if (tok->tp != _PUBLIC_KEY) {
|
||||
log_fn(LOG_ERR, "Missing signing key"); goto err;
|
||||
}
|
||||
router->identity_pkey = tok->val.public_key;
|
||||
|
||||
NEXT_TOKEN();
|
||||
while (tok->tp == K_ACCEPT || tok->tp == K_REJECT) {
|
||||
router_add_exit_policy(router, tok);
|
||||
NEXT_TOKEN();
|
||||
}
|
||||
|
||||
if (tok->tp != K_ROUTER_SIGNATURE) {
|
||||
log_fn(LOG_ERR,"Missing router signature");
|
||||
goto err;
|
||||
}
|
||||
NEXT_TOKEN();
|
||||
if (tok->tp != _SIGNATURE) {
|
||||
log_fn(LOG_ERR,"Missing router signature");
|
||||
goto err;
|
||||
}
|
||||
assert (router->identity_pkey);
|
||||
#if 0
|
||||
/* XXX This should get re-enabled, once directory servers properly
|
||||
* XXX relay signed router blocks. */
|
||||
if (crypto_pk_public_checksig(router->identity_pkey, tok->val.signature,
|
||||
128, signed_digest) != 20) {
|
||||
log_fn(LOG_ERR, "Invalid signature");
|
||||
goto err;
|
||||
}
|
||||
if (memcmp(digest, signed_digest, 20)) {
|
||||
log_fn(LOG_ERR, "Mismatched signature");
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
return router;
|
||||
|
||||
err:
|
||||
router_release_token(tok);
|
||||
if(router->address)
|
||||
free(router->address);
|
||||
if(router->pkey)
|
||||
crypto_free_pk_env(router->pkey);
|
||||
if(router->signing_pkey)
|
||||
crypto_free_pk_env(router->signing_pkey);
|
||||
if(router->link_pkey)
|
||||
crypto_free_pk_env(router->link_pkey);
|
||||
if(router->onion_pkey)
|
||||
crypto_free_pk_env(router->onion_pkey);
|
||||
if(router->identity_pkey)
|
||||
crypto_free_pk_env(router->identity_pkey);
|
||||
router_free_exit_policy(router);
|
||||
free(router);
|
||||
return NULL;
|
||||
|
||||
+99
-74
@@ -49,19 +49,19 @@ test_buffers() {
|
||||
char str[256];
|
||||
char str2[256];
|
||||
|
||||
char *buf;
|
||||
int buflen, buf_datalen;
|
||||
buf_t *buf;
|
||||
buf_t *buf2;
|
||||
|
||||
int s, i, j, eof;
|
||||
|
||||
/****
|
||||
* buf_new
|
||||
****/
|
||||
if (buf_new(&buf, &buflen, &buf_datalen))
|
||||
if (!(buf = buf_new()))
|
||||
test_fail();
|
||||
|
||||
test_eq(buflen, MAX_BUF_SIZE);
|
||||
test_eq(buf_datalen, 0);
|
||||
test_eq(buf_capacity(buf), MAX_BUF_SIZE);
|
||||
test_eq(buf_datalen(buf), 0);
|
||||
|
||||
/****
|
||||
* read_to_buf
|
||||
@@ -75,52 +75,52 @@ test_buffers() {
|
||||
|
||||
s = open("/tmp/tor_test/data", O_RDONLY, 0);
|
||||
eof = 0;
|
||||
i = read_to_buf(s, 10, &buf, &buflen, &buf_datalen, &eof);
|
||||
test_eq(buflen, MAX_BUF_SIZE);
|
||||
test_eq(buf_datalen, 10);
|
||||
i = read_to_buf(s, 10, buf, &eof);
|
||||
test_eq(buf_capacity(buf), MAX_BUF_SIZE);
|
||||
test_eq(buf_datalen(buf), 10);
|
||||
test_eq(eof, 0);
|
||||
test_eq(i, 10);
|
||||
test_memeq(str, buf, 10);
|
||||
test_memeq(str, (char*)_buf_peek_raw_buffer(buf), 10);
|
||||
|
||||
/* Test reading 0 bytes. */
|
||||
i = read_to_buf(s, 0, &buf, &buflen, &buf_datalen, &eof);
|
||||
test_eq(buflen, MAX_BUF_SIZE);
|
||||
test_eq(buf_datalen, 10);
|
||||
i = read_to_buf(s, 0, buf, &eof);
|
||||
test_eq(buf_capacity(buf), MAX_BUF_SIZE);
|
||||
test_eq(buf_datalen(buf), 10);
|
||||
test_eq(eof, 0);
|
||||
test_eq(i, 0);
|
||||
|
||||
/* Now test when buffer is filled exactly. */
|
||||
buflen = 16;
|
||||
i = read_to_buf(s, 6, &buf, &buflen, &buf_datalen, &eof);
|
||||
test_eq(buflen, 16);
|
||||
test_eq(buf_datalen, 16);
|
||||
buf2 = buf_new_with_capacity(6);
|
||||
i = read_to_buf(s, 6, buf2, &eof);
|
||||
test_eq(buf_capacity(buf2), 6);
|
||||
test_eq(buf_datalen(buf2), 6);
|
||||
test_eq(eof, 0);
|
||||
test_eq(i, 6);
|
||||
test_memeq(str, buf, 16);
|
||||
test_memeq(str+10, (char*)_buf_peek_raw_buffer(buf2), 6);
|
||||
buf_free(buf2);
|
||||
|
||||
/* Now test when buffer is filled with more data to read. */
|
||||
buflen = 32;
|
||||
i = read_to_buf(s, 128, &buf, &buflen, &buf_datalen, &eof);
|
||||
test_eq(buflen, 32);
|
||||
test_eq(buf_datalen, 32);
|
||||
buf2 = buf_new_with_capacity(32);
|
||||
i = read_to_buf(s, 128, buf2, &eof);
|
||||
test_eq(buf_capacity(buf2), 32);
|
||||
test_eq(buf_datalen(buf2), 32);
|
||||
test_eq(eof, 0);
|
||||
test_eq(i, 16);
|
||||
test_memeq(str, buf, 32);
|
||||
test_eq(i, 32);
|
||||
buf_free(buf2);
|
||||
|
||||
/* Now read to eof. */
|
||||
buflen = MAX_BUF_SIZE;
|
||||
test_assert(buflen > 256);
|
||||
i = read_to_buf(s, 1024, &buf, &buflen, &buf_datalen, &eof);
|
||||
test_eq(i, (256-32));
|
||||
test_eq(buflen, MAX_BUF_SIZE);
|
||||
test_eq(buf_datalen, 256);
|
||||
test_memeq(str, buf, 256);
|
||||
test_assert(buf_capacity(buf) > 256);
|
||||
i = read_to_buf(s, 1024, buf, &eof);
|
||||
test_eq(i, (256-32-10-6));
|
||||
test_eq(buf_capacity(buf), MAX_BUF_SIZE);
|
||||
test_eq(buf_datalen(buf), 256-6-32);
|
||||
test_memeq(str, (char*)_buf_peek_raw_buffer(buf), 10); /* XXX Check rest. */
|
||||
test_eq(eof, 0);
|
||||
|
||||
i = read_to_buf(s, 1024, &buf, &buflen, &buf_datalen, &eof);
|
||||
i = read_to_buf(s, 1024, buf, &eof);
|
||||
test_eq(i, 0);
|
||||
test_eq(buflen, MAX_BUF_SIZE);
|
||||
test_eq(buf_datalen, 256);
|
||||
test_eq(buf_capacity(buf), MAX_BUF_SIZE);
|
||||
test_eq(buf_datalen(buf), 256-6-32);
|
||||
test_eq(eof, 1);
|
||||
|
||||
close(s);
|
||||
@@ -128,50 +128,59 @@ test_buffers() {
|
||||
/****
|
||||
* find_on_inbuf
|
||||
****/
|
||||
buf_free(buf);
|
||||
buf = buf_new();
|
||||
s = open("/tmp/tor_test/data", O_RDONLY, 0);
|
||||
eof = 0;
|
||||
i = read_to_buf(s, 1024, buf, &eof);
|
||||
test_eq(256, i);
|
||||
close(s);
|
||||
|
||||
test_eq(((int)'d') + 1, find_on_inbuf("abcd", 4, buf, buf_datalen));
|
||||
test_eq(-1, find_on_inbuf("xyzzy", 5, buf, buf_datalen));
|
||||
test_eq(((int)'d') + 1, find_on_inbuf("abcd", 4, buf));
|
||||
test_eq(-1, find_on_inbuf("xyzzy", 5, buf));
|
||||
/* Make sure we don't look off the end of the buffef */
|
||||
buf[256] = 'A';
|
||||
buf[257] = 'X';
|
||||
test_eq(-1, find_on_inbuf("\xff" "A", 2, buf, buf_datalen));
|
||||
test_eq(-1, find_on_inbuf("AX", 2, buf, buf_datalen));
|
||||
((char*)_buf_peek_raw_buffer(buf))[256] = 'A';
|
||||
((char*)_buf_peek_raw_buffer(buf))[257] = 'X';
|
||||
test_eq(-1, find_on_inbuf("\xff" "A", 2, buf));
|
||||
test_eq(-1, find_on_inbuf("AX", 2, buf));
|
||||
/* Make sure we use the string length */
|
||||
test_eq(((int)'d')+1, find_on_inbuf("abcdX", 4, buf, buf_datalen));
|
||||
test_eq(((int)'d')+1, find_on_inbuf("abcdX", 4, buf));
|
||||
|
||||
/****
|
||||
* fetch_from_buf
|
||||
****/
|
||||
memset(str2, 255, 256);
|
||||
test_eq(246, fetch_from_buf(str2, 10, &buf, &buflen, &buf_datalen));
|
||||
test_eq(246, fetch_from_buf(str2, 10, buf));
|
||||
test_memeq(str2, str, 10);
|
||||
test_memeq(str+10,buf,246);
|
||||
test_eq(buf_datalen,246);
|
||||
test_memeq(str+10,(char*)_buf_peek_raw_buffer(buf),246);
|
||||
test_eq(buf_datalen(buf),246);
|
||||
|
||||
test_eq(0, fetch_from_buf(str2, 246, &buf, &buflen, &buf_datalen));
|
||||
test_eq(0, fetch_from_buf(str2, 246, buf));
|
||||
test_memeq(str2, str+10, 246);
|
||||
test_eq(buflen,MAX_BUF_SIZE);
|
||||
test_eq(buf_datalen,0);
|
||||
test_eq(buf_capacity(buf),MAX_BUF_SIZE);
|
||||
test_eq(buf_datalen(buf),0);
|
||||
|
||||
/****
|
||||
* write_to_buf
|
||||
****/
|
||||
memset(buf, (int)'-', 256);
|
||||
i = write_to_buf("Hello world", 11, &buf, &buflen, &buf_datalen);
|
||||
memset((char *)_buf_peek_raw_buffer(buf), (int)'-', 256);
|
||||
i = write_to_buf("Hello world", 11, buf);
|
||||
test_eq(i, 11);
|
||||
test_eq(buf_datalen, 11);
|
||||
test_memeq(buf, "Hello world", 11);
|
||||
i = write_to_buf("XYZZY", 5, &buf, &buflen, &buf_datalen);
|
||||
test_eq(buf_datalen(buf), 11);
|
||||
test_memeq((char*)_buf_peek_raw_buffer(buf), "Hello world", 11);
|
||||
i = write_to_buf("XYZZY", 5, buf);
|
||||
test_eq(i, 16);
|
||||
test_eq(buf_datalen, 16);
|
||||
test_memeq(buf, "Hello worldXYZZY", 16);
|
||||
test_eq(buf_datalen(buf), 16);
|
||||
test_memeq((char*)_buf_peek_raw_buffer(buf), "Hello worldXYZZY", 16);
|
||||
/* Test when buffer is overfull. */
|
||||
#if 0
|
||||
buflen = 18;
|
||||
test_eq(-1, write_to_buf("This string will not fit.", 25,
|
||||
&buf, &buflen, &buf_datalen));
|
||||
test_eq(buf_datalen, 16);
|
||||
test_memeq(buf, "Hello worldXYZZY--", 18);
|
||||
buflen = MAX_BUF_SIZE;
|
||||
#endif
|
||||
|
||||
/****
|
||||
* flush_buf
|
||||
@@ -482,7 +491,8 @@ test_onion_handshake() {
|
||||
}
|
||||
|
||||
/* from main.c */
|
||||
int dump_router_to_string(char *s, int maxlen, routerinfo_t *router);
|
||||
int dump_router_to_string(char *s, int maxlen, routerinfo_t *router,
|
||||
crypto_pk_env_t *ident_key);
|
||||
void dump_directory_to_string(char *s, int maxlen);
|
||||
|
||||
/* from routers.c */
|
||||
@@ -491,28 +501,30 @@ int compare_recommended_versions(char *myversion, char *start);
|
||||
void
|
||||
test_dir_format()
|
||||
{
|
||||
|
||||
char buf[2048], buf2[2048];
|
||||
char *pk1_str = NULL, *pk2_str = NULL, *cp;
|
||||
int pk1_str_len, pk2_str_len;
|
||||
char buf[8192], buf2[8192];
|
||||
char *pk1_str = NULL, *pk2_str = NULL, *pk3_str = NULL, *cp;
|
||||
int pk1_str_len, pk2_str_len, pk3_str_len;
|
||||
routerinfo_t r1, r2;
|
||||
crypto_pk_env_t *pk1 = NULL, *pk2 = NULL;
|
||||
routerinfo_t *rp1, *rp2;
|
||||
crypto_pk_env_t *pk1 = NULL, *pk2 = NULL, *pk3 = NULL;
|
||||
routerinfo_t *rp1 = NULL, *rp2 = NULL;
|
||||
struct exit_policy_t ex1, ex2;
|
||||
directory_t *dir1 = NULL, *dir2 = NULL;
|
||||
|
||||
test_assert( (pk1 = crypto_new_pk_env(CRYPTO_PK_RSA)) );
|
||||
test_assert( (pk2 = crypto_new_pk_env(CRYPTO_PK_RSA)) );
|
||||
test_assert( (pk3 = crypto_new_pk_env(CRYPTO_PK_RSA)) );
|
||||
test_assert(! crypto_pk_generate_key(pk1));
|
||||
test_assert(! crypto_pk_generate_key(pk2));
|
||||
test_assert(! crypto_pk_generate_key(pk3));
|
||||
|
||||
r1.address = "testaddr1.foo.bar";
|
||||
r1.addr = 0xc0a80001u; /* 192.168.0.1 */
|
||||
r1.or_port = 9000;
|
||||
r1.ap_port = 9002;
|
||||
r1.dir_port = 9003;
|
||||
r1.pkey = pk1;
|
||||
r1.signing_pkey = NULL;
|
||||
r1.onion_pkey = pk1;
|
||||
r1.identity_pkey = pk2;
|
||||
r1.link_pkey = pk3;
|
||||
r1.bandwidth = 1000;
|
||||
r1.exit_policy = NULL;
|
||||
|
||||
@@ -530,8 +542,9 @@ test_dir_format()
|
||||
r2.or_port = 9005;
|
||||
r2.ap_port = 0;
|
||||
r2.dir_port = 0;
|
||||
r2.pkey = pk2;
|
||||
r2.signing_pkey = pk1;
|
||||
r2.onion_pkey = pk2;
|
||||
r2.identity_pkey = pk1;
|
||||
r2.link_pkey = pk2;
|
||||
r2.bandwidth = 3000;
|
||||
r2.exit_policy = &ex1;
|
||||
|
||||
@@ -539,14 +552,23 @@ test_dir_format()
|
||||
&pk1_str_len));
|
||||
test_assert(!crypto_pk_write_public_key_to_string(pk2 , &pk2_str,
|
||||
&pk2_str_len));
|
||||
strcpy(buf2, "router testaddr1.foo.bar 9000 9002 9003 1000\n");
|
||||
test_assert(!crypto_pk_write_public_key_to_string(pk3 , &pk3_str,
|
||||
&pk3_str_len));
|
||||
|
||||
strcpy(buf2, "router testaddr1.foo.bar 9000 9002 9003 1000\nonion-key\n");
|
||||
strcat(buf2, pk1_str);
|
||||
strcat(buf2, "\n");
|
||||
strcat(buf2, "link-key\n");
|
||||
strcat(buf2, pk3_str);
|
||||
strcat(buf2, "signing-key\n");
|
||||
strcat(buf2, pk2_str);
|
||||
strcat(buf2, "router-signature\n");
|
||||
|
||||
memset(buf, 0, 2048);
|
||||
test_assert(dump_router_to_string(buf, 2048, &r1)>0);
|
||||
test_assert(dump_router_to_string(buf, 2048, &r1, pk1)>0);
|
||||
buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same 2ce*/
|
||||
test_streq(buf, buf2);
|
||||
|
||||
|
||||
test_assert(dump_router_to_string(buf, 2048, &r1, pk1)>0);
|
||||
cp = buf;
|
||||
rp1 = router_get_entry_from_string(&cp);
|
||||
test_assert(rp1);
|
||||
@@ -555,16 +577,18 @@ test_dir_format()
|
||||
test_eq(rp1->ap_port, r1.ap_port);
|
||||
test_eq(rp1->dir_port, r1.dir_port);
|
||||
test_eq(rp1->bandwidth, r1.bandwidth);
|
||||
test_assert(crypto_pk_cmp_keys(rp1->pkey, pk1) == 0);
|
||||
test_assert(rp1->signing_pkey == NULL);
|
||||
test_assert(crypto_pk_cmp_keys(rp1->onion_pkey, pk1) == 0);
|
||||
test_assert(crypto_pk_cmp_keys(rp1->link_pkey, pk3) == 0);
|
||||
test_assert(crypto_pk_cmp_keys(rp1->identity_pkey, pk2) == 0);
|
||||
test_assert(rp1->exit_policy == NULL);
|
||||
|
||||
#if 0
|
||||
strcpy(buf2, "router tor.tor.tor 9005 0 0 3000\n");
|
||||
strcat(buf2, pk2_str);
|
||||
strcat(buf2, "signing-key\n");
|
||||
strcat(buf2, pk1_str);
|
||||
strcat(buf2, "accept *:80\nreject 18.*:24\n\n");
|
||||
test_assert(dump_router_to_string(buf, 2048, &r2)>0);
|
||||
test_assert(dump_router_to_string(buf, 2048, &r2, pk2)>0);
|
||||
test_streq(buf, buf2);
|
||||
|
||||
cp = buf;
|
||||
@@ -575,8 +599,8 @@ test_dir_format()
|
||||
test_eq(rp2->ap_port, r2.ap_port);
|
||||
test_eq(rp2->dir_port, r2.dir_port);
|
||||
test_eq(rp2->bandwidth, r2.bandwidth);
|
||||
test_assert(crypto_pk_cmp_keys(rp2->pkey, pk2) == 0);
|
||||
test_assert(crypto_pk_cmp_keys(rp2->signing_pkey, pk1) == 0);
|
||||
test_assert(crypto_pk_cmp_keys(rp2->onion_pkey, pk2) == 0);
|
||||
test_assert(crypto_pk_cmp_keys(rp2->identity_pkey, pk1) == 0);
|
||||
test_eq(rp2->exit_policy->policy_type, EXIT_POLICY_ACCEPT);
|
||||
test_streq(rp2->exit_policy->string, "accept *:80");
|
||||
test_streq(rp2->exit_policy->address, "*");
|
||||
@@ -586,6 +610,7 @@ test_dir_format()
|
||||
test_streq(rp2->exit_policy->next->address, "18.*");
|
||||
test_streq(rp2->exit_policy->next->port, "24");
|
||||
test_assert(rp2->exit_policy->next->next == NULL);
|
||||
#endif
|
||||
|
||||
/* Okay, now for the directories. */
|
||||
dir1 = (directory_t*) tor_malloc(sizeof(directory_t));
|
||||
@@ -593,7 +618,7 @@ test_dir_format()
|
||||
dir1->routers = (routerinfo_t**) tor_malloc(sizeof(routerinfo_t*)*2);
|
||||
dir1->routers[0] = &r1;
|
||||
dir1->routers[1] = &r2;
|
||||
test_assert(! dump_signed_directory_to_string_impl(buf, 2048, dir1, pk1));
|
||||
test_assert(! dump_signed_directory_to_string_impl(buf, 4096, dir1, pk1));
|
||||
/* puts(buf); */
|
||||
|
||||
test_assert(! router_get_dir_from_string_impl(buf, &dir2, pk1));
|
||||
|
||||
Reference in New Issue
Block a user