aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/Makefile.am67
-rw-r--r--src/common/Makefile.nmake11
-rw-r--r--src/common/OpenBSD_malloc_Linux.c2057
-rw-r--r--src/common/address.c259
-rw-r--r--src/common/address.h27
-rw-r--r--src/common/aes.c43
-rw-r--r--src/common/aes.h6
-rw-r--r--src/common/ciphers.inc169
-rw-r--r--src/common/compat.c167
-rw-r--r--src/common/compat.h58
-rw-r--r--src/common/compat_libevent.c105
-rw-r--r--src/common/compat_libevent.h6
-rw-r--r--src/common/container.c165
-rw-r--r--src/common/container.h69
-rw-r--r--src/common/crypto.c515
-rw-r--r--src/common/crypto.h40
-rw-r--r--src/common/crypto_curve25519.c191
-rw-r--r--src/common/crypto_curve25519.h68
-rw-r--r--src/common/crypto_format.c46
-rw-r--r--src/common/di_ops.c93
-rw-r--r--src/common/di_ops.h18
-rwxr-xr-xsrc/common/gen_server_ciphers.py115
-rw-r--r--src/common/get_mozilla_ciphers.py30
-rw-r--r--src/common/ht.h490
-rw-r--r--src/common/include.am96
-rw-r--r--src/common/log.c147
-rw-r--r--src/common/memarea.c6
-rw-r--r--src/common/memarea.h6
-rw-r--r--src/common/mempool.c16
-rw-r--r--src/common/mempool.h6
-rw-r--r--src/common/procmon.c41
-rw-r--r--src/common/procmon.h2
-rw-r--r--src/common/sha256.c331
-rw-r--r--src/common/strlcat.c70
-rw-r--r--src/common/strlcpy.c60
-rw-r--r--src/common/torgzip.c2
-rw-r--r--src/common/torgzip.h6
-rw-r--r--src/common/torint.h10
-rw-r--r--src/common/torlog.h82
-rw-r--r--src/common/tortls.c532
-rw-r--r--src/common/tortls.h22
-rw-r--r--src/common/util.c868
-rw-r--r--src/common/util.h118
43 files changed, 2897 insertions, 4339 deletions
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
deleted file mode 100644
index 5e7684259..000000000
--- a/src/common/Makefile.am
+++ /dev/null
@@ -1,67 +0,0 @@
-
-noinst_LIBRARIES = libor.a libor-crypto.a libor-event.a
-
-EXTRA_DIST = common_sha1.i sha256.c Makefile.nmake
-
-#CFLAGS = -Wall -Wpointer-arith -O2
-
-if USE_OPENBSD_MALLOC
-libor_extra_source=OpenBSD_malloc_Linux.c
-else
-libor_extra_source=
-endif
-
-libor_a_SOURCES = \
- address.c \
- compat.c \
- container.c \
- di_ops.c \
- log.c \
- memarea.c \
- mempool.c \
- procmon.c \
- util.c \
- util_codedigest.c \
- $(libor_extra_source)
-
-libor_crypto_a_SOURCES = \
- aes.c \
- crypto.c \
- torgzip.c \
- tortls.c
-
-libor_event_a_SOURCES = compat_libevent.c
-
-noinst_HEADERS = \
- address.h \
- aes.h \
- ciphers.inc \
- compat.h \
- compat_libevent.h \
- container.h \
- crypto.h \
- di_ops.h \
- ht.h \
- memarea.h \
- mempool.h \
- procmon.h \
- strlcat.c \
- strlcpy.c \
- torgzip.h \
- torint.h \
- torlog.h \
- tortls.h \
- util.h
-
-common_sha1.i: $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)
- if test "@SHA1SUM@" != none; then \
- (cd "$(srcdir)" && "@SHA1SUM@" $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)) | "@SED@" -n 's/^\(.*\)$$/"\1\\n"/p' > common_sha1.i; \
- elif test "@OPENSSL@" != none; then \
- (cd "$(srcdir)" && "@OPENSSL@" sha1 $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)) | "@SED@" -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > common_sha1.i; \
- else \
- rm common_sha1.i; \
- touch common_sha1.i; \
- fi
-
-util_codedigest.o: common_sha1.i
-crypto.o: sha256.c
diff --git a/src/common/Makefile.nmake b/src/common/Makefile.nmake
index e54827367..0ebeaaaf7 100644
--- a/src/common/Makefile.nmake
+++ b/src/common/Makefile.nmake
@@ -1,15 +1,19 @@
all: libor.lib libor-crypto.lib libor-event.lib
-CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include
+CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\ext
LIBOR_OBJECTS = address.obj compat.obj container.obj di_ops.obj \
log.obj memarea.obj mempool.obj procmon.obj util.obj \
util_codedigest.obj
-LIBOR_CRYPTO_OBJECTS = aes.obj crypto.obj torgzip.obj tortls.obj
+LIBOR_CRYPTO_OBJECTS = aes.obj crypto.obj torgzip.obj tortls.obj \
+ crypto_curve25519.obj curve25519-donna.obj
LIBOR_EVENT_OBJECTS = compat_libevent.obj
+curve25519-donna.obj: ..\ext\curve25519_donna\curve25519-donna.c
+ $(CC) $(CFLAGS) /D inline=_inline /c ..\ext\curve25519_donna\curve25519-donna.c
+
libor.lib: $(LIBOR_OBJECTS)
lib $(LIBOR_OBJECTS) /out:libor.lib
@@ -18,3 +22,6 @@ libor-crypto.lib: $(LIBOR_CRYPTO_OBJECTS)
libor-event.lib: $(LIBOR_EVENT_OBJECTS)
lib $(LIBOR_EVENT_OBJECTS) /out:libor-event.lib
+
+clean:
+ del *.obj *.lib libor*.lib
diff --git a/src/common/OpenBSD_malloc_Linux.c b/src/common/OpenBSD_malloc_Linux.c
deleted file mode 100644
index da8272981..000000000
--- a/src/common/OpenBSD_malloc_Linux.c
+++ /dev/null
@@ -1,2057 +0,0 @@
-/* Version 1.83 for Linux.
- * Compilation: gcc -shared -fPIC -O2 OpenBSD_malloc_Linux.c -o malloc.so
- * Launching: LD_PRELOAD=/path/to/malloc.so firefox
- */
-
-/* $OpenBSD: malloc.c,v 1.83 2006/05/14 19:53:40 otto Exp $ */
-
-/*
- * ----------------------------------------------------------------------------
- * "THE BEER-WARE LICENSE" (Revision 42):
- * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
- * ----------------------------------------------------------------------------
- */
-
-/* We use this macro to remove some code that we don't actually want,
- * rather than to fix its warnings. */
-#define BUILDING_FOR_TOR
-
-/*
- * Defining MALLOC_EXTRA_SANITY will enable extra checks which are
- * related to internal conditions and consistency in malloc.c. This has
- * a noticeable runtime performance hit, and generally will not do you
- * any good unless you fiddle with the internals of malloc or want
- * to catch random pointer corruption as early as possible.
- */
-#ifndef MALLOC_EXTRA_SANITY
-#undef MALLOC_EXTRA_SANITY
-#endif
-
-/*
- * Defining MALLOC_STATS will enable you to call malloc_dump() and set
- * the [dD] options in the MALLOC_OPTIONS environment variable.
- * It has no run-time performance hit, but does pull in stdio...
- */
-#ifndef MALLOC_STATS
-#undef MALLOC_STATS
-#endif
-
-/*
- * What to use for Junk. This is the byte value we use to fill with
- * when the 'J' option is enabled.
- */
-#define SOME_JUNK 0xd0 /* as in "Duh" :-) */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/param.h>
-#include <sys/mman.h>
-#include <sys/uio.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <errno.h>
-#include <err.h>
-/* For SIZE_T_MAX */
-#include "torint.h"
-
-//#include "thread_private.h"
-
-/*
- * The basic parameters you can tweak.
- *
- * malloc_pageshift pagesize = 1 << malloc_pageshift
- * It's probably best if this is the native
- * page size, but it shouldn't have to be.
- *
- * malloc_minsize minimum size of an allocation in bytes.
- * If this is too small it's too much work
- * to manage them. This is also the smallest
- * unit of alignment used for the storage
- * returned by malloc/realloc.
- *
- */
-
-static int align = 0;
-static size_t g_alignment = 0;
-
-extern int __libc_enable_secure;
-
-#ifndef HAVE_ISSETUGID
-static int issetugid(void)
-{
- if (__libc_enable_secure) return 1;
- if (getuid() != geteuid()) return 1;
- if (getgid() != getegid()) return 1;
- return 0;
-}
-#endif
-
-#define PGSHIFT 12
-#undef MADV_FREE
-#define MADV_FREE MADV_DONTNEED
-#include <pthread.h>
-static pthread_mutex_t gen_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-#define _MALLOC_LOCK_INIT() {;}
-#define _MALLOC_LOCK() {pthread_mutex_lock(&gen_mutex);}
-#define _MALLOC_UNLOCK() {pthread_mutex_unlock(&gen_mutex);}
-
-#if defined(__sparc__) || defined(__alpha__)
-#define malloc_pageshift 13U
-#endif
-#if defined(__ia64__)
-#define malloc_pageshift 14U
-#endif
-
-#ifndef malloc_pageshift
-#define malloc_pageshift (PGSHIFT)
-#endif
-
-/*
- * No user serviceable parts behind this point.
- *
- * This structure describes a page worth of chunks.
- */
-struct pginfo {
- struct pginfo *next; /* next on the free list */
- void *page; /* Pointer to the page */
- u_short size; /* size of this page's chunks */
- u_short shift; /* How far to shift for this size chunks */
- u_short free; /* How many free chunks */
- u_short total; /* How many chunk */
- u_long bits[1];/* Which chunks are free */
-};
-
-/* How many bits per u_long in the bitmap */
-#define MALLOC_BITS (int)((NBBY * sizeof(u_long)))
-
-/*
- * This structure describes a number of free pages.
- */
-struct pgfree {
- struct pgfree *next; /* next run of free pages */
- struct pgfree *prev; /* prev run of free pages */
- void *page; /* pointer to free pages */
- void *pdir; /* pointer to the base page's dir */
- size_t size; /* number of bytes free */
-};
-
-/*
- * Magic values to put in the page_directory
- */
-#define MALLOC_NOT_MINE ((struct pginfo*) 0)
-#define MALLOC_FREE ((struct pginfo*) 1)
-#define MALLOC_FIRST ((struct pginfo*) 2)
-#define MALLOC_FOLLOW ((struct pginfo*) 3)
-#define MALLOC_MAGIC ((struct pginfo*) 4)
-
-#ifndef malloc_minsize
-#define malloc_minsize 16UL
-#endif
-
-#if !defined(malloc_pagesize)
-#define malloc_pagesize (1UL<<malloc_pageshift)
-#endif
-
-#if ((1UL<<malloc_pageshift) != malloc_pagesize)
-#error "(1UL<<malloc_pageshift) != malloc_pagesize"
-#endif
-
-#ifndef malloc_maxsize
-#define malloc_maxsize ((malloc_pagesize)>>1)
-#endif
-
-/* A mask for the offset inside a page. */
-#define malloc_pagemask ((malloc_pagesize)-1)
-
-#define pageround(foo) (((foo) + (malloc_pagemask)) & ~malloc_pagemask)
-#define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)+malloc_pageshift)
-#define index2ptr(idx) ((void*)(((idx)-malloc_pageshift)<<malloc_pageshift))
-
-/* Set when initialization has been done */
-static unsigned int malloc_started;
-
-/* Number of free pages we cache */
-static unsigned int malloc_cache = 16;
-
-/* Structure used for linking discrete directory pages. */
-struct pdinfo {
- struct pginfo **base;
- struct pdinfo *prev;
- struct pdinfo *next;
- u_long dirnum;
-};
-static struct pdinfo *last_dir; /* Caches to the last and previous */
-static struct pdinfo *prev_dir; /* referenced directory pages. */
-
-static size_t pdi_off;
-static u_long pdi_mod;
-#define PD_IDX(num) ((num) / (malloc_pagesize/sizeof(struct pginfo *)))
-#define PD_OFF(num) ((num) & ((malloc_pagesize/sizeof(struct pginfo *))-1))
-#define PI_IDX(index) ((index) / pdi_mod)
-#define PI_OFF(index) ((index) % pdi_mod)
-
-/* The last index in the page directory we care about */
-static u_long last_index;
-
-/* Pointer to page directory. Allocated "as if with" malloc */
-static struct pginfo **page_dir;
-
-/* Free pages line up here */
-static struct pgfree free_list;
-
-/* Abort(), user doesn't handle problems. */
-static int malloc_abort = 2;
-
-/* Are we trying to die ? */
-static int suicide;
-
-#ifdef MALLOC_STATS
-/* dump statistics */
-static int malloc_stats;
-#endif
-
-/* avoid outputting warnings? */
-static int malloc_silent;
-
-/* always realloc ? */
-static int malloc_realloc;
-
-/* mprotect free pages PROT_NONE? */
-static int malloc_freeprot;
-
-/* use guard pages after allocations? */
-static size_t malloc_guard = 0;
-static size_t malloc_guarded;
-/* align pointers to end of page? */
-static int malloc_ptrguard;
-
-static int malloc_hint = 1;
-
-/* xmalloc behaviour ? */
-static int malloc_xmalloc;
-
-/* zero fill ? */
-static int malloc_zero;
-
-/* junk fill ? */
-static int malloc_junk;
-
-#ifdef __FreeBSD__
-/* utrace ? */
-static int malloc_utrace;
-
-struct ut {
- void *p;
- size_t s;
- void *r;
-};
-
-void utrace(struct ut *, int);
-
-#define UTRACE(a, b, c) \
- if (malloc_utrace) \
- {struct ut u; u.p=a; u.s = b; u.r=c; utrace(&u, sizeof u);}
-#else /* !__FreeBSD__ */
-#define UTRACE(a,b,c)
-#endif
-
-/* Status of malloc. */
-static int malloc_active;
-
-/* Allocated memory. */
-static size_t malloc_used;
-
-/* My last break. */
-static caddr_t malloc_brk;
-
-/* One location cache for free-list holders. */
-static struct pgfree *px;
-
-/* Compile-time options. */
-char *malloc_options;
-
-/* Name of the current public function. */
-static const char *malloc_func;
-
-#define MMAP(size) \
- mmap((void *)0, (size), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, \
- -1, (off_t)0)
-
-/*
- * Necessary function declarations.
- */
-static void *imalloc(size_t size);
-static void ifree(void *ptr);
-static void *irealloc(void *ptr, size_t size);
-static void *malloc_bytes(size_t size);
-void *memalign(size_t boundary, size_t size);
-size_t malloc_good_size(size_t size);
-
-/*
- * Function for page directory lookup.
- */
-static int
-pdir_lookup(u_long index, struct pdinfo ** pdi)
-{
- struct pdinfo *spi;
- u_long pidx = PI_IDX(index);
-
- if (last_dir != NULL && PD_IDX(last_dir->dirnum) == pidx)
- *pdi = last_dir;
- else if (prev_dir != NULL && PD_IDX(prev_dir->dirnum) == pidx)
- *pdi = prev_dir;
- else if (last_dir != NULL && prev_dir != NULL) {
- if ((PD_IDX(last_dir->dirnum) > pidx) ?
- (PD_IDX(last_dir->dirnum) - pidx) :
- (pidx - PD_IDX(last_dir->dirnum))
- < (PD_IDX(prev_dir->dirnum) > pidx) ?
- (PD_IDX(prev_dir->dirnum) - pidx) :
- (pidx - PD_IDX(prev_dir->dirnum)))
- *pdi = last_dir;
- else
- *pdi = prev_dir;
-
- if (PD_IDX((*pdi)->dirnum) > pidx) {
- for (spi = (*pdi)->prev;
- spi != NULL && PD_IDX(spi->dirnum) > pidx;
- spi = spi->prev)
- *pdi = spi;
- if (spi != NULL)
- *pdi = spi;
- } else
- for (spi = (*pdi)->next;
- spi != NULL && PD_IDX(spi->dirnum) <= pidx;
- spi = spi->next)
- *pdi = spi;
- } else {
- *pdi = (struct pdinfo *) ((caddr_t) page_dir + pdi_off);
- for (spi = *pdi;
- spi != NULL && PD_IDX(spi->dirnum) <= pidx;
- spi = spi->next)
- *pdi = spi;
- }
-
- return ((PD_IDX((*pdi)->dirnum) == pidx) ? 0 :
- (PD_IDX((*pdi)->dirnum) > pidx) ? 1 : -1);
-}
-
-#ifdef MALLOC_STATS
-void
-malloc_dump(int fd)
-{
- char buf[1024];
- struct pginfo **pd;
- struct pgfree *pf;
- struct pdinfo *pi;
- u_long j;
-
- pd = page_dir;
- pi = (struct pdinfo *) ((caddr_t) pd + pdi_off);
-
- /* print out all the pages */
- for (j = 0; j <= last_index;) {
- snprintf(buf, sizeof buf, "%08lx %5lu ", j << malloc_pageshift, j);
- write(fd, buf, strlen(buf));
- if (pd[PI_OFF(j)] == MALLOC_NOT_MINE) {
- for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_NOT_MINE;) {
- if (!PI_OFF(++j)) {
- if ((pi = pi->next) == NULL ||
- PD_IDX(pi->dirnum) != PI_IDX(j))
- break;
- pd = pi->base;
- j += pdi_mod;
- }
- }
- j--;
- snprintf(buf, sizeof buf, ".. %5lu not mine\n", j);
- write(fd, buf, strlen(buf));
- } else if (pd[PI_OFF(j)] == MALLOC_FREE) {
- for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_FREE;) {
- if (!PI_OFF(++j)) {
- if ((pi = pi->next) == NULL ||
- PD_IDX(pi->dirnum) != PI_IDX(j))
- break;
- pd = pi->base;
- j += pdi_mod;
- }
- }
- j--;
- snprintf(buf, sizeof buf, ".. %5lu free\n", j);
- write(fd, buf, strlen(buf));
- } else if (pd[PI_OFF(j)] == MALLOC_FIRST) {
- for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_FOLLOW;) {
- if (!PI_OFF(++j)) {
- if ((pi = pi->next) == NULL ||
- PD_IDX(pi->dirnum) != PI_IDX(j))
- break;
- pd = pi->base;
- j += pdi_mod;
- }
- }
- j--;
- snprintf(buf, sizeof buf, ".. %5lu in use\n", j);
- write(fd, buf, strlen(buf));
- } else if (pd[PI_OFF(j)] < MALLOC_MAGIC) {
- snprintf(buf, sizeof buf, "(%p)\n", pd[PI_OFF(j)]);
- write(fd, buf, strlen(buf));
- } else {
- snprintf(buf, sizeof buf, "%p %d (of %d) x %d @ %p --> %p\n",
- pd[PI_OFF(j)], pd[PI_OFF(j)]->free,
- pd[PI_OFF(j)]->total, pd[PI_OFF(j)]->size,
- pd[PI_OFF(j)]->page, pd[PI_OFF(j)]->next);
- write(fd, buf, strlen(buf));
- }
- if (!PI_OFF(++j)) {
- if ((pi = pi->next) == NULL)
- break;
- pd = pi->base;
- j += (1 + PD_IDX(pi->dirnum) - PI_IDX(j)) * pdi_mod;
- }
- }
-
- for (pf = free_list.next; pf; pf = pf->next) {
- snprintf(buf, sizeof buf, "Free: @%p [%p...%p[ %ld ->%p <-%p\n",
- pf, pf->page, (char *)pf->page + pf->size,
- pf->size, pf->prev, pf->next);
- write(fd, buf, strlen(buf));
- if (pf == pf->next) {
- snprintf(buf, sizeof buf, "Free_list loops\n");
- write(fd, buf, strlen(buf));
- break;
- }
- }
-
- /* print out various info */
- snprintf(buf, sizeof buf, "Minsize\t%lu\n", malloc_minsize);
- write(fd, buf, strlen(buf));
- snprintf(buf, sizeof buf, "Maxsize\t%lu\n", malloc_maxsize);
- write(fd, buf, strlen(buf));
- snprintf(buf, sizeof buf, "Pagesize\t%lu\n", malloc_pagesize);
- write(fd, buf, strlen(buf));
- snprintf(buf, sizeof buf, "Pageshift\t%u\n", malloc_pageshift);
- write(fd, buf, strlen(buf));
- snprintf(buf, sizeof buf, "In use\t%lu\n", (u_long) malloc_used);
- write(fd, buf, strlen(buf));
- snprintf(buf, sizeof buf, "Guarded\t%lu\n", (u_long) malloc_guarded);
- write(fd, buf, strlen(buf));
-}
-#endif /* MALLOC_STATS */
-
-extern char *__progname;
-
-static void
-wrterror(const char *p)
-{
-#ifndef BUILDING_FOR_TOR
- const char *q = " error: ";
- struct iovec iov[5];
-
- iov[0].iov_base = __progname;
- iov[0].iov_len = strlen(__progname);
- iov[1].iov_base = (char*)malloc_func;
- iov[1].iov_len = strlen(malloc_func);
- iov[2].iov_base = (char*)q;
- iov[2].iov_len = strlen(q);
- iov[3].iov_base = (char*)p;
- iov[3].iov_len = strlen(p);
- iov[4].iov_base = (char*)"\n";
- iov[4].iov_len = 1;
- writev(STDERR_FILENO, iov, 5);
-#else
- (void)p;
-#endif
- suicide = 1;
-#ifdef MALLOC_STATS
- if (malloc_stats)
- malloc_dump(STDERR_FILENO);
-#endif /* MALLOC_STATS */
- malloc_active--;
- if (malloc_abort)
- abort();
-}
-
-static void
-wrtwarning(const char *p)
-{
-#ifndef BUILDING_FOR_TOR
- const char *q = " warning: ";
- struct iovec iov[5];
-#endif
-
- if (malloc_abort)
- wrterror(p);
- else if (malloc_silent)
- return;
-
-#ifndef BUILDING_FOR_TOR
- iov[0].iov_base = __progname;
- iov[0].iov_len = strlen(__progname);
- iov[1].iov_base = (char*)malloc_func;
- iov[1].iov_len = strlen(malloc_func);
- iov[2].iov_base = (char*)q;
- iov[2].iov_len = strlen(q);
- iov[3].iov_base = (char*)p;
- iov[3].iov_len = strlen(p);
- iov[4].iov_base = (char*)"\n";
- iov[4].iov_len = 1;
-
- (void) writev(STDERR_FILENO, iov, 5);
-#else
- (void)p;
-#endif
-}
-
-#ifdef MALLOC_STATS
-static void
-malloc_exit(void)
-{
- char *q = "malloc() warning: Couldn't dump stats\n";
- int save_errno = errno, fd;
-
- fd = open("malloc.out", O_RDWR|O_APPEND);
- if (fd != -1) {
- malloc_dump(fd);
- close(fd);
- } else
- write(STDERR_FILENO, q, strlen(q));
- errno = save_errno;
-}
-#endif /* MALLOC_STATS */
-
-/*
- * Allocate aligned mmaped chunk
- */
-
-static void *MMAP_A(size_t pages, size_t alignment)
-{
- void *j, *p;
- size_t first_size, rest, begin, end;
- if (pages%malloc_pagesize != 0)
- pages = pages - pages%malloc_pagesize + malloc_pagesize;
- first_size = pages + alignment - malloc_pagesize;
- p = MMAP(first_size);
- rest = ((size_t)p) % alignment;
- j = (rest == 0) ? p : (void*) ((size_t)p + alignment - rest);
- begin = (size_t)j - (size_t)p;
- if (begin != 0) munmap(p, begin);
- end = (size_t)p + first_size - ((size_t)j + pages);
- if(end != 0) munmap( (void*) ((size_t)j + pages), end);
-
- return j;
-}
-
-
-/*
- * Allocate a number of pages from the OS
- */
-static void *
-map_pages(size_t pages)
-{
- struct pdinfo *pi, *spi;
- struct pginfo **pd;
- u_long idx, pidx, lidx;
- caddr_t result, tail;
- u_long index, lindex;
- void *pdregion = NULL;
- size_t dirs, cnt;
-
- pages <<= malloc_pageshift;
- if (!align)
- result = MMAP(pages + malloc_guard);
- else {
- result = MMAP_A(pages + malloc_guard, g_alignment);
- }
- if (result == MAP_FAILED) {
-#ifdef MALLOC_EXTRA_SANITY
- wrtwarning("(ES): map_pages fails");
-#endif /* MALLOC_EXTRA_SANITY */
- errno = ENOMEM;
- return (NULL);
- }
- index = ptr2index(result);
- tail = result + pages + malloc_guard;
- lindex = ptr2index(tail) - 1;
- if (malloc_guard)
- mprotect(result + pages, malloc_guard, PROT_NONE);
-
- pidx = PI_IDX(index);
- lidx = PI_IDX(lindex);
-
- if (tail > malloc_brk) {
- malloc_brk = tail;
- last_index = lindex;
- }
-
- dirs = lidx - pidx;
-
- /* Insert directory pages, if needed. */
- if (pdir_lookup(index, &pi) != 0)
- dirs++;
-
- if (dirs > 0) {
- pdregion = MMAP(malloc_pagesize * dirs);
- if (pdregion == MAP_FAILED) {
- munmap(result, tail - result);
-#ifdef MALLOC_EXTRA_SANITY
- wrtwarning("(ES): map_pages fails");
-#endif
- errno = ENOMEM;
- return (NULL);
- }
- }
-
- cnt = 0;
- for (idx = pidx, spi = pi; idx <= lidx; idx++) {
- if (pi == NULL || PD_IDX(pi->dirnum) != idx) {
- pd = (struct pginfo **)((char *)pdregion +
- cnt * malloc_pagesize);
- cnt++;
- memset(pd, 0, malloc_pagesize);
- pi = (struct pdinfo *) ((caddr_t) pd + pdi_off);
- pi->base = pd;
- pi->prev = spi;
- pi->next = spi->next;
- pi->dirnum = idx * (malloc_pagesize /
- sizeof(struct pginfo *));
-
- if (spi->next != NULL)
- spi->next->prev = pi;
- spi->next = pi;
- }
- if (idx > pidx && idx < lidx) {
- pi->dirnum += pdi_mod;
- } else if (idx == pidx) {
- if (pidx == lidx) {
- pi->dirnum += (u_long)(tail - result) >>
- malloc_pageshift;
- } else {
- pi->dirnum += pdi_mod - PI_OFF(index);
- }
- } else {
- pi->dirnum += PI_OFF(ptr2index(tail - 1)) + 1;
- }
-#ifdef MALLOC_EXTRA_SANITY
- if (PD_OFF(pi->dirnum) > pdi_mod || PD_IDX(pi->dirnum) > idx) {
- wrterror("(ES): pages directory overflow");
- errno = EFAULT;
- return (NULL);
- }
-#endif /* MALLOC_EXTRA_SANITY */
- if (idx == pidx && pi != last_dir) {
- prev_dir = last_dir;
- last_dir = pi;
- }
- spi = pi;
- pi = spi->next;
- }
-#ifdef MALLOC_EXTRA_SANITY
- if (cnt > dirs)
- wrtwarning("(ES): cnt > dirs");
-#endif /* MALLOC_EXTRA_SANITY */
- if (cnt < dirs)
- munmap((char *)pdregion + cnt * malloc_pagesize,
- (dirs - cnt) * malloc_pagesize);
-
- return (result);
-}
-
-/*
- * Initialize the world
- */
-static void
-malloc_init(void)
-{
- char *p, b[64];
- int i, j, save_errno = errno;
-
- _MALLOC_LOCK_INIT();
-
-#ifdef MALLOC_EXTRA_SANITY
- malloc_junk = 1;
-#endif /* MALLOC_EXTRA_SANITY */
-
- for (i = 0; i < 3; i++) {
- switch (i) {
- case 0:
- j = (int) readlink("/etc/malloc.conf", b, sizeof b - 1);
- if (j <= 0)
- continue;
- b[j] = '\0';
- p = b;
- break;
- case 1:
- if (issetugid() == 0)
- p = getenv("MALLOC_OPTIONS");
- else
- continue;
- break;
- case 2:
- p = malloc_options;
- break;
- default:
- p = NULL;
- }
-
- for (; p != NULL && *p != '\0'; p++) {
- switch (*p) {
- case '>':
- malloc_cache <<= 1;
- break;
- case '<':
- malloc_cache >>= 1;
- break;
- case 'a':
- malloc_abort = 0;
- break;
- case 'A':
- malloc_abort = 1;
- break;
-#ifdef MALLOC_STATS
- case 'd':
- malloc_stats = 0;
- break;
- case 'D':
- malloc_stats = 1;
- break;
-#endif /* MALLOC_STATS */
- case 'f':
- malloc_freeprot = 0;
- break;
- case 'F':
- malloc_freeprot = 1;
- break;
- case 'g':
- malloc_guard = 0;
- break;
- case 'G':
- malloc_guard = malloc_pagesize;
- break;
- case 'h':
- malloc_hint = 0;
- break;
- case 'H':
- malloc_hint = 1;
- break;
- case 'j':
- malloc_junk = 0;
- break;
- case 'J':
- malloc_junk = 1;
- break;
- case 'n':
- malloc_silent = 0;
- break;
- case 'N':
- malloc_silent = 1;
- break;
- case 'p':
- malloc_ptrguard = 0;
- break;
- case 'P':
- malloc_ptrguard = 1;
- break;
- case 'r':
- malloc_realloc = 0;
- break;
- case 'R':
- malloc_realloc = 1;
- break;
-#ifdef __FreeBSD__
- case 'u':
- malloc_utrace = 0;
- break;
- case 'U':
- malloc_utrace = 1;
- break;
-#endif /* __FreeBSD__ */
- case 'x':
- malloc_xmalloc = 0;
- break;
- case 'X':
- malloc_xmalloc = 1;
- break;
- case 'z':
- malloc_zero = 0;
- break;
- case 'Z':
- malloc_zero = 1;
- break;
- default:
- j = malloc_abort;
- malloc_abort = 0;
- wrtwarning("unknown char in MALLOC_OPTIONS");
- malloc_abort = j;
- break;
- }
- }
- }
-
- UTRACE(0, 0, 0);
-
- /*
- * We want junk in the entire allocation, and zero only in the part
- * the user asked for.
- */
- if (malloc_zero)
- malloc_junk = 1;
-
-#ifdef MALLOC_STATS
- if (malloc_stats && (atexit(malloc_exit) == -1))
- wrtwarning("atexit(2) failed."
- " Will not be able to dump malloc stats on exit");
-#endif /* MALLOC_STATS */
-
- if (malloc_pagesize != getpagesize()) {
- wrterror("malloc() replacement compiled with a different "
- "page size from what we're running with. Failing.");
- errno = ENOMEM;
- return;
- }
-
- /* Allocate one page for the page directory. */
- page_dir = (struct pginfo **)MMAP(malloc_pagesize);
-
- if (page_dir == MAP_FAILED) {
- wrterror("mmap(2) failed, check limits");
- errno = ENOMEM;
- return;
- }
- pdi_off = (malloc_pagesize - sizeof(struct pdinfo)) & ~(malloc_minsize - 1);
- pdi_mod = pdi_off / sizeof(struct pginfo *);
-
- last_dir = (struct pdinfo *) ((caddr_t) page_dir + pdi_off);
- last_dir->base = page_dir;
- last_dir->prev = last_dir->next = NULL;
- last_dir->dirnum = malloc_pageshift;
-
- /* Been here, done that. */
- malloc_started++;
-
- /* Recalculate the cache size in bytes, and make sure it's nonzero. */
- if (!malloc_cache)
- malloc_cache++;
- malloc_cache <<= malloc_pageshift;
- errno = save_errno;
-}
-
-/*
- * Allocate a number of complete pages
- */
-static void *
-malloc_pages(size_t size)
-{
- void *p, *delay_free = NULL, *tp;
- size_t i;
- struct pginfo **pd;
- struct pdinfo *pi;
- u_long pidx, index;
- struct pgfree *pf;
-
- size = pageround(size) + malloc_guard;
-
- p = NULL;
- /* Look for free pages before asking for more */
- if (!align)
- for (pf = free_list.next; pf; pf = pf->next) {
-
-#ifdef MALLOC_EXTRA_SANITY
- if (pf->size & malloc_pagemask) {
- wrterror("(ES): junk length entry on free_list");
- errno = EFAULT;
- return (NULL);
- }
- if (!pf->size) {
- wrterror("(ES): zero length entry on free_list");
- errno = EFAULT;
- return (NULL);
- }
- if (pf->page > (pf->page + pf->size)) {
- wrterror("(ES): sick entry on free_list");
- errno = EFAULT;
- return (NULL);
- }
- if ((pi = pf->pdir) == NULL) {
- wrterror("(ES): invalid page directory on free-list");
- errno = EFAULT;
- return (NULL);
- }
- if ((pidx = PI_IDX(ptr2index(pf->page))) != PD_IDX(pi->dirnum)) {
- wrterror("(ES): directory index mismatch on free-list");
- errno = EFAULT;
- return (NULL);
- }
- pd = pi->base;
- if (pd[PI_OFF(ptr2index(pf->page))] != MALLOC_FREE) {
- wrterror("(ES): non-free first page on free-list");
- errno = EFAULT;
- return (NULL);
- }
- pidx = PI_IDX(ptr2index((pf->page) + (pf->size)) - 1);
- for (pi = pf->pdir; pi != NULL && PD_IDX(pi->dirnum) < pidx;
- pi = pi->next)
- ;
- if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
- wrterror("(ES): last page not referenced in page directory");
- errno = EFAULT;
- return (NULL);
- }
- pd = pi->base;
- if (pd[PI_OFF(ptr2index((pf->page) + (pf->size)) - 1)] != MALLOC_FREE) {
- wrterror("(ES): non-free last page on free-list");
- errno = EFAULT;
- return (NULL);
- }
-#endif /* MALLOC_EXTRA_SANITY */
-
- if (pf->size < size)
- continue;
-
- if (pf->size == size) {
- p = pf->page;
- pi = pf->pdir;
- if (pf->next != NULL)
- pf->next->prev = pf->prev;
- pf->prev->next = pf->next;
- delay_free = pf;
- break;
- }
- p = pf->page;
- pf->page = (char *) pf->page + size;
- pf->size -= size;
- pidx = PI_IDX(ptr2index(pf->page));
- for (pi = pf->pdir; pi != NULL && PD_IDX(pi->dirnum) < pidx;
- pi = pi->next)
- ;
- if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
- wrterror("(ES): hole in directories");
- errno = EFAULT;
- return (NULL);
- }
- tp = pf->pdir;
- pf->pdir = pi;
- pi = tp;
- break;
- }
-
- size -= malloc_guard;
-
-#ifdef MALLOC_EXTRA_SANITY
- if (p != NULL && pi != NULL) {
- pidx = PD_IDX(pi->dirnum);
- pd = pi->base;
- }
- if (p != NULL && pd[PI_OFF(ptr2index(p))] != MALLOC_FREE) {
- wrterror("(ES): allocated non-free page on free-list");
- errno = EFAULT;
- return (NULL);
- }
-#endif /* MALLOC_EXTRA_SANITY */
-
- if (p != NULL && (malloc_guard || malloc_freeprot))
- mprotect(p, size, PROT_READ | PROT_WRITE);
-
- size >>= malloc_pageshift;
-
- /* Map new pages */
- if (p == NULL)
- p = map_pages(size);
-
- if (p != NULL) {
- index = ptr2index(p);
- pidx = PI_IDX(index);
- pdir_lookup(index, &pi);
-#ifdef MALLOC_EXTRA_SANITY
- if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
- wrterror("(ES): mapped pages not found in directory");
- errno = EFAULT;
- return (NULL);
- }
-#endif /* MALLOC_EXTRA_SANITY */
- if (pi != last_dir) {
- prev_dir = last_dir;
- last_dir = pi;
- }
- pd = pi->base;
- pd[PI_OFF(index)] = MALLOC_FIRST;
-
- for (i = 1; i < size; i++) {
- if (!PI_OFF(index + i)) {
- pidx++;
- pi = pi->next;
-#ifdef MALLOC_EXTRA_SANITY
- if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
- wrterror("(ES): hole in mapped pages directory");
- errno = EFAULT;
- return (NULL);
- }
-#endif /* MALLOC_EXTRA_SANITY */
- pd = pi->base;
- }
- pd[PI_OFF(index + i)] = MALLOC_FOLLOW;
- }
- if (malloc_guard) {
- if (!PI_OFF(index + i)) {
- pidx++;
- pi = pi->next;
-#ifdef MALLOC_EXTRA_SANITY
- if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
- wrterror("(ES): hole in mapped pages directory");
- errno = EFAULT;
- return (NULL);
- }
-#endif /* MALLOC_EXTRA_SANITY */
- pd = pi->base;
- }
- pd[PI_OFF(index + i)] = MALLOC_FIRST;
- }
-
- malloc_used += size << malloc_pageshift;
- malloc_guarded += malloc_guard;
-
- if (malloc_junk)
- memset(p, SOME_JUNK, size << malloc_pageshift);
- }
- if (delay_free) {
- if (px == NULL)
- px = delay_free;
- else
- ifree(delay_free);
- }
- return (p);
-}
-
-/*
- * Allocate a page of fragments
- */
-
-static __inline__ int
-malloc_make_chunks(int bits)
-{
- struct pginfo *bp, **pd;
- struct pdinfo *pi;
-#ifdef MALLOC_EXTRA_SANITY
- u_long pidx;
-#endif /* MALLOC_EXTRA_SANITY */
- void *pp;
- long i, k;
- size_t l;
-
- /* Allocate a new bucket */
- pp = malloc_pages((size_t) malloc_pagesize);
- if (pp == NULL)
- return (0);
-
- /* Find length of admin structure */
- l = sizeof *bp - sizeof(u_long);
- l += sizeof(u_long) *
- (((malloc_pagesize >> bits) + MALLOC_BITS - 1) / MALLOC_BITS);
-
- /* Don't waste more than two chunks on this */
-
- /*
- * If we are to allocate a memory protected page for the malloc(0)
- * case (when bits=0), it must be from a different page than the
- * pginfo page.
- * --> Treat it like the big chunk alloc, get a second data page.
- */
- if (bits != 0 && (1UL << (bits)) <= l + l) {
- bp = (struct pginfo *) pp;
- } else {
- bp = (struct pginfo *) imalloc(l);
- if (bp == NULL) {
- ifree(pp);
- return (0);
- }
- }
-
- /* memory protect the page allocated in the malloc(0) case */
- if (bits == 0) {
- bp->size = 0;
- bp->shift = 1;
- i = malloc_minsize - 1;
- while (i >>= 1)
- bp->shift++;
- bp->total = bp->free = malloc_pagesize >> bp->shift;
- bp->page = pp;
-
- k = mprotect(pp, malloc_pagesize, PROT_NONE);
- if (k < 0) {
- ifree(pp);
- ifree(bp);
- return (0);
- }
- } else {
- bp->size = (1UL << bits);
- bp->shift = bits;
- bp->total = bp->free = malloc_pagesize >> bits;
- bp->page = pp;
- }
-
- /* set all valid bits in the bitmap */
- k = bp->total;
- i = 0;
-
- /* Do a bunch at a time */
- for (; (k - i) >= MALLOC_BITS; i += MALLOC_BITS)
- bp->bits[i / MALLOC_BITS] = ~0UL;
-
- for (; i < k; i++)
- bp->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS);
-
- k = (long)l;
- if (bp == bp->page) {
- /* Mark the ones we stole for ourselves */
- for (i = 0; k > 0; i++) {
- bp->bits[i / MALLOC_BITS] &= ~(1UL << (i % MALLOC_BITS));
- bp->free--;
- bp->total--;
- k -= (1 << bits);
- }
- }
- /* MALLOC_LOCK */
-
- pdir_lookup(ptr2index(pp), &pi);
-#ifdef MALLOC_EXTRA_SANITY
- pidx = PI_IDX(ptr2index(pp));
- if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
- wrterror("(ES): mapped pages not found in directory");
- errno = EFAULT;
- return (0);
- }
-#endif /* MALLOC_EXTRA_SANITY */
- if (pi != last_dir) {
- prev_dir = last_dir;
- last_dir = pi;
- }
- pd = pi->base;
- pd[PI_OFF(ptr2index(pp))] = bp;
-
- bp->next = page_dir[bits];
- page_dir[bits] = bp;
-
- /* MALLOC_UNLOCK */
- return (1);
-}
-
-/*
- * Allocate a fragment
- */
-static void *
-malloc_bytes(size_t size)
-{
- int i, j;
- size_t k;
- u_long u, *lp;
- struct pginfo *bp;
-
- /* Don't bother with anything less than this */
- /* unless we have a malloc(0) requests */
- if (size != 0 && size < malloc_minsize)
- size = malloc_minsize;
-
- /* Find the right bucket */
- if (size == 0)
- j = 0;
- else {
- size_t ii;
- j = 1;
- ii = size - 1;
- while (ii >>= 1)
- j++;
- }
-
- /* If it's empty, make a page more of that size chunks */
- if (page_dir[j] == NULL && !malloc_make_chunks(j))
- return (NULL);
-
- bp = page_dir[j];
-
- /* Find first word of bitmap which isn't empty */
- for (lp = bp->bits; !*lp; lp++);
-
- /* Find that bit, and tweak it */
- u = 1;
- k = 0;
- while (!(*lp & u)) {
- u += u;
- k++;
- }
-
- if (malloc_guard) {
- /* Walk to a random position. */
-// i = arc4random() % bp->free;
- i = rand() % bp->free;
- while (i > 0) {
- u += u;
- k++;
- if (k >= MALLOC_BITS) {
- lp++;
- u = 1;
- k = 0;
- }
-#ifdef MALLOC_EXTRA_SANITY
- if (lp - bp->bits > (bp->total - 1) / MALLOC_BITS) {
- wrterror("chunk overflow");
- errno = EFAULT;
- return (NULL);
- }
-#endif /* MALLOC_EXTRA_SANITY */
- if (*lp & u)
- i--;
- }
- }
- *lp ^= u;
-
- /* If there are no more free, remove from free-list */
- if (!--bp->free) {
- page_dir[j] = bp->next;
- bp->next = NULL;
- }
- /* Adjust to the real offset of that chunk */
- k += (lp - bp->bits) * MALLOC_BITS;
- k <<= bp->shift;
-
- if (malloc_junk && bp->size != 0)
- memset((char *)bp->page + k, SOME_JUNK, (size_t)bp->size);
-
- return ((u_char *) bp->page + k);
-}
-
-/*
- * Magic so that malloc(sizeof(ptr)) is near the end of the page.
- */
-#define PTR_GAP (malloc_pagesize - sizeof(void *))
-#define PTR_SIZE (sizeof(void *))
-#define PTR_ALIGNED(p) (((unsigned long)p & malloc_pagemask) == PTR_GAP)
-
-/*
- * Allocate a piece of memory
- */
-static void *
-imalloc(size_t size)
-{
- void *result;
- int ptralloc = 0;
-
- if (!malloc_started)
- malloc_init();
-
- if (suicide)
- abort();
-
- /* does not matter if malloc_bytes fails */
- if (px == NULL)
- px = malloc_bytes(sizeof *px);
-
- if (malloc_ptrguard && size == PTR_SIZE) {
- ptralloc = 1;
- size = malloc_pagesize;
- }
- if (size > SIZE_MAX - malloc_pagesize) { /* Check for overflow */
- result = NULL;
- errno = ENOMEM;
- } else if (size <= malloc_maxsize)
- result = malloc_bytes(size);
- else
- result = malloc_pages(size);
-
- if (malloc_abort == 1 && result == NULL)
- wrterror("allocation failed");
-
- if (malloc_zero && result != NULL)
- memset(result, 0, size);
-
- if (result && ptralloc)
- return ((char *) result + PTR_GAP);
- return (result);
-}
-
-/*
- * Change the size of an allocation.
- */
-static void *
-irealloc(void *ptr, size_t size)
-{
- void *p;
- size_t osize;
- u_long index, i;
- struct pginfo **mp;
- struct pginfo **pd;
- struct pdinfo *pi;
-#ifdef MALLOC_EXTRA_SANITY
- u_long pidx;
-#endif /* MALLOC_EXTRA_SANITY */
-
- if (suicide)
- abort();
-
- if (!malloc_started) {
- wrtwarning("malloc() has never been called");
- return (NULL);
- }
- if (malloc_ptrguard && PTR_ALIGNED(ptr)) {
- if (size <= PTR_SIZE)
- return (ptr);
-
- p = imalloc(size);
- if (p)
- memcpy(p, ptr, PTR_SIZE);
- ifree(ptr);
- return (p);
- }
- index = ptr2index(ptr);
-
- if (index < malloc_pageshift) {
- wrtwarning("junk pointer, too low to make sense");
- return (NULL);
- }
- if (index > last_index) {
- wrtwarning("junk pointer, too high to make sense");
- return (NULL);
- }
- pdir_lookup(index, &pi);
-#ifdef MALLOC_EXTRA_SANITY
- pidx = PI_IDX(index);
- if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
- wrterror("(ES): mapped pages not found in directory");
- errno = EFAULT;
- return (NULL);
- }
-#endif /* MALLOC_EXTRA_SANITY */
- if (pi != last_dir) {
- prev_dir = last_dir;
- last_dir = pi;
- }
- pd = pi->base;
- mp = &pd[PI_OFF(index)];
-
- if (*mp == MALLOC_FIRST) { /* Page allocation */
-
- /* Check the pointer */
- if ((u_long) ptr & malloc_pagemask) {
- wrtwarning("modified (page-) pointer");
- return (NULL);
- }
- /* Find the size in bytes */
- i = index;
- if (!PI_OFF(++i)) {
- pi = pi->next;
- if (pi != NULL && PD_IDX(pi->dirnum) != PI_IDX(i))
- pi = NULL;
- if (pi != NULL)
- pd = pi->base;
- }
- for (osize = malloc_pagesize;
- pi != NULL && pd[PI_OFF(i)] == MALLOC_FOLLOW;) {
- osize += malloc_pagesize;
- if (!PI_OFF(++i)) {
- pi = pi->next;
- if (pi != NULL && PD_IDX(pi->dirnum) != PI_IDX(i))
- pi = NULL;
- if (pi != NULL)
- pd = pi->base;
- }
- }
-
- if (!malloc_realloc && size <= osize &&
- size > osize - malloc_pagesize) {
- if (malloc_junk)
- memset((char *)ptr + size, SOME_JUNK, osize - size);
- return (ptr); /* ..don't do anything else. */
- }
- } else if (*mp >= MALLOC_MAGIC) { /* Chunk allocation */
-
- /* Check the pointer for sane values */
- if ((u_long) ptr & ((1UL << ((*mp)->shift)) - 1)) {
- wrtwarning("modified (chunk-) pointer");
- return (NULL);
- }
- /* Find the chunk index in the page */
- i = ((u_long) ptr & malloc_pagemask) >> (*mp)->shift;
-
- /* Verify that it isn't a free chunk already */
- if ((*mp)->bits[i / MALLOC_BITS] & (1UL << (i % MALLOC_BITS))) {
- wrtwarning("chunk is already free");
- return (NULL);
- }
- osize = (*mp)->size;
-
- if (!malloc_realloc && size <= osize &&
- (size > osize / 2 || osize == malloc_minsize)) {
- if (malloc_junk)
- memset((char *) ptr + size, SOME_JUNK, osize - size);
- return (ptr); /* ..don't do anything else. */
- }
- } else {
- wrtwarning("irealloc: pointer to wrong page");
- return (NULL);
- }
-
- p = imalloc(size);
-
- if (p != NULL) {
- /* copy the lesser of the two sizes, and free the old one */
- /* Don't move from/to 0 sized region !!! */
- if (osize != 0 && size != 0) {
- if (osize < size)
- memcpy(p, ptr, osize);
- else
- memcpy(p, ptr, size);
- }
- ifree(ptr);
- }
- return (p);
-}
-
-/*
- * Free a sequence of pages
- */
-static __inline__ void
-free_pages(void *ptr, u_long index, struct pginfo * info)
-{
- u_long i, pidx, lidx;
- size_t l, cachesize = 0;
- struct pginfo **pd;
- struct pdinfo *pi, *spi;
- struct pgfree *pf, *pt = NULL;
- caddr_t tail;
-
- if (info == MALLOC_FREE) {
- wrtwarning("page is already free");
- return;
- }
- if (info != MALLOC_FIRST) {
- wrtwarning("free_pages: pointer to wrong page");
- return;
- }
- if ((u_long) ptr & malloc_pagemask) {
- wrtwarning("modified (page-) pointer");
- return;
- }
- /* Count how many pages and mark them free at the same time */
- pidx = PI_IDX(index);
- pdir_lookup(index, &pi);
-#ifdef MALLOC_EXTRA_SANITY
- if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
- wrterror("(ES): mapped pages not found in directory");
- errno = EFAULT;
- return;
- }
-#endif /* MALLOC_EXTRA_SANITY */
-
- spi = pi; /* Save page index for start of region. */
-
- pd = pi->base;
- pd[PI_OFF(index)] = MALLOC_FREE;
- i = 1;
- if (!PI_OFF(index + i)) {
- pi = pi->next;
- if (pi == NULL || PD_IDX(pi->dirnum) != PI_IDX(index + i))
- pi = NULL;
- else
- pd = pi->base;
- }
- while (pi != NULL && pd[PI_OFF(index + i)] == MALLOC_FOLLOW) {
- pd[PI_OFF(index + i)] = MALLOC_FREE;
- i++;
- if (!PI_OFF(index + i)) {
- if ((pi = pi->next) == NULL ||
- PD_IDX(pi->dirnum) != PI_IDX(index + i))
- pi = NULL;
- else
- pd = pi->base;
- }
- }
-
- l = i << malloc_pageshift;
-
- if (malloc_junk)
- memset(ptr, SOME_JUNK, l);
-
- malloc_used -= l;
- malloc_guarded -= malloc_guard;
- if (malloc_guard) {
-#ifdef MALLOC_EXTRA_SANITY
- if (pi == NULL || PD_IDX(pi->dirnum) != PI_IDX(index + i)) {
- wrterror("(ES): hole in mapped pages directory");
- errno = EFAULT;
- return;
- }
-#endif /* MALLOC_EXTRA_SANITY */
- pd[PI_OFF(index + i)] = MALLOC_FREE;
- l += malloc_guard;
- }
- tail = (caddr_t)ptr + l;
-
- if (malloc_hint)
- madvise(ptr, l, MADV_FREE);
-
- if (malloc_freeprot)
- mprotect(ptr, l, PROT_NONE);
-
- /* Add to free-list. */
- if (px == NULL && (px = malloc_bytes(sizeof *px)) == NULL)
- goto not_return;
- px->page = ptr;
- px->pdir = spi;
- px->size = l;
-
- if (free_list.next == NULL) {
- /* Nothing on free list, put this at head. */
- px->next = NULL;
- px->prev = &free_list;
- free_list.next = px;
- pf = px;
- px = NULL;
- } else {
- /*
- * Find the right spot, leave pf pointing to the modified
- * entry.
- */
-
- /* Race ahead here, while calculating cache size. */
- for (pf = free_list.next;
- (caddr_t)ptr > ((caddr_t)pf->page + pf->size)
- && pf->next != NULL;
- pf = pf->next)
- cachesize += pf->size;
-
- /* Finish cache size calculation. */
- pt = pf;
- while (pt) {
- cachesize += pt->size;
- pt = pt->next;
- }
-
- if ((caddr_t)pf->page > tail) {
- /* Insert before entry */
- px->next = pf;
- px->prev = pf->prev;
- pf->prev = px;
- px->prev->next = px;
- pf = px;
- px = NULL;
- } else if (((caddr_t)pf->page + pf->size) == ptr) {
- /* Append to the previous entry. */
- cachesize -= pf->size;
- pf->size += l;
- if (pf->next != NULL &&
- pf->next->page == ((caddr_t)pf->page + pf->size)) {
- /* And collapse the next too. */
- pt = pf->next;
- pf->size += pt->size;
- pf->next = pt->next;
- if (pf->next != NULL)
- pf->next->prev = pf;
- }
- } else if (pf->page == tail) {
- /* Prepend to entry. */
- cachesize -= pf->size;
- pf->size += l;
- pf->page = ptr;
- pf->pdir = spi;
- } else if (pf->next == NULL) {
- /* Append at tail of chain. */
- px->next = NULL;
- px->prev = pf;
- pf->next = px;
- pf = px;
- px = NULL;
- } else {
- wrterror("freelist is destroyed");
- errno = EFAULT;
- return;
- }
- }
-
- if (pf->pdir != last_dir) {
- prev_dir = last_dir;
- last_dir = pf->pdir;
- }
-
- /* Return something to OS ? */
- if (pf->size > (malloc_cache - cachesize)) {
-
- /*
- * Keep the cache intact. Notice that the '>' above guarantees that
- * the pf will always have at least one page afterwards.
- */
- if (munmap((char *) pf->page + (malloc_cache - cachesize),
- pf->size - (malloc_cache - cachesize)) != 0)
- goto not_return;
- tail = (caddr_t)pf->page + pf->size;
- lidx = ptr2index(tail) - 1;
- pf->size = malloc_cache - cachesize;
-
- index = ptr2index((caddr_t)pf->page + pf->size);
-
- pidx = PI_IDX(index);
- if (prev_dir != NULL && PD_IDX(prev_dir->dirnum) >= pidx)
- prev_dir = NULL; /* Will be wiped out below ! */
-
- for (pi = pf->pdir; pi != NULL && PD_IDX(pi->dirnum) < pidx;
- pi = pi->next)
- ;
-
- spi = pi;
- if (pi != NULL && PD_IDX(pi->dirnum) == pidx) {
- pd = pi->base;
-
- for (i = index; i <= lidx;) {
- if (pd[PI_OFF(i)] != MALLOC_NOT_MINE) {
- pd[PI_OFF(i)] = MALLOC_NOT_MINE;
-#ifdef MALLOC_EXTRA_SANITY
- if (!PD_OFF(pi->dirnum)) {
- wrterror("(ES): pages directory underflow");
- errno = EFAULT;
- return;
- }
-#endif /* MALLOC_EXTRA_SANITY */
- pi->dirnum--;
- }
-#ifdef MALLOC_EXTRA_SANITY
- else
- wrtwarning("(ES): page already unmapped");
-#endif /* MALLOC_EXTRA_SANITY */
- i++;
- if (!PI_OFF(i)) {
- /*
- * If no page in that dir, free
- * directory page.
- */
- if (!PD_OFF(pi->dirnum)) {
- /* Remove from list. */
- if (spi == pi)
- spi = pi->prev;
- if (pi->prev != NULL)
- pi->prev->next = pi->next;
- if (pi->next != NULL)
- pi->next->prev = pi->prev;
- pi = pi->next;
- munmap(pd, malloc_pagesize);
- } else
- pi = pi->next;
- if (pi == NULL ||
- PD_IDX(pi->dirnum) != PI_IDX(i))
- break;
- pd = pi->base;
- }
- }
- if (pi && !PD_OFF(pi->dirnum)) {
- /* Resulting page dir is now empty. */
- /* Remove from list. */
- if (spi == pi) /* Update spi only if first. */
- spi = pi->prev;
- if (pi->prev != NULL)
- pi->prev->next = pi->next;
- if (pi->next != NULL)
- pi->next->prev = pi->prev;
- pi = pi->next;
- munmap(pd, malloc_pagesize);
- }
- }
- if (pi == NULL && malloc_brk == tail) {
- /* Resize down the malloc upper boundary. */
- last_index = index - 1;
- malloc_brk = index2ptr(index);
- }
-
- /* XXX: We could realloc/shrink the pagedir here I guess. */
- if (pf->size == 0) { /* Remove from free-list as well. */
- if (px)
- ifree(px);
- if ((px = pf->prev) != &free_list) {
- if (pi == NULL && last_index == (index - 1)) {
- if (spi == NULL) {
- malloc_brk = NULL;
- i = 11;
- } else {
- pd = spi->base;
- if (PD_IDX(spi->dirnum) < pidx)
- index =
- ((PD_IDX(spi->dirnum) + 1) *
- pdi_mod) - 1;
- for (pi = spi, i = index;
- pd[PI_OFF(i)] == MALLOC_NOT_MINE;
- i--)
-#ifdef MALLOC_EXTRA_SANITY
- if (!PI_OFF(i)) {
- pi = pi->prev;
- if (pi == NULL || i == 0)
- break;
- pd = pi->base;
- i = (PD_IDX(pi->dirnum) + 1) * pdi_mod;
- }
-#else /* !MALLOC_EXTRA_SANITY */
- {
- }
-#endif /* MALLOC_EXTRA_SANITY */
- malloc_brk = index2ptr(i + 1);
- }
- last_index = i;
- }
- if ((px->next = pf->next) != NULL)
- px->next->prev = px;
- } else {
- if ((free_list.next = pf->next) != NULL)
- free_list.next->prev = &free_list;
- }
- px = pf;
- last_dir = prev_dir;
- prev_dir = NULL;
- }
- }
-not_return:
- if (pt != NULL)
- ifree(pt);
-}
-
-/*
- * Free a chunk, and possibly the page it's on, if the page becomes empty.
- */
-
-/* ARGSUSED */
-static __inline__ void
-free_bytes(void *ptr, u_long index, struct pginfo * info)
-{
- struct pginfo **mp, **pd;
- struct pdinfo *pi;
-#ifdef MALLOC_EXTRA_SANITY
- u_long pidx;
-#endif /* MALLOC_EXTRA_SANITY */
- void *vp;
- long i;
- (void) index;
-
- /* Find the chunk number on the page */
- i = ((u_long) ptr & malloc_pagemask) >> info->shift;
-
- if ((u_long) ptr & ((1UL << (info->shift)) - 1)) {
- wrtwarning("modified (chunk-) pointer");
- return;
- }
- if (info->bits[i / MALLOC_BITS] & (1UL << (i % MALLOC_BITS))) {
- wrtwarning("chunk is already free");
- return;
- }
- if (malloc_junk && info->size != 0)
- memset(ptr, SOME_JUNK, (size_t)info->size);
-
- info->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS);
- info->free++;
-
- if (info->size != 0)
- mp = page_dir + info->shift;
- else
- mp = page_dir;
-
- if (info->free == 1) {
- /* Page became non-full */
-
- /* Insert in address order */
- while (*mp != NULL && (*mp)->next != NULL &&
- (*mp)->next->page < info->page)
- mp = &(*mp)->next;
- info->next = *mp;
- *mp = info;
- return;
- }
- if (info->free != info->total)
- return;
-
- /* Find & remove this page in the queue */
- while (*mp != info) {
- mp = &((*mp)->next);
-#ifdef MALLOC_EXTRA_SANITY
- if (!*mp) {
- wrterror("(ES): Not on queue");
- errno = EFAULT;
- return;
- }
-#endif /* MALLOC_EXTRA_SANITY */
- }
- *mp = info->next;
-
- /* Free the page & the info structure if need be */
- pdir_lookup(ptr2index(info->page), &pi);
-#ifdef MALLOC_EXTRA_SANITY
- pidx = PI_IDX(ptr2index(info->page));
- if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
- wrterror("(ES): mapped pages not found in directory");
- errno = EFAULT;
- return;
- }
-#endif /* MALLOC_EXTRA_SANITY */
- if (pi != last_dir) {
- prev_dir = last_dir;
- last_dir = pi;
- }
- pd = pi->base;
- pd[PI_OFF(ptr2index(info->page))] = MALLOC_FIRST;
-
- /* If the page was mprotected, unprotect it before releasing it */
- if (info->size == 0)
- mprotect(info->page, malloc_pagesize, PROT_READ | PROT_WRITE);
-
- vp = info->page; /* Order is important ! */
- if (vp != (void *) info)
- ifree(info);
- ifree(vp);
-}
-
-static void
-ifree(void *ptr)
-{
- struct pginfo *info, **pd;
- u_long index;
-#ifdef MALLOC_EXTRA_SANITY
- u_long pidx;
-#endif /* MALLOC_EXTRA_SANITY */
- struct pdinfo *pi;
-
- if (!malloc_started) {
- wrtwarning("malloc() has never been called");
- return;
- }
- /* If we're already sinking, don't make matters any worse. */
- if (suicide)
- return;
-
- if (malloc_ptrguard && PTR_ALIGNED(ptr))
- ptr = (char *) ptr - PTR_GAP;
-
- index = ptr2index(ptr);
-
- if (index < malloc_pageshift) {
- warnx("(%p)", ptr);
- wrtwarning("ifree: junk pointer, too low to make sense");
- return;
- }
- if (index > last_index) {
- warnx("(%p)", ptr);
- wrtwarning("ifree: junk pointer, too high to make sense");
- return;
- }
- pdir_lookup(index, &pi);
-#ifdef MALLOC_EXTRA_SANITY
- pidx = PI_IDX(index);
- if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
- wrterror("(ES): mapped pages not found in directory");
- errno = EFAULT;
- return;
- }
-#endif /* MALLOC_EXTRA_SANITY */
- if (pi != last_dir) {
- prev_dir = last_dir;
- last_dir = pi;
- }
- pd = pi->base;
- info = pd[PI_OFF(index)];
-
- if (info < MALLOC_MAGIC)
- free_pages(ptr, index, info);
- else
- free_bytes(ptr, index, info);
-
- /* does not matter if malloc_bytes fails */
- if (px == NULL)
- px = malloc_bytes(sizeof *px);
-
- return;
-}
-
-/*
- * Common function for handling recursion. Only
- * print the error message once, to avoid making the problem
- * potentially worse.
- */
-static void
-malloc_recurse(void)
-{
- static int noprint;
-
- if (noprint == 0) {
- noprint = 1;
- wrtwarning("recursive call");
- }
- malloc_active--;
- _MALLOC_UNLOCK();
- errno = EDEADLK;
-}
-
-/*
- * These are the public exported interface routines.
- */
-void *
-malloc(size_t size)
-{
- void *r;
-
- if (!align)
- _MALLOC_LOCK();
- malloc_func = " in malloc():";
- if (malloc_active++) {
- malloc_recurse();
- return (NULL);
- }
- r = imalloc(size);
- UTRACE(0, size, r);
- malloc_active--;
- if (!align)
- _MALLOC_UNLOCK();
- if (malloc_xmalloc && r == NULL) {
- wrterror("out of memory");
- errno = ENOMEM;
- }
- return (r);
-}
-
-void
-free(void *ptr)
-{
- /* This is legal. XXX quick path */
- if (ptr == NULL)
- return;
-
- _MALLOC_LOCK();
- malloc_func = " in free():";
- if (malloc_active++) {
- malloc_recurse();
- return;
- }
- ifree(ptr);
- UTRACE(ptr, 0, 0);
- malloc_active--;
- _MALLOC_UNLOCK();
- return;
-}
-
-void *
-realloc(void *ptr, size_t size)
-{
- void *r;
-
- _MALLOC_LOCK();
- malloc_func = " in realloc():";
- if (malloc_active++) {
- malloc_recurse();
- return (NULL);
- }
-
- if (ptr == NULL)
- r = imalloc(size);
- else
- r = irealloc(ptr, size);
-
- UTRACE(ptr, size, r);
- malloc_active--;
- _MALLOC_UNLOCK();
- if (malloc_xmalloc && r == NULL) {
- wrterror("out of memory");
- errno = ENOMEM;
- }
- return (r);
-}
-
-#ifndef SIZE_MAX
-//#if defined(__i386__)||defined(__arm__)||defined(__powerpc__)
-//#define SIZE_MAX 0xffffffff
-//#endif
-//#if defined(__x86_64__)
-//#define SIZE_MAX 0xffffffffffffffff
-//#endif
-#define SIZE_MAX SIZE_T_MAX
-#endif
-
-void *
-calloc(size_t num, size_t size)
-{
- void *p;
-
- if (num && SIZE_MAX / num < size) {
- fprintf(stderr,"OOOOPS");
- errno = ENOMEM;
- return NULL;
- }
- size *= num;
- p = malloc(size);
- if (p)
- memset(p, 0, size);
- return(p);
-}
-
-#ifndef BUILDING_FOR_TOR
-static int ispowerof2 (size_t a) {
- size_t b;
- for (b = 1ULL << (sizeof(size_t)*NBBY - 1); b > 1; b >>= 1)
- if (b == a)
- return 1;
- return 0;
-}
-#endif
-
-#ifndef BUILDING_FOR_TOR
-int posix_memalign(void **memptr, size_t alignment, size_t size)
-{
- void *r;
- size_t max;
- if ((alignment < PTR_SIZE) || (alignment%PTR_SIZE != 0)) return EINVAL;
- if (!ispowerof2(alignment)) return EINVAL;
- if (alignment < malloc_minsize) alignment = malloc_minsize;
- max = alignment > size ? alignment : size;
- if (alignment <= malloc_pagesize)
- r = malloc(max);
- else {
- _MALLOC_LOCK();
- align = 1;
- g_alignment = alignment;
- r = malloc(size);
- align=0;
- _MALLOC_UNLOCK();
- }
- *memptr = r;
- if (!r) return ENOMEM;
- return 0;
-}
-
-void *memalign(size_t boundary, size_t size)
-{
- void *r;
- posix_memalign(&r, boundary, size);
- return r;
-}
-
-void *valloc(size_t size)
-{
- void *r;
- posix_memalign(&r, malloc_pagesize, size);
- return r;
-}
-#endif
-
-size_t malloc_good_size(size_t size)
-{
- if (size == 0) {
- return 1;
- } else if (size <= malloc_maxsize) {
- int j;
- size_t ii;
- /* round up to the nearest power of 2, with same approach
- * as malloc_bytes() uses. */
- j = 1;
- ii = size - 1;
- while (ii >>= 1)
- j++;
- return ((size_t)1) << j;
- } else {
- return pageround(size);
- }
-}
diff --git a/src/common/address.c b/src/common/address.c
index df26f61f8..14a7b6bc9 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -181,6 +181,16 @@ tor_addr_make_unspec(tor_addr_t *a)
a->family = AF_UNSPEC;
}
+/** Set address <a>a</b> to the null address in address family <b>family</b>.
+ * The null address for AF_INET is 0.0.0.0. The null address for AF_INET6 is
+ * [::]. AF_UNSPEC is all null. */
+void
+tor_addr_make_null(tor_addr_t *a, sa_family_t family)
+{
+ memset(a, 0, sizeof(*a));
+ a->family = family;
+}
+
/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set
* *<b>addr</b> to the proper IP address and family. The <b>family</b>
* argument (which must be AF_INET, AF_INET6, or AF_UNSPEC) declares a
@@ -305,7 +315,8 @@ tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr)
* also treated as internal for now.)
*/
int
-tor_addr_is_internal(const tor_addr_t *addr, int for_listening)
+tor_addr_is_internal_(const tor_addr_t *addr, int for_listening,
+ const char *filename, int lineno)
{
uint32_t iph4 = 0;
uint32_t iph6[4];
@@ -355,8 +366,8 @@ tor_addr_is_internal(const tor_addr_t *addr, int for_listening)
/* unknown address family... assume it's not safe for external use */
/* rather than tor_assert(0) */
- log_warn(LD_BUG, "tor_addr_is_internal() called with a non-IP address of "
- "type %d", (int)v_family);
+ log_warn(LD_BUG, "tor_addr_is_internal() called from %s:%d with a "
+ "non-IP address of type %d", filename, lineno, (int)v_family);
tor_fragile_assert();
return 1;
}
@@ -558,9 +569,22 @@ tor_addr_to_PTR_name(char *out, size_t outlen,
*
* Return an address family on success, or -1 if an invalid address string is
* provided.
+ *
+ * If 'flags & TAPMP_EXTENDED_STAR' is false, then the wildcard address '*'
+ * yield an IPv4 wildcard.
+ *
+ * If 'flags & TAPMP_EXTENDED_STAR' is true, then the wildcard address '*'
+ * yields an AF_UNSPEC wildcard address, and the following change is made
+ * in the grammar above:
+ * Address ::= IPv4Address / "[" IPv6Address "]" / "*" / "*4" / "*6"
+ * with the new "*4" and "*6" productions creating a wildcard to match
+ * IPv4 or IPv6 addresses.
+ *
*/
int
-tor_addr_parse_mask_ports(const char *s, tor_addr_t *addr_out,
+tor_addr_parse_mask_ports(const char *s,
+ unsigned flags,
+ tor_addr_t *addr_out,
maskbits_t *maskbits_out,
uint16_t *port_min_out, uint16_t *port_max_out)
{
@@ -617,9 +641,23 @@ tor_addr_parse_mask_ports(const char *s, tor_addr_t *addr_out,
memset(addr_out, 0, sizeof(tor_addr_t));
if (!strcmp(address, "*")) {
- family = AF_INET; /* AF_UNSPEC ???? XXXX_IP6 */
+ if (flags & TAPMP_EXTENDED_STAR) {
+ family = AF_UNSPEC;
+ tor_addr_make_unspec(addr_out);
+ } else {
+ family = AF_INET;
+ tor_addr_from_ipv4h(addr_out, 0);
+ }
+ any_flag = 1;
+ } else if (!strcmp(address, "*4") && (flags & TAPMP_EXTENDED_STAR)) {
+ family = AF_INET;
tor_addr_from_ipv4h(addr_out, 0);
any_flag = 1;
+ } else if (!strcmp(address, "*6") && (flags & TAPMP_EXTENDED_STAR)) {
+ static char nil_bytes[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
+ family = AF_INET6;
+ tor_addr_from_ipv6_bytes(addr_out, nil_bytes);
+ any_flag = 1;
} else if (tor_inet_pton(AF_INET6, address, &in6_tmp) > 0) {
family = AF_INET6;
tor_addr_from_in6(addr_out, &in6_tmp);
@@ -1007,6 +1045,19 @@ fmt_addr_impl(const tor_addr_t *addr, int decorate)
return "???";
}
+/** Return a string representing the pair <b>addr</b> and <b>port</b>.
+ * This calls fmt_and_decorate_addr internally, so IPv6 addresses will
+ * have brackets, and the caveats of fmt_addr_impl apply.
+ */
+const char *
+fmt_addrport(const tor_addr_t *addr, uint16_t port)
+{
+ /* Add space for a colon and up to 5 digits. */
+ static char buf[TOR_ADDR_BUF_LEN + 6];
+ tor_snprintf(buf, sizeof(buf), "%s:%u", fmt_and_decorate_addr(addr), port);
+ return buf;
+}
+
/** Like fmt_addr(), but takes <b>addr</b> as a host-order IPv4
* addresses. Also not thread-safe, also clobbers its return buffer on
* repeated calls. */
@@ -1136,6 +1187,8 @@ get_interface_addresses_raw(int severity)
result = smartlist_new();
for (i = ifa; i; i = i->ifa_next) {
tor_addr_t tmp;
+ if ((i->ifa_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING))
+ continue;
if (!i->ifa_addr)
continue;
if (i->ifa_addr->sa_family != AF_INET &&
@@ -1220,14 +1273,14 @@ get_interface_addresses_raw(int severity)
/* This interface, AFAICT, only supports AF_INET addresses */
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
- log(severity, LD_NET, "socket failed: %s", strerror(errno));
+ tor_log(severity, LD_NET, "socket failed: %s", strerror(errno));
goto done;
}
/* Guess how much space we need. */
ifc.ifc_len = sz = 15*1024;
ifc.ifc_ifcu.ifcu_req = tor_malloc(sz);
if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
- log(severity, LD_NET, "ioctl failed: %s", strerror(errno));
+ tor_log(severity, LD_NET, "ioctl failed: %s", strerror(errno));
close(fd);
goto done;
}
@@ -1380,7 +1433,46 @@ is_internal_IP(uint32_t ip, int for_listening)
return tor_addr_is_internal(&myaddr, for_listening);
}
-/** Given an address of the form "host:port", try to divide it into its host
+/** Given an address of the form "ip:port", try to divide it into its
+ * ip and port portions, setting *<b>address_out</b> to a newly
+ * allocated string holding the address portion and *<b>port_out</b>
+ * to the port.
+ *
+ * Don't do DNS lookups and don't allow domain names in the <ip> field.
+ * Don't accept <b>addrport</b> of the form "<ip>" or "<ip>:0".
+ *
+ * Return 0 on success, -1 on failure. */
+int
+tor_addr_port_parse(int severity, const char *addrport,
+ tor_addr_t *address_out, uint16_t *port_out)
+{
+ int retval = -1;
+ int r;
+ char *addr_tmp = NULL;
+
+ tor_assert(addrport);
+ tor_assert(address_out);
+ tor_assert(port_out);
+
+ r = tor_addr_port_split(severity, addrport, &addr_tmp, port_out);
+ if (r < 0)
+ goto done;
+
+ if (!*port_out)
+ goto done;
+
+ /* make sure that address_out is an IP address */
+ if (tor_addr_parse(address_out, addr_tmp) < 0)
+ goto done;
+
+ retval = 0;
+
+ done:
+ tor_free(addr_tmp);
+ return retval;
+}
+
+/** Given an address of the form "host[:port]", try to divide it into its host
* ane port portions, setting *<b>address_out</b> to a newly allocated string
* holding the address portion and *<b>port_out</b> to the port (or 0 if no
* port is given). Return 0 on success, -1 on failure. */
@@ -1409,17 +1501,17 @@ addr_port_lookup(int severity, const char *addrport, char **address,
uint32_t *addr, uint16_t *port_out)
{
const char *colon;
- char *_address = NULL;
- int _port;
+ char *address_ = NULL;
+ int port_;
int ok = 1;
tor_assert(addrport);
colon = strrchr(addrport, ':');
if (colon) {
- _address = tor_strndup(addrport, colon-addrport);
- _port = (int) tor_parse_long(colon+1,10,1,65535,NULL,NULL);
- if (!_port) {
+ address_ = tor_strndup(addrport, colon-addrport);
+ port_ = (int) tor_parse_long(colon+1,10,1,65535,NULL,NULL);
+ if (!port_) {
log_fn(severity, LD_GENERAL, "Port %s out of range", escaped(colon+1));
ok = 0;
}
@@ -1432,28 +1524,28 @@ addr_port_lookup(int severity, const char *addrport, char **address,
ok = 0;
}
} else {
- _address = tor_strdup(addrport);
- _port = 0;
+ address_ = tor_strdup(addrport);
+ port_ = 0;
}
if (addr) {
/* There's an addr pointer, so we need to resolve the hostname. */
- if (tor_lookup_hostname(_address,addr)) {
- log_fn(severity, LD_NET, "Couldn't look up %s", escaped(_address));
+ if (tor_lookup_hostname(address_,addr)) {
+ log_fn(severity, LD_NET, "Couldn't look up %s", escaped(address_));
ok = 0;
*addr = 0;
}
}
if (address && ok) {
- *address = _address;
+ *address = address_;
} else {
if (address)
*address = NULL;
- tor_free(_address);
+ tor_free(address_);
}
if (port_out)
- *port_out = ok ? ((uint16_t) _port) : 0;
+ *port_out = ok ? ((uint16_t) port_) : 0;
return ok ? 0 : -1;
}
@@ -1476,32 +1568,6 @@ addr_mask_get_bits(uint32_t mask)
return -1;
}
-/** Compare two addresses <b>a1</b> and <b>a2</b> for equality under a
- * netmask of <b>mbits</b> bits. Return -1, 0, or 1.
- *
- * XXXX_IP6 Temporary function to allow masks as bitcounts everywhere. This
- * will be replaced with an IPv6-aware version as soon as 32-bit addresses are
- * no longer passed around.
- */
-int
-addr_mask_cmp_bits(uint32_t a1, uint32_t a2, maskbits_t bits)
-{
- if (bits > 32)
- bits = 32;
- else if (bits == 0)
- return 0;
-
- a1 >>= (32-bits);
- a2 >>= (32-bits);
-
- if (a1 < a2)
- return -1;
- else if (a1 > a2)
- return 1;
- else
- return 0;
-}
-
/** Parse a string <b>s</b> in the format of (*|port(-maxport)?)?, setting the
* various *out pointers as appropriate. Return 0 on success, -1 on failure.
*/
@@ -1554,93 +1620,6 @@ parse_port_range(const char *port, uint16_t *port_min_out,
return 0;
}
-/** Parse a string <b>s</b> in the format of
- * (IP(/mask|/mask-bits)?|*)(:(*|port(-maxport))?)?, setting the various
- * *out pointers as appropriate. Return 0 on success, -1 on failure.
- */
-int
-parse_addr_and_port_range(const char *s, uint32_t *addr_out,
- maskbits_t *maskbits_out, uint16_t *port_min_out,
- uint16_t *port_max_out)
-{
- char *address;
- char *mask, *port, *endptr;
- struct in_addr in;
- int bits;
-
- tor_assert(s);
- tor_assert(addr_out);
- tor_assert(maskbits_out);
- tor_assert(port_min_out);
- tor_assert(port_max_out);
-
- address = tor_strdup(s);
- /* Break 'address' into separate strings.
- */
- mask = strchr(address,'/');
- port = strchr(mask?mask:address,':');
- if (mask)
- *mask++ = '\0';
- if (port)
- *port++ = '\0';
- /* Now "address" is the IP|'*' part...
- * "mask" is the Mask|Maskbits part...
- * and "port" is the *|port|min-max part.
- */
-
- if (strcmp(address,"*")==0) {
- *addr_out = 0;
- } else if (tor_inet_aton(address, &in) != 0) {
- *addr_out = ntohl(in.s_addr);
- } else {
- log_warn(LD_GENERAL, "Malformed IP %s in address pattern; rejecting.",
- escaped(address));
- goto err;
- }
-
- if (!mask) {
- if (strcmp(address,"*")==0)
- *maskbits_out = 0;
- else
- *maskbits_out = 32;
- } else {
- endptr = NULL;
- bits = (int) strtol(mask, &endptr, 10);
- if (!*endptr) {
- /* strtol handled the whole mask. */
- if (bits < 0 || bits > 32) {
- log_warn(LD_GENERAL,
- "Bad number of mask bits on address range; rejecting.");
- goto err;
- }
- *maskbits_out = bits;
- } else if (tor_inet_aton(mask, &in) != 0) {
- bits = addr_mask_get_bits(ntohl(in.s_addr));
- if (bits < 0) {
- log_warn(LD_GENERAL,
- "Mask %s on address range isn't a prefix; dropping",
- escaped(mask));
- goto err;
- }
- *maskbits_out = bits;
- } else {
- log_warn(LD_GENERAL,
- "Malformed mask %s on address range; rejecting.",
- escaped(mask));
- goto err;
- }
- }
-
- if (parse_port_range(port, port_min_out, port_max_out)<0)
- goto err;
-
- tor_free(address);
- return 0;
- err:
- tor_free(address);
- return -1;
-}
-
/** Given an IPv4 in_addr struct *<b>in</b> (in network order, as usual),
* write it as a string into the <b>buf_len</b>-byte buffer in
* <b>buf</b>.
@@ -1698,3 +1677,15 @@ tor_addr_hostname_is_local(const char *name)
!strcasecmpend(name, ".local");
}
+/** Return a newly allocated tor_addr_port_t with <b>addr</b> and
+ <b>port</b> filled in. */
+tor_addr_port_t *
+tor_addr_port_new(const tor_addr_t *addr, uint16_t port)
+{
+ tor_addr_port_t *ap = tor_malloc_zero(sizeof(tor_addr_port_t));
+ if (addr)
+ tor_addr_copy(&ap->addr, addr);
+ ap->port = port;
+ return ap;
+}
+
diff --git a/src/common/address.h b/src/common/address.h
index c6c126862..77e585534 100644
--- a/src/common/address.h
+++ b/src/common/address.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,8 +8,8 @@
* \brief Headers for address.h
**/
-#ifndef _TOR_ADDRESS_H
-#define _TOR_ADDRESS_H
+#ifndef TOR_ADDRESS_H
+#define TOR_ADDRESS_H
#include "orconfig.h"
#include "torint.h"
@@ -40,7 +40,7 @@ typedef struct tor_addr_port_t
uint16_t port;
} tor_addr_port_t;
-#define TOR_ADDR_NULL {AF_UNSPEC, {0}};
+#define TOR_ADDR_NULL {AF_UNSPEC, {0}}
static INLINE const struct in6_addr *tor_addr_to_in6(const tor_addr_t *a);
static INLINE uint32_t tor_addr_to_ipv4n(const tor_addr_t *a);
@@ -55,6 +55,7 @@ socklen_t tor_addr_to_sockaddr(const tor_addr_t *a, uint16_t port,
int tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa,
uint16_t *port_out);
void tor_addr_make_unspec(tor_addr_t *a);
+void tor_addr_make_null(tor_addr_t *a, sa_family_t family);
char *tor_sockaddr_to_str(const struct sockaddr *sa);
/** Return an in6_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not
@@ -145,6 +146,7 @@ char *tor_dup_addr(const tor_addr_t *addr) ATTR_MALLOC;
* addresses. */
#define fmt_and_decorate_addr(a) fmt_addr_impl((a), 1)
const char *fmt_addr_impl(const tor_addr_t *addr, int decorate);
+const char *fmt_addrport(const tor_addr_t *addr, uint16_t port);
const char * fmt_addr32(uint32_t addr);
int get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr);
@@ -167,7 +169,10 @@ int tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2,
unsigned int tor_addr_hash(const tor_addr_t *addr);
int tor_addr_is_v4(const tor_addr_t *addr);
-int tor_addr_is_internal(const tor_addr_t *ip, int for_listening);
+int tor_addr_is_internal_(const tor_addr_t *ip, int for_listening,
+ const char *filename, int lineno);
+#define tor_addr_is_internal(addr, for_listening) \
+ tor_addr_is_internal_((addr), (for_listening), SHORT_FILE__, __LINE__)
/** Longest length that can be required for a reverse lookup name. */
/* 32 nybbles, 32 dots, 8 characters of "ip6.arpa", 1 NUL: 73 characters. */
@@ -179,7 +184,8 @@ int tor_addr_parse_PTR_name(tor_addr_t *result, const char *address,
int tor_addr_port_lookup(const char *s, tor_addr_t *addr_out,
uint16_t *port_out);
-int tor_addr_parse_mask_ports(const char *s,
+#define TAPMP_EXTENDED_STAR 1
+int tor_addr_parse_mask_ports(const char *s, unsigned flags,
tor_addr_t *addr_out, maskbits_t *mask_out,
uint16_t *port_min_out, uint16_t *port_max_out);
const char * tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len,
@@ -202,6 +208,9 @@ int tor_addr_is_loopback(const tor_addr_t *addr);
int tor_addr_port_split(int severity, const char *addrport,
char **address_out, uint16_t *port_out);
+int tor_addr_port_parse(int severity, const char *addrport,
+ tor_addr_t *address_out, uint16_t *port_out);
+
int tor_addr_hostname_is_local(const char *name);
/* IPv4 helpers */
@@ -210,16 +219,14 @@ int addr_port_lookup(int severity, const char *addrport, char **address,
uint32_t *addr, uint16_t *port_out);
int parse_port_range(const char *port, uint16_t *port_min_out,
uint16_t *port_max_out);
-int parse_addr_and_port_range(const char *s, uint32_t *addr_out,
- maskbits_t *maskbits_out, uint16_t *port_min_out,
- uint16_t *port_max_out);
int addr_mask_get_bits(uint32_t mask);
-int addr_mask_cmp_bits(uint32_t a1, uint32_t a2, maskbits_t bits);
/** Length of a buffer to allocate to hold the results of tor_inet_ntoa.*/
#define INET_NTOA_BUF_LEN 16
int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len);
char *tor_dup_ip(uint32_t addr) ATTR_MALLOC;
int get_interface_address(int severity, uint32_t *addr);
+tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port);
+
#endif
diff --git a/src/common/aes.c b/src/common/aes.c
index 295a90749..f454a7f7b 100644
--- a/src/common/aes.c
+++ b/src/common/aes.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -41,6 +41,7 @@
#include "aes.h"
#include "util.h"
#include "torlog.h"
+#include "di_ops.h"
#ifdef ANDROID
/* Android's OpenSSL seems to have removed all of its Engine support. */
@@ -134,8 +135,8 @@ int
evaluate_evp_for_aes(int force_val)
{
(void) force_val;
- log_notice(LD_CRYPTO, "This version of OpenSSL has a known-good EVP "
- "counter-mode implementation. Using it.");
+ log_info(LD_CRYPTO, "This version of OpenSSL has a known-good EVP "
+ "counter-mode implementation. Using it.");
return 0;
}
int
@@ -212,11 +213,11 @@ evaluate_evp_for_aes(int force_val)
e = ENGINE_get_cipher_engine(NID_aes_128_ecb);
if (e) {
- log_notice(LD_CRYPTO, "AES engine \"%s\" found; using EVP_* functions.",
+ log_info(LD_CRYPTO, "AES engine \"%s\" found; using EVP_* functions.",
ENGINE_get_name(e));
should_use_EVP = 1;
} else {
- log_notice(LD_CRYPTO, "No AES engine found; using AES_* functions.");
+ log_info(LD_CRYPTO, "No AES engine found; using AES_* functions.");
should_use_EVP = 0;
}
#endif
@@ -257,18 +258,18 @@ evaluate_ctr_for_aes(void)
for (i=0; i<16; ++i)
AES_ctr128_encrypt(&zero[i], &output[i], 1, &key, ivec, ivec_tmp, &pos);
- if (memcmp(output, encrypt_zero, 16)) {
+ if (fast_memneq(output, encrypt_zero, 16)) {
/* Counter mode is buggy */
log_notice(LD_CRYPTO, "This OpenSSL has a buggy version of counter mode; "
"not using it.");
} else {
/* Counter mode is okay */
- log_notice(LD_CRYPTO, "This OpenSSL has a good implementation of counter "
+ log_info(LD_CRYPTO, "This OpenSSL has a good implementation of counter "
"mode; using it.");
should_use_openssl_CTR = 1;
}
#else
- log_notice(LD_CRYPTO, "This version of OpenSSL has a slow implementation of "
+ log_info(LD_CRYPTO, "This version of OpenSSL has a slow implementation of "
"counter mode; not using it.");
#endif
return 0;
@@ -285,7 +286,7 @@ evaluate_ctr_for_aes(void)
* value of the current counter.
*/
static INLINE void
-_aes_fill_buf(aes_cnt_cipher_t *cipher)
+aes_fill_buf_(aes_cnt_cipher_t *cipher)
{
/* We don't currently use OpenSSL's counter mode implementation because:
* 1) some versions have known bugs
@@ -340,7 +341,7 @@ aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits)
EVP_EncryptInit(&cipher->key.evp, c, (const unsigned char*)key, NULL);
cipher->using_evp = 1;
} else {
- AES_set_encrypt_key((const unsigned char *)key, key_bits, &cipher->key.aes);
+ AES_set_encrypt_key((const unsigned char *)key, key_bits,&cipher->key.aes);
cipher->using_evp = 0;
}
@@ -360,7 +361,7 @@ aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits)
memset(cipher->buf, 0, sizeof(cipher->buf));
else
#endif
- _aes_fill_buf(cipher);
+ aes_fill_buf_(cipher);
}
/** Release storage held by <b>cipher</b>
@@ -387,9 +388,10 @@ aes_cipher_free(aes_cnt_cipher_t *cipher)
#ifdef CAN_USE_OPENSSL_CTR
/* Helper function to use EVP with openssl's counter-mode wrapper. */
-static void evp_block128_fn(const uint8_t in[16],
- uint8_t out[16],
- const void *key)
+static void
+evp_block128_fn(const uint8_t in[16],
+ uint8_t out[16],
+ const void *key)
{
EVP_CIPHER_CTX *ctx = (void*)key;
int inl=16, outl=16;
@@ -429,8 +431,7 @@ aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
&cipher->pos);
}
return;
- }
- else
+ } else
#endif
{
int c = cipher->pos;
@@ -453,7 +454,7 @@ aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
UPDATE_CTR_BUF(cipher, 1);
}
UPDATE_CTR_BUF(cipher, 0);
- _aes_fill_buf(cipher);
+ aes_fill_buf_(cipher);
}
}
}
@@ -469,8 +470,7 @@ aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len)
if (should_use_openssl_CTR) {
aes_crypt(cipher, data, len, data);
return;
- }
- else
+ } else
#endif
{
int c = cipher->pos;
@@ -493,7 +493,7 @@ aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len)
UPDATE_CTR_BUF(cipher, 1);
}
UPDATE_CTR_BUF(cipher, 0);
- _aes_fill_buf(cipher);
+ aes_fill_buf_(cipher);
}
}
}
@@ -515,7 +515,8 @@ aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv)
#ifdef CAN_USE_OPENSSL_CTR
if (!should_use_openssl_CTR)
#endif
- _aes_fill_buf(cipher);
+ aes_fill_buf_(cipher);
}
#endif
+
diff --git a/src/common/aes.h b/src/common/aes.h
index bde567f87..8ff28a762 100644
--- a/src/common/aes.h
+++ b/src/common/aes.h
@@ -1,12 +1,12 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Implements a minimal interface to counter-mode AES. */
-#ifndef _TOR_AES_H
-#define _TOR_AES_H
+#ifndef TOR_AES_H
+#define TOR_AES_H
/**
* \file aes.h
diff --git a/src/common/ciphers.inc b/src/common/ciphers.inc
index 137d78b11..ab4ac4072 100644
--- a/src/common/ciphers.inc
+++ b/src/common/ciphers.inc
@@ -4,86 +4,51 @@
*
* This file was automatically generated by get_mozilla_ciphers.py.
*/
-#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
- CIPHER(0xc00a, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
-#else
- XCIPHER(0xc00a, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
-#endif
-#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA
- CIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA)
-#else
- XCIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA)
-#endif
-#ifdef TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
- CIPHER(0x0088, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA)
-#else
- XCIPHER(0x0088, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA)
-#endif
-#ifdef TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA
- CIPHER(0x0087, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA)
+#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+ CIPHER(0xc02b, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
#else
- XCIPHER(0x0087, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA)
+ XCIPHER(0xc02b, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
#endif
-#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA
- CIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA)
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ CIPHER(0xc02f, TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
#else
- XCIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA)
+ XCIPHER(0xc02f, TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
#endif
-#ifdef TLS1_TXT_DHE_DSS_WITH_AES_256_SHA
- CIPHER(0x0038, TLS1_TXT_DHE_DSS_WITH_AES_256_SHA)
+#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+ CIPHER(0xc00a, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
#else
- XCIPHER(0x0038, TLS1_TXT_DHE_DSS_WITH_AES_256_SHA)
+ XCIPHER(0xc00a, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
#endif
-#ifdef TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA
- CIPHER(0xc00f, TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA)
+#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+ CIPHER(0xc009, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA)
#else
- XCIPHER(0xc00f, TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA)
+ XCIPHER(0xc009, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA)
#endif
-#ifdef TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA
- CIPHER(0xc005, TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA)
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA
+ CIPHER(0xc013, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA)
#else
- XCIPHER(0xc005, TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA)
+ XCIPHER(0xc013, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA)
#endif
-#ifdef TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA
- CIPHER(0x0084, TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA)
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA
+ CIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA)
#else
- XCIPHER(0x0084, TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA)
+ XCIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA)
#endif
-#ifdef TLS1_TXT_RSA_WITH_AES_256_SHA
- CIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA)
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA
+ CIPHER(0xc012, TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA)
#else
- XCIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA)
+ XCIPHER(0xc012, TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA)
#endif
#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA
CIPHER(0xc007, TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA)
#else
XCIPHER(0xc007, TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA)
#endif
-#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
- CIPHER(0xc009, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA)
-#else
- XCIPHER(0xc009, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA)
-#endif
#ifdef TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA
CIPHER(0xc011, TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA)
#else
XCIPHER(0xc011, TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA)
#endif
-#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA
- CIPHER(0xc013, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA)
-#else
- XCIPHER(0xc013, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA)
-#endif
-#ifdef TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
- CIPHER(0x0045, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA)
-#else
- XCIPHER(0x0045, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA)
-#endif
-#ifdef TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA
- CIPHER(0x0044, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA)
-#else
- XCIPHER(0x0044, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA)
-#endif
#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_SHA
CIPHER(0x0033, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA)
#else
@@ -94,89 +59,63 @@
#else
XCIPHER(0x0032, TLS1_TXT_DHE_DSS_WITH_AES_128_SHA)
#endif
-#ifdef TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA
- CIPHER(0xc00c, TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA)
-#else
- XCIPHER(0xc00c, TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA)
-#endif
-#ifdef TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA
- CIPHER(0xc00e, TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA)
-#else
- XCIPHER(0xc00e, TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA)
-#endif
-#ifdef TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA
- CIPHER(0xc002, TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA)
-#else
- XCIPHER(0xc002, TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA)
-#endif
-#ifdef TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA
- CIPHER(0xc004, TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA)
+#ifdef TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+ CIPHER(0x0045, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA)
#else
- XCIPHER(0xc004, TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA)
+ XCIPHER(0x0045, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA)
#endif
-#ifdef TLS1_TXT_RSA_WITH_SEED_SHA
- CIPHER(0x0096, TLS1_TXT_RSA_WITH_SEED_SHA)
+#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA
+ CIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA)
#else
- XCIPHER(0x0096, TLS1_TXT_RSA_WITH_SEED_SHA)
+ XCIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA)
#endif
-#ifdef TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA
- CIPHER(0x0041, TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA)
+#ifdef TLS1_TXT_DHE_DSS_WITH_AES_256_SHA
+ CIPHER(0x0038, TLS1_TXT_DHE_DSS_WITH_AES_256_SHA)
#else
- XCIPHER(0x0041, TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA)
+ XCIPHER(0x0038, TLS1_TXT_DHE_DSS_WITH_AES_256_SHA)
#endif
-#ifdef SSL3_TXT_RSA_RC4_128_MD5
- CIPHER(0x0004, SSL3_TXT_RSA_RC4_128_MD5)
+#ifdef TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
+ CIPHER(0x0088, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA)
#else
- XCIPHER(0x0004, SSL3_TXT_RSA_RC4_128_MD5)
+ XCIPHER(0x0088, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA)
#endif
-#ifdef SSL3_TXT_RSA_RC4_128_SHA
- CIPHER(0x0005, SSL3_TXT_RSA_RC4_128_SHA)
+#ifdef SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA
+ CIPHER(0x0016, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA)
#else
- XCIPHER(0x0005, SSL3_TXT_RSA_RC4_128_SHA)
+ XCIPHER(0x0016, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA)
#endif
#ifdef TLS1_TXT_RSA_WITH_AES_128_SHA
CIPHER(0x002f, TLS1_TXT_RSA_WITH_AES_128_SHA)
#else
XCIPHER(0x002f, TLS1_TXT_RSA_WITH_AES_128_SHA)
#endif
-#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA
- CIPHER(0xc008, TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA)
-#else
- XCIPHER(0xc008, TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA)
-#endif
-#ifdef TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA
- CIPHER(0xc012, TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA)
-#else
- XCIPHER(0xc012, TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA)
-#endif
-#ifdef SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA
- CIPHER(0x0016, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA)
+#ifdef TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA
+ CIPHER(0x0041, TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA)
#else
- XCIPHER(0x0016, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA)
+ XCIPHER(0x0041, TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA)
#endif
-#ifdef SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA
- CIPHER(0x0013, SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA)
+#ifdef TLS1_TXT_RSA_WITH_AES_256_SHA
+ CIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA)
#else
- XCIPHER(0x0013, SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA)
+ XCIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA)
#endif
-#ifdef TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA
- CIPHER(0xc00d, TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA)
+#ifdef TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA
+ CIPHER(0x0084, TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA)
#else
- XCIPHER(0xc00d, TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA)
+ XCIPHER(0x0084, TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA)
#endif
-#ifdef TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA
- CIPHER(0xc003, TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA)
+#ifdef SSL3_TXT_RSA_DES_192_CBC3_SHA
+ CIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA)
#else
- XCIPHER(0xc003, TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA)
+ XCIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA)
#endif
-/* No openssl macro found for 0xfeff */
-#ifdef SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA
- CIPHER(0xfeff, SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA)
+#ifdef SSL3_TXT_RSA_RC4_128_SHA
+ CIPHER(0x0005, SSL3_TXT_RSA_RC4_128_SHA)
#else
- XCIPHER(0xfeff, SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA)
+ XCIPHER(0x0005, SSL3_TXT_RSA_RC4_128_SHA)
#endif
-#ifdef SSL3_TXT_RSA_DES_192_CBC3_SHA
- CIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA)
+#ifdef SSL3_TXT_RSA_RC4_128_MD5
+ CIPHER(0x0004, SSL3_TXT_RSA_RC4_128_MD5)
#else
- XCIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA)
+ XCIPHER(0x0004, SSL3_TXT_RSA_RC4_128_MD5)
#endif
diff --git a/src/common/compat.c b/src/common/compat.c
index 59e3898de..d88c5f92d 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -18,7 +18,7 @@
/* XXXX024 We should just use AC_USE_SYSTEM_EXTENSIONS in our autoconf,
* and get this (and other important stuff!) automatically. Once we do that,
* make sure to also change the extern char **environ detection in
- * configure.in, because whether that is declared or not depends on whether
+ * configure.ac, because whether that is declared or not depends on whether
* we have _GNU_SOURCE defined! Maybe that means that once we take this out,
* we can also take out the configure check. */
#define _GNU_SOURCE
@@ -137,8 +137,13 @@ tor_open_cloexec(const char *path, int flags, unsigned mode)
fd = open(path, flags, mode);
#ifdef FD_CLOEXEC
- if (fd >= 0)
- fcntl(fd, F_SETFD, FD_CLOEXEC);
+ if (fd >= 0) {
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
+ log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno));
+ close(fd);
+ return -1;
+ }
+ }
#endif
return fd;
}
@@ -150,8 +155,13 @@ tor_fopen_cloexec(const char *path, const char *mode)
{
FILE *result = fopen(path, mode);
#ifdef FD_CLOEXEC
- if (result != NULL)
- fcntl(fileno(result), F_SETFD, FD_CLOEXEC);
+ if (result != NULL) {
+ if (fcntl(fileno(result), F_SETFD, FD_CLOEXEC) == -1) {
+ log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno));
+ fclose(result);
+ return NULL;
+ }
+ }
#endif
return result;
}
@@ -425,11 +435,10 @@ tor_vasprintf(char **strp, const char *fmt, va_list args)
else
*strp = strp_tmp;
return r;
-#elif defined(_MSC_VER)
+#elif defined(HAVE__VSCPRINTF)
/* On Windows, _vsnprintf won't tell us the length of the string if it
* overflows, so we need to use _vcsprintf to tell how much to allocate */
int len, r;
- char *res;
len = _vscprintf(fmt, args);
if (len < 0) {
*strp = NULL;
@@ -861,6 +870,9 @@ tor_lockfile_unlock(tor_lockfile_t *lockfile)
/** @{ */
/** Some old versions of Unix didn't define constants for these values,
* and instead expect you to say 0, 1, or 2. */
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
@@ -891,6 +903,18 @@ tor_fd_seekend(int fd)
#endif
}
+/** Move <b>fd</b> to position <b>pos</b> in the file. Return -1 on error, 0
+ * on success. */
+int
+tor_fd_setpos(int fd, off_t pos)
+{
+#ifdef _WIN32
+ return _lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0;
+#else
+ return lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0;
+#endif
+}
+
#undef DEBUG_SOCKET_COUNTING
#ifdef DEBUG_SOCKET_COUNTING
/** A bitarray of all fds that should be passed to tor_socket_close(). Only
@@ -1025,7 +1049,15 @@ tor_open_socket(int domain, int type, int protocol)
return s;
#if defined(FD_CLOEXEC)
- fcntl(s, F_SETFD, FD_CLOEXEC);
+ if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
+ log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno));
+#if defined(_WIN32)
+ closesocket(s);
+#else
+ close(s);
+#endif
+ return -1;
+ }
#endif
goto socket_ok; /* So that socket_ok will not be unused. */
@@ -1060,7 +1092,11 @@ tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len)
return s;
#if defined(FD_CLOEXEC)
- fcntl(s, F_SETFD, FD_CLOEXEC);
+ if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
+ log_warn(LD_NET, "Couldn't set FD_CLOEXEC: %s", strerror(errno));
+ close(s);
+ return TOR_INVALID_SOCKET;
+ }
#endif
goto socket_ok; /* So that socket_ok will not be unused. */
@@ -1084,17 +1120,31 @@ get_n_open_sockets(void)
return n;
}
-/** Turn <b>socket</b> into a nonblocking socket.
+/** Turn <b>socket</b> into a nonblocking socket. Return 0 on success, -1
+ * on failure.
*/
-void
+int
set_socket_nonblocking(tor_socket_t socket)
{
#if defined(_WIN32)
unsigned long nonblocking = 1;
ioctlsocket(socket, FIONBIO, (unsigned long*) &nonblocking);
#else
- fcntl(socket, F_SETFL, O_NONBLOCK);
+ int flags;
+
+ flags = fcntl(socket, F_GETFL, 0);
+ if (flags == -1) {
+ log_warn(LD_NET, "Couldn't get file status flags: %s", strerror(errno));
+ return -1;
+ }
+ flags |= O_NONBLOCK;
+ if (fcntl(socket, F_SETFL, flags) == -1) {
+ log_warn(LD_NET, "Couldn't set file status flags: %s", strerror(errno));
+ return -1;
+ }
#endif
+
+ return 0;
}
/**
@@ -1137,10 +1187,22 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
return -errno;
#if defined(FD_CLOEXEC)
- if (SOCKET_OK(fd[0]))
- fcntl(fd[0], F_SETFD, FD_CLOEXEC);
- if (SOCKET_OK(fd[1]))
- fcntl(fd[1], F_SETFD, FD_CLOEXEC);
+ if (SOCKET_OK(fd[0])) {
+ r = fcntl(fd[0], F_SETFD, FD_CLOEXEC);
+ if (r == -1) {
+ close(fd[0]);
+ close(fd[1]);
+ return -errno;
+ }
+ }
+ if (SOCKET_OK(fd[1])) {
+ r = fcntl(fd[1], F_SETFD, FD_CLOEXEC);
+ if (r == -1) {
+ close(fd[0]);
+ close(fd[1]);
+ return -errno;
+ }
+ }
#endif
goto sockets_ok; /* So that sockets_ok will not be unused. */
@@ -1163,9 +1225,9 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
* for now, and really, when localhost is down sometimes, we
* have other problems too.
*/
- tor_socket_t listener = -1;
- tor_socket_t connector = -1;
- tor_socket_t acceptor = -1;
+ tor_socket_t listener = TOR_INVALID_SOCKET;
+ tor_socket_t connector = TOR_INVALID_SOCKET;
+ tor_socket_t acceptor = TOR_INVALID_SOCKET;
struct sockaddr_in listen_addr;
struct sockaddr_in connect_addr;
int size;
@@ -1219,7 +1281,6 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
goto tidy_up_and_fail;
if (size != sizeof(listen_addr))
goto abort_tidy_up_and_fail;
- tor_close_socket(listener);
/* Now check we are talking to ourself by matching port and host on the
two sockets. */
if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1)
@@ -1230,6 +1291,7 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
|| listen_addr.sin_port != connect_addr.sin_port) {
goto abort_tidy_up_and_fail;
}
+ tor_close_socket(listener);
fd[0] = connector;
fd[1] = acceptor;
@@ -1244,11 +1306,11 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
tidy_up_and_fail:
if (saved_errno < 0)
saved_errno = errno;
- if (listener != -1)
+ if (SOCKET_OK(listener))
tor_close_socket(listener);
- if (connector != -1)
+ if (SOCKET_OK(connector))
tor_close_socket(connector);
- if (acceptor != -1)
+ if (SOCKET_OK(acceptor))
tor_close_socket(acceptor);
return -saved_errno;
#endif
@@ -1256,7 +1318,7 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
/** Number of extra file descriptors to keep in reserve beyond those that we
* tell Tor it's allowed to use. */
-#define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond _ConnLimit */
+#define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond ConnLimit_ */
/** Learn the maximum allowed number of file descriptors, and tell the system
* we want to use up to that number. (Some systems have a low soft limit, and
@@ -2060,30 +2122,6 @@ tor_lookup_hostname(const char *name, uint32_t *addr)
return -1;
}
-/** Initialize the insecure libc RNG. */
-void
-tor_init_weak_random(unsigned seed)
-{
-#ifdef _WIN32
- srand(seed);
-#else
- srandom(seed);
-#endif
-}
-
-/** Return a randomly chosen value in the range 0..TOR_RAND_MAX. This
- * entropy will not be cryptographically strong; do not rely on it
- * for anything an adversary should not be able to predict. */
-long
-tor_weak_random(void)
-{
-#ifdef _WIN32
- return rand();
-#else
- return random();
-#endif
-}
-
/** Hold the result of our call to <b>uname</b>. */
static char uname_result[256];
/** True iff uname_result is set. */
@@ -2290,8 +2328,33 @@ compute_num_cpus_impl(void)
return (int)info.dwNumberOfProcessors;
else
return -1;
-#elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF)
- long cpus = sysconf(_SC_NPROCESSORS_CONF);
+#elif defined(HAVE_SYSCONF)
+#ifdef _SC_NPROCESSORS_CONF
+ long cpus_conf = sysconf(_SC_NPROCESSORS_CONF);
+#else
+ long cpus_conf = -1;
+#endif
+#ifdef _SC_NPROCESSORS_ONLN
+ long cpus_onln = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+ long cpus_onln = -1;
+#endif
+ long cpus = -1;
+
+ if (cpus_conf > 0 && cpus_onln < 0) {
+ cpus = cpus_conf;
+ } else if (cpus_onln > 0 && cpus_conf < 0) {
+ cpus = cpus_onln;
+ } else if (cpus_onln > 0 && cpus_conf > 0) {
+ if (cpus_onln < cpus_conf) {
+ log_notice(LD_GENERAL, "I think we have %ld CPUS, but only %ld of them "
+ "are available. Telling Tor to only use %ld. You can over"
+ "ride this with the NumCPUs option",
+ cpus_conf, cpus_onln, cpus_onln);
+ }
+ cpus = cpus_onln;
+ }
+
if (cpus >= 1 && cpus < INT_MAX)
return (int)cpus;
else
@@ -2759,7 +2822,7 @@ tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex)
EnterCriticalSection(&cond->mutex);
tor_assert(WaitForSingleObject(event, 0) == WAIT_TIMEOUT);
- tor_assert(!smartlist_isin(cond->events, event));
+ tor_assert(!smartlist_contains(cond->events, event));
smartlist_add(cond->events, event);
LeaveCriticalSection(&cond->mutex);
diff --git a/src/common/compat.h b/src/common/compat.h
index 42648bb04..51fb8c527 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -1,10 +1,10 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#ifndef _TOR_COMPAT_H
-#define _TOR_COMPAT_H
+#ifndef TOR_COMPAT_H
+#define TOR_COMPAT_H
#include "orconfig.h"
#include "torint.h"
@@ -53,13 +53,13 @@
#endif
#include <stdio.h>
+#include <errno.h>
#if defined (WINCE)
#include <fcntl.h>
#include <io.h>
#include <math.h>
#include <projects.h>
-#define snprintf _snprintf
/* this is not exported as W .... */
#define SHGetPathFromIDListW SHGetPathFromIDList
/* wcecompat has vasprintf */
@@ -74,6 +74,10 @@
#error "It seems your platform does not represent NULL as zero. We can't cope."
#endif
+#ifndef DOUBLE_0_REP_IS_ZERO_BYTES
+#error "It seems your platform does not represent 0.0 as zeros. We can't cope."
+#endif
+
#if 'a'!=97 || 'z'!=122 || 'A'!=65 || ' '!=32
#error "It seems that you encode characters in something other than ASCII."
#endif
@@ -132,6 +136,16 @@ extern INLINE double U64_TO_DBL(uint64_t x) {
#define DBL_TO_U64(x) ((uint64_t) (x))
#endif
+#ifdef ENUM_VALS_ARE_SIGNED
+#define ENUM_BF(t) unsigned
+#else
+/** Wrapper for having a bitfield of an enumerated type. Where possible, we
+ * just use the enumerated type (so the compiler can help us and notice
+ * problems), but if enumerated types are unsigned, we must use unsigned,
+ * so that the loss of precision doesn't make large values negative. */
+#define ENUM_BF(t) t
+#endif
+
/* GCC has several useful attributes. */
#if defined(__GNUC__) && __GNUC__ >= 3
#define ATTR_NORETURN __attribute__((noreturn))
@@ -148,6 +162,7 @@ extern INLINE double U64_TO_DBL(uint64_t x) {
*
* #define ATTR_NONNULL(x) __attribute__((nonnull x)) */
#define ATTR_NONNULL(x)
+#define ATTR_UNUSED __attribute__ ((unused))
/** Macro: Evaluates to <b>exp</b> and hints the compiler that the value
* of <b>exp</b> will probably be true.
@@ -171,6 +186,7 @@ extern INLINE double U64_TO_DBL(uint64_t x) {
#define ATTR_MALLOC
#define ATTR_NORETURN
#define ATTR_NONNULL(x)
+#define ATTR_UNUSED
#define PREDICT_LIKELY(exp) (exp)
#define PREDICT_UNLIKELY(exp) (exp)
#endif
@@ -239,6 +255,19 @@ size_t strlcpy(char *dst, const char *src, size_t siz) ATTR_NONNULL((1,2));
#define I64_FORMAT "%lld"
#endif
+#if (SIZEOF_INTPTR_T == SIZEOF_INT)
+#define INTPTR_T_FORMAT "%d"
+#define INTPTR_PRINTF_ARG(x) ((int)(x))
+#elif (SIZEOF_INTPTR_T == SIZEOF_LONG)
+#define INTPTR_T_FORMAT "%ld"
+#define INTPTR_PRINTF_ARG(x) ((long)(x))
+#elif (SIZEOF_INTPTR_T == 8)
+#define INTPTR_T_FORMAT I64_FORMAT
+#define INTPTR_PRINTF_ARG(x) I64_PRINTF_ARG(x)
+#else
+#error Unknown: SIZEOF_INTPTR_T
+#endif
+
/** Represents an mmaped file. Allocated via tor_mmap_file; freed with
* tor_munmap_file. */
typedef struct tor_mmap_t {
@@ -308,10 +337,10 @@ char *tor_strtok_r_impl(char *str, const char *sep, char **lasts);
#endif
#ifdef _WIN32
-#define _SHORT_FILE_ (tor_fix_source_file(__FILE__))
+#define SHORT_FILE__ (tor_fix_source_file(__FILE__))
const char *tor_fix_source_file(const char *fname);
#else
-#define _SHORT_FILE_ (__FILE__)
+#define SHORT_FILE__ (__FILE__)
#define tor_fix_source_file(s) (s)
#endif
@@ -384,6 +413,7 @@ tor_lockfile_t *tor_lockfile_lock(const char *filename, int blocking,
void tor_lockfile_unlock(tor_lockfile_t *lockfile);
off_t tor_fd_getpos(int fd);
+int tor_fd_setpos(int fd, off_t pos);
int tor_fd_seekend(int fd);
#ifdef _WIN32
@@ -403,11 +433,13 @@ typedef int socklen_t;
* any inadvertant checks for the socket being <= 0 or > 0 will probably
* still work. */
#define tor_socket_t intptr_t
+#define TOR_SOCKET_T_FORMAT INTPTR_T_FORMAT
#define SOCKET_OK(s) ((SOCKET)(s) != INVALID_SOCKET)
#define TOR_INVALID_SOCKET INVALID_SOCKET
#else
/** Type used for a network socket. */
#define tor_socket_t int
+#define TOR_SOCKET_T_FORMAT "%d"
/** Macro: true iff 's' is a possible value for a valid initialized socket. */
#define SOCKET_OK(s) ((s) >= 0)
/** Error/uninitialized value for a tor_socket_t. */
@@ -489,7 +521,7 @@ int tor_inet_aton(const char *cp, struct in_addr *addr) ATTR_NONNULL((1,2));
const char *tor_inet_ntop(int af, const void *src, char *dst, size_t len);
int tor_inet_pton(int af, const char *src, void *dst);
int tor_lookup_hostname(const char *name, uint32_t *addr) ATTR_NONNULL((1,2));
-void set_socket_nonblocking(tor_socket_t socket);
+int set_socket_nonblocking(tor_socket_t socket);
int tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]);
int network_init(void);
@@ -523,10 +555,15 @@ int tor_socket_errno(tor_socket_t sock);
const char *tor_socket_strerror(int e);
#else
#define SOCK_ERRNO(e) e
+#if EAGAIN == EWOULDBLOCK
#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN)
+#else
+#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == EWOULDBLOCK)
+#endif
#define ERRNO_IS_EINPROGRESS(e) ((e) == EINPROGRESS)
#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS)
-#define ERRNO_IS_ACCEPT_EAGAIN(e) ((e) == EAGAIN || (e) == ECONNABORTED)
+#define ERRNO_IS_ACCEPT_EAGAIN(e) \
+ (ERRNO_IS_EAGAIN(e) || (e) == ECONNABORTED)
#define ERRNO_IS_ACCEPT_RESOURCE_LIMIT(e) \
((e) == EMFILE || (e) == ENFILE || (e) == ENOBUFS || (e) == ENOMEM)
#define ERRNO_IS_EADDRINUSE(e) ((e) == EADDRINUSE)
@@ -547,11 +584,6 @@ typedef enum {
SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED = 0x08,
} socks5_reply_status_t;
-/* ===== Insecure rng */
-void tor_init_weak_random(unsigned seed);
-long tor_weak_random(void);
-#define TOR_RAND_MAX (RAND_MAX)
-
/* ===== OS compatibility */
const char *get_uname(void);
diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c
index 6655ca87d..200a7c65f 100644
--- a/src/common/compat_libevent.c
+++ b/src/common/compat_libevent.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, The Tor Project, Inc. */
+/* Copyright (c) 2009-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -54,7 +54,9 @@ typedef uint32_t le_version_t;
* it is. */
#define LE_OTHER V(0,0,99)
+#if 0
static le_version_t tor_get_libevent_version(const char **v_out);
+#endif
#if defined(HAVE_EVENT_SET_LOG_CALLBACK) || defined(RUNNING_DOXYGEN)
/** A string which, if it appears in a libevent log, should be ignored. */
@@ -74,19 +76,19 @@ libevent_logging_callback(int severity, const char *msg)
}
switch (severity) {
case _EVENT_LOG_DEBUG:
- log(LOG_DEBUG, LD_NOCB|LD_NET, "Message from libevent: %s", buf);
+ log_debug(LD_NOCB|LD_NET, "Message from libevent: %s", buf);
break;
case _EVENT_LOG_MSG:
- log(LOG_INFO, LD_NOCB|LD_NET, "Message from libevent: %s", buf);
+ log_info(LD_NOCB|LD_NET, "Message from libevent: %s", buf);
break;
case _EVENT_LOG_WARN:
- log(LOG_WARN, LD_NOCB|LD_GENERAL, "Warning from libevent: %s", buf);
+ log_warn(LD_NOCB|LD_GENERAL, "Warning from libevent: %s", buf);
break;
case _EVENT_LOG_ERR:
- log(LOG_ERR, LD_NOCB|LD_GENERAL, "Error from libevent: %s", buf);
+ log_err(LD_NOCB|LD_GENERAL, "Error from libevent: %s", buf);
break;
default:
- log(LOG_WARN, LD_NOCB|LD_GENERAL, "Message [%d] from libevent: %s",
+ log_warn(LD_NOCB|LD_GENERAL, "Message [%d] from libevent: %s",
severity, buf);
break;
}
@@ -185,13 +187,6 @@ tor_libevent_initialize(tor_libevent_cfg *torcfg)
/* some paths below don't use torcfg, so avoid unused variable warnings */
(void)torcfg;
-#ifdef __APPLE__
- if (MACOSX_KQUEUE_IS_BROKEN ||
- tor_get_libevent_version(NULL) < V_OLD(1,1,'b')) {
- setenv("EVENT_NOKQUEUE","1",1);
- }
-#endif
-
#ifdef HAVE_EVENT2_EVENT_H
{
int attempts = 0;
@@ -266,13 +261,13 @@ tor_libevent_initialize(tor_libevent_cfg *torcfg)
#if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
/* Making this a NOTICE for now so we can link bugs to a libevent versions
* or methods better. */
- log(LOG_NOTICE, LD_GENERAL,
+ log_info(LD_GENERAL,
"Initialized libevent version %s using method %s. Good.",
event_get_version(), tor_libevent_get_method());
#else
- log(LOG_NOTICE, LD_GENERAL,
+ log_notice(LD_GENERAL,
"Initialized old libevent (version 1.0b or earlier).");
- log(LOG_WARN, LD_GENERAL,
+ log_warn(LD_GENERAL,
"You have a *VERY* old version of libevent. It is likely to be buggy; "
"please build Tor with a more recent version.");
#endif
@@ -364,6 +359,7 @@ le_versions_compatibility(le_version_t v)
return 5;
}
+#if 0
/** Return the version number of the currently running version of Libevent.
* See le_version_t for info on the format.
*/
@@ -386,6 +382,7 @@ tor_get_libevent_version(const char **v_out)
*v_out = v;
return r;
}
+#endif
/** Return a string representation of the version of the currently running
* version of Libevent. */
@@ -407,77 +404,9 @@ void
tor_check_libevent_version(const char *m, int server,
const char **badness_out)
{
- int buggy = 0, iffy = 0, slow = 0, thread_unsafe = 0;
- le_version_t version;
- const char *v = NULL;
- const char *badness = NULL;
- const char *sad_os = "";
-
- version = tor_get_libevent_version(&v);
-
- /* It would be better to disable known-buggy methods rather than warning
- * about them. But the problem is that with older versions of Libevent,
- * it's not trivial to get them to change their methods once they're
- * initialized... and with newer versions of Libevent, they aren't actually
- * broken. But we should revisit this if we ever find a post-1.4 version
- * of Libevent where we need to disable a given method. */
- if (!strcmp(m, "kqueue")) {
- if (version < V_OLD(1,1,'b'))
- buggy = 1;
- } else if (!strcmp(m, "epoll")) {
- if (version < V(1,1,0))
- iffy = 1;
- } else if (!strcmp(m, "poll")) {
- if (version < V_OLD(1,0,'e'))
- buggy = 1;
- if (version < V(1,1,0))
- slow = 1;
- } else if (!strcmp(m, "select")) {
- if (version < V(1,1,0))
- slow = 1;
- } else if (!strcmp(m, "win32")) {
- if (version < V_OLD(1,1,'b'))
- buggy = 1;
- }
-
- /* Libevent versions before 1.3b do very badly on operating systems with
- * user-space threading implementations. */
-#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
- if (server && version < V_OLD(1,3,'b')) {
- thread_unsafe = 1;
- sad_os = "BSD variants";
- }
-#elif defined(__APPLE__) || defined(__darwin__)
- if (server && version < V_OLD(1,3,'b')) {
- thread_unsafe = 1;
- sad_os = "Mac OS X";
- }
-#endif
-
- if (thread_unsafe) {
- log(LOG_WARN, LD_GENERAL,
- "Libevent version %s often crashes when running a Tor server with %s. "
- "Please use the latest version of libevent (1.3b or later)",v,sad_os);
- badness = "BROKEN";
- } else if (buggy) {
- log(LOG_WARN, LD_GENERAL,
- "There are serious bugs in using %s with libevent %s. "
- "Please use the latest version of libevent.", m, v);
- badness = "BROKEN";
- } else if (iffy) {
- log(LOG_WARN, LD_GENERAL,
- "There are minor bugs in using %s with libevent %s. "
- "You may want to use the latest version of libevent.", m, v);
- badness = "BUGGY";
- } else if (slow && server) {
- log(LOG_WARN, LD_GENERAL,
- "libevent %s can be very slow with %s. "
- "When running a server, please use the latest version of libevent.",
- v,m);
- badness = "SLOW";
- }
-
- *badness_out = badness;
+ (void) m;
+ (void) server;
+ *badness_out = NULL;
}
#if defined(LIBEVENT_VERSION)
@@ -511,7 +440,7 @@ tor_check_libevent_header_compatibility(void)
verybad = compat1 != compat2;
- log(verybad ? LOG_WARN : LOG_NOTICE,
+ tor_log(verybad ? LOG_WARN : LOG_NOTICE,
LD_GENERAL, "We were compiled with headers from version %s "
"of Libevent, but we're using a Libevent library that says it's "
"version %s.", HEADER_VERSION, event_get_version());
diff --git a/src/common/compat_libevent.h b/src/common/compat_libevent.h
index 56285ef80..2472e2c49 100644
--- a/src/common/compat_libevent.h
+++ b/src/common/compat_libevent.h
@@ -1,8 +1,8 @@
-/* Copyright (c) 2009-2012, The Tor Project, Inc. */
+/* Copyright (c) 2009-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#ifndef _TOR_COMPAT_LIBEVENT_H
-#define _TOR_COMPAT_LIBEVENT_H
+#ifndef TOR_COMPAT_LIBEVENT_H
+#define TOR_COMPAT_LIBEVENT_H
#include "orconfig.h"
diff --git a/src/common/container.c b/src/common/container.c
index ede98eca5..eec497a3e 100644
--- a/src/common/container.c
+++ b/src/common/container.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -163,7 +163,7 @@ smartlist_string_remove(smartlist_t *sl, const char *element)
/** Return true iff some element E of sl has E==element.
*/
int
-smartlist_isin(const smartlist_t *sl, const void *element)
+smartlist_contains(const smartlist_t *sl, const void *element)
{
int i;
for (i=0; i < sl->num_used; i++)
@@ -176,7 +176,7 @@ smartlist_isin(const smartlist_t *sl, const void *element)
* !strcmp(E,<b>element</b>)
*/
int
-smartlist_string_isin(const smartlist_t *sl, const char *element)
+smartlist_contains_string(const smartlist_t *sl, const char *element)
{
int i;
if (!sl) return 0;
@@ -203,7 +203,7 @@ smartlist_string_pos(const smartlist_t *sl, const char *element)
* !strcasecmp(E,<b>element</b>)
*/
int
-smartlist_string_isin_case(const smartlist_t *sl, const char *element)
+smartlist_contains_string_case(const smartlist_t *sl, const char *element)
{
int i;
if (!sl) return 0;
@@ -217,11 +217,11 @@ smartlist_string_isin_case(const smartlist_t *sl, const char *element)
* to the decimal encoding of <b>num</b>.
*/
int
-smartlist_string_num_isin(const smartlist_t *sl, int num)
+smartlist_contains_int_as_string(const smartlist_t *sl, int num)
{
char buf[32]; /* long enough for 64-bit int, and then some. */
tor_snprintf(buf,sizeof(buf),"%d", num);
- return smartlist_string_isin(sl, buf);
+ return smartlist_contains_string(sl, buf);
}
/** Return true iff the two lists contain the same strings in the same
@@ -247,7 +247,7 @@ smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2)
* tor_memeq(E,<b>element</b>,DIGEST_LEN)
*/
int
-smartlist_digest_isin(const smartlist_t *sl, const char *element)
+smartlist_contains_digest(const smartlist_t *sl, const char *element)
{
int i;
if (!sl) return 0;
@@ -257,19 +257,19 @@ smartlist_digest_isin(const smartlist_t *sl, const char *element)
return 0;
}
-/** Return true iff some element E of sl2 has smartlist_isin(sl1,E).
+/** Return true iff some element E of sl2 has smartlist_contains(sl1,E).
*/
int
smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2)
{
int i;
for (i=0; i < sl2->num_used; i++)
- if (smartlist_isin(sl1, sl2->list[i]))
+ if (smartlist_contains(sl1, sl2->list[i]))
return 1;
return 0;
}
-/** Remove every element E of sl1 such that !smartlist_isin(sl2,E).
+/** Remove every element E of sl1 such that !smartlist_contains(sl2,E).
* Does not preserve the order of sl1.
*/
void
@@ -277,13 +277,13 @@ smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2)
{
int i;
for (i=0; i < sl1->num_used; i++)
- if (!smartlist_isin(sl2, sl1->list[i])) {
+ if (!smartlist_contains(sl2, sl1->list[i])) {
sl1->list[i] = sl1->list[--sl1->num_used]; /* swap with the end */
i--; /* so we process the new i'th element */
}
}
-/** Remove every element E of sl1 such that smartlist_isin(sl2,E).
+/** Remove every element E of sl1 such that smartlist_contains(sl2,E).
* Does not preserve the order of sl1.
*/
void
@@ -571,59 +571,116 @@ smartlist_bsearch_idx(const smartlist_t *sl, const void *key,
int (*compare)(const void *key, const void **member),
int *found_out)
{
- const int len = smartlist_len(sl);
- int hi, lo, cmp, mid;
+ int hi, lo, cmp, mid, len, diff;
+ tor_assert(sl);
+ tor_assert(compare);
+ tor_assert(found_out);
+
+ len = smartlist_len(sl);
+
+ /* Check for the trivial case of a zero-length list */
if (len == 0) {
*found_out = 0;
+ /* We already know smartlist_len(sl) is 0 in this case */
return 0;
- } else if (len == 1) {
- cmp = compare(key, (const void **) &sl->list[0]);
- if (cmp == 0) {
- *found_out = 1;
- return 0;
- } else if (cmp < 0) {
- *found_out = 0;
- return 0;
- } else {
- *found_out = 0;
- return 1;
- }
}
- hi = smartlist_len(sl) - 1;
+ /* Okay, we have a real search to do */
+ tor_assert(len > 0);
lo = 0;
+ hi = len - 1;
+
+ /*
+ * These invariants are always true:
+ *
+ * For all i such that 0 <= i < lo, sl[i] < key
+ * For all i such that hi < i <= len, sl[i] > key
+ */
while (lo <= hi) {
- mid = (lo + hi) / 2;
+ diff = hi - lo;
+ /*
+ * We want mid = (lo + hi) / 2, but that could lead to overflow, so
+ * instead diff = hi - lo (non-negative because of loop condition), and
+ * then hi = lo + diff, mid = (lo + lo + diff) / 2 = lo + (diff / 2).
+ */
+ mid = lo + (diff / 2);
cmp = compare(key, (const void**) &(sl->list[mid]));
- if (cmp>0) { /* key > sl[mid] */
- lo = mid+1;
- } else if (cmp<0) { /* key < sl[mid] */
- hi = mid-1;
- } else { /* key == sl[mid] */
+ if (cmp == 0) {
+ /* sl[mid] == key; we found it */
*found_out = 1;
return mid;
- }
- }
- /* lo > hi. */
- {
- tor_assert(lo >= 0);
- if (lo < smartlist_len(sl)) {
- cmp = compare(key, (const void**) &(sl->list[lo]));
+ } else if (cmp > 0) {
+ /*
+ * key > sl[mid] and an index i such that sl[i] == key must
+ * have i > mid if it exists.
+ */
+
+ /*
+ * Since lo <= mid <= hi, hi can only decrease on each iteration (by
+ * being set to mid - 1) and hi is initially len - 1, mid < len should
+ * always hold, and this is not symmetric with the left end of list
+ * mid > 0 test below. A key greater than the right end of the list
+ * should eventually lead to lo == hi == mid == len - 1, and then
+ * we set lo to len below and fall out to the same exit we hit for
+ * a key in the middle of the list but not matching. Thus, we just
+ * assert for consistency here rather than handle a mid == len case.
+ */
+ tor_assert(mid < len);
+ /* Move lo to the element immediately after sl[mid] */
+ lo = mid + 1;
+ } else {
+ /* This should always be true in this case */
tor_assert(cmp < 0);
- } else if (smartlist_len(sl)) {
- cmp = compare(key, (const void**) &(sl->list[smartlist_len(sl)-1]));
- tor_assert(cmp > 0);
+
+ /*
+ * key < sl[mid] and an index i such that sl[i] == key must
+ * have i < mid if it exists.
+ */
+
+ if (mid > 0) {
+ /* Normal case, move hi to the element immediately before sl[mid] */
+ hi = mid - 1;
+ } else {
+ /* These should always be true in this case */
+ tor_assert(mid == lo);
+ tor_assert(mid == 0);
+ /*
+ * We were at the beginning of the list and concluded that every
+ * element e compares e > key.
+ */
+ *found_out = 0;
+ return 0;
+ }
}
}
+
+ /*
+ * lo > hi; we have no element matching key but we have elements falling
+ * on both sides of it. The lo index points to the first element > key.
+ */
+ tor_assert(lo == hi + 1); /* All other cases should have been handled */
+ tor_assert(lo >= 0);
+ tor_assert(lo <= len);
+ tor_assert(hi >= 0);
+ tor_assert(hi <= len);
+
+ if (lo < len) {
+ cmp = compare(key, (const void **) &(sl->list[lo]));
+ tor_assert(cmp < 0);
+ } else {
+ cmp = compare(key, (const void **) &(sl->list[len-1]));
+ tor_assert(cmp > 0);
+ }
+
*found_out = 0;
return lo;
}
/** Helper: compare two const char **s. */
static int
-_compare_string_ptrs(const void **_a, const void **_b)
+compare_string_ptrs_(const void **_a, const void **_b)
{
return strcmp((const char*)*_a, (const char*)*_b);
}
@@ -633,14 +690,14 @@ _compare_string_ptrs(const void **_a, const void **_b)
void
smartlist_sort_strings(smartlist_t *sl)
{
- smartlist_sort(sl, _compare_string_ptrs);
+ smartlist_sort(sl, compare_string_ptrs_);
}
/** Return the most frequent string in the sorted list <b>sl</b> */
char *
smartlist_get_most_frequent_string(smartlist_t *sl)
{
- return smartlist_get_most_frequent(sl, _compare_string_ptrs);
+ return smartlist_get_most_frequent(sl, compare_string_ptrs_);
}
/** Remove duplicate strings from a sorted list, and free them with tor_free().
@@ -648,7 +705,7 @@ smartlist_get_most_frequent_string(smartlist_t *sl)
void
smartlist_uniq_strings(smartlist_t *sl)
{
- smartlist_uniq(sl, _compare_string_ptrs, _tor_free);
+ smartlist_uniq(sl, compare_string_ptrs_, tor_free_);
}
/* Heap-based priority queue implementation for O(lg N) insert and remove.
@@ -849,7 +906,7 @@ smartlist_pqueue_assert_ok(smartlist_t *sl,
/** Helper: compare two DIGEST_LEN digests. */
static int
-_compare_digests(const void **_a, const void **_b)
+compare_digests_(const void **_a, const void **_b)
{
return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST_LEN);
}
@@ -858,7 +915,7 @@ _compare_digests(const void **_a, const void **_b)
void
smartlist_sort_digests(smartlist_t *sl)
{
- smartlist_sort(sl, _compare_digests);
+ smartlist_sort(sl, compare_digests_);
}
/** Remove duplicate digests from a sorted list, and free them with tor_free().
@@ -866,12 +923,12 @@ smartlist_sort_digests(smartlist_t *sl)
void
smartlist_uniq_digests(smartlist_t *sl)
{
- smartlist_uniq(sl, _compare_digests, _tor_free);
+ smartlist_uniq(sl, compare_digests_, tor_free_);
}
/** Helper: compare two DIGEST256_LEN digests. */
static int
-_compare_digests256(const void **_a, const void **_b)
+compare_digests256_(const void **_a, const void **_b)
{
return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST256_LEN);
}
@@ -880,7 +937,7 @@ _compare_digests256(const void **_a, const void **_b)
void
smartlist_sort_digests256(smartlist_t *sl)
{
- smartlist_sort(sl, _compare_digests256);
+ smartlist_sort(sl, compare_digests256_);
}
/** Return the most frequent member of the sorted list of DIGEST256_LEN
@@ -888,7 +945,7 @@ smartlist_sort_digests256(smartlist_t *sl)
char *
smartlist_get_most_frequent_digest256(smartlist_t *sl)
{
- return smartlist_get_most_frequent(sl, _compare_digests256);
+ return smartlist_get_most_frequent(sl, compare_digests256_);
}
/** Remove duplicate 256-bit digests from a sorted list, and free them with
@@ -897,7 +954,7 @@ smartlist_get_most_frequent_digest256(smartlist_t *sl)
void
smartlist_uniq_digests256(smartlist_t *sl)
{
- smartlist_uniq(sl, _compare_digests256, _tor_free);
+ smartlist_uniq(sl, compare_digests256_, tor_free_);
}
/** Helper: Declare an entry type and a map type to implement a mapping using
diff --git a/src/common/container.h b/src/common/container.h
index dab3b83f3..fb9374794 100644
--- a/src/common/container.h
+++ b/src/common/container.h
@@ -1,10 +1,10 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#ifndef _TOR_CONTAINER_H
-#define _TOR_CONTAINER_H
+#ifndef TOR_CONTAINER_H
+#define TOR_CONTAINER_H
#include "util.h"
@@ -35,13 +35,13 @@ void smartlist_remove(smartlist_t *sl, const void *element);
void *smartlist_pop_last(smartlist_t *sl);
void smartlist_reverse(smartlist_t *sl);
void smartlist_string_remove(smartlist_t *sl, const char *element);
-int smartlist_isin(const smartlist_t *sl, const void *element);
-int smartlist_string_isin(const smartlist_t *sl, const char *element);
+int smartlist_contains(const smartlist_t *sl, const void *element);
+int smartlist_contains_string(const smartlist_t *sl, const char *element);
int smartlist_string_pos(const smartlist_t *, const char *elt);
-int smartlist_string_isin_case(const smartlist_t *sl, const char *element);
-int smartlist_string_num_isin(const smartlist_t *sl, int num);
+int smartlist_contains_string_case(const smartlist_t *sl, const char *element);
+int smartlist_contains_int_as_string(const smartlist_t *sl, int num);
int smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2);
-int smartlist_digest_isin(const smartlist_t *sl, const char *element);
+int smartlist_contains_digest(const smartlist_t *sl, const char *element);
int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2);
void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2);
void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2);
@@ -471,64 +471,74 @@ void* strmap_remove_lc(strmap_t *map, const char *key);
#define DECLARE_TYPED_DIGESTMAP_FNS(prefix, maptype, valtype) \
typedef struct maptype maptype; \
typedef struct prefix##iter_t prefix##iter_t; \
- static INLINE maptype* prefix##new(void) \
+ ATTR_UNUSED static INLINE maptype* \
+ prefix##new(void) \
{ \
return (maptype*)digestmap_new(); \
} \
- static INLINE digestmap_t* prefix##to_digestmap(maptype *map) \
+ ATTR_UNUSED static INLINE digestmap_t* \
+ prefix##to_digestmap(maptype *map) \
{ \
return (digestmap_t*)map; \
} \
- static INLINE valtype* prefix##get(maptype *map, const char *key) \
+ ATTR_UNUSED static INLINE valtype* \
+ prefix##get(maptype *map, const char *key) \
{ \
return (valtype*)digestmap_get((digestmap_t*)map, key); \
} \
- static INLINE valtype* prefix##set(maptype *map, const char *key, \
- valtype *val) \
+ ATTR_UNUSED static INLINE valtype* \
+ prefix##set(maptype *map, const char *key, valtype *val) \
{ \
return (valtype*)digestmap_set((digestmap_t*)map, key, val); \
} \
- static INLINE valtype* prefix##remove(maptype *map, const char *key) \
+ ATTR_UNUSED static INLINE valtype* \
+ prefix##remove(maptype *map, const char *key) \
{ \
return (valtype*)digestmap_remove((digestmap_t*)map, key); \
} \
- static INLINE void prefix##free(maptype *map, void (*free_val)(void*)) \
+ ATTR_UNUSED static INLINE void \
+ prefix##free(maptype *map, void (*free_val)(void*)) \
{ \
digestmap_free((digestmap_t*)map, free_val); \
} \
- static INLINE int prefix##isempty(maptype *map) \
+ ATTR_UNUSED static INLINE int \
+ prefix##isempty(maptype *map) \
{ \
return digestmap_isempty((digestmap_t*)map); \
} \
- static INLINE int prefix##size(maptype *map) \
+ ATTR_UNUSED static INLINE int \
+ prefix##size(maptype *map) \
{ \
return digestmap_size((digestmap_t*)map); \
} \
- static INLINE prefix##iter_t *prefix##iter_init(maptype *map) \
+ ATTR_UNUSED static INLINE \
+ prefix##iter_t *prefix##iter_init(maptype *map) \
{ \
return (prefix##iter_t*) digestmap_iter_init((digestmap_t*)map); \
} \
- static INLINE prefix##iter_t *prefix##iter_next(maptype *map, \
- prefix##iter_t *iter) \
+ ATTR_UNUSED static INLINE \
+ prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter) \
{ \
return (prefix##iter_t*) digestmap_iter_next( \
(digestmap_t*)map, (digestmap_iter_t*)iter); \
} \
- static INLINE prefix##iter_t *prefix##iter_next_rmv(maptype *map, \
- prefix##iter_t *iter) \
+ ATTR_UNUSED static INLINE prefix##iter_t* \
+ prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter) \
{ \
return (prefix##iter_t*) digestmap_iter_next_rmv( \
(digestmap_t*)map, (digestmap_iter_t*)iter); \
} \
- static INLINE void prefix##iter_get(prefix##iter_t *iter, \
- const char **keyp, \
- valtype **valp) \
+ ATTR_UNUSED static INLINE void \
+ prefix##iter_get(prefix##iter_t *iter, \
+ const char **keyp, \
+ valtype **valp) \
{ \
void *v; \
digestmap_iter_get((digestmap_iter_t*) iter, keyp, &v); \
*valp = v; \
} \
- static INLINE int prefix##iter_done(prefix##iter_t *iter) \
+ ATTR_UNUSED static INLINE int \
+ prefix##iter_done(prefix##iter_t *iter) \
{ \
return digestmap_iter_done((digestmap_iter_t*)iter); \
}
@@ -623,7 +633,7 @@ digestset_add(digestset_t *set, const char *digest)
/** If <b>digest</b> is in <b>set</b>, return nonzero. Otherwise,
* <em>probably</em> return zero. */
static INLINE int
-digestset_isin(const digestset_t *set, const char *digest)
+digestset_contains(const digestset_t *set, const char *digest)
{
const uint32_t *p = (const uint32_t *)digest;
const uint32_t d1 = p[0] + (p[1]>>16);
@@ -675,11 +685,6 @@ median_int32(int32_t *array, int n_elements)
{
return find_nth_int32(array, n_elements, (n_elements-1)/2);
}
-static INLINE long
-median_long(long *array, int n_elements)
-{
- return find_nth_long(array, n_elements, (n_elements-1)/2);
-}
#endif
diff --git a/src/common/crypto.c b/src/common/crypto.c
index 30990ecc8..925beb352 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -57,8 +57,8 @@
#include "container.h"
#include "compat.h"
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,7)
-#error "We require OpenSSL >= 0.9.7"
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
+#error "We require OpenSSL >= 0.9.8"
#endif
#ifdef ANDROID
@@ -69,31 +69,6 @@
/** Longest recognized */
#define MAX_DNS_LABEL_SIZE 63
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8) && \
- !defined(RUNNING_DOXYGEN)
-/** @{ */
-/** On OpenSSL versions before 0.9.8, there is no working SHA256
- * implementation, so we use Tom St Denis's nice speedy one, slightly adapted
- * to our needs. These macros make it usable by us. */
-#define SHA256_CTX sha256_state
-#define SHA256_Init sha256_init
-#define SHA256_Update sha256_process
-#define LTC_ARGCHK(x) tor_assert(x)
-/** @} */
-#include "sha256.c"
-#define SHA256_Final(a,b) sha256_done(b,a)
-
-static unsigned char *
-SHA256(const unsigned char *m, size_t len, unsigned char *d)
-{
- SHA256_CTX ctx;
- SHA256_Init(&ctx);
- SHA256_Update(&ctx, m, len);
- SHA256_Final(d, &ctx);
- return d;
-}
-#endif
-
/** Macro: is k a valid RSA public or private key? */
#define PUBLIC_KEY_OK(k) ((k) && (k)->key && (k)->key->n)
/** Macro: is k a valid RSA private key? */
@@ -101,9 +76,9 @@ SHA256(const unsigned char *m, size_t len, unsigned char *d)
#ifdef TOR_IS_MULTITHREADED
/** A number of preallocated mutexes for use by OpenSSL. */
-static tor_mutex_t **_openssl_mutexes = NULL;
+static tor_mutex_t **openssl_mutexes_ = NULL;
/** How many mutexes have we allocated for use by OpenSSL? */
-static int _n_openssl_mutexes = 0;
+static int n_openssl_mutexes_ = 0;
#endif
/** A public key, or a public/private key-pair. */
@@ -138,8 +113,8 @@ crypto_get_rsa_padding_overhead(int padding)
{
switch (padding)
{
- case RSA_PKCS1_OAEP_PADDING: return 42;
- case RSA_PKCS1_PADDING: return 11;
+ case RSA_PKCS1_OAEP_PADDING: return PKCS1_OAEP_PADDING_OVERHEAD;
+ case RSA_PKCS1_PADDING: return PKCS1_PADDING_OVERHEAD;
default: tor_assert(0); return -1;
}
}
@@ -158,7 +133,7 @@ crypto_get_rsa_padding(int padding)
}
/** Boolean: has OpenSSL's crypto been initialized? */
-static int _crypto_global_initialized = 0;
+static int crypto_global_initialized_ = 0;
/** Log all pending crypto errors at level <b>severity</b>. Use
* <b>doing</b> to describe our current activities.
@@ -176,10 +151,11 @@ crypto_log_errors(int severity, const char *doing)
if (!lib) lib = "(null)";
if (!func) func = "(null)";
if (doing) {
- log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)",
- doing, msg, lib, func);
+ tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)",
+ doing, msg, lib, func);
} else {
- log(severity, LD_CRYPTO, "crypto error: %s (in %s:%s)", msg, lib, func);
+ tor_log(severity, LD_CRYPTO, "crypto error: %s (in %s:%s)",
+ msg, lib, func);
}
}
}
@@ -193,10 +169,10 @@ log_engine(const char *fn, ENGINE *e)
const char *name, *id;
name = ENGINE_get_name(e);
id = ENGINE_get_id(e);
- log(LOG_NOTICE, LD_CRYPTO, "Using OpenSSL engine %s [%s] for %s",
- name?name:"?", id?id:"?", fn);
+ log_notice(LD_CRYPTO, "Default OpenSSL engine for %s is %s [%s]",
+ fn, name?name:"?", id?id:"?");
} else {
- log(LOG_INFO, LD_CRYPTO, "Using default implementation for %s", fn);
+ log_info(LD_CRYPTO, "Using default implementation for %s", fn);
}
}
#endif
@@ -221,16 +197,60 @@ try_load_engine(const char *path, const char *engine)
}
#endif
+static char *crypto_openssl_version_str = NULL;
+/* Return a human-readable version of the run-time openssl version number. */
+const char *
+crypto_openssl_get_version_str(void)
+{
+ if (crypto_openssl_version_str == NULL) {
+ const char *raw_version = SSLeay_version(SSLEAY_VERSION);
+ const char *end_of_version = NULL;
+ /* The output should be something like "OpenSSL 1.0.0b 10 May 2012. Let's
+ trim that down. */
+ if (!strcmpstart(raw_version, "OpenSSL ")) {
+ raw_version += strlen("OpenSSL ");
+ end_of_version = strchr(raw_version, ' ');
+ }
+
+ if (end_of_version)
+ crypto_openssl_version_str = tor_strndup(raw_version,
+ end_of_version-raw_version);
+ else
+ crypto_openssl_version_str = tor_strdup(raw_version);
+ }
+ return crypto_openssl_version_str;
+}
+
/** Initialize the crypto library. Return 0 on success, -1 on failure.
*/
int
crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
{
- if (!_crypto_global_initialized) {
+ if (!crypto_global_initialized_) {
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
- _crypto_global_initialized = 1;
+ crypto_global_initialized_ = 1;
setup_openssl_threading();
+
+ if (SSLeay() == OPENSSL_VERSION_NUMBER &&
+ !strcmp(SSLeay_version(SSLEAY_VERSION), OPENSSL_VERSION_TEXT)) {
+ log_info(LD_CRYPTO, "OpenSSL version matches version from headers "
+ "(%lx: %s).", SSLeay(), SSLeay_version(SSLEAY_VERSION));
+ } else {
+ log_warn(LD_CRYPTO, "OpenSSL version from headers does not match the "
+ "version we're running with. If you get weird crashes, that "
+ "might be why. (Compiled with %lx: %s; running with %lx: %s).",
+ (unsigned long)OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT,
+ SSLeay(), SSLeay_version(SSLEAY_VERSION));
+ }
+
+ if (SSLeay() < OPENSSL_V_SERIES(1,0,0)) {
+ log_notice(LD_CRYPTO,
+ "Your OpenSSL version seems to be %s. We recommend 1.0.0 "
+ "or later.",
+ crypto_openssl_get_version_str());
+ }
+
if (useAccel > 0) {
#ifdef DISABLE_ENGINES
(void)accelName;
@@ -268,7 +288,7 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
}
log_engine("RSA", ENGINE_get_default_RSA());
log_engine("DH", ENGINE_get_default_DH());
- log_engine("RAND", ENGINE_get_default_RAND());
+ log_engine("RAND (which we will not use)", ENGINE_get_default_RAND());
log_engine("SHA1", ENGINE_get_digest_engine(NID_sha1));
log_engine("3DES", ENGINE_get_cipher_engine(NID_des_ede3_ecb));
log_engine("AES", ENGINE_get_cipher_engine(NID_aes_128_ecb));
@@ -277,6 +297,13 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
log_info(LD_CRYPTO, "NOT using OpenSSL engine support.");
}
+ if (RAND_get_rand_method() != RAND_SSLeay()) {
+ log_notice(LD_CRYPTO, "It appears that one of our engines has provided "
+ "a replacement the OpenSSL RNG. Resetting it to the default "
+ "implementation.");
+ RAND_set_rand_method(RAND_SSLeay());
+ }
+
evaluate_evp_for_aes(-1);
evaluate_ctr_for_aes();
@@ -294,7 +321,7 @@ crypto_thread_cleanup(void)
/** used by tortls.c: wrap an RSA* in a crypto_pk_t. */
crypto_pk_t *
-_crypto_new_pk_from_rsa(RSA *rsa)
+crypto_new_pk_from_rsa_(RSA *rsa)
{
crypto_pk_t *env;
tor_assert(rsa);
@@ -307,7 +334,7 @@ _crypto_new_pk_from_rsa(RSA *rsa)
/** Helper, used by tor-checkkey.c and tor-gencert.c. Return the RSA from a
* crypto_pk_t. */
RSA *
-_crypto_pk_get_rsa(crypto_pk_t *env)
+crypto_pk_get_rsa_(crypto_pk_t *env)
{
return env->key;
}
@@ -315,7 +342,7 @@ _crypto_pk_get_rsa(crypto_pk_t *env)
/** used by tortls.c: get an equivalent EVP_PKEY* for a crypto_pk_t. Iff
* private is set, include the private-key portion of the key. */
EVP_PKEY *
-_crypto_pk_get_evp_pkey(crypto_pk_t *env, int private)
+crypto_pk_get_evp_pkey_(crypto_pk_t *env, int private)
{
RSA *key = NULL;
EVP_PKEY *pkey = NULL;
@@ -343,7 +370,7 @@ _crypto_pk_get_evp_pkey(crypto_pk_t *env, int private)
/** Used by tortls.c: Get the DH* from a crypto_dh_t.
*/
DH *
-_crypto_dh_get_dh(crypto_dh_t *dh)
+crypto_dh_get_dh_(crypto_dh_t *dh)
{
return dh->dh;
}
@@ -358,7 +385,7 @@ crypto_pk_new(void)
rsa = RSA_new();
tor_assert(rsa);
- return _crypto_new_pk_from_rsa(rsa);
+ return crypto_new_pk_from_rsa_(rsa);
}
/** Release a reference to an asymmetric key; when all the references
@@ -441,11 +468,7 @@ crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits)
if (env->key)
RSA_free(env->key);
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
- /* In OpenSSL 0.9.7, RSA_generate_key is all we have. */
- env->key = RSA_generate_key(bits, 65537, NULL, NULL);
-#else
- /* In OpenSSL 0.9.8, RSA_generate_key is deprecated. */
+
{
BIGNUM *e = BN_new();
RSA *r = NULL;
@@ -463,11 +486,11 @@ crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits)
r = NULL;
done:
if (e)
- BN_free(e);
+ BN_clear_free(e);
if (r)
RSA_free(r);
- }
-#endif
+ }
+
if (!env->key) {
crypto_log_errors(LOG_WARN, "generating RSA key");
return -1;
@@ -711,19 +734,23 @@ crypto_pk_public_exponent_ok(crypto_pk_t *env)
return BN_is_word(env->key->e, 65537);
}
-/** Compare the public-key components of a and b. Return -1 if a\<b, 0
- * if a==b, and 1 if a\>b.
+/** Compare the public-key components of a and b. Return less than 0
+ * if a\<b, 0 if a==b, and greater than 0 if a\>b. A NULL key is
+ * considered to be less than all non-NULL keys, and equal to itself.
+ *
+ * Note that this may leak information about the keys through timing.
*/
int
crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b)
{
int result;
+ char a_is_non_null = (a != NULL) && (a->key != NULL);
+ char b_is_non_null = (b != NULL) && (b->key != NULL);
+ char an_argument_is_null = !a_is_non_null | !b_is_non_null;
- if (!a || !b)
- return -1;
-
- if (!a->key || !b->key)
- return -1;
+ result = tor_memcmp(&a_is_non_null, &b_is_non_null, sizeof(a_is_non_null));
+ if (an_argument_is_null)
+ return result;
tor_assert(PUBLIC_KEY_OK(a));
tor_assert(PUBLIC_KEY_OK(b));
@@ -733,6 +760,18 @@ crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b)
return BN_cmp((a->key)->e, (b->key)->e);
}
+/** Compare the public-key components of a and b. Return non-zero iff
+ * a==b. A NULL key is considered to be distinct from all non-NULL
+ * keys, and equal to itself.
+ *
+ * Note that this may leak information about the keys through timing.
+ */
+int
+crypto_pk_eq_keys(crypto_pk_t *a, crypto_pk_t *b)
+{
+ return (crypto_pk_cmp_keys(a, b) == 0);
+}
+
/** Return the size of the public key modulus in <b>env</b>, in bytes. */
size_t
crypto_pk_keysize(crypto_pk_t *env)
@@ -791,7 +830,7 @@ crypto_pk_copy_full(crypto_pk_t *env)
return NULL;
}
- return _crypto_new_pk_from_rsa(new_key);
+ return crypto_new_pk_from_rsa_(new_key);
}
/** Encrypt <b>fromlen</b> bytes from <b>from</b> with the public key
@@ -1158,7 +1197,7 @@ crypto_pk_asn1_decode(const char *str, size_t len)
crypto_log_errors(LOG_WARN,"decoding public key");
return NULL;
}
- return _crypto_new_pk_from_rsa(rsa);
+ return crypto_new_pk_from_rsa_(rsa);
}
/** Given a private or public key <b>pk</b>, put a SHA1 hash of the
@@ -1262,23 +1301,6 @@ crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out, int add_space)
return 0;
}
-/** Return true iff <b>s</b> is in the correct format for a fingerprint.
- */
-int
-crypto_pk_check_fingerprint_syntax(const char *s)
-{
- int i;
- for (i = 0; i < FINGERPRINT_LEN; ++i) {
- if ((i%5) == 4) {
- if (!TOR_ISSPACE(s[i])) return 0;
- } else {
- if (!TOR_ISXDIGIT(s[i])) return 0;
- }
- }
- if (s[FINGERPRINT_LEN]) return 0;
- return 1;
-}
-
/* symmetric crypto */
/** Return a pointer to the key set for the cipher in <b>env</b>.
@@ -1427,7 +1449,7 @@ crypto_digest256(char *digest, const char *m, size_t len,
int
crypto_digest_all(digests_t *ds_out, const char *m, size_t len)
{
- digest_algorithm_t i;
+ int i;
tor_assert(ds_out);
memset(ds_out, 0, sizeof(*ds_out));
if (crypto_digest(ds_out->d[DIGEST_SHA1], m, len) < 0)
@@ -1474,7 +1496,7 @@ struct crypto_digest_t {
SHA256_CTX sha2; /**< state for SHA256 */
} d; /**< State for the digest we're using. Only one member of the
* union is usable, depending on the value of <b>algorithm</b>. */
- digest_algorithm_t algorithm : 8; /**< Which algorithm is in use? */
+ ENUM_BF(digest_algorithm_t) algorithm : 8; /**< Which algorithm is in use? */
};
/** Allocate and return a new digest object to compute SHA1 digests.
@@ -1599,6 +1621,29 @@ crypto_digest_assign(crypto_digest_t *into,
memcpy(into,from,sizeof(crypto_digest_t));
}
+/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
+ * at <b>digest_out</b> to the hash of the concatenation of those strings,
+ * plus the optional string <b>append</b>, computed with the algorithm
+ * <b>alg</b>.
+ * <b>out_len</b> must be \<= DIGEST256_LEN. */
+void
+crypto_digest_smartlist(char *digest_out, size_t len_out,
+ const smartlist_t *lst, const char *append,
+ digest_algorithm_t alg)
+{
+ crypto_digest_t *d;
+ if (alg == DIGEST_SHA1)
+ d = crypto_digest_new();
+ else
+ d = crypto_digest256_new(alg);
+ SMARTLIST_FOREACH(lst, const char *, cp,
+ crypto_digest_add_bytes(d, cp, strlen(cp)));
+ if (append)
+ crypto_digest_add_bytes(d, append, strlen(append));
+ crypto_digest_get_digest(d, digest_out, len_out);
+ crypto_digest_free(d);
+}
+
/** Compute the HMAC-SHA-1 of the <b>msg_len</b> bytes in <b>msg</b>, using
* the <b>key</b> of length <b>key_len</b>. Store the DIGEST_LEN-byte result
* in <b>hmac_out</b>.
@@ -1623,63 +1668,11 @@ crypto_hmac_sha256(char *hmac_out,
const char *key, size_t key_len,
const char *msg, size_t msg_len)
{
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(0,9,8)
/* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */
tor_assert(key_len < INT_MAX);
tor_assert(msg_len < INT_MAX);
HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len,
(unsigned char*)hmac_out, NULL);
-#else
- /* OpenSSL doesn't have an EVP implementation for SHA256. We'll need
- to do HMAC on our own.
-
- HMAC isn't so hard: To compute HMAC(key, msg):
- 1. If len(key) > blocksize, key = H(key).
- 2. If len(key) < blocksize, right-pad key up to blocksize with 0 bytes.
- 3. let ipad = key xor 0x363636363636....36
- let opad = key xor 0x5c5c5c5c5c5c....5c
- The result is H(opad | H( ipad | msg ) )
- */
-#define BLOCKSIZE 64
-#define DIGESTSIZE 32
- uint8_t k[BLOCKSIZE];
- uint8_t pad[BLOCKSIZE];
- uint8_t d[DIGESTSIZE];
- int i;
- SHA256_CTX st;
-
- tor_assert(key_len < INT_MAX);
- tor_assert(msg_len < INT_MAX);
-
- if (key_len <= BLOCKSIZE) {
- memset(k, 0, sizeof(k));
- memcpy(k, key, key_len); /* not time invariant in key_len */
- } else {
- SHA256((const uint8_t *)key, key_len, k);
- memset(k+DIGESTSIZE, 0, sizeof(k)-DIGESTSIZE);
- }
- for (i = 0; i < BLOCKSIZE; ++i)
- pad[i] = k[i] ^ 0x36;
- SHA256_Init(&st);
- SHA256_Update(&st, pad, BLOCKSIZE);
- SHA256_Update(&st, (uint8_t*)msg, msg_len);
- SHA256_Final(d, &st);
-
- for (i = 0; i < BLOCKSIZE; ++i)
- pad[i] = k[i] ^ 0x5c;
- SHA256_Init(&st);
- SHA256_Update(&st, pad, BLOCKSIZE);
- SHA256_Update(&st, d, DIGESTSIZE);
- SHA256_Final((uint8_t*)hmac_out, &st);
-
- /* Now clear everything. */
- memwipe(k, 0, sizeof(k));
- memwipe(pad, 0, sizeof(pad));
- memwipe(d, 0, sizeof(d));
- memwipe(&st, 0, sizeof(st));
-#undef BLOCKSIZE
-#undef DIGESTSIZE
-#endif
}
/* DH */
@@ -1929,7 +1922,7 @@ crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname)
/* If the space is occupied, free the previous TLS DH prime */
if (dh_param_p_tls) {
- BN_free(dh_param_p_tls);
+ BN_clear_free(dh_param_p_tls);
dh_param_p_tls = NULL;
}
@@ -2057,6 +2050,16 @@ crypto_dh_new(int dh_type)
return NULL;
}
+/** Return a copy of <b>dh</b>, sharing its internal state. */
+crypto_dh_t *
+crypto_dh_dup(const crypto_dh_t *dh)
+{
+ crypto_dh_t *dh_new = tor_malloc_zero(sizeof(crypto_dh_t));
+ dh_new->dh = dh->dh;
+ DH_up_ref(dh->dh);
+ return dh_new;
+}
+
/** Return the length of the DH key in <b>dh</b>, in bytes.
*/
int
@@ -2081,8 +2084,8 @@ crypto_dh_generate_public(crypto_dh_t *dh)
log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-"
"the-universe chances really do happen. Trying again.");
/* Free and clear the keys, so OpenSSL will actually try again. */
- BN_free(dh->dh->pub_key);
- BN_free(dh->dh->priv_key);
+ BN_clear_free(dh->dh->pub_key);
+ BN_clear_free(dh->dh->priv_key);
dh->dh->pub_key = dh->dh->priv_key = NULL;
goto again;
}
@@ -2144,10 +2147,10 @@ tor_check_dh_key(int severity, BIGNUM *bn)
log_fn(severity, LD_CRYPTO, "DH key must be at most p-2.");
goto err;
}
- BN_free(x);
+ BN_clear_free(x);
return 0;
err:
- BN_free(x);
+ BN_clear_free(x);
s = BN_bn2hex(bn);
log_fn(severity, LD_CRYPTO, "Rejecting insecure DH key [%s]", s);
OPENSSL_free(s);
@@ -2195,8 +2198,8 @@ crypto_dh_compute_secret(int severity, crypto_dh_t *dh,
goto error;
}
secret_len = result;
- if (crypto_expand_key_material(secret_tmp, secret_len,
- secret_out, secret_bytes_out)<0)
+ if (crypto_expand_key_material_TAP((uint8_t*)secret_tmp, secret_len,
+ (uint8_t*)secret_out, secret_bytes_out)<0)
goto error;
secret_len = secret_bytes_out;
@@ -2206,7 +2209,7 @@ crypto_dh_compute_secret(int severity, crypto_dh_t *dh,
done:
crypto_log_errors(LOG_WARN, "completing DH handshake");
if (pubkey_bn)
- BN_free(pubkey_bn);
+ BN_clear_free(pubkey_bn);
if (secret_tmp) {
memwipe(secret_tmp, 0, secret_tmp_len);
tor_free(secret_tmp);
@@ -2222,15 +2225,18 @@ crypto_dh_compute_secret(int severity, crypto_dh_t *dh,
* <b>key_out</b> by taking the first <b>key_out_len</b> bytes of
* H(K | [00]) | H(K | [01]) | ....
*
+ * This is the key expansion algorithm used in the "TAP" circuit extension
+ * mechanism; it shouldn't be used for new protocols.
+ *
* Return 0 on success, -1 on failure.
*/
int
-crypto_expand_key_material(const char *key_in, size_t key_in_len,
- char *key_out, size_t key_out_len)
+crypto_expand_key_material_TAP(const uint8_t *key_in, size_t key_in_len,
+ uint8_t *key_out, size_t key_out_len)
{
int i;
- char *cp, *tmp = tor_malloc(key_in_len+1);
- char digest[DIGEST_LEN];
+ uint8_t *cp, *tmp = tor_malloc(key_in_len+1);
+ uint8_t digest[DIGEST_LEN];
/* If we try to get more than this amount of key data, we'll repeat blocks.*/
tor_assert(key_out_len <= DIGEST_LEN*256);
@@ -2239,7 +2245,7 @@ crypto_expand_key_material(const char *key_in, size_t key_in_len,
for (cp = key_out, i=0; cp < key_out+key_out_len;
++i, cp += DIGEST_LEN) {
tmp[key_in_len] = i;
- if (crypto_digest(digest, tmp, key_in_len+1))
+ if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1))
goto err;
memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out)));
}
@@ -2255,6 +2261,65 @@ crypto_expand_key_material(const char *key_in, size_t key_in_len,
return -1;
}
+/** Expand some secret key material according to RFC5869, using SHA256 as the
+ * underlying hash. The <b>key_in_len</b> bytes at <b>key_in</b> are the
+ * secret key material; the <b>salt_in_len</b> bytes at <b>salt_in</b> and the
+ * <b>info_in_len</b> bytes in <b>info_in_len</b> are the algorithm's "salt"
+ * and "info" parameters respectively. On success, write <b>key_out_len</b>
+ * bytes to <b>key_out</b> and return 0. On failure, return -1.
+ */
+int
+crypto_expand_key_material_rfc5869_sha256(
+ const uint8_t *key_in, size_t key_in_len,
+ const uint8_t *salt_in, size_t salt_in_len,
+ const uint8_t *info_in, size_t info_in_len,
+ uint8_t *key_out, size_t key_out_len)
+{
+ uint8_t prk[DIGEST256_LEN];
+ uint8_t tmp[DIGEST256_LEN + 128 + 1];
+ uint8_t mac[DIGEST256_LEN];
+ int i;
+ uint8_t *outp;
+ size_t tmp_len;
+
+ crypto_hmac_sha256((char*)prk,
+ (const char*)salt_in, salt_in_len,
+ (const char*)key_in, key_in_len);
+
+ /* If we try to get more than this amount of key data, we'll repeat blocks.*/
+ tor_assert(key_out_len <= DIGEST256_LEN * 256);
+ tor_assert(info_in_len <= 128);
+ memset(tmp, 0, sizeof(tmp));
+ outp = key_out;
+ i = 1;
+
+ while (key_out_len) {
+ size_t n;
+ if (i > 1) {
+ memcpy(tmp, mac, DIGEST256_LEN);
+ memcpy(tmp+DIGEST256_LEN, info_in, info_in_len);
+ tmp[DIGEST256_LEN+info_in_len] = i;
+ tmp_len = DIGEST256_LEN + info_in_len + 1;
+ } else {
+ memcpy(tmp, info_in, info_in_len);
+ tmp[info_in_len] = i;
+ tmp_len = info_in_len + 1;
+ }
+ crypto_hmac_sha256((char*)mac,
+ (const char*)prk, DIGEST256_LEN,
+ (const char*)tmp, tmp_len);
+ n = key_out_len < DIGEST256_LEN ? key_out_len : DIGEST256_LEN;
+ memcpy(outp, mac, n);
+ key_out_len -= n;
+ outp += n;
+ ++i;
+ }
+
+ memwipe(tmp, 0, sizeof(tmp));
+ memwipe(mac, 0, sizeof(mac));
+ return 0;
+}
+
/** Free a DH key exchange object.
*/
void
@@ -2282,35 +2347,27 @@ crypto_dh_free(crypto_dh_t *dh)
* that fd without checking whether it fit in the fd_set. Thus, if the
* system has not just been started up, it is unsafe to call */
#define RAND_POLL_IS_SAFE \
- ((OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,7,'j') && \
- OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)) || \
- OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,8,'c'))
+ (OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,8,'c'))
/** Set the seed of the weak RNG to a random value. */
-static void
-seed_weak_rng(void)
+void
+crypto_seed_weak_rng(tor_weak_rng_t *rng)
{
unsigned seed;
crypto_rand((void*)&seed, sizeof(seed));
- tor_init_weak_random(seed);
+ tor_init_weak_random(rng, seed);
}
-/** Seed OpenSSL's random number generator with bytes from the operating
- * system. <b>startup</b> should be true iff we have just started Tor and
- * have not yet allocated a bunch of fds. Return 0 on success, -1 on failure.
+/** Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
+ * storing it into <b>out</b>.
*/
int
-crypto_seed_rng(int startup)
+crypto_strongest_rand(uint8_t *out, size_t out_len)
{
- int rand_poll_status = 0;
-
- /* local variables */
#ifdef _WIN32
- unsigned char buf[ADD_ENTROPY];
static int provider_set = 0;
static HCRYPTPROV provider;
#else
- char buf[ADD_ENTROPY];
static const char *filenames[] = {
"/dev/srandom", "/dev/urandom", "/dev/random", NULL
};
@@ -2318,58 +2375,77 @@ crypto_seed_rng(int startup)
size_t n;
#endif
- /* OpenSSL has a RAND_poll function that knows about more kinds of
- * entropy than we do. We'll try calling that, *and* calling our own entropy
- * functions. If one succeeds, we'll accept the RNG as seeded. */
- if (startup || RAND_POLL_IS_SAFE) {
- rand_poll_status = RAND_poll();
- if (rand_poll_status == 0)
- log_warn(LD_CRYPTO, "RAND_poll() failed.");
- }
-
#ifdef _WIN32
if (!provider_set) {
if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
if ((unsigned long)GetLastError() != (unsigned long)NTE_BAD_KEYSET) {
log_warn(LD_CRYPTO, "Can't get CryptoAPI provider [1]");
- return rand_poll_status ? 0 : -1;
+ return -1;
}
}
provider_set = 1;
}
- if (!CryptGenRandom(provider, sizeof(buf), buf)) {
+ if (!CryptGenRandom(provider, out_len, out)) {
log_warn(LD_CRYPTO, "Can't get entropy from CryptoAPI.");
- return rand_poll_status ? 0 : -1;
+ return -1;
}
- RAND_seed(buf, sizeof(buf));
- memwipe(buf, 0, sizeof(buf));
- seed_weak_rng();
+
return 0;
#else
for (i = 0; filenames[i]; ++i) {
fd = open(filenames[i], O_RDONLY, 0);
if (fd<0) continue;
- log_info(LD_CRYPTO, "Seeding RNG from \"%s\"", filenames[i]);
- n = read_all(fd, buf, sizeof(buf), 0);
+ log_info(LD_CRYPTO, "Reading entropy from \"%s\"", filenames[i]);
+ n = read_all(fd, (char*)out, out_len, 0);
close(fd);
- if (n != sizeof(buf)) {
+ if (n != out_len) {
log_warn(LD_CRYPTO,
"Error reading from entropy source (read only %lu bytes).",
(unsigned long)n);
return -1;
}
- RAND_seed(buf, (int)sizeof(buf));
- memwipe(buf, 0, sizeof(buf));
- seed_weak_rng();
+
return 0;
}
- log_warn(LD_CRYPTO, "Cannot seed RNG -- no entropy source found.");
- return rand_poll_status ? 0 : -1;
+ log_warn(LD_CRYPTO, "Cannot get strong entropy: no entropy source found.");
+ return -1;
#endif
}
+/** Seed OpenSSL's random number generator with bytes from the operating
+ * system. <b>startup</b> should be true iff we have just started Tor and
+ * have not yet allocated a bunch of fds. Return 0 on success, -1 on failure.
+ */
+int
+crypto_seed_rng(int startup)
+{
+ int rand_poll_ok = 0, load_entropy_ok = 0;
+ uint8_t buf[ADD_ENTROPY];
+
+ /* OpenSSL has a RAND_poll function that knows about more kinds of
+ * entropy than we do. We'll try calling that, *and* calling our own entropy
+ * functions. If one succeeds, we'll accept the RNG as seeded. */
+ if (startup || RAND_POLL_IS_SAFE) {
+ rand_poll_ok = RAND_poll();
+ if (rand_poll_ok == 0)
+ log_warn(LD_CRYPTO, "RAND_poll() failed.");
+ }
+
+ load_entropy_ok = !crypto_strongest_rand(buf, sizeof(buf));
+ if (load_entropy_ok) {
+ RAND_seed(buf, sizeof(buf));
+ }
+
+ memwipe(buf, 0, sizeof(buf));
+
+ if (rand_poll_ok || load_entropy_ok)
+ return 0;
+ else
+ return -1;
+}
+
/** Write <b>n</b> bytes of strong random data to <b>to</b>. Return 0 on
* success, -1 on failure.
*/
@@ -2517,7 +2593,7 @@ smartlist_shuffle(smartlist_t *sl)
}
}
-/** Base-64 encode <b>srclen</b> bytes of data from <b>src</b>. Write
+/** Base64 encode <b>srclen</b> bytes of data from <b>src</b>. Write
* the result into <b>dest</b>, if it will fit within <b>destlen</b>
* bytes. Return the number of bytes written on success; -1 if
* destlen is too short, or other failure.
@@ -2576,7 +2652,7 @@ static const uint8_t base64_decode_table[256] = {
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
};
-/** Base-64 decode <b>srclen</b> bytes of data from <b>src</b>. Write
+/** Base64 decode <b>srclen</b> bytes of data from <b>src</b>. Write
* the result into <b>dest</b>, if it will fit within <b>destlen</b>
* bytes. Return the number of bytes written on success; -1 if
* destlen is too short, or other failure.
@@ -2683,7 +2759,7 @@ base64_decode(char *dest, size_t destlen, const char *src, size_t srclen)
#undef SP
#undef PAD
-/** Base-64 encode DIGEST_LINE bytes from <b>digest</b>, remove the trailing =
+/** Base64 encode DIGEST_LINE bytes from <b>digest</b>, remove the trailing =
* and newline characters, and store the nul-terminated result in the first
* BASE64_DIGEST_LEN+1 bytes of <b>d64</b>. */
int
@@ -2696,7 +2772,7 @@ digest_to_base64(char *d64, const char *digest)
return 0;
}
-/** Given a base-64 encoded, nul-terminated digest in <b>d64</b> (without
+/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
* trailing newline or = characters), decode it and store the result in the
* first DIGEST_LEN bytes at <b>digest</b>. */
int
@@ -2721,7 +2797,7 @@ digest_from_base64(char *digest, const char *d64)
#endif
}
-/** Base-64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the
+/** Base64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the
* trailing = and newline characters, and store the nul-terminated result in
* the first BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>. */
int
@@ -2734,7 +2810,7 @@ digest256_to_base64(char *d64, const char *digest)
return 0;
}
-/** Given a base-64 encoded, nul-terminated digest in <b>d64</b> (without
+/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
* trailing newline or = characters), decode it and store the result in the
* first DIGEST256_LEN bytes at <b>digest</b>. */
int
@@ -2759,7 +2835,7 @@ digest256_from_base64(char *digest, const char *d64)
#endif
}
-/** Implements base32 encoding as in rfc3548. Limitation: Requires
+/** Implements base32 encoding as in RFC 4648. Limitation: Requires
* that srclen*8 is a multiple of 5.
*/
void
@@ -2784,7 +2860,7 @@ base32_encode(char *dest, size_t destlen, const char *src, size_t srclen)
dest[i] = '\0';
}
-/** Implements base32 decoding as in rfc3548. Limitation: Requires
+/** Implements base32 decoding as in RFC 4648. Limitation: Requires
* that srclen*5 is a multiple of 8. Returns 0 if successful, -1 otherwise.
*/
int
@@ -2937,21 +3013,27 @@ memwipe(void *mem, uint8_t byte, size_t sz)
}
#ifdef TOR_IS_MULTITHREADED
+
+#ifndef OPENSSL_THREADS
+#error OpenSSL has been built without thread support. Tor requires an \
+ OpenSSL library with thread support enabled.
+#endif
+
/** Helper: OpenSSL uses this callback to manipulate mutexes. */
static void
-_openssl_locking_cb(int mode, int n, const char *file, int line)
+openssl_locking_cb_(int mode, int n, const char *file, int line)
{
(void)file;
(void)line;
- if (!_openssl_mutexes)
+ if (!openssl_mutexes_)
/* This is not a really good fix for the
* "release-freed-lock-from-separate-thread-on-shutdown" problem, but
* it can't hurt. */
return;
if (mode & CRYPTO_LOCK)
- tor_mutex_acquire(_openssl_mutexes[n]);
+ tor_mutex_acquire(openssl_mutexes_[n]);
else
- tor_mutex_release(_openssl_mutexes[n]);
+ tor_mutex_release(openssl_mutexes_[n]);
}
/** OpenSSL helper type: wraps a Tor mutex so that OpenSSL can use it
@@ -2963,7 +3045,7 @@ struct CRYPTO_dynlock_value {
/** OpenSSL callback function to allocate a lock: see CRYPTO_set_dynlock_*
* documentation in OpenSSL's docs for more info. */
static struct CRYPTO_dynlock_value *
-_openssl_dynlock_create_cb(const char *file, int line)
+openssl_dynlock_create_cb_(const char *file, int line)
{
struct CRYPTO_dynlock_value *v;
(void)file;
@@ -2976,7 +3058,7 @@ _openssl_dynlock_create_cb(const char *file, int line)
/** OpenSSL callback function to acquire or release a lock: see
* CRYPTO_set_dynlock_* documentation in OpenSSL's docs for more info. */
static void
-_openssl_dynlock_lock_cb(int mode, struct CRYPTO_dynlock_value *v,
+openssl_dynlock_lock_cb_(int mode, struct CRYPTO_dynlock_value *v,
const char *file, int line)
{
(void)file;
@@ -2990,7 +3072,7 @@ _openssl_dynlock_lock_cb(int mode, struct CRYPTO_dynlock_value *v,
/** OpenSSL callback function to free a lock: see CRYPTO_set_dynlock_*
* documentation in OpenSSL's docs for more info. */
static void
-_openssl_dynlock_destroy_cb(struct CRYPTO_dynlock_value *v,
+openssl_dynlock_destroy_cb_(struct CRYPTO_dynlock_value *v,
const char *file, int line)
{
(void)file;
@@ -3007,15 +3089,15 @@ setup_openssl_threading(void)
{
int i;
int n = CRYPTO_num_locks();
- _n_openssl_mutexes = n;
- _openssl_mutexes = tor_malloc(n*sizeof(tor_mutex_t *));
+ n_openssl_mutexes_ = n;
+ openssl_mutexes_ = tor_malloc(n*sizeof(tor_mutex_t *));
for (i=0; i < n; ++i)
- _openssl_mutexes[i] = tor_mutex_new();
- CRYPTO_set_locking_callback(_openssl_locking_cb);
+ openssl_mutexes_[i] = tor_mutex_new();
+ CRYPTO_set_locking_callback(openssl_locking_cb_);
CRYPTO_set_id_callback(tor_get_thread_id);
- CRYPTO_set_dynlock_create_callback(_openssl_dynlock_create_cb);
- CRYPTO_set_dynlock_lock_callback(_openssl_dynlock_lock_cb);
- CRYPTO_set_dynlock_destroy_callback(_openssl_dynlock_destroy_cb);
+ CRYPTO_set_dynlock_create_callback(openssl_dynlock_create_cb_);
+ CRYPTO_set_dynlock_lock_callback(openssl_dynlock_lock_cb_);
+ CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy_cb_);
return 0;
}
#else
@@ -3036,11 +3118,11 @@ crypto_global_cleanup(void)
ERR_free_strings();
if (dh_param_p)
- BN_free(dh_param_p);
+ BN_clear_free(dh_param_p);
if (dh_param_p_tls)
- BN_free(dh_param_p_tls);
+ BN_clear_free(dh_param_p_tls);
if (dh_param_g)
- BN_free(dh_param_g);
+ BN_clear_free(dh_param_g);
#ifndef DISABLE_ENGINES
ENGINE_cleanup();
@@ -3049,18 +3131,19 @@ crypto_global_cleanup(void)
CONF_modules_unload(1);
CRYPTO_cleanup_all_ex_data();
#ifdef TOR_IS_MULTITHREADED
- if (_n_openssl_mutexes) {
- int n = _n_openssl_mutexes;
- tor_mutex_t **ms = _openssl_mutexes;
+ if (n_openssl_mutexes_) {
+ int n = n_openssl_mutexes_;
+ tor_mutex_t **ms = openssl_mutexes_;
int i;
- _openssl_mutexes = NULL;
- _n_openssl_mutexes = 0;
+ openssl_mutexes_ = NULL;
+ n_openssl_mutexes_ = 0;
for (i=0;i<n;++i) {
tor_mutex_free(ms[i]);
}
tor_free(ms);
}
#endif
+ tor_free(crypto_openssl_version_str);
return 0;
}
diff --git a/src/common/crypto.h b/src/common/crypto.h
index 7d5627178..2fbca4c26 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -10,8 +10,8 @@
* \brief Headers for crypto.c
**/
-#ifndef _TOR_CRYPTO_H
-#define _TOR_CRYPTO_H
+#ifndef TOR_CRYPTO_H
+#define TOR_CRYPTO_H
#include <stdio.h>
#include "torint.h"
@@ -51,7 +51,7 @@
/** Length of the output of our message digest. */
#define DIGEST_LEN 20
/** Length of the output of our second (improved) message digests. (For now
- * this is just sha256, but any it can be any other 256-byte digest). */
+ * this is just sha256, but it could be any other 256-bit digest.) */
#define DIGEST256_LEN 32
/** Length of our symmetric cipher's keys. */
#define CIPHER_KEY_LEN 16
@@ -111,6 +111,7 @@ typedef struct crypto_digest_t crypto_digest_t;
typedef struct crypto_dh_t crypto_dh_t;
/* global state */
+const char * crypto_openssl_get_version_str(void);
int crypto_global_init(int hardwareAccel,
const char *accelName,
const char *accelPath);
@@ -147,6 +148,7 @@ int crypto_pk_write_private_key_to_filename(crypto_pk_t *env,
int crypto_pk_check_key(crypto_pk_t *env);
int crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b);
+int crypto_pk_eq_keys(crypto_pk_t *a, crypto_pk_t *b);
size_t crypto_pk_keysize(crypto_pk_t *env);
int crypto_pk_num_bits(crypto_pk_t *env);
crypto_pk_t *crypto_pk_dup_key(crypto_pk_t *orig);
@@ -181,7 +183,6 @@ crypto_pk_t *crypto_pk_asn1_decode(const char *str, size_t len);
int crypto_pk_get_digest(crypto_pk_t *pk, char *digest_out);
int crypto_pk_get_all_digests(crypto_pk_t *pk, digests_t *digests_out);
int crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out,int add_space);
-int crypto_pk_check_fingerprint_syntax(const char *s);
/* symmetric crypto */
const char *crypto_cipher_get_key(crypto_cipher_t *env);
@@ -204,6 +205,10 @@ int crypto_digest(char *digest, const char *m, size_t len);
int crypto_digest256(char *digest, const char *m, size_t len,
digest_algorithm_t algorithm);
int crypto_digest_all(digests_t *ds_out, const char *m, size_t len);
+struct smartlist_t;
+void crypto_digest_smartlist(char *digest_out, size_t len_out,
+ const struct smartlist_t *lst, const char *append,
+ digest_algorithm_t alg);
const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg);
int crypto_digest_algorithm_parse_name(const char *name);
crypto_digest_t *crypto_digest_new(void);
@@ -228,6 +233,7 @@ void crypto_hmac_sha256(char *hmac_out,
#define DH_TYPE_REND 2
#define DH_TYPE_TLS 3
crypto_dh_t *crypto_dh_new(int dh_type);
+crypto_dh_t *crypto_dh_dup(const crypto_dh_t *dh);
int crypto_dh_get_bytes(crypto_dh_t *dh);
int crypto_dh_generate_public(crypto_dh_t *dh);
int crypto_dh_get_public(crypto_dh_t *dh, char *pubkey_out,
@@ -236,15 +242,25 @@ ssize_t crypto_dh_compute_secret(int severity, crypto_dh_t *dh,
const char *pubkey, size_t pubkey_len,
char *secret_out, size_t secret_out_len);
void crypto_dh_free(crypto_dh_t *dh);
-int crypto_expand_key_material(const char *key_in, size_t in_len,
- char *key_out, size_t key_out_len);
+
+int crypto_expand_key_material_TAP(const uint8_t *key_in,
+ size_t key_in_len,
+ uint8_t *key_out, size_t key_out_len);
+int crypto_expand_key_material_rfc5869_sha256(
+ const uint8_t *key_in, size_t key_in_len,
+ const uint8_t *salt_in, size_t salt_in_len,
+ const uint8_t *info_in, size_t info_in_len,
+ uint8_t *key_out, size_t key_out_len);
/* random numbers */
int crypto_seed_rng(int startup);
int crypto_rand(char *to, size_t n);
+int crypto_strongest_rand(uint8_t *out, size_t out_len);
int crypto_rand_int(unsigned int max);
uint64_t crypto_rand_uint64(uint64_t max);
double crypto_rand_double(void);
+struct tor_weak_rng_t;
+void crypto_seed_weak_rng(struct tor_weak_rng_t *rng);
char *crypto_random_hostname(int min_rand_len, int max_rand_len,
const char *prefix, const char *suffix);
@@ -255,7 +271,7 @@ void smartlist_shuffle(struct smartlist_t *sl);
int base64_encode(char *dest, size_t destlen, const char *src, size_t srclen);
int base64_decode(char *dest, size_t destlen, const char *src, size_t srclen);
-/** Characters that can appear (case-insensitively) in a base-32 encoding. */
+/** Characters that can appear (case-insensitively) in a base32 encoding. */
#define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567"
void base32_encode(char *dest, size_t destlen, const char *src, size_t srclen);
int base32_decode(char *dest, size_t destlen, const char *src, size_t srclen);
@@ -280,11 +296,11 @@ void memwipe(void *mem, uint8_t byte, size_t sz);
struct rsa_st;
struct evp_pkey_st;
struct dh_st;
-struct rsa_st *_crypto_pk_get_rsa(crypto_pk_t *env);
-crypto_pk_t *_crypto_new_pk_from_rsa(struct rsa_st *rsa);
-struct evp_pkey_st *_crypto_pk_get_evp_pkey(crypto_pk_t *env,
+struct rsa_st *crypto_pk_get_rsa_(crypto_pk_t *env);
+crypto_pk_t *crypto_new_pk_from_rsa_(struct rsa_st *rsa);
+struct evp_pkey_st *crypto_pk_get_evp_pkey_(crypto_pk_t *env,
int private);
-struct dh_st *_crypto_dh_get_dh(crypto_dh_t *dh);
+struct dh_st *crypto_dh_get_dh_(crypto_dh_t *dh);
/* Prototypes for private functions only used by crypto.c and test.c*/
void add_spaces_to_fp(char *out, size_t outlen, const char *in);
#endif
diff --git a/src/common/crypto_curve25519.c b/src/common/crypto_curve25519.c
new file mode 100644
index 000000000..88c723f37
--- /dev/null
+++ b/src/common/crypto_curve25519.c
@@ -0,0 +1,191 @@
+/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/* Wrapper code for a curve25519 implementation. */
+
+#define CRYPTO_CURVE25519_PRIVATE
+#include "orconfig.h"
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include "crypto.h"
+#include "crypto_curve25519.h"
+#include "util.h"
+#include "torlog.h"
+
+/* ==============================
+ Part 1: wrap a suitable curve25519 implementation as curve25519_impl
+ ============================== */
+
+#ifdef USE_CURVE25519_DONNA
+int curve25519_donna(uint8_t *mypublic,
+ const uint8_t *secret, const uint8_t *basepoint);
+#endif
+#ifdef USE_CURVE25519_NACL
+#ifdef HAVE_CRYPTO_SCALARMULT_CURVE25519_H
+#include <crypto_scalarmult_curve25519.h>
+#elif defined(HAVE_NACL_CRYPTO_SCALARMULT_CURVE25519_H)
+#include <nacl/crypto_scalarmult_curve25519.h>
+#endif
+#endif
+
+int
+curve25519_impl(uint8_t *output, const uint8_t *secret,
+ const uint8_t *basepoint)
+{
+ uint8_t bp[CURVE25519_PUBKEY_LEN];
+ int r;
+ memcpy(bp, basepoint, CURVE25519_PUBKEY_LEN);
+ /* Clear the high bit, in case our backend foolishly looks at it. */
+ bp[31] &= 0x7f;
+#ifdef USE_CURVE25519_DONNA
+ r = curve25519_donna(output, secret, bp);
+#elif defined(USE_CURVE25519_NACL)
+ r = crypto_scalarmult_curve25519(output, secret, bp);
+#else
+#error "No implementation of curve25519 is available."
+#endif
+ memwipe(bp, 0, sizeof(bp));
+ return r;
+}
+
+/* ==============================
+ Part 2: Wrap curve25519_impl with some convenience types and functions.
+ ============================== */
+
+/**
+ * Return true iff a curve25519_public_key_t seems valid. (It's not necessary
+ * to see if the point is on the curve, since the twist is also secure, but we
+ * do need to make sure that it isn't the point at infinity.) */
+int
+curve25519_public_key_is_ok(const curve25519_public_key_t *key)
+{
+ return !safe_mem_is_zero(key->public_key, CURVE25519_PUBKEY_LEN);
+}
+
+/** Generate a new keypair and return the secret key. If <b>extra_strong</b>
+ * is true, this key is possibly going to get used more than once, so
+ * use a better-than-usual RNG. Return 0 on success, -1 on failure. */
+int
+curve25519_secret_key_generate(curve25519_secret_key_t *key_out,
+ int extra_strong)
+{
+ uint8_t k_tmp[CURVE25519_SECKEY_LEN];
+
+ if (crypto_rand((char*)key_out->secret_key, CURVE25519_SECKEY_LEN) < 0)
+ return -1;
+ if (extra_strong && !crypto_strongest_rand(k_tmp, CURVE25519_SECKEY_LEN)) {
+ /* If they asked for extra-strong entropy and we have some, use it as an
+ * HMAC key to improve not-so-good entropy rather than using it directly,
+ * just in case the extra-strong entropy is less amazing than we hoped. */
+ crypto_hmac_sha256((char *)key_out->secret_key,
+ (const char *)k_tmp, sizeof(k_tmp),
+ (const char *)key_out->secret_key, CURVE25519_SECKEY_LEN);
+ }
+ memwipe(k_tmp, 0, sizeof(k_tmp));
+ key_out->secret_key[0] &= 248;
+ key_out->secret_key[31] &= 127;
+ key_out->secret_key[31] |= 64;
+
+ return 0;
+}
+
+void
+curve25519_public_key_generate(curve25519_public_key_t *key_out,
+ const curve25519_secret_key_t *seckey)
+{
+ static const uint8_t basepoint[32] = {9};
+
+ curve25519_impl(key_out->public_key, seckey->secret_key, basepoint);
+}
+
+int
+curve25519_keypair_generate(curve25519_keypair_t *keypair_out,
+ int extra_strong)
+{
+ if (curve25519_secret_key_generate(&keypair_out->seckey, extra_strong) < 0)
+ return -1;
+ curve25519_public_key_generate(&keypair_out->pubkey, &keypair_out->seckey);
+ return 0;
+}
+
+int
+curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair,
+ const char *fname,
+ const char *tag)
+{
+ char contents[32 + CURVE25519_SECKEY_LEN + CURVE25519_PUBKEY_LEN];
+ int r;
+
+ memset(contents, 0, sizeof(contents));
+ tor_snprintf(contents, sizeof(contents), "== c25519v1: %s ==", tag);
+ tor_assert(strlen(contents) <= 32);
+ memcpy(contents+32, keypair->seckey.secret_key, CURVE25519_SECKEY_LEN);
+ memcpy(contents+32+CURVE25519_SECKEY_LEN,
+ keypair->pubkey.public_key, CURVE25519_PUBKEY_LEN);
+
+ r = write_bytes_to_file(fname, contents, sizeof(contents), 1);
+
+ memwipe(contents, 0, sizeof(contents));
+ return r;
+}
+
+int
+curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out,
+ char **tag_out,
+ const char *fname)
+{
+ char prefix[33];
+ char *content;
+ struct stat st;
+ int r = -1;
+
+ *tag_out = NULL;
+
+ st.st_size = 0;
+ content = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
+ if (! content)
+ goto end;
+ if (st.st_size != 32 + CURVE25519_SECKEY_LEN + CURVE25519_PUBKEY_LEN)
+ goto end;
+
+ memcpy(prefix, content, 32);
+ prefix[32] = '\0';
+ if (strcmpstart(prefix, "== c25519v1: ") ||
+ strcmpend(prefix, " =="))
+ goto end;
+
+ *tag_out = tor_strndup(prefix+strlen("== c25519v1: "),
+ strlen(prefix) - strlen("== c25519v1: =="));
+
+ memcpy(keypair_out->seckey.secret_key, content+32, CURVE25519_SECKEY_LEN);
+ curve25519_public_key_generate(&keypair_out->pubkey, &keypair_out->seckey);
+ if (tor_memneq(keypair_out->pubkey.public_key,
+ content + 32 + CURVE25519_SECKEY_LEN,
+ CURVE25519_PUBKEY_LEN))
+ goto end;
+
+ r = 0;
+
+ end:
+ if (content) {
+ memwipe(content, 0, (size_t) st.st_size);
+ tor_free(content);
+ }
+ if (r != 0) {
+ memset(keypair_out, 0, sizeof(*keypair_out));
+ tor_free(*tag_out);
+ }
+ return r;
+}
+
+/** Perform the curve25519 ECDH handshake with <b>skey</b> and <b>pkey</b>,
+ * writing CURVE25519_OUTPUT_LEN bytes of output into <b>output</b>. */
+void
+curve25519_handshake(uint8_t *output,
+ const curve25519_secret_key_t *skey,
+ const curve25519_public_key_t *pkey)
+{
+ curve25519_impl(output, skey->secret_key, pkey->public_key);
+}
+
diff --git a/src/common/crypto_curve25519.h b/src/common/crypto_curve25519.h
new file mode 100644
index 000000000..652f1883c
--- /dev/null
+++ b/src/common/crypto_curve25519.h
@@ -0,0 +1,68 @@
+/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_CRYPTO_CURVE25519_H
+#define TOR_CRYPTO_CURVE25519_H
+
+#include "torint.h"
+
+/** Length of a curve25519 public key when encoded. */
+#define CURVE25519_PUBKEY_LEN 32
+/** Length of a curve25519 secret key when encoded. */
+#define CURVE25519_SECKEY_LEN 32
+/** Length of the result of a curve25519 handshake. */
+#define CURVE25519_OUTPUT_LEN 32
+
+/** Wrapper type for a curve25519 public key */
+typedef struct curve25519_public_key_t {
+ uint8_t public_key[CURVE25519_PUBKEY_LEN];
+} curve25519_public_key_t;
+
+/** Wrapper type for a curve25519 secret key */
+typedef struct curve25519_secret_key_t {
+ uint8_t secret_key[CURVE25519_SECKEY_LEN];
+} curve25519_secret_key_t;
+
+/** A paired public and private key for curve25519. **/
+typedef struct curve25519_keypair_t {
+ curve25519_public_key_t pubkey;
+ curve25519_secret_key_t seckey;
+} curve25519_keypair_t;
+
+#ifdef CURVE25519_ENABLED
+int curve25519_public_key_is_ok(const curve25519_public_key_t *);
+
+int curve25519_secret_key_generate(curve25519_secret_key_t *key_out,
+ int extra_strong);
+void curve25519_public_key_generate(curve25519_public_key_t *key_out,
+ const curve25519_secret_key_t *seckey);
+int curve25519_keypair_generate(curve25519_keypair_t *keypair_out,
+ int extra_strong);
+
+void curve25519_handshake(uint8_t *output,
+ const curve25519_secret_key_t *,
+ const curve25519_public_key_t *);
+
+int curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair,
+ const char *fname,
+ const char *tag);
+
+int curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out,
+ char **tag_out,
+ const char *fname);
+
+#ifdef CRYPTO_CURVE25519_PRIVATE
+int curve25519_impl(uint8_t *output, const uint8_t *secret,
+ const uint8_t *basepoint);
+#endif
+#endif
+
+#define CURVE25519_BASE64_PADDED_LEN 44
+
+int curve25519_public_from_base64(curve25519_public_key_t *pkey,
+ const char *input);
+int curve25519_public_to_base64(char *output,
+ const curve25519_public_key_t *pkey);
+
+#endif
+
diff --git a/src/common/crypto_format.c b/src/common/crypto_format.c
new file mode 100644
index 000000000..93932f839
--- /dev/null
+++ b/src/common/crypto_format.c
@@ -0,0 +1,46 @@
+/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/* Formatting and parsing code for crypto-related data structures. */
+
+#define CRYPTO_CURVE25519_PRIVATE
+#include "orconfig.h"
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include "crypto.h"
+#include "crypto_curve25519.h"
+#include "util.h"
+#include "torlog.h"
+
+int
+curve25519_public_to_base64(char *output,
+ const curve25519_public_key_t *pkey)
+{
+ char buf[128];
+ base64_encode(buf, sizeof(buf),
+ (const char*)pkey->public_key, CURVE25519_PUBKEY_LEN);
+ buf[CURVE25519_BASE64_PADDED_LEN] = '\0';
+ memcpy(output, buf, CURVE25519_BASE64_PADDED_LEN+1);
+ return 0;
+}
+
+int
+curve25519_public_from_base64(curve25519_public_key_t *pkey,
+ const char *input)
+{
+ size_t len = strlen(input);
+ if (len == CURVE25519_BASE64_PADDED_LEN - 1) {
+ /* not padded */
+ return digest256_from_base64((char*)pkey->public_key, input);
+ } else if (len == CURVE25519_BASE64_PADDED_LEN) {
+ char buf[128];
+ if (base64_decode(buf, sizeof(buf), input, len) != CURVE25519_PUBKEY_LEN)
+ return -1;
+ memcpy(pkey->public_key, buf, CURVE25519_PUBKEY_LEN);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
diff --git a/src/common/di_ops.c b/src/common/di_ops.c
index 7683c59de..14a144340 100644
--- a/src/common/di_ops.c
+++ b/src/common/di_ops.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Tor Project, Inc. */
+/* Copyright (c) 2011-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,6 +8,8 @@
#include "orconfig.h"
#include "di_ops.h"
+#include "torlog.h"
+#include "util.h"
/**
* Timing-safe version of memcmp. As memcmp, compare the <b>sz</b> bytes at
@@ -123,7 +125,7 @@ tor_memeq(const void *a, const void *b, size_t sz)
*
* If any_difference != 0:
* 0 < any_difference < 256, so
- * 0 < any_difference - 1 < 255
+ * 0 <= any_difference - 1 < 255
* (any_difference - 1) >> 8 == 0
* 1 & ((any_difference - 1) >> 8) == 0
*/
@@ -131,3 +133,90 @@ tor_memeq(const void *a, const void *b, size_t sz)
return 1 & ((any_difference - 1) >> 8);
}
+/* Implement di_digest256_map_t as a linked list of entries. */
+struct di_digest256_map_t {
+ struct di_digest256_map_t *next;
+ uint8_t key[32];
+ void *val;
+};
+
+/** Release all storage held in <b>map</b>, calling free_fn on each value
+ * as we go. */
+void
+dimap_free(di_digest256_map_t *map, dimap_free_fn free_fn)
+{
+ while (map) {
+ di_digest256_map_t *victim = map;
+ map = map->next;
+ if (free_fn)
+ free_fn(victim->val);
+ tor_free(victim);
+ }
+}
+
+/** Adjust the map at *<b>map</b>, adding an entry for <b>key</b> ->
+ * <b>val</b>, where <b>key</b> is a DIGEST256_LEN-byte key.
+ *
+ * The caller MUST NOT add a key that already appears in the map.
+ */
+void
+dimap_add_entry(di_digest256_map_t **map,
+ const uint8_t *key, void *val)
+{
+ di_digest256_map_t *new_ent;
+ {
+ void *old_val = dimap_search(*map, key, NULL);
+ tor_assert(! old_val);
+ tor_assert(val);
+ }
+ new_ent = tor_malloc_zero(sizeof(di_digest256_map_t));
+ new_ent->next = *map;
+ memcpy(new_ent->key, key, 32);
+ new_ent->val = val;
+ *map = new_ent;
+}
+
+/** Search the map at <b>map</b> for an entry whose key is <b>key</b> (a
+ * DIGEST256_LEN-byte key) returning the corresponding value if we found one,
+ * and returning <b>dflt_val</b> if the key wasn't found.
+ *
+ * This operation takes an amount of time dependent only on the length of
+ * <b>map</b>, not on the position or presence of <b>key</b> within <b>map</b>.
+ */
+void *
+dimap_search(const di_digest256_map_t *map, const uint8_t *key,
+ void *dflt_val)
+{
+ uintptr_t result = (uintptr_t)dflt_val;
+
+ while (map) {
+ uintptr_t r = (uintptr_t) tor_memeq(map->key, key, 32);
+ r -= 1; /* Now r is (uintptr_t)-1 if memeq returned false, and
+ * 0 if memeq returned true. */
+
+ result &= r;
+ result |= ((uintptr_t)(map->val)) & ~r;
+
+ map = map->next;
+ }
+
+ return (void *)result;
+}
+
+/**
+ * Return true iff the <b>sz</b> bytes at <b>mem</b> are all zero. Runs in
+ * time independent of the contents of <b>mem</b>.
+ */
+int
+safe_mem_is_zero(const void *mem, size_t sz)
+{
+ uint32_t total = 0;
+ const uint8_t *ptr = mem;
+
+ while (sz--) {
+ total |= *ptr++;
+ }
+
+ return 1 & ((total - 1) >> 8);
+}
+
diff --git a/src/common/di_ops.h b/src/common/di_ops.h
index 8f0bb698f..d93534b69 100644
--- a/src/common/di_ops.h
+++ b/src/common/di_ops.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -27,5 +27,21 @@ int tor_memeq(const void *a, const void *b, size_t sz);
#define fast_memeq(a,b,c) (0==memcmp((a),(b),(c)))
#define fast_memneq(a,b,c) (0!=memcmp((a),(b),(c)))
+int safe_mem_is_zero(const void *mem, size_t sz);
+
+/** A type for a map from DIGEST256_LEN-byte blobs to void*, such that
+ * data lookups take an amount of time proportional only to the size
+ * of the map, and not to the position or presence of the item in the map.
+ *
+ * Not efficient for large maps! */
+typedef struct di_digest256_map_t di_digest256_map_t;
+typedef void (*dimap_free_fn)(void *);
+
+void dimap_free(di_digest256_map_t *map, dimap_free_fn free_fn);
+void dimap_add_entry(di_digest256_map_t **map,
+ const uint8_t *key, void *val);
+void *dimap_search(const di_digest256_map_t *map, const uint8_t *key,
+ void *dflt_val);
+
#endif
diff --git a/src/common/gen_server_ciphers.py b/src/common/gen_server_ciphers.py
new file mode 100755
index 000000000..97ed9d046
--- /dev/null
+++ b/src/common/gen_server_ciphers.py
@@ -0,0 +1,115 @@
+#!/usr/bin/python
+# Copyright 2014, The Tor Project, Inc
+# See LICENSE for licensing information
+
+# This script parses openssl headers to find ciphersuite names, determines
+# which ones we should be willing to use as a server, and sorts them according
+# to preference rules.
+#
+# Run it on all the files in your openssl include directory.
+
+import re
+import sys
+
+EPHEMERAL_INDICATORS = [ "_EDH_", "_DHE_", "_ECDHE_" ]
+BAD_STUFF = [ "_DES_40_", "MD5", "_RC4_", "_DES_64_",
+ "_SEED_", "_CAMELLIA_", "_NULL" ]
+
+# these never get #ifdeffed.
+MANDATORY = [
+ "TLS1_TXT_DHE_RSA_WITH_AES_256_SHA",
+ "TLS1_TXT_DHE_RSA_WITH_AES_128_SHA",
+ "SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA",
+]
+
+def find_ciphers(filename):
+ with open(filename) as f:
+ for line in f:
+ m = re.search(r'(?:SSL3|TLS1)_TXT_\w+', line)
+ if m:
+ yield m.group(0)
+
+def usable_cipher(ciph):
+ ephemeral = False
+ for e in EPHEMERAL_INDICATORS:
+ if e in ciph:
+ ephemeral = True
+ if not ephemeral:
+ return False
+
+ if "_RSA_" not in ciph:
+ return False
+
+ for b in BAD_STUFF:
+ if b in ciph:
+ return False
+ return True
+
+# All fields we sort on, in order of priority.
+FIELDS = [ 'cipher', 'fwsec', 'mode', 'digest', 'bitlength' ]
+# Map from sorted fields to recognized value in descending order of goodness
+FIELD_VALS = { 'cipher' : [ 'AES', 'DES'],
+ 'fwsec' : [ 'ECDHE', 'DHE' ],
+ 'mode' : [ 'GCM', 'CBC' ],
+ 'digest' : [ 'SHA384', 'SHA256', 'SHA' ],
+ 'bitlength' : [ '256', '128', '192' ],
+}
+
+class Ciphersuite(object):
+ def __init__(self, name, fwsec, cipher, bitlength, mode, digest):
+ self.name = name
+ self.fwsec = fwsec
+ self.cipher = cipher
+ self.bitlength = bitlength
+ self.mode = mode
+ self.digest = digest
+
+ for f in FIELDS:
+ assert(getattr(self, f) in FIELD_VALS[f])
+
+ def sort_key(self):
+ return tuple(FIELD_VALS[f].index(getattr(self,f)) for f in FIELDS)
+
+
+def parse_cipher(ciph):
+ m = re.match('(?:TLS1|SSL3)_TXT_(EDH|DHE|ECDHE)_RSA(?:_WITH)?_(AES|DES)_(256|128|192)(|_CBC|_CBC3|_GCM)_(SHA|SHA256|SHA384)$', ciph)
+
+ if not m:
+ print "/* Couldn't parse %s ! */"%ciph
+ return None
+
+ fwsec, cipher, bits, mode, digest = m.groups()
+ if fwsec == 'EDH':
+ fwsec = 'DHE'
+
+ if mode in [ '_CBC3', '_CBC', '' ]:
+ mode = 'CBC'
+ elif mode == '_GCM':
+ mode = 'GCM'
+
+ return Ciphersuite(ciph, fwsec, cipher, bits, mode, digest)
+
+ALL_CIPHERS = []
+
+for fname in sys.argv[1:]:
+ ALL_CIPHERS += (parse_cipher(c)
+ for c in find_ciphers(fname)
+ if usable_cipher(c) )
+
+ALL_CIPHERS.sort(key=Ciphersuite.sort_key)
+
+for c in ALL_CIPHERS:
+ if c is ALL_CIPHERS[-1]:
+ colon = ';'
+ else:
+ colon = ' ":"'
+
+ if c.name in MANDATORY:
+ print " /* Required */"
+ print ' %s%s'%(c.name,colon)
+ else:
+ print "#ifdef %s"%c.name
+ print ' %s%s'%(c.name,colon)
+ print "#endif"
+
+
diff --git a/src/common/get_mozilla_ciphers.py b/src/common/get_mozilla_ciphers.py
index c7e9a84a0..0636eb365 100644
--- a/src/common/get_mozilla_ciphers.py
+++ b/src/common/get_mozilla_ciphers.py
@@ -41,12 +41,12 @@ fileA = open(ff('security/manager/ssl/src/nsNSSComponent.cpp'),'r')
inCipherSection = False
cipherLines = []
for line in fileA:
- if line.startswith('static CipherPref CipherPrefs'):
+ if line.startswith('static const CipherPref sCipherPrefs[]'):
# Get the starting boundary of the Cipher Preferences
inCipherSection = True
elif inCipherSection:
line = line.strip()
- if line.startswith('{NULL, 0}'):
+ if line.startswith('{ nullptr, 0}'):
# At the ending boundary of the Cipher Prefs
break
else:
@@ -56,12 +56,30 @@ fileA.close()
# Parse the lines and put them into a dict
ciphers = {}
cipher_pref = {}
+key_pending = None
for line in cipherLines:
- m = re.search(r'^{\s*\"([^\"]+)\",\s*(\S*)\s*}', line)
+ m = re.search(r'^{\s*\"([^\"]+)\",\s*(\S+)\s*(?:,\s*(true|false))?\s*}', line)
if m:
- key,value = m.groups()
- ciphers[key] = value
- cipher_pref[value] = key
+ assert not key_pending
+ key,value,enabled = m.groups()
+ if enabled == 'true':
+ ciphers[key] = value
+ cipher_pref[value] = key
+ continue
+ m = re.search(r'^{\s*\"([^\"]+)\",', line)
+ if m:
+ assert not key_pending
+ key_pending = m.group(1)
+ continue
+ m = re.search(r'^\s*(\S+)(?:,\s*(true|false))?\s*}', line)
+ if m:
+ assert key_pending
+ key = key_pending
+ value,enabled = m.groups()
+ key_pending = None
+ if enabled == 'true':
+ ciphers[key] = value
+ cipher_pref[value] = key
####
# Now find the correct order for the ciphers
diff --git a/src/common/ht.h b/src/common/ht.h
deleted file mode 100644
index 25156c416..000000000
--- a/src/common/ht.h
+++ /dev/null
@@ -1,490 +0,0 @@
-/* Copyright (c) 2002, Christopher Clark.
- * Copyright (c) 2005-2006, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
-/* See license at end. */
-
-/* Based on ideas by Christopher Clark and interfaces from Niels Provos. */
-
-#ifndef _TOR_HT_H
-#define _TOR_HT_H
-
-#define HT_HEAD(name, type) \
- struct name { \
- /* The hash table itself. */ \
- struct type **hth_table; \
- /* How long is the hash table? */ \
- unsigned hth_table_length; \
- /* How many elements does the table contain? */ \
- unsigned hth_n_entries; \
- /* How many elements will we allow in the table before resizing it? */ \
- unsigned hth_load_limit; \
- /* Position of hth_table_length in the primes table. */ \
- int hth_prime_idx; \
- }
-
-#define HT_INITIALIZER() \
- { NULL, 0, 0, 0, -1 }
-
-#ifdef HT_NO_CACHE_HASH_VALUES
-#define HT_ENTRY(type) \
- struct { \
- struct type *hte_next; \
- }
-#else
-#define HT_ENTRY(type) \
- struct { \
- struct type *hte_next; \
- unsigned hte_hash; \
- }
-#endif
-
-#define HT_EMPTY(head) \
- ((head)->hth_n_entries == 0)
-
-/* How many elements in 'head'? */
-#define HT_SIZE(head) \
- ((head)->hth_n_entries)
-
-/* Return memory usage for a hashtable (not counting the entries themselves) */
-#define HT_MEM_USAGE(head) \
- (sizeof(*head) + (head)->hth_table_length * sizeof(void*))
-
-#define HT_FIND(name, head, elm) name##_HT_FIND((head), (elm))
-#define HT_INSERT(name, head, elm) name##_HT_INSERT((head), (elm))
-#define HT_REPLACE(name, head, elm) name##_HT_REPLACE((head), (elm))
-#define HT_REMOVE(name, head, elm) name##_HT_REMOVE((head), (elm))
-#define HT_START(name, head) name##_HT_START(head)
-#define HT_NEXT(name, head, elm) name##_HT_NEXT((head), (elm))
-#define HT_NEXT_RMV(name, head, elm) name##_HT_NEXT_RMV((head), (elm))
-#define HT_CLEAR(name, head) name##_HT_CLEAR(head)
-#define HT_INIT(name, head) name##_HT_INIT(head)
-/* Helper: */
-static INLINE unsigned
-ht_improve_hash(unsigned h)
-{
- /* Aim to protect against poor hash functions by adding logic here
- * - logic taken from java 1.4 hashtable source */
- h += ~(h << 9);
- h ^= ((h >> 14) | (h << 18)); /* >>> */
- h += (h << 4);
- h ^= ((h >> 10) | (h << 22)); /* >>> */
- return h;
-}
-
-#if 0
-/** Basic string hash function, from Java standard String.hashCode(). */
-static INLINE unsigned
-ht_string_hash(const char *s)
-{
- unsigned h = 0;
- int m = 1;
- while (*s) {
- h += ((signed char)*s++)*m;
- m = (m<<5)-1; /* m *= 31 */
- }
- return h;
-}
-#endif
-
-/** Basic string hash function, from Python's str.__hash__() */
-static INLINE unsigned
-ht_string_hash(const char *s)
-{
- unsigned h;
- const unsigned char *cp = (const unsigned char *)s;
- h = *cp << 7;
- while (*cp) {
- h = (1000003*h) ^ *cp++;
- }
- /* This conversion truncates the length of the string, but that's ok. */
- h ^= (unsigned)(cp-(const unsigned char*)s);
- return h;
-}
-
-#ifndef HT_NO_CACHE_HASH_VALUES
-#define HT_SET_HASH_(elm, field, hashfn) \
- do { (elm)->field.hte_hash = hashfn(elm); } while (0)
-#define HT_SET_HASHVAL_(elm, field, val) \
- do { (elm)->field.hte_hash = (val); } while (0)
-#define HT_ELT_HASH_(elm, field, hashfn) \
- ((elm)->field.hte_hash)
-#else
-#define HT_SET_HASH_(elm, field, hashfn) \
- ((void)0)
-#define HT_ELT_HASH_(elm, field, hashfn) \
- (hashfn(elm))
-#define HT_SET_HASHVAL_(elm, field, val) \
- ((void)0)
-#endif
-
-/* Helper: alias for the bucket containing 'elm'. */
-#define HT_BUCKET_(head, field, elm, hashfn) \
- ((head)->hth_table[HT_ELT_HASH_(elm,field,hashfn) \
- % head->hth_table_length])
-
-#define HT_FOREACH(x, name, head) \
- for ((x) = HT_START(name, head); \
- (x) != NULL; \
- (x) = HT_NEXT(name, head, x))
-
-#define HT_PROTOTYPE(name, type, field, hashfn, eqfn) \
- int name##_HT_GROW(struct name *ht, unsigned min_capacity); \
- void name##_HT_CLEAR(struct name *ht); \
- int name##_HT_REP_IS_BAD_(const struct name *ht); \
- static INLINE void \
- name##_HT_INIT(struct name *head) { \
- head->hth_table_length = 0; \
- head->hth_table = NULL; \
- head->hth_n_entries = 0; \
- head->hth_load_limit = 0; \
- head->hth_prime_idx = -1; \
- } \
- /* Helper: returns a pointer to the right location in the table \
- * 'head' to find or insert the element 'elm'. */ \
- static INLINE struct type ** \
- name##_HT_FIND_P_(struct name *head, struct type *elm) \
- { \
- struct type **p; \
- if (!head->hth_table) \
- return NULL; \
- p = &HT_BUCKET_(head, field, elm, hashfn); \
- while (*p) { \
- if (eqfn(*p, elm)) \
- return p; \
- p = &(*p)->field.hte_next; \
- } \
- return p; \
- } \
- /* Return a pointer to the element in the table 'head' matching 'elm', \
- * or NULL if no such element exists */ \
- static INLINE struct type * \
- name##_HT_FIND(const struct name *head, struct type *elm) \
- { \
- struct type **p; \
- struct name *h = (struct name *) head; \
- HT_SET_HASH_(elm, field, hashfn); \
- p = name##_HT_FIND_P_(h, elm); \
- return p ? *p : NULL; \
- } \
- /* Insert the element 'elm' into the table 'head'. Do not call this \
- * function if the table might already contain a matching element. */ \
- static INLINE void \
- name##_HT_INSERT(struct name *head, struct type *elm) \
- { \
- struct type **p; \
- if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \
- name##_HT_GROW(head, head->hth_n_entries+1); \
- ++head->hth_n_entries; \
- HT_SET_HASH_(elm, field, hashfn); \
- p = &HT_BUCKET_(head, field, elm, hashfn); \
- elm->field.hte_next = *p; \
- *p = elm; \
- } \
- /* Insert the element 'elm' into the table 'head'. If there already \
- * a matching element in the table, replace that element and return \
- * it. */ \
- static INLINE struct type * \
- name##_HT_REPLACE(struct name *head, struct type *elm) \
- { \
- struct type **p, *r; \
- if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \
- name##_HT_GROW(head, head->hth_n_entries+1); \
- HT_SET_HASH_(elm, field, hashfn); \
- p = name##_HT_FIND_P_(head, elm); \
- r = *p; \
- *p = elm; \
- if (r && (r!=elm)) { \
- elm->field.hte_next = r->field.hte_next; \
- r->field.hte_next = NULL; \
- return r; \
- } else { \
- ++head->hth_n_entries; \
- return NULL; \
- } \
- } \
- /* Remove any element matching 'elm' from the table 'head'. If such \
- * an element is found, return it; otherwise return NULL. */ \
- static INLINE struct type * \
- name##_HT_REMOVE(struct name *head, struct type *elm) \
- { \
- struct type **p, *r; \
- HT_SET_HASH_(elm, field, hashfn); \
- p = name##_HT_FIND_P_(head,elm); \
- if (!p || !*p) \
- return NULL; \
- r = *p; \
- *p = r->field.hte_next; \
- r->field.hte_next = NULL; \
- --head->hth_n_entries; \
- return r; \
- } \
- /* Invoke the function 'fn' on every element of the table 'head', \
- * using 'data' as its second argument. If the function returns \
- * nonzero, remove the most recently examined element before invoking \
- * the function again. */ \
- static INLINE void \
- name##_HT_FOREACH_FN(struct name *head, \
- int (*fn)(struct type *, void *), \
- void *data) \
- { \
- unsigned idx; \
- struct type **p, **nextp, *next; \
- if (!head->hth_table) \
- return; \
- for (idx=0; idx < head->hth_table_length; ++idx) { \
- p = &head->hth_table[idx]; \
- while (*p) { \
- nextp = &(*p)->field.hte_next; \
- next = *nextp; \
- if (fn(*p, data)) { \
- --head->hth_n_entries; \
- *p = next; \
- } else { \
- p = nextp; \
- } \
- } \
- } \
- } \
- /* Return a pointer to the first element in the table 'head', under \
- * an arbitrary order. This order is stable under remove operations, \
- * but not under others. If the table is empty, return NULL. */ \
- static INLINE struct type ** \
- name##_HT_START(struct name *head) \
- { \
- unsigned b = 0; \
- while (b < head->hth_table_length) { \
- if (head->hth_table[b]) \
- return &head->hth_table[b]; \
- ++b; \
- } \
- return NULL; \
- } \
- /* Return the next element in 'head' after 'elm', under the arbitrary \
- * order used by HT_START. If there are no more elements, return \
- * NULL. If 'elm' is to be removed from the table, you must call \
- * this function for the next value before you remove it. \
- */ \
- static INLINE struct type ** \
- name##_HT_NEXT(struct name *head, struct type **elm) \
- { \
- if ((*elm)->field.hte_next) { \
- return &(*elm)->field.hte_next; \
- } else { \
- unsigned b = (HT_ELT_HASH_(*elm, field, hashfn) \
- % head->hth_table_length)+1; \
- while (b < head->hth_table_length) { \
- if (head->hth_table[b]) \
- return &head->hth_table[b]; \
- ++b; \
- } \
- return NULL; \
- } \
- } \
- static INLINE struct type ** \
- name##_HT_NEXT_RMV(struct name *head, struct type **elm) \
- { \
- unsigned h = HT_ELT_HASH_(*elm, field, hashfn); \
- *elm = (*elm)->field.hte_next; \
- --head->hth_n_entries; \
- if (*elm) { \
- return elm; \
- } else { \
- unsigned b = (h % head->hth_table_length)+1; \
- while (b < head->hth_table_length) { \
- if (head->hth_table[b]) \
- return &head->hth_table[b]; \
- ++b; \
- } \
- return NULL; \
- } \
- }
-
-#define HT_GENERATE(name, type, field, hashfn, eqfn, load, mallocfn, \
- reallocfn, freefn) \
- static unsigned name##_PRIMES[] = { \
- 53, 97, 193, 389, \
- 769, 1543, 3079, 6151, \
- 12289, 24593, 49157, 98317, \
- 196613, 393241, 786433, 1572869, \
- 3145739, 6291469, 12582917, 25165843, \
- 50331653, 100663319, 201326611, 402653189, \
- 805306457, 1610612741 \
- }; \
- static unsigned name##_N_PRIMES = \
- (unsigned)(sizeof(name##_PRIMES)/sizeof(name##_PRIMES[0])); \
- /* Expand the internal table of 'head' until it is large enough to \
- * hold 'size' elements. Return 0 on success, -1 on allocation \
- * failure. */ \
- int \
- name##_HT_GROW(struct name *head, unsigned size) \
- { \
- unsigned new_len, new_load_limit; \
- int prime_idx; \
- struct type **new_table; \
- if (head->hth_prime_idx == (int)name##_N_PRIMES - 1) \
- return 0; \
- if (head->hth_load_limit > size) \
- return 0; \
- prime_idx = head->hth_prime_idx; \
- do { \
- new_len = name##_PRIMES[++prime_idx]; \
- new_load_limit = (unsigned)(load*new_len); \
- } while (new_load_limit <= size && \
- prime_idx < (int)name##_N_PRIMES); \
- if ((new_table = mallocfn(new_len*sizeof(struct type*)))) { \
- unsigned b; \
- memset(new_table, 0, new_len*sizeof(struct type*)); \
- for (b = 0; b < head->hth_table_length; ++b) { \
- struct type *elm, *next; \
- unsigned b2; \
- elm = head->hth_table[b]; \
- while (elm) { \
- next = elm->field.hte_next; \
- b2 = HT_ELT_HASH_(elm, field, hashfn) % new_len; \
- elm->field.hte_next = new_table[b2]; \
- new_table[b2] = elm; \
- elm = next; \
- } \
- } \
- if (head->hth_table) \
- freefn(head->hth_table); \
- head->hth_table = new_table; \
- } else { \
- unsigned b, b2; \
- new_table = reallocfn(head->hth_table, new_len*sizeof(struct type*)); \
- if (!new_table) return -1; \
- memset(new_table + head->hth_table_length, 0, \
- (new_len - head->hth_table_length)*sizeof(struct type*)); \
- for (b=0; b < head->hth_table_length; ++b) { \
- struct type *e, **pE; \
- for (pE = &new_table[b], e = *pE; e != NULL; e = *pE) { \
- b2 = HT_ELT_HASH_(e, field, hashfn) % new_len; \
- if (b2 == b) { \
- pE = &e->field.hte_next; \
- } else { \
- *pE = e->field.hte_next; \
- e->field.hte_next = new_table[b2]; \
- new_table[b2] = e; \
- } \
- } \
- } \
- head->hth_table = new_table; \
- } \
- head->hth_table_length = new_len; \
- head->hth_prime_idx = prime_idx; \
- head->hth_load_limit = new_load_limit; \
- return 0; \
- } \
- /* Free all storage held by 'head'. Does not free 'head' itself, or \
- * individual elements. */ \
- void \
- name##_HT_CLEAR(struct name *head) \
- { \
- if (head->hth_table) \
- freefn(head->hth_table); \
- head->hth_table_length = 0; \
- name##_HT_INIT(head); \
- } \
- /* Debugging helper: return false iff the representation of 'head' is \
- * internally consistent. */ \
- int \
- name##_HT_REP_IS_BAD_(const struct name *head) \
- { \
- unsigned n, i; \
- struct type *elm; \
- if (!head->hth_table_length) { \
- if (!head->hth_table && !head->hth_n_entries && \
- !head->hth_load_limit && head->hth_prime_idx == -1) \
- return 0; \
- else \
- return 1; \
- } \
- if (!head->hth_table || head->hth_prime_idx < 0 || \
- !head->hth_load_limit) \
- return 2; \
- if (head->hth_n_entries > head->hth_load_limit) \
- return 3; \
- if (head->hth_table_length != name##_PRIMES[head->hth_prime_idx]) \
- return 4; \
- if (head->hth_load_limit != (unsigned)(load*head->hth_table_length)) \
- return 5; \
- for (n = i = 0; i < head->hth_table_length; ++i) { \
- for (elm = head->hth_table[i]; elm; elm = elm->field.hte_next) { \
- if (HT_ELT_HASH_(elm, field, hashfn) != hashfn(elm)) \
- return 1000 + i; \
- if ((HT_ELT_HASH_(elm, field, hashfn) % head->hth_table_length) != i) \
- return 10000 + i; \
- ++n; \
- } \
- } \
- if (n != head->hth_n_entries) \
- return 6; \
- return 0; \
- }
-
-/** Implements an over-optimized "find and insert if absent" block;
- * not meant for direct usage by typical code, or usage outside the critical
- * path.*/
-#define HT_FIND_OR_INSERT_(name, field, hashfn, head, eltype, elm, var, y, n) \
- { \
- struct name *var##_head_ = head; \
- struct eltype **var; \
- if (!var##_head_->hth_table || \
- var##_head_->hth_n_entries >= var##_head_->hth_load_limit) \
- name##_HT_GROW(var##_head_, var##_head_->hth_n_entries+1); \
- HT_SET_HASH_((elm), field, hashfn); \
- var = name##_HT_FIND_P_(var##_head_, (elm)); \
- if (*var) { \
- y; \
- } else { \
- n; \
- } \
- }
-#define HT_FOI_INSERT_(field, head, elm, newent, var) \
- { \
- HT_SET_HASHVAL_(newent, field, (elm)->field.hte_hash); \
- newent->field.hte_next = NULL; \
- *var = newent; \
- ++((head)->hth_n_entries); \
- }
-
-/*
- * Copyright 2005, Nick Mathewson. Implementation logic is adapted from code
- * by Christopher Clark, retrofit to allow drop-in memory management, and to
- * use the same interface as Niels Provos's tree.h. This is probably still
- * a derived work, so the original license below still applies.
- *
- * Copyright (c) 2002, Christopher Clark
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of the original author; nor the names of any contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#endif
-
diff --git a/src/common/include.am b/src/common/include.am
new file mode 100644
index 000000000..b796ebfae
--- /dev/null
+++ b/src/common/include.am
@@ -0,0 +1,96 @@
+
+noinst_LIBRARIES+= src/common/libor.a src/common/libor-crypto.a src/common/libor-event.a
+
+EXTRA_DIST+= \
+ src/common/common_sha1.i \
+ src/common/Makefile.nmake
+
+#CFLAGS = -Wall -Wpointer-arith -O2
+AM_CPPFLAGS += -I$(srcdir)/src/common -Isrc/common
+
+if USE_OPENBSD_MALLOC
+libor_extra_source=src/ext/OpenBSD_malloc_Linux.c
+else
+libor_extra_source=
+endif
+
+if BUILD_CURVE25519_DONNA
+src_common_libcurve25519_donna_a_SOURCES=\
+ src/ext/curve25519_donna/curve25519-donna.c
+noinst_LIBRARIES+=src/common/libcurve25519_donna.a
+LIBDONNA=src/common/libcurve25519_donna.a
+else
+if BUILD_CURVE25519_DONNA_C64
+src_common_libcurve25519_donna_a_SOURCES=\
+ src/ext/curve25519_donna/curve25519-donna-c64.c
+noinst_LIBRARIES+=src/common/libcurve25519_donna.a
+LIBDONNA=src/common/libcurve25519_donna.a
+else
+LIBDONNA=
+endif
+endif
+
+src_common_libcurve25519_donna_a_CFLAGS =
+
+if CURVE25519_ENABLED
+libcrypto_extra_source=src/common/crypto_curve25519.c
+endif
+
+src_common_libor_a_SOURCES = \
+ src/common/address.c \
+ src/common/compat.c \
+ src/common/container.c \
+ src/common/di_ops.c \
+ src/common/log.c \
+ src/common/memarea.c \
+ src/common/mempool.c \
+ src/common/procmon.c \
+ src/common/util.c \
+ src/common/util_codedigest.c \
+ $(libor_extra_source)
+
+src_common_libor_crypto_a_SOURCES = \
+ src/common/aes.c \
+ src/common/crypto.c \
+ src/common/crypto_format.c \
+ src/common/torgzip.c \
+ src/common/tortls.c \
+ $(libcrypto_extra_source)
+
+src_common_libor_event_a_SOURCES = src/common/compat_libevent.c
+
+COMMONHEADERS = \
+ src/common/address.h \
+ src/common/aes.h \
+ src/common/ciphers.inc \
+ src/common/compat.h \
+ src/common/compat_libevent.h \
+ src/common/container.h \
+ src/common/crypto.h \
+ src/common/crypto_curve25519.h \
+ src/common/di_ops.h \
+ src/common/memarea.h \
+ src/common/mempool.h \
+ src/common/procmon.h \
+ src/common/torgzip.h \
+ src/common/torint.h \
+ src/common/torlog.h \
+ src/common/tortls.h \
+ src/common/util.h
+
+noinst_HEADERS+= $(COMMONHEADERS)
+
+DISTCLEANFILES+= src/common/common_sha1.i
+
+src/common/common_sha1.i: $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(COMMONHEADERS)
+ $(AM_V_GEN)if test "@SHA1SUM@" != none; then \
+ (cd "$(srcdir)" && "@SHA1SUM@" $(src_common_libor_SOURCES) $(src_common_libor_crypto_a_SOURCES) $(COMMONHEADERS)) | "@SED@" -n 's/^\(.*\)$$/"\1\\n"/p' > $@; \
+ elif test "@OPENSSL@" != none; then \
+ (cd "$(srcdir)" && "@OPENSSL@" sha1 $(src_common_libor_SOURCES) $(src_Common_libor_crypto_a_SOURCES) $(COMMONHEADERS)) | "@SED@" -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > $@; \
+ else \
+ rm $@; \
+ touch $@; \
+ fi
+
+src/common/util_codedigest.o: src/common/common_sha1.i
+
diff --git a/src/common/log.c b/src/common/log.c
index 5e2e6b5b5..e196a1128 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -131,7 +131,7 @@ static smartlist_t *pending_cb_messages = NULL;
/** What's the lowest log level anybody cares about? Checking this lets us
* bail out early from log_debug if we aren't debugging. */
-int _log_global_min_severity = LOG_NOTICE;
+int log_global_min_severity_ = LOG_NOTICE;
static void delete_log(logfile_t *victim);
static void close_log(logfile_t *victim);
@@ -140,11 +140,12 @@ static char *domain_to_string(log_domain_mask_t domain,
char *buf, size_t buflen);
static INLINE char *format_msg(char *buf, size_t buf_len,
log_domain_mask_t domain, int severity, const char *funcname,
+ const char *suffix,
const char *format, va_list ap, size_t *msg_len_out)
- CHECK_PRINTF(6,0);
+ CHECK_PRINTF(7,0);
static void logv(int severity, log_domain_mask_t domain, const char *funcname,
- const char *format, va_list ap)
- CHECK_PRINTF(4,0);
+ const char *suffix, const char *format, va_list ap)
+ CHECK_PRINTF(5,0);
/** Name of the application: used to generate the message we write at the
* start of each new log. */
@@ -177,7 +178,7 @@ set_log_time_granularity(int granularity_msec)
* <b>buf_len</b> character buffer in <b>buf</b>.
*/
static INLINE size_t
-_log_prefix(char *buf, size_t buf_len, int severity)
+log_prefix_(char *buf, size_t buf_len, int severity)
{
time_t t;
struct timeval now;
@@ -230,7 +231,7 @@ log_tor_version(logfile_t *lf, int reset)
/* We are resetting, but we aren't at the start of the file; no
* need to log again. */
return 0;
- n = _log_prefix(buf, sizeof(buf), LOG_NOTICE);
+ n = log_prefix_(buf, sizeof(buf), LOG_NOTICE);
if (appname) {
tor_snprintf(buf+n, sizeof(buf)-n,
"%s opening %slog file.\n", appname, is_new?"new ":"");
@@ -251,6 +252,7 @@ log_tor_version(logfile_t *lf, int reset)
static INLINE char *
format_msg(char *buf, size_t buf_len,
log_domain_mask_t domain, int severity, const char *funcname,
+ const char *suffix,
const char *format, va_list ap, size_t *msg_len_out)
{
size_t n;
@@ -262,7 +264,7 @@ format_msg(char *buf, size_t buf_len,
buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */
buf_end = buf+buf_len; /* point *after* the last char we can write to */
- n = _log_prefix(buf, buf_len, severity);
+ n = log_prefix_(buf, buf_len, severity);
end_of_prefix = buf+n;
if (log_domains_are_logged) {
@@ -312,6 +314,13 @@ format_msg(char *buf, size_t buf_len,
n = buf_len;
} else {
n += r;
+ if (suffix) {
+ size_t suffix_len = strlen(suffix);
+ if (buf_len-n >= suffix_len) {
+ memcpy(buf+n, suffix, suffix_len);
+ n += suffix_len;
+ }
+ }
}
buf[n]='\n';
buf[n+1]='\0';
@@ -325,7 +334,7 @@ format_msg(char *buf, size_t buf_len,
*/
static void
logv(int severity, log_domain_mask_t domain, const char *funcname,
- const char *format, va_list ap)
+ const char *suffix, const char *format, va_list ap)
{
char buf[10024];
size_t msg_len = 0;
@@ -361,8 +370,8 @@ logv(int severity, log_domain_mask_t domain, const char *funcname,
if (!formatted) {
end_of_prefix =
- format_msg(buf, sizeof(buf), domain, severity, funcname, format, ap,
- &msg_len);
+ format_msg(buf, sizeof(buf), domain, severity, funcname, suffix,
+ format, ap, &msg_len);
formatted = 1;
}
@@ -423,10 +432,10 @@ void
tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (severity > _log_global_min_severity)
+ if (severity > log_global_min_severity_)
return;
va_start(ap,format);
- logv(severity, domain, NULL, format, ap);
+ logv(severity, domain, NULL, NULL, format, ap);
va_end(ap);
}
@@ -436,89 +445,121 @@ tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
* variadic macros. All arguments are as for log_fn, except for
* <b>fn</b>, which is the name of the calling functions. */
void
-_log_fn(int severity, log_domain_mask_t domain, const char *fn,
+log_fn_(int severity, log_domain_mask_t domain, const char *fn,
const char *format, ...)
{
va_list ap;
- if (severity > _log_global_min_severity)
+ if (severity > log_global_min_severity_)
return;
va_start(ap,format);
- logv(severity, domain, fn, format, ap);
+ logv(severity, domain, fn, NULL, format, ap);
+ va_end(ap);
+}
+void
+log_fn_ratelim_(ratelim_t *ratelim, int severity, log_domain_mask_t domain,
+ const char *fn, const char *format, ...)
+{
+ va_list ap;
+ char *m;
+ if (severity > log_global_min_severity_)
+ return;
+ m = rate_limit_log(ratelim, approx_time());
+ if (m == NULL)
+ return;
+ va_start(ap, format);
+ logv(severity, domain, fn, m, format, ap);
va_end(ap);
+ tor_free(m);
}
#else
/** @{ */
/** Variant implementation of log_fn, log_debug, log_info,... for C compilers
* without variadic macros. In this case, the calling function sets
- * _log_fn_function_name to the name of the function, then invokes the
- * appropriate _log_fn, _log_debug, etc. */
-const char *_log_fn_function_name=NULL;
+ * log_fn_function_name_ to the name of the function, then invokes the
+ * appropriate log_fn_, log_debug_, etc. */
+const char *log_fn_function_name_=NULL;
void
-_log_fn(int severity, log_domain_mask_t domain, const char *format, ...)
+log_fn_(int severity, log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (severity > _log_global_min_severity)
+ if (severity > log_global_min_severity_)
return;
va_start(ap,format);
- logv(severity, domain, _log_fn_function_name, format, ap);
+ logv(severity, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
void
-_log_debug(log_domain_mask_t domain, const char *format, ...)
+log_fn_ratelim_(ratelim_t *ratelim, int severity, log_domain_mask_t domain,
+ const char *format, ...)
+{
+ va_list ap;
+ char *m;
+ if (severity > log_global_min_severity_)
+ return;
+ m = rate_limit_log(ratelim, approx_time());
+ if (m == NULL)
+ return;
+ va_start(ap, format);
+ logv(severity, domain, log_fn_function_name_, m, format, ap);
+ va_end(ap);
+ tor_free(m);
+}
+void
+log_debug_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
/* For GCC we do this check in the macro. */
- if (PREDICT_LIKELY(LOG_DEBUG > _log_global_min_severity))
+ if (PREDICT_LIKELY(LOG_DEBUG > log_global_min_severity_))
return;
va_start(ap,format);
- logv(LOG_DEBUG, domain, _log_fn_function_name, format, ap);
+ logv(LOG_DEBUG, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
void
-_log_info(log_domain_mask_t domain, const char *format, ...)
+log_info_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (LOG_INFO > _log_global_min_severity)
+ if (LOG_INFO > log_global_min_severity_)
return;
va_start(ap,format);
- logv(LOG_INFO, domain, _log_fn_function_name, format, ap);
+ logv(LOG_INFO, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
void
-_log_notice(log_domain_mask_t domain, const char *format, ...)
+log_notice_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (LOG_NOTICE > _log_global_min_severity)
+ if (LOG_NOTICE > log_global_min_severity_)
return;
va_start(ap,format);
- logv(LOG_NOTICE, domain, _log_fn_function_name, format, ap);
+ logv(LOG_NOTICE, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
void
-_log_warn(log_domain_mask_t domain, const char *format, ...)
+log_warn_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (LOG_WARN > _log_global_min_severity)
+ if (LOG_WARN > log_global_min_severity_)
return;
va_start(ap,format);
- logv(LOG_WARN, domain, _log_fn_function_name, format, ap);
+ logv(LOG_WARN, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
void
-_log_err(log_domain_mask_t domain, const char *format, ...)
+log_err_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
- if (LOG_ERR > _log_global_min_severity)
+ if (LOG_ERR > log_global_min_severity_)
return;
va_start(ap,format);
- logv(LOG_ERR, domain, _log_fn_function_name, format, ap);
+ logv(LOG_ERR, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
- _log_fn_function_name = NULL;
+ log_fn_function_name_ = NULL;
}
/** @} */
#endif
@@ -638,7 +679,7 @@ add_stream_log_impl(const log_severity_list_t *severity,
lf->next = logfiles;
logfiles = lf;
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
}
/** Add a log handler named <b>name</b> to send all messages in <b>severity</b>
@@ -706,7 +747,7 @@ add_callback_log(const log_severity_list_t *severity, log_callback cb)
LOCK_LOGS();
logfiles = lf;
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
UNLOCK_LOGS();
return 0;
}
@@ -726,7 +767,7 @@ change_callback_log_severity(int loglevelMin, int loglevelMax,
memcpy(lf->severities, &severities, sizeof(severities));
}
}
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
UNLOCK_LOGS();
}
@@ -792,7 +833,7 @@ close_temp_logs(void)
}
}
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
UNLOCK_LOGS();
}
@@ -833,14 +874,16 @@ add_file_log(const log_severity_list_t *severity, const char *filename)
fd = tor_open_cloexec(filename, O_WRONLY|O_CREAT|O_APPEND, 0644);
if (fd<0)
return -1;
- if (tor_fd_seekend(fd)<0)
+ if (tor_fd_seekend(fd)<0) {
+ close(fd);
return -1;
+ }
LOCK_LOGS();
add_stream_log_impl(severity, filename, fd);
logfiles->needs_close = 1;
lf = logfiles;
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
if (log_tor_version(lf, 0) < 0) {
delete_log(lf);
@@ -871,7 +914,7 @@ add_syslog_log(const log_severity_list_t *severity)
LOCK_LOGS();
lf->next = logfiles;
logfiles = lf;
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
UNLOCK_LOGS();
return 0;
}
@@ -907,7 +950,7 @@ log_level_to_string(int level)
static const char *domain_list[] = {
"GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
"HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
- "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", NULL
+ "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", "CHANNEL", NULL
};
/** Return a bitmask for the log domain for which <b>domain</b> is the name,
@@ -1106,7 +1149,7 @@ switch_logs_debug(void)
for (i = LOG_DEBUG; i >= LOG_ERR; --i)
lf->severities->masks[SEVERITY_MASK_IDX(i)] = ~0u;
}
- _log_global_min_severity = get_min_log_level();
+ log_global_min_severity_ = get_min_log_level();
UNLOCK_LOGS();
}
diff --git a/src/common/memarea.c b/src/common/memarea.c
index 07bd593cc..0ae0ccca1 100644
--- a/src/common/memarea.c
+++ b/src/common/memarea.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, The Tor Project, Inc. */
+/* Copyright (c) 2008-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/** \file memarea.c
@@ -77,7 +77,7 @@ typedef struct memarea_chunk_t {
* full. */
union {
char mem[1]; /**< Memory space in this chunk. */
- void *_void_for_alignment; /**< Dummy; used to make sure mem is aligned. */
+ void *void_for_alignment_; /**< Dummy; used to make sure mem is aligned. */
} u;
} memarea_chunk_t;
@@ -118,7 +118,7 @@ alloc_chunk(size_t sz, int freelist_ok)
size_t chunk_size = freelist_ok ? CHUNK_SIZE : sz;
memarea_chunk_t *res;
chunk_size += SENTINEL_LEN;
- res = tor_malloc_roundup(&chunk_size);
+ res = tor_malloc(chunk_size);
res->next_chunk = NULL;
res->mem_size = chunk_size - CHUNK_HEADER_SIZE - SENTINEL_LEN;
res->next_mem = res->u.mem;
diff --git a/src/common/memarea.h b/src/common/memarea.h
index b3c76d8d0..8b88585d3 100644
--- a/src/common/memarea.h
+++ b/src/common/memarea.h
@@ -1,9 +1,9 @@
-/* Copyright (c) 2008-2012, The Tor Project, Inc. */
+/* Copyright (c) 2008-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Tor dependencies */
-#ifndef _TOR_MEMAREA_H
-#define _TOR_MEMAREA_H
+#ifndef TOR_MEMAREA_H
+#define TOR_MEMAREA_H
typedef struct memarea_t memarea_t;
diff --git a/src/common/mempool.c b/src/common/mempool.c
index 637f081c8..438988876 100644
--- a/src/common/mempool.c
+++ b/src/common/mempool.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#if 1
/* Tor dependencies */
@@ -71,7 +71,6 @@
#define ASSERT(x) tor_assert(x)
#undef ALLOC_CAN_RETURN_NULL
#define TOR
-//#define ALLOC_ROUNDUP(p) tor_malloc_roundup(p)
/* End Tor dependencies */
#else
/* If you're not building this as part of Tor, you'll want to define the
@@ -115,7 +114,7 @@ struct mp_allocated_t {
* (Not actual size.) */
char mem[1];
/** An extra element to the union to insure correct alignment. */
- ALIGNMENT_TYPE _dummy;
+ ALIGNMENT_TYPE dummy_;
} u;
};
@@ -166,25 +165,16 @@ static mp_chunk_t *
mp_chunk_new(mp_pool_t *pool)
{
size_t sz = pool->new_chunk_capacity * pool->item_alloc_size;
-#ifdef ALLOC_ROUNDUP
- size_t alloc_size = CHUNK_OVERHEAD + sz;
- mp_chunk_t *chunk = ALLOC_ROUNDUP(&alloc_size);
-#else
mp_chunk_t *chunk = ALLOC(CHUNK_OVERHEAD + sz);
-#endif
+
#ifdef MEMPOOL_STATS
++pool->total_chunks_allocated;
#endif
CHECK_ALLOC(chunk);
memset(chunk, 0, sizeof(mp_chunk_t)); /* Doesn't clear the whole thing. */
chunk->magic = MP_CHUNK_MAGIC;
-#ifdef ALLOC_ROUNDUP
- chunk->mem_size = alloc_size - CHUNK_OVERHEAD;
- chunk->capacity = chunk->mem_size / pool->item_alloc_size;
-#else
chunk->capacity = pool->new_chunk_capacity;
chunk->mem_size = sz;
-#endif
chunk->next_mem = chunk->mem;
chunk->pool = pool;
return chunk;
diff --git a/src/common/mempool.h b/src/common/mempool.h
index bc424acde..0fc1e4c67 100644
--- a/src/common/mempool.h
+++ b/src/common/mempool.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -6,8 +6,8 @@
* \brief Headers for mempool.c
**/
-#ifndef _TOR_MEMPOOL_H
-#define _TOR_MEMPOOL_H
+#ifndef TOR_MEMPOOL_H
+#define TOR_MEMPOOL_H
/** A memory pool is a context in which a large number of fixed-sized
* objects can be allocated efficiently. See mempool.c for implementation
diff --git a/src/common/procmon.c b/src/common/procmon.c
index 36b1a4855..0a49689e3 100644
--- a/src/common/procmon.c
+++ b/src/common/procmon.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Tor Project, Inc. */
+/* Copyright (c) 2011-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -25,9 +25,21 @@
#ifdef _WIN32
#include <windows.h>
+#endif
-/* Windows does not define pid_t, but _getpid() returns an int. */
+#if (0 == SIZEOF_PID_T) && defined(_WIN32)
+/* Windows does not define pid_t sometimes, but _getpid() returns an int.
+ * Everybody else needs to have a pid_t. */
typedef int pid_t;
+#define PID_T_FORMAT "%d"
+#elif (SIZEOF_PID_T == SIZEOF_INT) || (SIZEOF_PID_T == SIZEOF_SHORT)
+#define PID_T_FORMAT "%d"
+#elif (SIZEOF_PID_T == SIZEOF_LONG)
+#define PID_T_FORMAT "%ld"
+#elif (SIZEOF_PID_T == SIZEOF_INT64_T)
+#define PID_T_FORMAT I64_FORMAT
+#else
+#error Unknown: SIZEOF_PID_T
#endif
/* Define to 1 if process-termination monitors on this OS and Libevent
@@ -204,15 +216,17 @@ tor_process_monitor_new(struct event_base *base,
if (procmon->hproc != NULL) {
procmon->poll_hproc = 1;
- log_info(procmon->log_domain, "Successfully opened handle to process %d; "
+ log_info(procmon->log_domain, "Successfully opened handle to process "
+ PID_T_FORMAT"; "
"monitoring it.",
- (int)(procmon->pid));
+ procmon->pid);
} else {
/* If we couldn't get a handle to the process, we'll try again the
* first time we poll. */
- log_info(procmon->log_domain, "Failed to open handle to process %d; will "
+ log_info(procmon->log_domain, "Failed to open handle to process "
+ PID_T_FORMAT"; will "
"try again later.",
- (int)(procmon->pid));
+ procmon->pid);
}
#endif
@@ -257,7 +271,8 @@ tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
if (!GetExitCodeProcess(procmon->hproc, &exit_code)) {
char *errmsg = format_win32_error(GetLastError());
log_warn(procmon->log_domain, "Error \"%s\" occurred while polling "
- "handle for monitored process %d; assuming it's dead.",
+ "handle for monitored process "PID_T_FORMAT"; assuming "
+ "it's dead.",
errmsg, procmon->pid);
tor_free(errmsg);
its_dead_jim = 1;
@@ -273,7 +288,7 @@ tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
if (procmon->hproc != NULL) {
log_info(procmon->log_domain, "Successfully opened handle to monitored "
- "process %d.",
+ "process "PID_T_FORMAT".",
procmon->pid);
its_dead_jim = 0;
procmon->poll_hproc = 1;
@@ -292,8 +307,8 @@ tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
if (!its_dead_jim)
log_info(procmon->log_domain, "Failed to open handle to monitored "
- "process %d, and error code %lu (%s) is not 'invalid "
- "parameter' -- assuming the process is still alive.",
+ "process "PID_T_FORMAT", and error code %lu (%s) is not "
+ "'invalid parameter' -- assuming the process is still alive.",
procmon->pid,
err_code, errmsg);
@@ -306,9 +321,9 @@ tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
its_dead_jim = its_dead_jim && (errno == ESRCH);
#endif
- log(its_dead_jim ? LOG_NOTICE : LOG_INFO,
- procmon->log_domain, "Monitored process %d is %s.",
- (int)procmon->pid,
+ tor_log(its_dead_jim ? LOG_NOTICE : LOG_INFO,
+ procmon->log_domain, "Monitored process "PID_T_FORMAT" is %s.",
+ procmon->pid,
its_dead_jim ? "dead" : "still alive");
if (its_dead_jim) {
diff --git a/src/common/procmon.h b/src/common/procmon.h
index 88d64d6a1..b9388e2e9 100644
--- a/src/common/procmon.h
+++ b/src/common/procmon.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Tor Project, Inc. */
+/* Copyright (c) 2011-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/common/sha256.c b/src/common/sha256.c
deleted file mode 100644
index 813c68d2a..000000000
--- a/src/common/sha256.c
+++ /dev/null
@@ -1,331 +0,0 @@
-/* Copyright (c) 2009-2012, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-/* This SHA256 implementation is adapted from the public domain one in
- LibTomCrypt, version 1.6. Tor uses it on platforms where OpenSSL doesn't
- have a SHA256. */
-
-
-typedef struct sha256_state {
- uint64_t length;
- uint32_t state[8], curlen;
- unsigned char buf[64];
-} sha256_state;
-
-#define CRYPT_OK 0
-#define CRYPT_NOP -1
-#define CRYPT_INVALID_ARG -2
-
-#define LOAD32H(x,y) STMT_BEGIN x = ntohl(get_uint32((const char*)y)); STMT_END
-#define STORE32H(x,y) STMT_BEGIN set_uint32((char*)y, htonl(x)); STMT_END
-#define STORE64H(x,y) STMT_BEGIN \
- set_uint32((char*)y, htonl((uint32_t)((x)>>32))); \
- set_uint32(((char*)y)+4, htonl((uint32_t)((x)&0xffffffff))); \
- STMT_END
-#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
-#ifndef MIN
- #define MIN(x, y) ( ((x)<(y))?(x):(y) )
-#endif
-
-
-/* LibTomCrypt, modular cryptographic library -- Tom St Denis
- *
- * LibTomCrypt is a library that provides various cryptographic
- * algorithms in a highly modular and flexible manner.
- *
- * The library is free for all purposes without any express
- * guarantee it works.
- *
- * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
- */
-
-/**
- @file sha256.c
- SHA256 by Tom St Denis
-*/
-
-
-#ifdef LTC_SMALL_CODE
-/* the K array */
-static const uint32_t K[64] = {
- 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
- 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
- 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
- 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
- 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
- 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
- 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
- 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
- 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
- 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
- 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
- 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
- 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
-};
-#endif
-
-/* Various logical functions */
-#define Ch(x,y,z) (z ^ (x & (y ^ z)))
-#define Maj(x,y,z) (((x | y) & z) | (x & y))
-#define S(x, n) RORc((x),(n))
-#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
-#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
-#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
-#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
-#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
-
-/* compress 512-bits */
-#ifdef LTC_CLEAN_STACK
-static int _sha256_compress(sha256_state * md, unsigned char *buf)
-#else
-static int sha256_compress(sha256_state * md, unsigned char *buf)
-#endif
-{
- uint32_t S[8], W[64], t0, t1;
-#ifdef LTC_SMALL_CODE
- uint32_t t;
-#endif
- int i;
-
- /* copy state into S */
- for (i = 0; i < 8; i++) {
- S[i] = md->state[i];
- }
-
- /* copy the state into 512-bits into W[0..15] */
- for (i = 0; i < 16; i++) {
- LOAD32H(W[i], buf + (4*i));
- }
-
- /* fill W[16..63] */
- for (i = 16; i < 64; i++) {
- W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
- }
-
- /* Compress */
-#ifdef LTC_SMALL_CODE
-#define RND(a,b,c,d,e,f,g,h,i) \
- t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
- t1 = Sigma0(a) + Maj(a, b, c); \
- d += t0; \
- h = t0 + t1;
-
- for (i = 0; i < 64; ++i) {
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i);
- t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
- S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
- }
-#else
-#define RND(a,b,c,d,e,f,g,h,i,ki) \
- t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \
- t1 = Sigma0(a) + Maj(a, b, c); \
- d += t0; \
- h = t0 + t1;
-
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3);
- RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee);
- RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f);
- RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814);
- RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208);
- RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa);
- RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb);
- RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7);
- RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2);
-
-#undef RND
-
-#endif
-
- /* feedback */
- for (i = 0; i < 8; i++) {
- md->state[i] = md->state[i] + S[i];
- }
- return CRYPT_OK;
-}
-
-#ifdef LTC_CLEAN_STACK
-static int sha256_compress(sha256_state * md, unsigned char *buf)
-{
- int err;
- err = _sha256_compress(md, buf);
- burn_stack(sizeof(uint32_t) * 74);
- return err;
-}
-#endif
-
-/**
- Initialize the hash state
- @param md The hash state you wish to initialize
- @return CRYPT_OK if successful
-*/
-static int sha256_init(sha256_state * md)
-{
- LTC_ARGCHK(md != NULL);
-
- md->curlen = 0;
- md->length = 0;
- md->state[0] = 0x6A09E667UL;
- md->state[1] = 0xBB67AE85UL;
- md->state[2] = 0x3C6EF372UL;
- md->state[3] = 0xA54FF53AUL;
- md->state[4] = 0x510E527FUL;
- md->state[5] = 0x9B05688CUL;
- md->state[6] = 0x1F83D9ABUL;
- md->state[7] = 0x5BE0CD19UL;
- return CRYPT_OK;
-}
-
-/**
- Process a block of memory though the hash
- @param md The hash state
- @param in The data to hash
- @param inlen The length of the data (octets)
- @return CRYPT_OK if successful
-*/
-static int sha256_process (sha256_state * md, const unsigned char *in, unsigned long inlen)
-{
- unsigned long n;
- int err;
- LTC_ARGCHK(md != NULL);
- LTC_ARGCHK(in != NULL);
- if (md->curlen > sizeof(md->buf)) {
- return CRYPT_INVALID_ARG;
- }
- while (inlen > 0) {
- if (md->curlen == 0 && inlen >= 64) {
- if ((err = sha256_compress (md, (unsigned char *)in)) != CRYPT_OK) {
- return err;
- }
- md->length += 64 * 8;
- in += 64;
- inlen -= 64;
- } else {
- n = MIN(inlen, (64 - md->curlen));
- memcpy(md->buf + md->curlen, in, (size_t)n);
- md->curlen += n;
- in += n;
- inlen -= n;
- if (md->curlen == 64) {
- if ((err = sha256_compress (md, md->buf)) != CRYPT_OK) {
- return err;
- }
- md->length += 8*64;
- md->curlen = 0;
- }
- }
- }
- return CRYPT_OK;
-}
-
-/**
- Terminate the hash to get the digest
- @param md The hash state
- @param out [out] The destination of the hash (32 bytes)
- @return CRYPT_OK if successful
-*/
-static int sha256_done(sha256_state * md, unsigned char *out)
-{
- int i;
-
- LTC_ARGCHK(md != NULL);
- LTC_ARGCHK(out != NULL);
-
- if (md->curlen >= sizeof(md->buf)) {
- return CRYPT_INVALID_ARG;
- }
-
-
- /* increase the length of the message */
- md->length += md->curlen * 8;
-
- /* append the '1' bit */
- md->buf[md->curlen++] = (unsigned char)0x80;
-
- /* if the length is currently above 56 bytes we append zeros
- * then compress. Then we can fall back to padding zeros and length
- * encoding like normal.
- */
- if (md->curlen > 56) {
- while (md->curlen < 64) {
- md->buf[md->curlen++] = (unsigned char)0;
- }
- sha256_compress(md, md->buf);
- md->curlen = 0;
- }
-
- /* pad upto 56 bytes of zeroes */
- while (md->curlen < 56) {
- md->buf[md->curlen++] = (unsigned char)0;
- }
-
- /* store length */
- STORE64H(md->length, md->buf+56);
- sha256_compress(md, md->buf);
-
- /* copy output */
- for (i = 0; i < 8; i++) {
- STORE32H(md->state[i], out+(4*i));
- }
-#ifdef LTC_CLEAN_STACK
- zeromem(md, sizeof(sha256_state));
-#endif
- return CRYPT_OK;
-}
-
-/* $Source: /cvs/libtom/libtomcrypt/src/hashes/sha2/sha256.c,v $ */
-/* $Revision: 1.9 $ */
-/* $Date: 2006/11/01 09:28:17 $ */
diff --git a/src/common/strlcat.c b/src/common/strlcat.c
deleted file mode 100644
index 316733bcc..000000000
--- a/src/common/strlcat.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/* $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $ */
-
-/*
- * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char *rcsid = "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $";
-#endif /* LIBC_SCCS and not lint */
-
-#include <sys/types.h>
-#include <string.h>
-
-/*
- * Appends src to string dst of size siz (unlike strncat, siz is the
- * full size of dst, not space left). At most siz-1 characters
- * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
- * Returns strlen(src) + MIN(siz, strlen(initial dst)).
- * If retval >= siz, truncation occurred.
- */
-size_t
-strlcat(char *dst, const char *src, size_t siz)
-{
- register char *d = dst;
- register const char *s = src;
- register size_t n = siz;
- size_t dlen;
-
- /* Find the end of dst and adjust bytes left but don't go past end */
- while (n-- != 0 && *d != '\0')
- d++;
- dlen = d - dst;
- n = siz - dlen;
-
- if (n == 0)
- return(dlen + strlen(s));
- while (*s != '\0') {
- if (n != 1) {
- *d++ = *s;
- n--;
- }
- s++;
- }
- *d = '\0';
-
- return(dlen + (s - src)); /* count does not include NUL */
-}
diff --git a/src/common/strlcpy.c b/src/common/strlcpy.c
deleted file mode 100644
index 9fc47903a..000000000
--- a/src/common/strlcpy.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/* $OpenBSD: strlcpy.c,v 1.2 1998/11/06 04:33:16 wvdputte Exp $ */
-
-/*
- * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char *rcsid = "$OpenBSD: strlcpy.c,v 1.2 1998/11/06 04:33:16 wvdputte Exp $";
-#endif /* LIBC_SCCS and not lint */
-
-#include <sys/types.h>
-#include <string.h>
-
-/*
- * Copy src to string dst of size siz. At most siz-1 characters
- * will be copied. Always NUL terminates (unless siz == 0).
- * Returns strlen(src); if retval >= siz, truncation occurred.
- */
-size_t strlcpy(char *dst, const char *src, size_t siz)
-{
- register char *d = dst;
- register const char *s = src;
- register size_t n = siz;
-
- if (n == 0)
- return(strlen(s));
- while (*s != '\0') {
- if (n != 1) {
- *d++ = *s;
- n--;
- }
- s++;
- }
- *d = '\0';
-
- return(s - src); /* count does not include NUL */
-}
diff --git a/src/common/torgzip.c b/src/common/torgzip.c
index da4136228..4328c63c8 100644
--- a/src/common/torgzip.c
+++ b/src/common/torgzip.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/common/torgzip.h b/src/common/torgzip.h
index d3ded81f9..be1016445 100644
--- a/src/common/torgzip.h
+++ b/src/common/torgzip.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,8 +8,8 @@
* \brief Headers for torgzip.h
**/
-#ifndef _TOR_TORGZIP_H
-#define _TOR_TORGZIP_H
+#ifndef TOR_TORGZIP_H
+#define TOR_TORGZIP_H
/** Enumeration of what kind of compression to use. Only ZLIB_METHOD is
* guaranteed to be supported by the compress/uncompress functions here;
diff --git a/src/common/torint.h b/src/common/torint.h
index 8771802d7..a993d7649 100644
--- a/src/common/torint.h
+++ b/src/common/torint.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,8 +8,8 @@
* \brief Header file to define uint32_t and friends
**/
-#ifndef _TOR_TORINT_H
-#define _TOR_TORINT_H
+#ifndef TOR_TORINT_H
+#define TOR_TORINT_H
#include "orconfig.h"
@@ -214,16 +214,20 @@ typedef int32_t ssize_t;
#if (SIZEOF_VOID_P > 4 && SIZEOF_VOID_P <= 8)
#ifndef HAVE_INTPTR_T
typedef int64_t intptr_t;
+#define SIZEOF_INTPTR_T 8
#endif
#ifndef HAVE_UINTPTR_T
typedef uint64_t uintptr_t;
+#define SIZEOF_UINTPTR_T 8
#endif
#elif (SIZEOF_VOID_P > 2 && SIZEOF_VOID_P <= 4)
#ifndef HAVE_INTPTR_T
typedef int32_t intptr_t;
+#define SIZEOF_INTPTR_T 4
#endif
#ifndef HAVE_UINTPTR_T
typedef uint32_t uintptr_t;
+#define SIZEOF_UINTPTR_T 4
#endif
#else
#error "void * is either >8 bytes or <= 2. In either case, I am confused."
diff --git a/src/common/torlog.h b/src/common/torlog.h
index 28890a44a..8675d7b6e 100644
--- a/src/common/torlog.h
+++ b/src/common/torlog.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -10,7 +10,7 @@
* \brief Headers for log.c
**/
-#ifndef _TOR_LOG_H
+#ifndef TOR_TORLOG_H
#include "compat.h"
@@ -94,8 +94,10 @@
#define LD_HANDSHAKE (1u<<19)
/** Heartbeat messages */
#define LD_HEARTBEAT (1u<<20)
+/** Abstract channel_t code */
+#define LD_CHANNEL (1u<<21)
/** Number of logging domains in the code. */
-#define N_LOGGING_DOMAINS 21
+#define N_LOGGING_DOMAINS 22
/** This log message is not safe to send to a callback-based logger
* immediately. Used as a flag, not a log domain. */
@@ -151,66 +153,80 @@ void set_log_time_granularity(int granularity_msec);
void tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
CHECK_PRINTF(3,4);
-#define log tor_log /* hack it so we don't conflict with log() as much */
#if defined(__GNUC__) || defined(RUNNING_DOXYGEN)
-extern int _log_global_min_severity;
+extern int log_global_min_severity_;
-void _log_fn(int severity, log_domain_mask_t domain,
+void log_fn_(int severity, log_domain_mask_t domain,
const char *funcname, const char *format, ...)
CHECK_PRINTF(4,5);
+struct ratelim_t;
+void log_fn_ratelim_(struct ratelim_t *ratelim, int severity,
+ log_domain_mask_t domain, const char *funcname,
+ const char *format, ...)
+ CHECK_PRINTF(5,6);
/** Log a message at level <b>severity</b>, using a pretty-printed version
* of the current function name. */
#define log_fn(severity, domain, args...) \
- _log_fn(severity, domain, __PRETTY_FUNCTION__, args)
+ log_fn_(severity, domain, __PRETTY_FUNCTION__, args)
+/** As log_fn, but use <b>ratelim</b> (an instance of ratelim_t) to control
+ * the frequency at which messages can appear.
+ */
+#define log_fn_ratelim(ratelim, severity, domain, args...) \
+ log_fn_ratelim_(ratelim, severity, domain, __PRETTY_FUNCTION__, args)
#define log_debug(domain, args...) \
STMT_BEGIN \
- if (PREDICT_UNLIKELY(_log_global_min_severity == LOG_DEBUG)) \
- _log_fn(LOG_DEBUG, domain, __PRETTY_FUNCTION__, args); \
+ if (PREDICT_UNLIKELY(log_global_min_severity_ == LOG_DEBUG)) \
+ log_fn_(LOG_DEBUG, domain, __PRETTY_FUNCTION__, args); \
STMT_END
#define log_info(domain, args...) \
- _log_fn(LOG_INFO, domain, __PRETTY_FUNCTION__, args)
+ log_fn_(LOG_INFO, domain, __PRETTY_FUNCTION__, args)
#define log_notice(domain, args...) \
- _log_fn(LOG_NOTICE, domain, __PRETTY_FUNCTION__, args)
+ log_fn_(LOG_NOTICE, domain, __PRETTY_FUNCTION__, args)
#define log_warn(domain, args...) \
- _log_fn(LOG_WARN, domain, __PRETTY_FUNCTION__, args)
+ log_fn_(LOG_WARN, domain, __PRETTY_FUNCTION__, args)
#define log_err(domain, args...) \
- _log_fn(LOG_ERR, domain, __PRETTY_FUNCTION__, args)
+ log_fn_(LOG_ERR, domain, __PRETTY_FUNCTION__, args)
#else /* ! defined(__GNUC__) */
-void _log_fn(int severity, log_domain_mask_t domain, const char *format, ...);
-void _log_debug(log_domain_mask_t domain, const char *format, ...);
-void _log_info(log_domain_mask_t domain, const char *format, ...);
-void _log_notice(log_domain_mask_t domain, const char *format, ...);
-void _log_warn(log_domain_mask_t domain, const char *format, ...);
-void _log_err(log_domain_mask_t domain, const char *format, ...);
+void log_fn_(int severity, log_domain_mask_t domain, const char *format, ...);
+struct ratelim_t;
+void log_fn_ratelim_(struct ratelim_t *ratelim, int severity,
+ log_domain_mask_t domain, const char *format, ...);
+void log_debug_(log_domain_mask_t domain, const char *format, ...);
+void log_info_(log_domain_mask_t domain, const char *format, ...);
+void log_notice_(log_domain_mask_t domain, const char *format, ...);
+void log_warn_(log_domain_mask_t domain, const char *format, ...);
+void log_err_(log_domain_mask_t domain, const char *format, ...);
#if defined(_MSC_VER) && _MSC_VER < 1300
/* MSVC 6 and earlier don't have __func__, or even __LINE__. */
-#define log_fn _log_fn
-#define log_debug _log_debug
-#define log_info _log_info
-#define log_notice _log_notice
-#define log_warn _log_warn
-#define log_err _log_err
+#define log_fn log_fn_
+#define log_fn_ratelim log_fn_ratelim_
+#define log_debug log_debug_
+#define log_info log_info_
+#define log_notice log_notice_
+#define log_warn log_warn_
+#define log_err log_err_
#else
/* We don't have GCC's varargs macros, so use a global variable to pass the
* function name to log_fn */
-extern const char *_log_fn_function_name;
+extern const char *log_fn_function_name_;
/* We abuse the comma operator here, since we can't use the standard
* do {...} while (0) trick to wrap this macro, since the macro can't take
* arguments. */
-#define log_fn (_log_fn_function_name=__func__),_log_fn
-#define log_debug (_log_fn_function_name=__func__),_log_debug
-#define log_info (_log_fn_function_name=__func__),_log_info
-#define log_notice (_log_fn_function_name=__func__),_log_notice
-#define log_warn (_log_fn_function_name=__func__),_log_warn
-#define log_err (_log_fn_function_name=__func__),_log_err
+#define log_fn (log_fn_function_name_=__func__),log_fn_
+#define log_fn_ratelim (log_fn_function_name_=__func__),log_fn_ratelim_
+#define log_debug (log_fn_function_name_=__func__),log_debug_
+#define log_info (log_fn_function_name_=__func__),log_info_
+#define log_notice (log_fn_function_name_=__func__),log_notice_
+#define log_warn (log_fn_function_name_=__func__),log_warn_
+#define log_err (log_fn_function_name_=__func__),log_err_
#endif
#endif /* !GNUC */
-# define _TOR_LOG_H
+# define TOR_TORLOG_H
#endif
diff --git a/src/common/tortls.c b/src/common/tortls.c
index 60aac6492..8f3f6a713 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -58,8 +58,8 @@
#include "container.h"
#include <string.h>
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,7)
-#error "We require OpenSSL >= 0.9.7"
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
+#error "We require OpenSSL >= 0.9.8"
#endif
/* Enable the "v2" TLS handshake.
@@ -127,8 +127,32 @@ typedef struct tor_tls_context_t {
crypto_pk_t *auth_key;
} tor_tls_context_t;
+/** Return values for tor_tls_classify_client_ciphers.
+ *
+ * @{
+ */
+/** An error occurred when examining the client ciphers */
+#define CIPHERS_ERR -1
+/** The client cipher list indicates that a v1 handshake was in use. */
+#define CIPHERS_V1 1
+/** The client cipher list indicates that the client is using the v2 or the
+ * v3 handshake, but that it is (probably!) lying about what ciphers it
+ * supports */
+#define CIPHERS_V2 2
+/** The client cipher list indicates that the client is using the v2 or the
+ * v3 handshake, and that it is telling the truth about what ciphers it
+ * supports */
+#define CIPHERS_UNRESTRICTED 3
+/** @} */
+
#define TOR_TLS_MAGIC 0x71571571
+typedef enum {
+ TOR_TLS_ST_HANDSHAKE, TOR_TLS_ST_OPEN, TOR_TLS_ST_GOTCLOSE,
+ TOR_TLS_ST_SENTCLOSE, TOR_TLS_ST_CLOSED, TOR_TLS_ST_RENEGOTIATE,
+ TOR_TLS_ST_BUFFEREVENT
+} tor_tls_state_t;
+
/** Holds a SSL object and its associated data. Members are only
* accessed from within tortls.c.
*/
@@ -138,12 +162,9 @@ struct tor_tls_t {
SSL *ssl; /**< An OpenSSL SSL object. */
int socket; /**< The underlying file descriptor for this TLS connection. */
char *address; /**< An address to log when describing this connection. */
- enum {
- TOR_TLS_ST_HANDSHAKE, TOR_TLS_ST_OPEN, TOR_TLS_ST_GOTCLOSE,
- TOR_TLS_ST_SENTCLOSE, TOR_TLS_ST_CLOSED, TOR_TLS_ST_RENEGOTIATE,
- TOR_TLS_ST_BUFFEREVENT
- } state : 3; /**< The current SSL state, depending on which operations have
- * completed successfully. */
+ ENUM_BF(tor_tls_state_t) state : 3; /**< The current SSL state,
+ * depending on which operations
+ * have completed successfully. */
unsigned int isServer:1; /**< True iff this is a server-side connection */
unsigned int wasV2Handshake:1; /**< True iff the original handshake for
* this connection used the updated version
@@ -152,6 +173,9 @@ struct tor_tls_t {
* one certificate). */
/** True iff we should call negotiated_callback when we're done reading. */
unsigned int got_renegotiate:1;
+ /** Return value from tor_tls_classify_client_ciphers, or 0 if we haven't
+ * called that function yet. */
+ int8_t client_cipher_list_type;
/** Incremented every time we start the server side of a handshake. */
uint8_t server_handshake_count;
size_t wantwrite_n; /**< 0 normally, >0 if we returned wantwrite last
@@ -210,14 +234,16 @@ static X509* tor_tls_create_certificate(crypto_pk_t *rsa,
crypto_pk_t *rsa_sign,
const char *cname,
const char *cname_sign,
- unsigned int lifetime);
+ unsigned int cert_lifetime);
static int tor_tls_context_init_one(tor_tls_context_t **ppcontext,
crypto_pk_t *identity,
unsigned int key_lifetime,
+ unsigned int flags,
int is_client);
static tor_tls_context_t *tor_tls_context_new(crypto_pk_t *identity,
unsigned int key_lifetime,
+ unsigned int flags,
int is_client);
static int check_cert_lifetime_internal(int severity, const X509 *cert,
int past_tolerance, int future_tolerance);
@@ -234,8 +260,8 @@ static tor_tls_context_t *client_tls_context = NULL;
static int tls_library_is_initialized = 0;
/* Module-internal error codes. */
-#define _TOR_TLS_SYSCALL (_MIN_TOR_TLS_ERROR_VAL - 2)
-#define _TOR_TLS_ZERORETURN (_MIN_TOR_TLS_ERROR_VAL - 1)
+#define TOR_TLS_SYSCALL_ (MIN_TOR_TLS_ERROR_VAL_ - 2)
+#define TOR_TLS_ZERORETURN_ (MIN_TOR_TLS_ERROR_VAL_ - 1)
/** Write a description of the current state of <b>tls</b> into the
* <b>sz</b>-byte buffer at <b>buf</b>. */
@@ -308,11 +334,11 @@ tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
if (!lib) lib = "(null)";
if (!func) func = "(null)";
if (doing) {
- log(severity, domain, "TLS error while %s%s%s: %s (in %s:%s:%s)",
+ tor_log(severity, domain, "TLS error while %s%s%s: %s (in %s:%s:%s)",
doing, addr?" with ":"", addr?addr:"",
msg, lib, func, state);
} else {
- log(severity, domain, "TLS error%s%s: %s (in %s:%s:%s)",
+ tor_log(severity, domain, "TLS error%s%s: %s (in %s:%s:%s)",
addr?" with ":"", addr?addr:"",
msg, lib, func, state);
}
@@ -336,35 +362,19 @@ tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing)
static int
tor_errno_to_tls_error(int e)
{
-#if defined(_WIN32)
- switch (e) {
- case WSAECONNRESET: // most common
- return TOR_TLS_ERROR_CONNRESET;
- case WSAETIMEDOUT:
- return TOR_TLS_ERROR_TIMEOUT;
- case WSAENETUNREACH:
- case WSAEHOSTUNREACH:
- return TOR_TLS_ERROR_NO_ROUTE;
- case WSAECONNREFUSED:
- return TOR_TLS_ERROR_CONNREFUSED; // least common
- default:
- return TOR_TLS_ERROR_MISC;
- }
-#else
switch (e) {
- case ECONNRESET: // most common
+ case SOCK_ERRNO(ECONNRESET): // most common
return TOR_TLS_ERROR_CONNRESET;
- case ETIMEDOUT:
+ case SOCK_ERRNO(ETIMEDOUT):
return TOR_TLS_ERROR_TIMEOUT;
- case EHOSTUNREACH:
- case ENETUNREACH:
+ case SOCK_ERRNO(EHOSTUNREACH):
+ case SOCK_ERRNO(ENETUNREACH):
return TOR_TLS_ERROR_NO_ROUTE;
- case ECONNREFUSED:
+ case SOCK_ERRNO(ECONNREFUSED):
return TOR_TLS_ERROR_CONNREFUSED; // least common
default:
return TOR_TLS_ERROR_MISC;
}
-#endif
}
/** Given a TOR_TLS_* error code, return a string equivalent. */
@@ -393,9 +403,9 @@ tor_tls_err_to_string(int err)
/** Given a TLS object and the result of an SSL_* call, use
* SSL_get_error to determine whether an error has occurred, and if so
* which one. Return one of TOR_TLS_{DONE|WANTREAD|WANTWRITE|ERROR}.
- * If extra&CATCH_SYSCALL is true, return _TOR_TLS_SYSCALL instead of
+ * If extra&CATCH_SYSCALL is true, return TOR_TLS_SYSCALL_ instead of
* reporting syscall errors. If extra&CATCH_ZERO is true, return
- * _TOR_TLS_ZERORETURN instead of reporting zero-return errors.
+ * TOR_TLS_ZERORETURN_ instead of reporting zero-return errors.
*
* If an error has occurred, log it at level <b>severity</b> and describe the
* current action as <b>doing</b>.
@@ -415,14 +425,14 @@ tor_tls_get_error(tor_tls_t *tls, int r, int extra,
return TOR_TLS_WANTWRITE;
case SSL_ERROR_SYSCALL:
if (extra&CATCH_SYSCALL)
- return _TOR_TLS_SYSCALL;
+ return TOR_TLS_SYSCALL_;
if (r == 0) {
- log(severity, LD_NET, "TLS error: unexpected close while %s (%s)",
+ tor_log(severity, LD_NET, "TLS error: unexpected close while %s (%s)",
doing, SSL_state_string_long(tls->ssl));
tor_error = TOR_TLS_ERROR_IO;
} else {
int e = tor_socket_errno(tls->socket);
- log(severity, LD_NET,
+ tor_log(severity, LD_NET,
"TLS error: <syscall error while %s> (errno=%d: %s; state=%s)",
doing, e, tor_socket_strerror(e),
SSL_state_string_long(tls->ssl));
@@ -432,8 +442,8 @@ tor_tls_get_error(tor_tls_t *tls, int r, int extra,
return tor_error;
case SSL_ERROR_ZERO_RETURN:
if (extra&CATCH_ZERO)
- return _TOR_TLS_ZERORETURN;
- log(severity, LD_NET, "TLS connection closed while %s in state %s",
+ return TOR_TLS_ZERORETURN_;
+ tor_log(severity, LD_NET, "TLS connection closed while %s in state %s",
doing, SSL_state_string_long(tls->ssl));
tls_log_errors(tls, severity, domain, doing);
return TOR_TLS_CLOSE;
@@ -478,7 +488,7 @@ tor_tls_init(void)
* a test of intelligence and determination.
*/
if (version > OPENSSL_V(0,9,8,'k') && version <= OPENSSL_V(0,9,8,'l')) {
- log_notice(LD_GENERAL, "OpenSSL %s looks like version 0.9.8l, but "
+ log_info(LD_GENERAL, "OpenSSL %s looks like version 0.9.8l, but "
"some vendors have backported renegotiation code from "
"0.9.8m without updating the version number. "
"I will try SSL3_FLAGS and SSL_OP to enable renegotation.",
@@ -486,12 +496,12 @@ tor_tls_init(void)
use_unsafe_renegotiation_flag = 1;
use_unsafe_renegotiation_op = 1;
} else if (version > OPENSSL_V(0,9,8,'l')) {
- log_notice(LD_GENERAL, "OpenSSL %s looks like version 0.9.8m or later; "
+ log_info(LD_GENERAL, "OpenSSL %s looks like version 0.9.8m or later; "
"I will try SSL_OP to enable renegotiation",
SSLeay_version(SSLEAY_VERSION));
use_unsafe_renegotiation_op = 1;
} else if (version <= OPENSSL_V(0,9,8,'k')) {
- log_notice(LD_GENERAL, "OpenSSL %s [%lx] looks like it's older than "
+ log_info(LD_GENERAL, "OpenSSL %s [%lx] looks like it's older than "
"0.9.8l, but some vendors have backported 0.9.8l's "
"renegotiation code to earlier versions, and some have "
"backported the code from 0.9.8m or 0.9.8n. I'll set both "
@@ -505,6 +515,37 @@ tor_tls_init(void)
SSLeay_version(SSLEAY_VERSION), version);
}
+#if (SIZEOF_VOID_P >= 8 && \
+ !defined(OPENSSL_NO_EC) && \
+ OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1))
+ if (version >= OPENSSL_V_SERIES(1,0,1)) {
+ /* Warn if we could *almost* be running with much faster ECDH.
+ If we're built for a 64-bit target, using OpenSSL 1.0.1, but we
+ don't have one of the built-in __uint128-based speedups, we are
+ just one build operation away from an accelerated handshake.
+
+ (We could be looking at OPENSSL_NO_EC_NISTP_64_GCC_128 instead of
+ doing this test, but that gives compile-time options, not runtime
+ behavior.)
+ */
+ EC_KEY *key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+ const EC_GROUP *g = key ? EC_KEY_get0_group(key) : NULL;
+ const EC_METHOD *m = g ? EC_GROUP_method_of(g) : NULL;
+ const int warn = (m == EC_GFp_simple_method() ||
+ m == EC_GFp_mont_method() ||
+ m == EC_GFp_nist_method());
+ EC_KEY_free(key);
+
+ if (warn)
+ log_notice(LD_GENERAL, "We were built to run on a 64-bit CPU, with "
+ "OpenSSL 1.0.1 or later, but with a version of OpenSSL "
+ "that apparently lacks accelerated support for the NIST "
+ "P-224 and P-256 groups. Building openssl with such "
+ "support (using the enable-ec_nistp_64_gcc_128 option "
+ "when configuring it) would make ECDH much faster.");
+ }
+#endif
+
tor_tls_allocate_tor_tls_object_ex_data_index();
tls_library_is_initialized = 1;
@@ -567,9 +608,10 @@ tor_x509_name_new(const char *cname)
/** Generate and sign an X509 certificate with the public key <b>rsa</b>,
* signed by the private key <b>rsa_sign</b>. The commonName of the
* certificate will be <b>cname</b>; the commonName of the issuer will be
- * <b>cname_sign</b>. The cert will be valid for <b>cert_lifetime</b> seconds
- * starting from now. Return a certificate on success, NULL on
- * failure.
+ * <b>cname_sign</b>. The cert will be valid for <b>cert_lifetime</b>
+ * seconds, starting from some time in the past.
+ *
+ * Return a certificate on success, NULL on failure.
*/
static X509 *
tor_tls_create_certificate(crypto_pk_t *rsa,
@@ -591,15 +633,20 @@ tor_tls_create_certificate(crypto_pk_t *rsa,
tor_tls_init();
- start_time = time(NULL);
+ /* Make sure we're part-way through the certificate lifetime, rather
+ * than having it start right now. Don't choose quite uniformly, since
+ * then we might pick a time where we're about to expire. Lastly, be
+ * sure to start on a day boundary. */
+ start_time = time(NULL) - crypto_rand_int(cert_lifetime) + 2*24*3600;
+ start_time -= start_time % (24*3600);
tor_assert(rsa);
tor_assert(cname);
tor_assert(rsa_sign);
tor_assert(cname_sign);
- if (!(sign_pkey = _crypto_pk_get_evp_pkey(rsa_sign,1)))
+ if (!(sign_pkey = crypto_pk_get_evp_pkey_(rsa_sign,1)))
goto error;
- if (!(pkey = _crypto_pk_get_evp_pkey(rsa,0)))
+ if (!(pkey = crypto_pk_get_evp_pkey_(rsa,0)))
goto error;
if (!(x509 = X509_new()))
goto error;
@@ -647,7 +694,7 @@ tor_tls_create_certificate(crypto_pk_t *rsa,
if (pkey)
EVP_PKEY_free(pkey);
if (serial_number)
- BN_free(serial_number);
+ BN_clear_free(serial_number);
if (name)
X509_NAME_free(name);
if (name_issuer)
@@ -657,11 +704,58 @@ tor_tls_create_certificate(crypto_pk_t *rsa,
#undef SERIAL_NUMBER_SIZE
}
-/** List of ciphers that servers should select from.*/
+/** List of ciphers that servers should select from when the client might be
+ * claiming extra unsupported ciphers in order to avoid fingerprinting. */
#define SERVER_CIPHER_LIST \
(TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":" \
TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":" \
SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA)
+
+/** List of ciphers that servers should select from when we actually have
+ * our choice of what cipher to use. */
+const char UNRESTRICTED_SERVER_CIPHER_LIST[] =
+ /* This list is autogenerated with the gen_server_ciphers.py script;
+ * don't hand-edit it. */
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+ TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ":"
+#endif
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ":"
+#endif
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384
+ TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 ":"
+#endif
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256
+ TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 ":"
+#endif
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA
+ TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA ":"
+#endif
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA
+ TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA ":"
+#endif
+#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384
+ TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 ":"
+#endif
+#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256
+ TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 ":"
+#endif
+#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256
+ TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 ":"
+#endif
+#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256
+ TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 ":"
+#endif
+ /* Required */
+ TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":"
+ /* Required */
+ TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":"
+#ifdef TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA
+ TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA ":"
+#endif
+ /* Required */
+ SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA;
+
/* Note: to set up your own private testing network with link crypto
* disabled, set your Tors' cipher list to
* (SSL3_TXT_RSA_NULL_SHA). If you do this, you won't be able to communicate
@@ -754,7 +848,7 @@ tor_cert_new(X509 *x509_cert)
if ((pkey = X509_get_pubkey(x509_cert)) &&
(rsa = EVP_PKEY_get1_RSA(pkey))) {
- crypto_pk_t *pk = _crypto_new_pk_from_rsa(rsa);
+ crypto_pk_t *pk = crypto_new_pk_from_rsa_(rsa);
crypto_pk_get_all_digests(pk, &cert->pkey_digests);
cert->pkey_digests_set = 1;
crypto_pk_free(pk);
@@ -778,13 +872,8 @@ tor_cert_decode(const uint8_t *certificate, size_t certificate_len)
if (certificate_len > INT_MAX)
return NULL;
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
- /* This ifdef suppresses a type warning. Take out this case once everybody
- * is using OpenSSL 0.9.8 or later. */
- x509 = d2i_X509(NULL, (unsigned char**)&cp, (int)certificate_len);
-#else
x509 = d2i_X509(NULL, &cp, (int)certificate_len);
-#endif
+
if (!x509)
return NULL; /* Couldn't decode */
if (cp - certificate != (int)certificate_len) {
@@ -901,7 +990,7 @@ tor_tls_cert_get_key(tor_cert_t *cert)
EVP_PKEY_free(pkey);
return NULL;
}
- result = _crypto_new_pk_from_rsa(rsa);
+ result = crypto_new_pk_from_rsa_(rsa);
EVP_PKEY_free(pkey);
return result;
}
@@ -1019,17 +1108,20 @@ tor_tls_context_incref(tor_tls_context_t *ctx)
/** Create new global client and server TLS contexts.
*
* If <b>server_identity</b> is NULL, this will not generate a server
- * TLS context. If <b>is_public_server</b> is non-zero, this will use
+ * TLS context. If TOR_TLS_CTX_IS_PUBLIC_SERVER is set in <b>flags</b>, use
* the same TLS context for incoming and outgoing connections, and
- * ignore <b>client_identity</b>. */
+ * ignore <b>client_identity</b>. If one of TOR_TLS_CTX_USE_ECDHE_P{224,256}
+ * is set in <b>flags</b>, use that ECDHE group if possible; otherwise use
+ * the default ECDHE group. */
int
-tor_tls_context_init(int is_public_server,
+tor_tls_context_init(unsigned flags,
crypto_pk_t *client_identity,
crypto_pk_t *server_identity,
unsigned int key_lifetime)
{
int rv1 = 0;
int rv2 = 0;
+ const int is_public_server = flags & TOR_TLS_CTX_IS_PUBLIC_SERVER;
if (is_public_server) {
tor_tls_context_t *new_ctx;
@@ -1039,7 +1131,7 @@ tor_tls_context_init(int is_public_server,
rv1 = tor_tls_context_init_one(&server_tls_context,
server_identity,
- key_lifetime, 0);
+ key_lifetime, flags, 0);
if (rv1 >= 0) {
new_ctx = server_tls_context;
@@ -1056,6 +1148,7 @@ tor_tls_context_init(int is_public_server,
rv1 = tor_tls_context_init_one(&server_tls_context,
server_identity,
key_lifetime,
+ flags,
0);
} else {
tor_tls_context_t *old_ctx = server_tls_context;
@@ -1069,6 +1162,7 @@ tor_tls_context_init(int is_public_server,
rv2 = tor_tls_context_init_one(&client_tls_context,
client_identity,
key_lifetime,
+ flags,
1);
}
@@ -1085,10 +1179,12 @@ static int
tor_tls_context_init_one(tor_tls_context_t **ppcontext,
crypto_pk_t *identity,
unsigned int key_lifetime,
+ unsigned int flags,
int is_client)
{
tor_tls_context_t *new_ctx = tor_tls_context_new(identity,
key_lifetime,
+ flags,
is_client);
tor_tls_context_t *old_ctx = *ppcontext;
@@ -1112,7 +1208,7 @@ tor_tls_context_init_one(tor_tls_context_t **ppcontext,
*/
static tor_tls_context_t *
tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
- int is_client)
+ unsigned flags, int is_client)
{
crypto_pk_t *rsa = NULL, *rsa_auth = NULL;
EVP_PKEY *pkey = NULL;
@@ -1150,7 +1246,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
authcert = tor_tls_create_certificate(rsa_auth, identity, nickname, nn2,
key_lifetime);
if (!cert || !idcert || !authcert) {
- log(LOG_WARN, LD_CRYPTO, "Error creating certificate");
+ log_warn(LD_CRYPTO, "Error creating certificate");
goto error;
}
}
@@ -1181,6 +1277,10 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
goto error;
SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv2);
+ /* Prefer the server's ordering of ciphers: the client's ordering has
+ * historically been chosen for fingerprinting resistance. */
+ SSL_CTX_set_options(result->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
+
/* Disable TLS1.1 and TLS1.2 if they exist. We need to do this to
* workaround a bug present in all OpenSSL 1.0.1 versions (as of 1
* June 2012), wherein renegotiating while using one of these TLS
@@ -1189,19 +1289,29 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
* version. Once some version of OpenSSL does TLS1.1 and TLS1.2
* renegotiation properly, we can turn them back on when built with
* that version. */
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V(1,0,1,'e')
#ifdef SSL_OP_NO_TLSv1_2
SSL_CTX_set_options(result->ctx, SSL_OP_NO_TLSv1_2);
#endif
#ifdef SSL_OP_NO_TLSv1_1
SSL_CTX_set_options(result->ctx, SSL_OP_NO_TLSv1_1);
#endif
+#endif
+
/* Disable TLS tickets if they're supported. We never want to use them;
* using them can make our perfect forward secrecy a little worse, *and*
* create an opportunity to fingerprint us (since it's unusual to use them
* with TLS sessions turned off).
+ *
+ * In 0.2.4, clients advertise support for them though, to avoid a TLS
+ * distinguishability vector. This can give us worse PFS, though, if we
+ * get a server that doesn't set SSL_OP_NO_TICKET. With luck, there will
+ * be few such servers by the time 0.2.4 is more stable.
*/
#ifdef SSL_OP_NO_TICKET
- SSL_CTX_set_options(result->ctx, SSL_OP_NO_TICKET);
+ if (! is_client) {
+ SSL_CTX_set_options(result->ctx, SSL_OP_NO_TICKET);
+ }
#endif
if (
@@ -1222,6 +1332,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
}
SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_DH_USE);
+ SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_ECDH_USE);
#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
SSL_CTX_set_options(result->ctx,
@@ -1257,7 +1368,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF);
if (!is_client) {
tor_assert(rsa);
- if (!(pkey = _crypto_pk_get_evp_pkey(rsa,1)))
+ if (!(pkey = crypto_pk_get_evp_pkey_(rsa,1)))
goto error;
if (!SSL_CTX_use_PrivateKey(result->ctx, pkey))
goto error;
@@ -1269,9 +1380,29 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
{
crypto_dh_t *dh = crypto_dh_new(DH_TYPE_TLS);
tor_assert(dh);
- SSL_CTX_set_tmp_dh(result->ctx, _crypto_dh_get_dh(dh));
+ SSL_CTX_set_tmp_dh(result->ctx, crypto_dh_get_dh_(dh));
crypto_dh_free(dh);
}
+#if (!defined(OPENSSL_NO_EC) && \
+ OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0))
+ if (! is_client) {
+ int nid;
+ EC_KEY *ec_key;
+ if (flags & TOR_TLS_CTX_USE_ECDHE_P224)
+ nid = NID_secp224r1;
+ else if (flags & TOR_TLS_CTX_USE_ECDHE_P256)
+ nid = NID_X9_62_prime256v1;
+ else
+ nid = NID_X9_62_prime256v1;
+ /* Use P-256 for ECDHE. */
+ ec_key = EC_KEY_new_by_curve_name(nid);
+ if (ec_key != NULL) /*XXXX Handle errors? */
+ SSL_CTX_set_tmp_ecdh(result->ctx, ec_key);
+ EC_KEY_free(ec_key);
+ }
+#else
+ (void)flags;
+#endif
SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER,
always_accept_verify_cb);
/* let us realloc bufs that we're writing from */
@@ -1308,28 +1439,108 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
}
#ifdef V2_HANDSHAKE_SERVER
-/** Return true iff the cipher list suggested by the client for <b>ssl</b> is
- * a list that indicates that the client knows how to do the v2 TLS connection
- * handshake. */
+
+/* Here's the old V2 cipher list we sent from 0.2.1.1-alpha up to
+ * 0.2.3.17-beta. If a client is using this list, we can't believe the ciphers
+ * that it claims to support. We'll prune this list to remove the ciphers
+ * *we* don't recognize. */
+static uint16_t v2_cipher_list[] = {
+ 0xc00a, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA */
+ 0xc014, /* TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA */
+ 0x0039, /* TLS1_TXT_DHE_RSA_WITH_AES_256_SHA */
+ 0x0038, /* TLS1_TXT_DHE_DSS_WITH_AES_256_SHA */
+ 0xc00f, /* TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA */
+ 0xc005, /* TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA */
+ 0x0035, /* TLS1_TXT_RSA_WITH_AES_256_SHA */
+ 0xc007, /* TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA */
+ 0xc009, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA */
+ 0xc011, /* TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA */
+ 0xc013, /* TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA */
+ 0x0033, /* TLS1_TXT_DHE_RSA_WITH_AES_128_SHA */
+ 0x0032, /* TLS1_TXT_DHE_DSS_WITH_AES_128_SHA */
+ 0xc00c, /* TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA */
+ 0xc00e, /* TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA */
+ 0xc002, /* TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA */
+ 0xc004, /* TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA */
+ 0x0004, /* SSL3_TXT_RSA_RC4_128_MD5 */
+ 0x0005, /* SSL3_TXT_RSA_RC4_128_SHA */
+ 0x002f, /* TLS1_TXT_RSA_WITH_AES_128_SHA */
+ 0xc008, /* TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA */
+ 0xc012, /* TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA */
+ 0x0016, /* SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA */
+ 0x0013, /* SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA */
+ 0xc00d, /* TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA */
+ 0xc003, /* TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA */
+ 0xfeff, /* SSL3_TXT_RSA_FIPS_WITH_3DES_EDE_CBC_SHA */
+ 0x000a, /* SSL3_TXT_RSA_DES_192_CBC3_SHA */
+ 0
+};
+/** Have we removed the unrecognized ciphers from v2_cipher_list yet? */
+static int v2_cipher_list_pruned = 0;
+
+/** Remove from v2_cipher_list every cipher that we don't support, so that
+ * comparing v2_cipher_list to a client's cipher list will give a sensible
+ * result. */
+static void
+prune_v2_cipher_list(void)
+{
+ uint16_t *inp, *outp;
+ const SSL_METHOD *m = SSLv23_method();
+
+ inp = outp = v2_cipher_list;
+ while (*inp) {
+ unsigned char cipherid[2];
+ const SSL_CIPHER *cipher;
+ /* Is there no better way to do this? */
+ set_uint16(cipherid, htons(*inp));
+ cipher = m->get_cipher_by_char(cipherid);
+ if (cipher) {
+ tor_assert((cipher->id & 0xffff) == *inp);
+ *outp++ = *inp++;
+ } else {
+ inp++;
+ }
+ }
+ *outp = 0;
+
+ v2_cipher_list_pruned = 1;
+}
+
+/* Return the name of the negotiated ciphersuite in use on <b>tls</b> */
+const char *
+tor_tls_get_ciphersuite_name(tor_tls_t *tls)
+{
+ return SSL_get_cipher(tls->ssl);
+}
+
+/** Examine the client cipher list in <b>ssl</b>, and determine what kind of
+ * client it is. Return one of CIPHERS_ERR, CIPHERS_V1, CIPHERS_V2,
+ * CIPHERS_UNRESTRICTED.
+ **/
static int
-tor_tls_client_is_using_v2_ciphers(const SSL *ssl, const char *address)
+tor_tls_classify_client_ciphers(const SSL *ssl,
+ STACK_OF(SSL_CIPHER) *peer_ciphers)
{
- int i;
- SSL_SESSION *session;
+ int i, res;
+ tor_tls_t *tor_tls;
+ if (PREDICT_UNLIKELY(!v2_cipher_list_pruned))
+ prune_v2_cipher_list();
+
+ tor_tls = tor_tls_get_by_ssl(ssl);
+ if (tor_tls && tor_tls->client_cipher_list_type)
+ return tor_tls->client_cipher_list_type;
+
/* If we reached this point, we just got a client hello. See if there is
* a cipher list. */
- if (!(session = SSL_get_session((SSL *)ssl))) {
- log_info(LD_NET, "No session on TLS?");
- return 0;
- }
- if (!session->ciphers) {
+ if (!peer_ciphers) {
log_info(LD_NET, "No ciphers on session");
- return 0;
+ res = CIPHERS_ERR;
+ goto done;
}
/* Now we need to see if there are any ciphers whose presence means we're
* dealing with an updated Tor. */
- for (i = 0; i < sk_SSL_CIPHER_num(session->ciphers); ++i) {
- SSL_CIPHER *cipher = sk_SSL_CIPHER_value(session->ciphers, i);
+ for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) {
+ SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
const char *ciphername = SSL_CIPHER_get_name(cipher);
if (strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) &&
strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) &&
@@ -1337,28 +1548,111 @@ tor_tls_client_is_using_v2_ciphers(const SSL *ssl, const char *address)
strcmp(ciphername, "(NONE)")) {
log_debug(LD_NET, "Got a non-version-1 cipher called '%s'", ciphername);
// return 1;
- goto dump_list;
+ goto v2_or_higher;
}
}
- return 0;
- dump_list:
+ res = CIPHERS_V1;
+ goto done;
+ v2_or_higher:
+ {
+ const uint16_t *v2_cipher = v2_cipher_list;
+ for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) {
+ SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
+ uint16_t id = cipher->id & 0xffff;
+ if (id == 0x00ff) /* extended renegotiation indicator. */
+ continue;
+ if (!id || id != *v2_cipher) {
+ res = CIPHERS_UNRESTRICTED;
+ goto dump_ciphers;
+ }
+ ++v2_cipher;
+ }
+ if (*v2_cipher != 0) {
+ res = CIPHERS_UNRESTRICTED;
+ goto dump_ciphers;
+ }
+ res = CIPHERS_V2;
+ }
+
+ dump_ciphers:
{
smartlist_t *elts = smartlist_new();
char *s;
- for (i = 0; i < sk_SSL_CIPHER_num(session->ciphers); ++i) {
- SSL_CIPHER *cipher = sk_SSL_CIPHER_value(session->ciphers, i);
+ for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) {
+ SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i);
const char *ciphername = SSL_CIPHER_get_name(cipher);
smartlist_add(elts, (char*)ciphername);
}
s = smartlist_join_strings(elts, ":", 0, NULL);
- log_debug(LD_NET, "Got a non-version-1 cipher list from %s. It is: '%s'",
- address, s);
+ log_debug(LD_NET, "Got a %s V2/V3 cipher list from %s. It is: '%s'",
+ (res == CIPHERS_V2) ? "fictitious" : "real", ADDR(tor_tls), s);
tor_free(s);
smartlist_free(elts);
}
- return 1;
+ done:
+ if (tor_tls)
+ return tor_tls->client_cipher_list_type = res;
+
+ return res;
}
+/** Return true iff the cipher list suggested by the client for <b>ssl</b> is
+ * a list that indicates that the client knows how to do the v2 TLS connection
+ * handshake. */
+static int
+tor_tls_client_is_using_v2_ciphers(const SSL *ssl)
+{
+ SSL_SESSION *session;
+ if (!(session = SSL_get_session((SSL *)ssl))) {
+ log_info(LD_NET, "No session on TLS?");
+ return CIPHERS_ERR;
+ }
+
+ return tor_tls_classify_client_ciphers(ssl, session->ciphers) >= CIPHERS_V2;
+}
+
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0)
+/** Callback to get invoked on a server after we've read the list of ciphers
+ * the client supports, but before we pick our own ciphersuite.
+ *
+ * We can't abuse an info_cb for this, since by the time one of the
+ * client_hello info_cbs is called, we've already picked which ciphersuite to
+ * use.
+ *
+ * Technically, this function is an abuse of this callback, since the point of
+ * a session_secret_cb is to try to set up and/or verify a shared-secret for
+ * authentication on the fly. But as long as we return 0, we won't actually be
+ * setting up a shared secret, and all will be fine.
+ */
+static int
+tor_tls_session_secret_cb(SSL *ssl, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers,
+ SSL_CIPHER **cipher, void *arg)
+{
+ (void) secret;
+ (void) secret_len;
+ (void) peer_ciphers;
+ (void) cipher;
+ (void) arg;
+
+ if (tor_tls_classify_client_ciphers(ssl, peer_ciphers) ==
+ CIPHERS_UNRESTRICTED) {
+ SSL_set_cipher_list(ssl, UNRESTRICTED_SERVER_CIPHER_LIST);
+ }
+
+ SSL_set_session_secret_cb(ssl, NULL, NULL);
+
+ return 0;
+}
+static void
+tor_tls_setup_session_secret_cb(tor_tls_t *tls)
+{
+ SSL_set_session_secret_cb(tls->ssl, tor_tls_session_secret_cb, NULL);
+}
+#else
+#define tor_tls_setup_session_secret_cb(tls) STMT_NIL
+#endif
+
/** Invoked when a TLS state changes: log the change at severity 'debug' */
static void
tor_tls_debug_state_callback(const SSL *ssl, int type, int val)
@@ -1400,7 +1694,7 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
}
/* Now check the cipher list. */
- if (tor_tls_client_is_using_v2_ciphers(ssl, ADDR(tls))) {
+ if (tor_tls_client_is_using_v2_ciphers(ssl)) {
if (tls->wasV2Handshake)
return; /* We already turned this stuff off for the first handshake;
* This is a renegotiation. */
@@ -1625,6 +1919,9 @@ tor_tls_new(int sock, int isServer)
SSL_set_info_callback(result->ssl, tor_tls_debug_state_callback);
}
+ if (isServer)
+ tor_tls_setup_session_secret_cb(result);
+
/* Not expected to get called. */
tls_log_errors(NULL, LOG_WARN, LD_NET, "creating tor_tls_t object");
return result;
@@ -1721,6 +2018,10 @@ tor_tls_free(tor_tls_t *tls)
if (!tls)
return;
tor_assert(tls->ssl);
+ {
+ size_t r,w;
+ tor_tls_get_n_raw_bytes(tls,&r,&w); /* ensure written_by_tls is updated */
+ }
#ifdef SSL_set_tlsext_host_name
SSL_set_tlsext_host_name(tls->ssl, NULL);
#endif
@@ -1761,7 +2062,7 @@ tor_tls_read(tor_tls_t *tls, char *cp, size_t len)
return r;
}
err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG, LD_NET);
- if (err == _TOR_TLS_ZERORETURN || err == TOR_TLS_CLOSE) {
+ if (err == TOR_TLS_ZERORETURN_ || err == TOR_TLS_CLOSE) {
log_debug(LD_NET,"read returned r=%d; TLS is closed",r);
tls->state = TOR_TLS_ST_CLOSED;
return TOR_TLS_CLOSE;
@@ -1772,6 +2073,13 @@ tor_tls_read(tor_tls_t *tls, char *cp, size_t len)
}
}
+/** Total number of bytes that we've used TLS to send. Used to track TLS
+ * overhead. */
+static uint64_t total_bytes_written_over_tls = 0;
+/** Total number of bytes that TLS has put on the network for us. Used to
+ * track TLS overhead. */
+static uint64_t total_bytes_written_by_tls = 0;
+
/** Underlying function for TLS writing. Write up to <b>n</b>
* characters from <b>cp</b> onto <b>tls</b>. On success, returns the
* number of characters written. On failure, returns TOR_TLS_ERROR,
@@ -1798,6 +2106,7 @@ tor_tls_write(tor_tls_t *tls, const char *cp, size_t n)
r = SSL_write(tls->ssl, cp, (int)n);
err = tor_tls_get_error(tls, r, 0, "writing", LOG_INFO, LD_NET);
if (err == TOR_TLS_DONE) {
+ total_bytes_written_over_tls += r;
return r;
}
if (err == TOR_TLS_WANTWRITE || err == TOR_TLS_WANTREAD) {
@@ -1866,7 +2175,7 @@ tor_tls_finish_handshake(tor_tls_t *tls)
/* There doesn't seem to be a clear OpenSSL API to clear mode flags. */
tls->ssl->mode &= ~SSL_MODE_NO_AUTO_CHAIN;
#ifdef V2_HANDSHAKE_SERVER
- if (tor_tls_client_is_using_v2_ciphers(tls->ssl, ADDR(tls))) {
+ if (tor_tls_client_is_using_v2_ciphers(tls->ssl)) {
/* This check is redundant, but back when we did it in the callback,
* we might have not been able to look up the tor_tls_t if the code
* was buggy. Fixing that. */
@@ -1974,7 +2283,7 @@ tor_tls_shutdown(tor_tls_t *tls)
} while (r>0);
err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading to shut down",
LOG_INFO, LD_NET);
- if (err == _TOR_TLS_ZERORETURN) {
+ if (err == TOR_TLS_ZERORETURN_) {
tls->state = TOR_TLS_ST_GOTCLOSE;
/* fall through... */
} else {
@@ -1990,11 +2299,11 @@ tor_tls_shutdown(tor_tls_t *tls)
}
err = tor_tls_get_error(tls, r, CATCH_SYSCALL|CATCH_ZERO, "shutting down",
LOG_INFO, LD_NET);
- if (err == _TOR_TLS_SYSCALL) {
+ if (err == TOR_TLS_SYSCALL_) {
/* The underlying TCP connection closed while we were shutting down. */
tls->state = TOR_TLS_ST_CLOSED;
return TOR_TLS_DONE;
- } else if (err == _TOR_TLS_ZERORETURN) {
+ } else if (err == TOR_TLS_ZERORETURN_) {
/* The TLS connection says that it sent a shutdown record, but
* isn't done shutting down yet. Make sure that this hasn't
* happened before, then go back to the start of the function
@@ -2002,7 +2311,7 @@ tor_tls_shutdown(tor_tls_t *tls)
*/
if (tls->state == TOR_TLS_ST_GOTCLOSE ||
tls->state == TOR_TLS_ST_SENTCLOSE) {
- log(LOG_WARN, LD_NET,
+ log_warn(LD_NET,
"TLS returned \"half-closed\" value while already half-closed");
return TOR_TLS_ERROR_MISC;
}
@@ -2052,7 +2361,7 @@ log_cert_lifetime(int severity, const X509 *cert, const char *problem)
struct tm tm;
if (problem)
- log(severity, LD_GENERAL,
+ tor_log(severity, LD_GENERAL,
"Certificate %s. Either their clock is set wrong, or your clock "
"is wrong.",
problem);
@@ -2075,9 +2384,9 @@ log_cert_lifetime(int severity, const X509 *cert, const char *problem)
BIO_get_mem_ptr(bio, &buf);
s2 = tor_strndup(buf->data, buf->length);
- strftime(mytime, 32, "%b %d %H:%M:%S %Y GMT", tor_gmtime_r(&now, &tm));
+ strftime(mytime, 32, "%b %d %H:%M:%S %Y UTC", tor_gmtime_r(&now, &tm));
- log(severity, LD_GENERAL,
+ tor_log(severity, LD_GENERAL,
"(certificate lifetime runs from %s through %s. Your time is %s.)",
s1,s2,mytime);
@@ -2164,7 +2473,7 @@ tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity_key)
rsa = EVP_PKEY_get1_RSA(id_pkey);
if (!rsa)
goto done;
- *identity_key = _crypto_new_pk_from_rsa(rsa);
+ *identity_key = crypto_new_pk_from_rsa_(rsa);
r = 0;
@@ -2287,18 +2596,31 @@ tor_tls_get_n_raw_bytes(tor_tls_t *tls, size_t *n_read, size_t *n_written)
"r=%lu, last_read=%lu, w=%lu, last_written=%lu",
r, tls->last_read_count, w, tls->last_write_count);
}
+ total_bytes_written_by_tls += *n_written;
tls->last_read_count = r;
tls->last_write_count = w;
}
+/** Return a ratio of the bytes that TLS has sent to the bytes that we've told
+ * it to send. Used to track whether our TLS records are getting too tiny. */
+double
+tls_get_write_overhead_ratio(void)
+{
+ if (total_bytes_written_over_tls == 0)
+ return 1.0;
+
+ return U64_TO_DBL(total_bytes_written_by_tls) /
+ U64_TO_DBL(total_bytes_written_over_tls);
+}
+
/** Implement check_no_tls_errors: If there are any pending OpenSSL
* errors, log an error message. */
void
-_check_no_tls_errors(const char *fname, int line)
+check_no_tls_errors_(const char *fname, int line)
{
if (ERR_peek_error() == 0)
return;
- log(LOG_WARN, LD_CRYPTO, "Unhandled OpenSSL errors found at %s:%d: ",
+ log_warn(LD_CRYPTO, "Unhandled OpenSSL errors found at %s:%d: ",
tor_fix_source_file(fname), line);
tls_log_errors(NULL, LOG_WARN, LD_NET, NULL);
}
diff --git a/src/common/tortls.h b/src/common/tortls.h
index 491a5419d..49c488b36 100644
--- a/src/common/tortls.h
+++ b/src/common/tortls.h
@@ -1,10 +1,10 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#ifndef _TOR_TORTLS_H
-#define _TOR_TORTLS_H
+#ifndef TOR_TORTLS_H
+#define TOR_TORTLS_H
/**
* \file tortls.h
@@ -21,7 +21,7 @@ typedef struct tor_tls_t tor_tls_t;
typedef struct tor_cert_t tor_cert_t;
/* Possible return values for most tor_tls_* functions. */
-#define _MIN_TOR_TLS_ERROR_VAL -9
+#define MIN_TOR_TLS_ERROR_VAL_ -9
#define TOR_TLS_ERROR_MISC -9
/* Rename to unexpected close or something. XXXX */
#define TOR_TLS_ERROR_IO -8
@@ -54,7 +54,12 @@ const char *tor_tls_err_to_string(int err);
void tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz);
void tor_tls_free_all(void);
-int tor_tls_context_init(int is_public_server,
+
+#define TOR_TLS_CTX_IS_PUBLIC_SERVER (1u<<0)
+#define TOR_TLS_CTX_USE_ECDHE_P256 (1u<<1)
+#define TOR_TLS_CTX_USE_ECDHE_P224 (1u<<2)
+
+int tor_tls_context_init(unsigned flags,
crypto_pk_t *client_identity,
crypto_pk_t *server_identity,
unsigned int key_lifetime);
@@ -90,6 +95,8 @@ void tor_tls_get_buffer_sizes(tor_tls_t *tls,
size_t *rbuf_capacity, size_t *rbuf_bytes,
size_t *wbuf_capacity, size_t *wbuf_bytes);
+double tls_get_write_overhead_ratio(void);
+
int tor_tls_used_v1_handshake(tor_tls_t *tls);
int tor_tls_received_v3_certificate(tor_tls_t *tls);
int tor_tls_get_num_server_handshakes(tor_tls_t *tls);
@@ -98,9 +105,9 @@ int tor_tls_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out);
/* Log and abort if there are unhandled TLS errors in OpenSSL's error stack.
*/
-#define check_no_tls_errors() _check_no_tls_errors(__FILE__,__LINE__)
+#define check_no_tls_errors() check_no_tls_errors_(__FILE__,__LINE__)
-void _check_no_tls_errors(const char *fname, int line);
+void check_no_tls_errors_(const char *fname, int line);
void tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
int severity, int domain, const char *doing);
@@ -129,6 +136,7 @@ int tor_tls_cert_is_valid(int severity,
const tor_cert_t *cert,
const tor_cert_t *signing_cert,
int check_rsa_1024);
+const char *tor_tls_get_ciphersuite_name(tor_tls_t *tls);
#endif
diff --git a/src/common/util.c b/src/common/util.c
index b16afa13e..5eb0f9a69 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -20,7 +20,6 @@
#define UTIL_PRIVATE
#include "util.h"
#include "torlog.h"
-#undef log
#include "crypto.h"
#include "torint.h"
#include "container.h"
@@ -39,8 +38,8 @@
#endif
/* math.h needs this on Linux */
-#ifndef __USE_ISOC99
-#define __USE_ISOC99 1
+#ifndef _USE_ISOC99_
+#define _USE_ISOC99_ 1
#endif
#include <math.h>
#include <stdlib.h>
@@ -125,7 +124,7 @@
* ignored otherwise.
*/
void *
-_tor_malloc(size_t size DMALLOC_PARAMS)
+tor_malloc_(size_t size DMALLOC_PARAMS)
{
void *result;
@@ -159,7 +158,7 @@ _tor_malloc(size_t size DMALLOC_PARAMS)
* the process on error. (Same as calloc(size,1), but never returns NULL.)
*/
void *
-_tor_malloc_zero(size_t size DMALLOC_PARAMS)
+tor_malloc_zero_(size_t size DMALLOC_PARAMS)
{
/* You may ask yourself, "wouldn't it be smart to use calloc instead of
* malloc+memset? Perhaps libc's calloc knows some nifty optimization trick
@@ -167,7 +166,7 @@ _tor_malloc_zero(size_t size DMALLOC_PARAMS)
* we're allocating something very big (it knows if it just got the memory
* from the OS in a pre-zeroed state). We don't want to use tor_malloc_zero
* for big stuff, so we don't bother with calloc. */
- void *result = _tor_malloc(size DMALLOC_FN_ARGS);
+ void *result = tor_malloc_(size DMALLOC_FN_ARGS);
memset(result, 0, size);
return result;
}
@@ -184,7 +183,7 @@ _tor_malloc_zero(size_t size DMALLOC_PARAMS)
* smaller than size). Don't do that then.
*/
void *
-_tor_calloc(size_t nmemb, size_t size DMALLOC_PARAMS)
+tor_calloc_(size_t nmemb, size_t size DMALLOC_PARAMS)
{
/* You may ask yourself, "wouldn't it be smart to use calloc instead of
* malloc+memset? Perhaps libc's calloc knows some nifty optimization trick
@@ -197,7 +196,7 @@ _tor_calloc(size_t nmemb, size_t size DMALLOC_PARAMS)
tor_assert(nmemb < max_nmemb);
- result = _tor_malloc_zero((nmemb * size) DMALLOC_FN_ARGS);
+ result = tor_malloc_zero_((nmemb * size) DMALLOC_FN_ARGS);
return result;
}
@@ -206,7 +205,7 @@ _tor_calloc(size_t nmemb, size_t size DMALLOC_PARAMS)
* terminate. (Like realloc(ptr,size), but never returns NULL.)
*/
void *
-_tor_realloc(void *ptr, size_t size DMALLOC_PARAMS)
+tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS)
{
void *result;
@@ -230,7 +229,7 @@ _tor_realloc(void *ptr, size_t size DMALLOC_PARAMS)
* NULL.)
*/
char *
-_tor_strdup(const char *s DMALLOC_PARAMS)
+tor_strdup_(const char *s DMALLOC_PARAMS)
{
char *dup;
tor_assert(s);
@@ -254,12 +253,12 @@ _tor_strdup(const char *s DMALLOC_PARAMS)
* NULL.)
*/
char *
-_tor_strndup(const char *s, size_t n DMALLOC_PARAMS)
+tor_strndup_(const char *s, size_t n DMALLOC_PARAMS)
{
char *dup;
tor_assert(s);
tor_assert(n < SIZE_T_CEILING);
- dup = _tor_malloc((n+1) DMALLOC_FN_ARGS);
+ dup = tor_malloc_((n+1) DMALLOC_FN_ARGS);
/* Performance note: Ordinarily we prefer strlcpy to strncpy. But
* this function gets called a whole lot, and platform strncpy is
* much faster than strlcpy when strlen(s) is much longer than n.
@@ -272,55 +271,38 @@ _tor_strndup(const char *s, size_t n DMALLOC_PARAMS)
/** Allocate a chunk of <b>len</b> bytes, with the same contents as the
* <b>len</b> bytes starting at <b>mem</b>. */
void *
-_tor_memdup(const void *mem, size_t len DMALLOC_PARAMS)
+tor_memdup_(const void *mem, size_t len DMALLOC_PARAMS)
{
char *dup;
tor_assert(len < SIZE_T_CEILING);
tor_assert(mem);
- dup = _tor_malloc(len DMALLOC_FN_ARGS);
+ dup = tor_malloc_(len DMALLOC_FN_ARGS);
memcpy(dup, mem, len);
return dup;
}
+/** As tor_memdup(), but add an extra 0 byte at the end of the resulting
+ * memory. */
+void *
+tor_memdup_nulterm(const void *mem, size_t len DMALLOC_PARAMS)
+{
+ char *dup;
+ tor_assert(len < SIZE_T_CEILING+1);
+ tor_assert(mem);
+ dup = tor_malloc_(len+1 DMALLOC_FN_ARGS);
+ memcpy(dup, mem, len);
+ dup[len] = '\0';
+ return dup;
+}
+
/** Helper for places that need to take a function pointer to the right
* spelling of "free()". */
void
-_tor_free(void *mem)
+tor_free_(void *mem)
{
tor_free(mem);
}
-#if defined(HAVE_MALLOC_GOOD_SIZE) && !defined(HAVE_MALLOC_GOOD_SIZE_PROTOTYPE)
-/* Some version of Mac OSX have malloc_good_size in their libc, but not
- * actually defined in malloc/malloc.h. We detect this and work around it by
- * prototyping.
- */
-extern size_t malloc_good_size(size_t size);
-#endif
-
-/** Allocate and return a chunk of memory of size at least *<b>size</b>, using
- * the same resources we would use to malloc *<b>sizep</b>. Set *<b>sizep</b>
- * to the number of usable bytes in the chunk of memory. */
-void *
-_tor_malloc_roundup(size_t *sizep DMALLOC_PARAMS)
-{
-#ifdef HAVE_MALLOC_GOOD_SIZE
- tor_assert(*sizep < SIZE_T_CEILING);
- *sizep = malloc_good_size(*sizep);
- return _tor_malloc(*sizep DMALLOC_FN_ARGS);
-#elif 0 && defined(HAVE_MALLOC_USABLE_SIZE) && !defined(USE_DMALLOC)
- /* Never use malloc_usable_size(); it makes valgrind really unhappy,
- * and doesn't win much in terms of usable space where it exists. */
- void *result;
- tor_assert(*sizep < SIZE_T_CEILING);
- result = _tor_malloc(*sizep DMALLOC_FN_ARGS);
- *sizep = malloc_usable_size(result);
- return result;
-#else
- return _tor_malloc(*sizep DMALLOC_FN_ARGS);
-#endif
-}
-
/** Call the platform malloc info function, and dump the results to the log at
* level <b>severity</b>. If no such function exists, do nothing. */
void
@@ -354,8 +336,8 @@ tor_log_mallinfo(int severity)
* ===== */
/**
- * Returns the natural logarithm of d base 2. We define this wrapper here so
- * as to make it easier not to conflict with Tor's log() macro.
+ * Returns the natural logarithm of d base e. We defined this wrapper here so
+ * to avoid conflicts with old versions of tor_log(), which were named log().
*/
double
tor_mathlog(double d)
@@ -363,9 +345,9 @@ tor_mathlog(double d)
return log(d);
}
-/** Return the long integer closest to d. We define this wrapper here so
- * that not all users of math.h need to use the right incancations to get
- * the c99 functions. */
+/** Return the long integer closest to <b>d</b>. We define this wrapper
+ * here so that not all users of math.h need to use the right incantations
+ * to get the c99 functions. */
long
tor_lround(double d)
{
@@ -378,6 +360,21 @@ tor_lround(double d)
#endif
}
+/** Return the 64-bit integer closest to d. We define this wrapper here so
+ * that not all users of math.h need to use the right incantations to get the
+ * c99 functions. */
+int64_t
+tor_llround(double d)
+{
+#if defined(HAVE_LLROUND)
+ return (int64_t)llround(d);
+#elif defined(HAVE_RINT)
+ return (int64_t)rint(d);
+#else
+ return (int64_t)(d > 0 ? d + 0.5 : ceil(d - 0.5));
+#endif
+}
+
/** Returns floor(log2(u64)). If u64 is 0, (incorrectly) returns 0. */
int
tor_log2(uint64_t u64)
@@ -410,12 +407,24 @@ tor_log2(uint64_t u64)
return r;
}
-/** Return the power of 2 closest to <b>u64</b>. */
+/** Return the power of 2 in range [1,UINT64_MAX] closest to <b>u64</b>. If
+ * there are two powers of 2 equally close, round down. */
uint64_t
round_to_power_of_2(uint64_t u64)
{
- int lg2 = tor_log2(u64);
- uint64_t low = U64_LITERAL(1) << lg2, high = U64_LITERAL(1) << (lg2+1);
+ int lg2;
+ uint64_t low;
+ uint64_t high;
+ if (u64 == 0)
+ return 1;
+
+ lg2 = tor_log2(u64);
+ low = U64_LITERAL(1) << lg2;
+
+ if (lg2 == 63)
+ return low;
+
+ high = U64_LITERAL(1) << (lg2+1);
if (high - u64 < u64 - low)
return high;
else
@@ -655,6 +664,16 @@ fast_memcmpstart(const void *mem, size_t memlen,
return fast_memcmp(mem, prefix, plen);
}
+/** Given a nul-terminated string s, set every character before the nul
+ * to zero. */
+void
+tor_strclear(char *s)
+{
+ while (*s) {
+ *s++ = '\0';
+ }
+}
+
/** Return a pointer to the first char of s that is not whitespace and
* not a comment, or to the terminating NUL if no such character exists.
*/
@@ -1013,7 +1032,7 @@ base16_encode(char *dest, size_t destlen, const char *src, size_t srclen)
/** Helper: given a hex digit, return its value, or -1 if it isn't hex. */
static INLINE int
-_hex_decode_digit(char c)
+hex_decode_digit_(char c)
{
switch (c) {
case '0': return 0;
@@ -1041,7 +1060,7 @@ _hex_decode_digit(char c)
int
hex_decode_digit(char c)
{
- return _hex_decode_digit(c);
+ return hex_decode_digit_(c);
}
/** Given a hexadecimal string of <b>srclen</b> bytes in <b>src</b>, decode it
@@ -1059,8 +1078,8 @@ base16_decode(char *dest, size_t destlen, const char *src, size_t srclen)
return -1;
end = src+srclen;
while (src<end) {
- v1 = _hex_decode_digit(*src);
- v2 = _hex_decode_digit(*(src+1));
+ v1 = hex_decode_digit_(*src);
+ v2 = hex_decode_digit_(*(src+1));
if (v1<0||v2<0)
return -1;
*(uint8_t*)dest = (v1<<4)|v2;
@@ -1160,130 +1179,21 @@ esc_for_log(const char *s)
const char *
escaped(const char *s)
{
- static char *_escaped_val = NULL;
- tor_free(_escaped_val);
+ static char *escaped_val_ = NULL;
+ tor_free(escaped_val_);
if (s)
- _escaped_val = esc_for_log(s);
+ escaped_val_ = esc_for_log(s);
else
- _escaped_val = NULL;
+ escaped_val_ = NULL;
- return _escaped_val;
-}
-
-/** Rudimentary string wrapping code: given a un-wrapped <b>string</b> (no
- * newlines!), break the string into newline-terminated lines of no more than
- * <b>width</b> characters long (not counting newline) and insert them into
- * <b>out</b> in order. Precede the first line with prefix0, and subsequent
- * lines with prefixRest.
- */
-/* This uses a stupid greedy wrapping algorithm right now:
- * - For each line:
- * - Try to fit as much stuff as possible, but break on a space.
- * - If the first "word" of the line will extend beyond the allowable
- * width, break the word at the end of the width.
- */
-void
-wrap_string(smartlist_t *out, const char *string, size_t width,
- const char *prefix0, const char *prefixRest)
-{
- size_t p0Len, pRestLen, pCurLen;
- const char *eos, *prefixCur;
- tor_assert(out);
- tor_assert(string);
- tor_assert(width);
- if (!prefix0)
- prefix0 = "";
- if (!prefixRest)
- prefixRest = "";
-
- p0Len = strlen(prefix0);
- pRestLen = strlen(prefixRest);
- tor_assert(width > p0Len && width > pRestLen);
- eos = strchr(string, '\0');
- tor_assert(eos);
- pCurLen = p0Len;
- prefixCur = prefix0;
-
- while ((eos-string)+pCurLen > width) {
- const char *eol = string + width - pCurLen;
- while (eol > string && *eol != ' ')
- --eol;
- /* eol is now the last space that can fit, or the start of the string. */
- if (eol > string) {
- size_t line_len = (eol-string) + pCurLen + 2;
- char *line = tor_malloc(line_len);
- memcpy(line, prefixCur, pCurLen);
- memcpy(line+pCurLen, string, eol-string);
- line[line_len-2] = '\n';
- line[line_len-1] = '\0';
- smartlist_add(out, line);
- string = eol + 1;
- } else {
- size_t line_len = width + 2;
- char *line = tor_malloc(line_len);
- memcpy(line, prefixCur, pCurLen);
- memcpy(line+pCurLen, string, width - pCurLen);
- line[line_len-2] = '\n';
- line[line_len-1] = '\0';
- smartlist_add(out, line);
- string += width-pCurLen;
- }
- prefixCur = prefixRest;
- pCurLen = pRestLen;
- }
-
- if (string < eos) {
- size_t line_len = (eos-string) + pCurLen + 2;
- char *line = tor_malloc(line_len);
- memcpy(line, prefixCur, pCurLen);
- memcpy(line+pCurLen, string, eos-string);
- line[line_len-2] = '\n';
- line[line_len-1] = '\0';
- smartlist_add(out, line);
- }
+ return escaped_val_;
}
/* =====
* Time
* ===== */
-/**
- * Converts struct timeval to a double value.
- * Preserves microsecond precision, but just barely.
- * Error is approx +/- 0.1 usec when dealing with epoch values.
- */
-double
-tv_to_double(const struct timeval *tv)
-{
- double conv = tv->tv_sec;
- conv += tv->tv_usec/1000000.0;
- return conv;
-}
-
-/**
- * Converts timeval to milliseconds.
- */
-int64_t
-tv_to_msec(const struct timeval *tv)
-{
- int64_t conv = ((int64_t)tv->tv_sec)*1000L;
- /* Round ghetto-style */
- conv += ((int64_t)tv->tv_usec+500)/1000L;
- return conv;
-}
-
-/**
- * Converts timeval to microseconds.
- */
-int64_t
-tv_to_usec(const struct timeval *tv)
-{
- int64_t conv = ((int64_t)tv->tv_sec)*1000000L;
- conv += tv->tv_usec;
- return conv;
-}
-
/** Return the number of microseconds elapsed between *start and *end.
*/
long
@@ -1322,6 +1232,18 @@ tv_mdiff(const struct timeval *start, const struct timeval *end)
return mdiff;
}
+/**
+ * Converts timeval to milliseconds.
+ */
+int64_t
+tv_to_msec(const struct timeval *tv)
+{
+ int64_t conv = ((int64_t)tv->tv_sec)*1000L;
+ /* Round ghetto-style */
+ conv += ((int64_t)tv->tv_usec+500)/1000L;
+ return conv;
+}
+
/** Yield true iff <b>y</b> is a leap-year. */
#define IS_LEAPYEAR(y) (!(y % 4) && ((y % 100) || !(y % 400)))
/** Helper: Return the number of leap-days between Jan 1, y1 and Jan 1, y2. */
@@ -1336,7 +1258,7 @@ n_leapdays(int y1, int y2)
static const int days_per_month[] =
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-/** Compute a time_t given a struct tm. The result is given in GMT, and
+/** Compute a time_t given a struct tm. The result is given in UTC, and
* does not account for leap seconds. Return 0 on success, -1 on failure.
*/
int
@@ -1377,10 +1299,11 @@ static const char *MONTH_NAMES[] =
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-/** Set <b>buf</b> to the RFC1123 encoding of the GMT value of <b>t</b>.
+/** Set <b>buf</b> to the RFC1123 encoding of the UTC value of <b>t</b>.
* The buffer must be at least RFC1123_TIME_LEN+1 bytes long.
*
- * (RFC1123 format is Fri, 29 Sep 2006 15:54:20 GMT)
+ * (RFC1123 format is "Fri, 29 Sep 2006 15:54:20 GMT". Note the "GMT"
+ * rather than "UTC".)
*/
void
format_rfc1123_time(char *buf, time_t t)
@@ -1398,8 +1321,11 @@ format_rfc1123_time(char *buf, time_t t)
memcpy(buf+8, MONTH_NAMES[tm.tm_mon], 3);
}
-/** Parse the RFC1123 encoding of some time (in GMT) from <b>buf</b>,
- * and store the result in *<b>t</b>.
+/** Parse the (a subset of) the RFC1123 encoding of some time (in UTC) from
+ * <b>buf</b>, and store the result in *<b>t</b>.
+ *
+ * Note that we only accept the subset generated by format_rfc1123_time above,
+ * not the full range of formats suggested by RFC 1123.
*
* Return 0 on success, -1 on failure.
*/
@@ -1827,6 +1753,10 @@ file_status(const char *fname)
return FN_DIR;
else if (st.st_mode & S_IFREG)
return FN_FILE;
+#ifndef _WIN32
+ else if (st.st_mode & S_IFIFO)
+ return FN_FILE;
+#endif
else
return FN_ERROR;
}
@@ -2257,6 +2187,46 @@ write_bytes_to_new_file(const char *fname, const char *str, size_t len,
(bin?O_BINARY:O_TEXT));
}
+/**
+ * Read the contents of the open file <b>fd</b> presuming it is a FIFO
+ * (or similar) file descriptor for which the size of the file isn't
+ * known ahead of time. Return NULL on failure, and a NUL-terminated
+ * string on success. On success, set <b>sz_out</b> to the number of
+ * bytes read.
+ */
+char *
+read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out)
+{
+ ssize_t r;
+ size_t pos = 0;
+ char *string = NULL;
+ size_t string_max = 0;
+
+ if (max_bytes_to_read+1 >= SIZE_T_CEILING)
+ return NULL;
+
+ do {
+ /* XXXX This "add 1K" approach is a little goofy; if we care about
+ * performance here, we should be doubling. But in practice we shouldn't
+ * be using this function on big files anyway. */
+ string_max = pos + 1024;
+ if (string_max > max_bytes_to_read)
+ string_max = max_bytes_to_read + 1;
+ string = tor_realloc(string, string_max);
+ r = read(fd, string + pos, string_max - pos - 1);
+ if (r < 0) {
+ tor_free(string);
+ return NULL;
+ }
+
+ pos += r;
+ } while (r > 0 && pos < max_bytes_to_read);
+
+ *sz_out = pos;
+ string[pos] = '\0';
+ return string;
+}
+
/** Read the contents of <b>filename</b> into a newly allocated
* string; return the string on success or NULL on failure.
*
@@ -2305,8 +2275,26 @@ read_file_to_str(const char *filename, int flags, struct stat *stat_out)
return NULL;
}
- if ((uint64_t)(statbuf.st_size)+1 >= SIZE_T_CEILING)
+#ifndef _WIN32
+/** When we detect that we're reading from a FIFO, don't read more than
+ * this many bytes. It's insane overkill for most uses. */
+#define FIFO_READ_MAX (1024*1024)
+ if (S_ISFIFO(statbuf.st_mode)) {
+ size_t sz = 0;
+ string = read_file_to_str_until_eof(fd, FIFO_READ_MAX, &sz);
+ if (string && stat_out) {
+ statbuf.st_size = sz;
+ memcpy(stat_out, &statbuf, sizeof(struct stat));
+ }
+ close(fd);
+ return string;
+ }
+#endif
+
+ if ((uint64_t)(statbuf.st_size)+1 >= SIZE_T_CEILING) {
+ close(fd);
return NULL;
+ }
string = tor_malloc((size_t)(statbuf.st_size+1));
@@ -2466,10 +2454,13 @@ unescape_string(const char *s, char **result, size_t *size_out)
* key portion and *<b>value_out</b> to a new string holding the value portion
* of the line, and return a pointer to the start of the next line. If we run
* out of data, return a pointer to the end of the string. If we encounter an
- * error, return NULL.
+ * error, return NULL and set *<b>err_out</b> (if provided) to an error
+ * message.
*/
const char *
-parse_config_line_from_str(const char *line, char **key_out, char **value_out)
+parse_config_line_from_str_verbose(const char *line, char **key_out,
+ char **value_out,
+ const char **err_out)
{
/* I believe the file format here is supposed to be:
FILE = (EMPTYLINE | LINE)* (EMPTYLASTLINE | LASTLINE)?
@@ -2543,12 +2534,18 @@ parse_config_line_from_str(const char *line, char **key_out, char **value_out)
/* Find the end of the line. */
if (*line == '\"') { // XXX No continuation handling is done here
- if (!(line = unescape_string(line, value_out, NULL)))
- return NULL;
+ if (!(line = unescape_string(line, value_out, NULL))) {
+ if (err_out)
+ *err_out = "Invalid escape sequence in quoted string";
+ return NULL;
+ }
while (*line == ' ' || *line == '\t')
++line;
- if (*line && *line != '#' && *line != '\n')
+ if (*line && *line != '#' && *line != '\n') {
+ if (err_out)
+ *err_out = "Excess data after quoted string";
return NULL;
+ }
} else {
/* Look for the end of the line. */
while (*line && *line != '\n' && (*line != '#' || continuation)) {
@@ -2683,9 +2680,9 @@ digit_to_num(char d)
* success, store the result in <b>out</b>, advance bufp to the next
* character, and return 0. On failure, return -1. */
static int
-scan_unsigned(const char **bufp, unsigned *out, int width, int base)
+scan_unsigned(const char **bufp, unsigned long *out, int width, int base)
{
- unsigned result = 0;
+ unsigned long result = 0;
int scanned_so_far = 0;
const int hex = base==16;
tor_assert(base == 10 || base == 16);
@@ -2697,8 +2694,8 @@ scan_unsigned(const char **bufp, unsigned *out, int width, int base)
while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp))
&& scanned_so_far < width) {
int digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++);
- unsigned new_result = result * base + digit;
- if (new_result > UINT32_MAX || new_result < result)
+ unsigned long new_result = result * base + digit;
+ if (new_result < result)
return -1; /* over/underflow. */
result = new_result;
++scanned_so_far;
@@ -2711,6 +2708,89 @@ scan_unsigned(const char **bufp, unsigned *out, int width, int base)
return 0;
}
+/** Helper: Read an signed int from *<b>bufp</b> of up to <b>width</b>
+ * characters. (Handle arbitrary width if <b>width</b> is less than 0.) On
+ * success, store the result in <b>out</b>, advance bufp to the next
+ * character, and return 0. On failure, return -1. */
+static int
+scan_signed(const char **bufp, long *out, int width)
+{
+ int neg = 0;
+ unsigned long result = 0;
+
+ if (!bufp || !*bufp || !out)
+ return -1;
+ if (width<0)
+ width=MAX_SCANF_WIDTH;
+
+ if (**bufp == '-') {
+ neg = 1;
+ ++*bufp;
+ --width;
+ }
+
+ if (scan_unsigned(bufp, &result, width, 10) < 0)
+ return -1;
+
+ if (neg) {
+ if (result > ((unsigned long)LONG_MAX) + 1)
+ return -1; /* Underflow */
+ *out = -(long)result;
+ } else {
+ if (result > LONG_MAX)
+ return -1; /* Overflow */
+ *out = (long)result;
+ }
+
+ return 0;
+}
+
+/** Helper: Read a decimal-formatted double from *<b>bufp</b> of up to
+ * <b>width</b> characters. (Handle arbitrary width if <b>width</b> is less
+ * than 0.) On success, store the result in <b>out</b>, advance bufp to the
+ * next character, and return 0. On failure, return -1. */
+static int
+scan_double(const char **bufp, double *out, int width)
+{
+ int neg = 0;
+ double result = 0;
+ int scanned_so_far = 0;
+
+ if (!bufp || !*bufp || !out)
+ return -1;
+ if (width<0)
+ width=MAX_SCANF_WIDTH;
+
+ if (**bufp == '-') {
+ neg = 1;
+ ++*bufp;
+ }
+
+ while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) {
+ const int digit = digit_to_num(*(*bufp)++);
+ result = result * 10 + digit;
+ ++scanned_so_far;
+ }
+ if (**bufp == '.') {
+ double fracval = 0, denominator = 1;
+ ++*bufp;
+ ++scanned_so_far;
+ while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) {
+ const int digit = digit_to_num(*(*bufp)++);
+ fracval = fracval * 10 + digit;
+ denominator *= 10;
+ ++scanned_so_far;
+ }
+ result += fracval / denominator;
+ }
+
+ if (!scanned_so_far) /* No actual digits scanned */
+ return -1;
+
+ *out = neg ? -result : result;
+ return 0;
+}
+
/** Helper: copy up to <b>width</b> non-space characters from <b>bufp</b> to
* <b>out</b>. Make sure <b>out</b> is nul-terminated. Advance <b>bufp</b>
* to the next non-space character or the EOS. */
@@ -2747,6 +2827,7 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
}
} else {
int width = -1;
+ int longmod = 0;
++pattern;
if (TOR_ISDIGIT(*pattern)) {
width = digit_to_num(*pattern++);
@@ -2759,17 +2840,57 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
if (!width) /* No zero-width things. */
return -1;
}
+ if (*pattern == 'l') {
+ longmod = 1;
+ ++pattern;
+ }
if (*pattern == 'u' || *pattern == 'x') {
- unsigned *u = va_arg(ap, unsigned *);
+ unsigned long u;
const int base = (*pattern == 'u') ? 10 : 16;
if (!*buf)
return n_matched;
- if (scan_unsigned(&buf, u, width, base)<0)
+ if (scan_unsigned(&buf, &u, width, base)<0)
+ return n_matched;
+ if (longmod) {
+ unsigned long *out = va_arg(ap, unsigned long *);
+ *out = u;
+ } else {
+ unsigned *out = va_arg(ap, unsigned *);
+ if (u > UINT_MAX)
+ return n_matched;
+ *out = (unsigned) u;
+ }
+ ++pattern;
+ ++n_matched;
+ } else if (*pattern == 'f') {
+ double *d = va_arg(ap, double *);
+ if (!longmod)
+ return -1; /* float not supported */
+ if (!*buf)
+ return n_matched;
+ if (scan_double(&buf, d, width)<0)
return n_matched;
++pattern;
++n_matched;
+ } else if (*pattern == 'd') {
+ long lng=0;
+ if (scan_signed(&buf, &lng, width)<0)
+ return n_matched;
+ if (longmod) {
+ long *out = va_arg(ap, long *);
+ *out = lng;
+ } else {
+ int *out = va_arg(ap, int *);
+ if (lng < INT_MIN || lng > INT_MAX)
+ return n_matched;
+ *out = (int)lng;
+ }
+ ++pattern;
+ ++n_matched;
} else if (*pattern == 's') {
char *s = va_arg(ap, char *);
+ if (longmod)
+ return -1;
if (width < 0)
return -1;
if (scan_string(&buf, s, width)<0)
@@ -2778,6 +2899,8 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
++n_matched;
} else if (*pattern == 'c') {
char *ch = va_arg(ap, char *);
+ if (longmod)
+ return -1;
if (width != -1)
return -1;
if (!*buf)
@@ -2788,6 +2911,8 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
} else if (*pattern == '%') {
if (*buf != '%')
return n_matched;
+ if (longmod)
+ return -1;
++buf;
++pattern;
} else {
@@ -2801,9 +2926,14 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
/** Minimal sscanf replacement: parse <b>buf</b> according to <b>pattern</b>
* and store the results in the corresponding argument fields. Differs from
- * sscanf in that it: Only handles %u, %x, %c and %Ns. Does not handle
- * arbitrarily long widths. %u and %x do not consume any space. Is
- * locale-independent. Returns -1 on malformed patterns.
+ * sscanf in that:
+ * <ul><li>It only handles %u, %lu, %x, %lx, %<NUM>s, %d, %ld, %lf, and %c.
+ * <li>It only handles decimal inputs for %lf. (12.3, not 1.23e1)
+ * <li>It does not handle arbitrarily long widths.
+ * <li>Numbers do not consume any space characters.
+ * <li>It is locale-independent.
+ * <li>%u and %x do not consume any space.
+ * <li>It returns -1 on malformed patterns.</ul>
*
* (As with other locale-independent functions, we need this to parse data that
* is in ASCII without worrying that the C library's locale-handling will make
@@ -3630,12 +3760,13 @@ tor_spawn_background(const char *const filename, const char **argv,
child_state = CHILD_STATE_MAXFD;
#ifdef _SC_OPEN_MAX
- if (-1 != max_fd) {
+ if (-1 == max_fd) {
max_fd = (int) sysconf(_SC_OPEN_MAX);
- if (max_fd == -1)
+ if (max_fd == -1) {
max_fd = DEFAULT_MAX_FD;
log_warn(LD_GENERAL,
"Cannot find maximum file descriptor, assuming %d", max_fd);
+ }
}
#else
max_fd = DEFAULT_MAX_FD;
@@ -3784,10 +3915,17 @@ tor_process_handle_destroy(process_handle_t *process_handle,
if (also_terminate_process) {
if (tor_terminate_process(process_handle) < 0) {
- log_notice(LD_GENERAL, "Failed to terminate process with PID '%d'",
- tor_process_get_pid(process_handle));
+ const char *errstr =
+#ifdef _WIN32
+ format_win32_error(GetLastError());
+#else
+ strerror(errno);
+#endif
+ log_notice(LD_GENERAL, "Failed to terminate process with "
+ "PID '%d' ('%s').", tor_process_get_pid(process_handle),
+ errstr);
} else {
- log_info(LD_GENERAL, "Terminated process with PID '%d'",
+ log_info(LD_GENERAL, "Terminated process with PID '%d'.",
tor_process_get_pid(process_handle));
}
}
@@ -4255,7 +4393,70 @@ tor_split_lines(smartlist_t *sl, char *buf, int len)
return smartlist_len(sl);
}
+/** Return a string corresponding to <b>stream_status</b>. */
+const char *
+stream_status_to_string(enum stream_status stream_status)
+{
+ switch (stream_status) {
+ case IO_STREAM_OKAY:
+ return "okay";
+ case IO_STREAM_EAGAIN:
+ return "temporarily unavailable";
+ case IO_STREAM_TERM:
+ return "terminated";
+ case IO_STREAM_CLOSED:
+ return "closed";
+ default:
+ tor_fragile_assert();
+ return "unknown";
+ }
+}
+
#ifdef _WIN32
+
+/** Return a smartlist containing lines outputted from
+ * <b>handle</b>. Return NULL on error, and set
+ * <b>stream_status_out</b> appropriately. */
+smartlist_t *
+tor_get_lines_from_handle(HANDLE *handle,
+ enum stream_status *stream_status_out)
+{
+ int pos;
+ char stdout_buf[600] = {0};
+ smartlist_t *lines = NULL;
+
+ tor_assert(stream_status_out);
+
+ *stream_status_out = IO_STREAM_TERM;
+
+ pos = tor_read_all_handle(handle, stdout_buf, sizeof(stdout_buf) - 1, NULL);
+ if (pos < 0) {
+ *stream_status_out = IO_STREAM_TERM;
+ return NULL;
+ }
+ if (pos == 0) {
+ *stream_status_out = IO_STREAM_EAGAIN;
+ return NULL;
+ }
+
+ /* End with a null even if there isn't a \r\n at the end */
+ /* TODO: What if this is a partial line? */
+ stdout_buf[pos] = '\0';
+
+ /* Split up the buffer */
+ lines = smartlist_new();
+ tor_split_lines(lines, stdout_buf, pos);
+
+ /* Currently 'lines' is populated with strings residing on the
+ stack. Replace them with their exact copies on the heap: */
+ SMARTLIST_FOREACH(lines, char *, line,
+ SMARTLIST_REPLACE_CURRENT(lines, line, tor_strdup(line)));
+
+ *stream_status_out = IO_STREAM_OKAY;
+
+ return lines;
+}
+
/** Read from stream, and send lines to log at the specified log level.
* Returns -1 if there is a error reading, and 0 otherwise.
* If the generated stream is flushed more often than on new lines, or
@@ -4303,6 +4504,33 @@ log_from_handle(HANDLE *pipe, int severity)
#else
+/** Return a smartlist containing lines outputted from
+ * <b>handle</b>. Return NULL on error, and set
+ * <b>stream_status_out</b> appropriately. */
+smartlist_t *
+tor_get_lines_from_handle(FILE *handle, enum stream_status *stream_status_out)
+{
+ enum stream_status stream_status;
+ char stdout_buf[400];
+ smartlist_t *lines = NULL;
+
+ while (1) {
+ memset(stdout_buf, 0, sizeof(stdout_buf));
+
+ stream_status = get_string_from_pipe(handle,
+ stdout_buf, sizeof(stdout_buf) - 1);
+ if (stream_status != IO_STREAM_OKAY)
+ goto done;
+
+ if (!lines) lines = smartlist_new();
+ smartlist_add(lines, tor_strdup(stdout_buf));
+ }
+
+ done:
+ *stream_status_out = stream_status;
+ return lines;
+}
+
/** Read from stream, and send lines to log at the specified log level.
* Returns 1 if stream is closed normally, -1 if there is a error reading, and
* 0 otherwise. Handles lines from tor-fw-helper and
@@ -4421,9 +4649,130 @@ get_string_from_pipe(FILE *stream, char *buf_out, size_t count)
return IO_STREAM_TERM;
}
-/* DOCDOC tor_check_port_forwarding */
+/** Parse a <b>line</b> from tor-fw-helper and issue an appropriate
+ * log message to our user. */
+static void
+handle_fw_helper_line(const char *line)
+{
+ smartlist_t *tokens = smartlist_new();
+ char *message = NULL;
+ char *message_for_log = NULL;
+ const char *external_port = NULL;
+ const char *internal_port = NULL;
+ const char *result = NULL;
+ int port = 0;
+ int success = 0;
+
+ smartlist_split_string(tokens, line, NULL,
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+
+ if (smartlist_len(tokens) < 5)
+ goto err;
+
+ if (strcmp(smartlist_get(tokens, 0), "tor-fw-helper") ||
+ strcmp(smartlist_get(tokens, 1), "tcp-forward"))
+ goto err;
+
+ external_port = smartlist_get(tokens, 2);
+ internal_port = smartlist_get(tokens, 3);
+ result = smartlist_get(tokens, 4);
+
+ if (smartlist_len(tokens) > 5) {
+ /* If there are more than 5 tokens, they are part of [<message>].
+ Let's use a second smartlist to form the whole message;
+ strncat loops suck. */
+ int i;
+ int message_words_n = smartlist_len(tokens) - 5;
+ smartlist_t *message_sl = smartlist_new();
+ for (i = 0; i < message_words_n; i++)
+ smartlist_add(message_sl, smartlist_get(tokens, 5+i));
+
+ tor_assert(smartlist_len(message_sl) > 0);
+ message = smartlist_join_strings(message_sl, " ", 0, NULL);
+
+ /* wrap the message in log-friendly wrapping */
+ tor_asprintf(&message_for_log, " ('%s')", message);
+
+ smartlist_free(message_sl);
+ }
+
+ port = atoi(external_port);
+ if (port < 1 || port > 65535)
+ goto err;
+
+ port = atoi(internal_port);
+ if (port < 1 || port > 65535)
+ goto err;
+
+ if (!strcmp(result, "SUCCESS"))
+ success = 1;
+ else if (!strcmp(result, "FAIL"))
+ success = 0;
+ else
+ goto err;
+
+ if (!success) {
+ log_warn(LD_GENERAL, "Tor was unable to forward TCP port '%s' to '%s'%s. "
+ "Please make sure that your router supports port "
+ "forwarding protocols (like NAT-PMP). Note that if '%s' is "
+ "your ORPort, your relay will be unable to receive inbound "
+ "traffic.", external_port, internal_port,
+ message_for_log ? message_for_log : "",
+ internal_port);
+ } else {
+ log_info(LD_GENERAL,
+ "Tor successfully forwarded TCP port '%s' to '%s'%s.",
+ external_port, internal_port,
+ message_for_log ? message_for_log : "");
+ }
+
+ goto done;
+
+ err:
+ log_warn(LD_GENERAL, "tor-fw-helper sent us a string we could not "
+ "parse (%s).", line);
+
+ done:
+ SMARTLIST_FOREACH(tokens, char *, cp, tor_free(cp));
+ smartlist_free(tokens);
+ tor_free(message);
+ tor_free(message_for_log);
+}
+
+/** Read what tor-fw-helper has to say in its stdout and handle it
+ * appropriately */
+static int
+handle_fw_helper_output(process_handle_t *process_handle)
+{
+ smartlist_t *fw_helper_output = NULL;
+ enum stream_status stream_status = 0;
+
+ fw_helper_output =
+ tor_get_lines_from_handle(tor_process_get_stdout_pipe(process_handle),
+ &stream_status);
+ if (!fw_helper_output) { /* didn't get any output from tor-fw-helper */
+ /* if EAGAIN we should retry in the future */
+ return (stream_status == IO_STREAM_EAGAIN) ? 0 : -1;
+ }
+
+ /* Handle the lines we got: */
+ SMARTLIST_FOREACH_BEGIN(fw_helper_output, char *, line) {
+ handle_fw_helper_line(line);
+ tor_free(line);
+ } SMARTLIST_FOREACH_END(line);
+
+ smartlist_free(fw_helper_output);
+
+ return 0;
+}
+
+/** Spawn tor-fw-helper and ask it to forward the ports in
+ * <b>ports_to_forward</b>. <b>ports_to_forward</b> contains strings
+ * of the form "<external port>:<internal port>", which is the format
+ * that tor-fw-helper expects. */
void
-tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
+tor_check_port_forwarding(const char *filename,
+ smartlist_t *ports_to_forward,
time_t now)
{
/* When fw-helper succeeds, how long do we wait until running it again */
@@ -4437,32 +4786,51 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
static process_handle_t *child_handle=NULL;
static time_t time_to_run_helper = 0;
- int stdout_status, stderr_status, retval;
- const char *argv[10];
- char s_dirport[6], s_orport[6];
+ int stderr_status, retval;
+ int stdout_status = 0;
tor_assert(filename);
- /* Set up command line for tor-fw-helper */
- snprintf(s_dirport, sizeof s_dirport, "%d", dir_port);
- snprintf(s_orport, sizeof s_orport, "%d", or_port);
-
- /* TODO: Allow different internal and external ports */
- argv[0] = filename;
- argv[1] = "--internal-or-port";
- argv[2] = s_orport;
- argv[3] = "--external-or-port";
- argv[4] = s_orport;
- argv[5] = "--internal-dir-port";
- argv[6] = s_dirport;
- argv[7] = "--external-dir-port";
- argv[8] = s_dirport;
- argv[9] = NULL;
-
/* Start the child, if it is not already running */
if ((!child_handle || child_handle->status != PROCESS_STATUS_RUNNING) &&
time_to_run_helper < now) {
- int status;
+ /*tor-fw-helper cli looks like this: tor_fw_helper -p :5555 -p 4555:1111 */
+ const char **argv; /* cli arguments */
+ int args_n, status;
+ int argv_index = 0; /* index inside 'argv' */
+
+ tor_assert(smartlist_len(ports_to_forward) > 0);
+
+ /* check for overflow during 'argv' allocation:
+ (len(ports_to_forward)*2 + 2)*sizeof(char*) > SIZE_MAX ==
+ len(ports_to_forward) > (((SIZE_MAX/sizeof(char*)) - 2)/2) */
+ if ((size_t) smartlist_len(ports_to_forward) >
+ (((SIZE_MAX/sizeof(char*)) - 2)/2)) {
+ log_warn(LD_GENERAL,
+ "Overflow during argv allocation. This shouldn't happen.");
+ return;
+ }
+ /* check for overflow during 'argv_index' increase:
+ ((len(ports_to_forward)*2 + 2) > INT_MAX) ==
+ len(ports_to_forward) > (INT_MAX - 2)/2 */
+ if (smartlist_len(ports_to_forward) > (INT_MAX - 2)/2) {
+ log_warn(LD_GENERAL,
+ "Overflow during argv_index increase. This shouldn't happen.");
+ return;
+ }
+
+ /* Calculate number of cli arguments: one for the filename, two
+ for each smartlist element (one for "-p" and one for the
+ ports), and one for the final NULL. */
+ args_n = 1 + 2*smartlist_len(ports_to_forward) + 1;
+ argv = tor_malloc_zero(sizeof(char*)*args_n);
+
+ argv[argv_index++] = filename;
+ SMARTLIST_FOREACH_BEGIN(ports_to_forward, const char *, port) {
+ argv[argv_index++] = "-p";
+ argv[argv_index++] = port;
+ } SMARTLIST_FOREACH_END(port);
+ argv[argv_index] = NULL;
/* Assume tor-fw-helper will succeed, start it later*/
time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_SUCCESS;
@@ -4479,6 +4847,9 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
status = tor_spawn_background(filename, argv, NULL, &child_handle);
#endif
+ tor_free_((void*)argv);
+ argv=NULL;
+
if (PROCESS_STATUS_ERROR == status) {
log_warn(LD_GENERAL, "Failed to start port forwarding helper %s",
filename);
@@ -4496,16 +4867,17 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
/* Read from stdout/stderr and log result */
retval = 0;
#ifdef _WIN32
- stdout_status = log_from_handle(child_handle->stdout_pipe, LOG_INFO);
- stderr_status = log_from_handle(child_handle->stderr_pipe, LOG_WARN);
- /* If we got this far (on Windows), the process started */
- retval = 0;
+ stderr_status = log_from_handle(child_handle->stderr_pipe, LOG_INFO);
#else
- stdout_status = log_from_pipe(child_handle->stdout_handle,
- LOG_INFO, filename, &retval);
stderr_status = log_from_pipe(child_handle->stderr_handle,
- LOG_WARN, filename, &retval);
+ LOG_INFO, filename, &retval);
#endif
+ if (handle_fw_helper_output(child_handle) < 0) {
+ log_warn(LD_GENERAL, "Failed to handle fw helper output.");
+ stdout_status = -1;
+ retval = -1;
+ }
+
if (retval) {
/* There was a problem in the child process */
time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_FAIL;
@@ -4551,3 +4923,45 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
}
}
+/** Initialize the insecure RNG <b>rng</b> from a seed value <b>seed</b>. */
+void
+tor_init_weak_random(tor_weak_rng_t *rng, unsigned seed)
+{
+ rng->state = (uint32_t)(seed & 0x7fffffff);
+}
+
+/** Return a randomly chosen value in the range 0..TOR_WEAK_RANDOM_MAX based
+ * on the RNG state of <b>rng</b>. This entropy will not be cryptographically
+ * strong; do not rely on it for anything an adversary should not be able to
+ * predict. */
+int32_t
+tor_weak_random(tor_weak_rng_t *rng)
+{
+ /* Here's a linear congruential generator. OpenBSD and glibc use these
+ * parameters; they aren't too bad, and should have maximal period over the
+ * range 0..INT32_MAX. We don't want to use the platform rand() or random(),
+ * since some platforms have bad weak RNGs that only return values in the
+ * range 0..INT16_MAX, which just isn't enough. */
+ rng->state = (rng->state * 1103515245 + 12345) & 0x7fffffff;
+ return (int32_t) rng->state;
+}
+
+/** Return a random number in the range [0 , <b>top</b>). {That is, the range
+ * of integers i such that 0 <= i < top.} Chooses uniformly. Requires that
+ * top is greater than 0. This randomness is not cryptographically strong; do
+ * not rely on it for anything an adversary should not be able to predict. */
+int32_t
+tor_weak_random_range(tor_weak_rng_t *rng, int32_t top)
+{
+ /* We don't want to just do tor_weak_random() % top, since random() is often
+ * implemented with an LCG whose modulus is a power of 2, and those are
+ * cyclic in their low-order bits. */
+ int divisor, result;
+ tor_assert(top > 0);
+ divisor = TOR_WEAK_RANDOM_MAX / top;
+ do {
+ result = (int32_t)(tor_weak_random(rng) / divisor);
+ } while (result >= top);
+ return result;
+}
+
diff --git a/src/common/util.h b/src/common/util.h
index 8977d273c..73daa6e2a 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,8 +8,8 @@
* \brief Headers for util.c
**/
-#ifndef _TOR_UTIL_H
-#define _TOR_UTIL_H
+#ifndef TOR_UTIL_H
+#define TOR_UTIL_H
#include "orconfig.h"
#include "torint.h"
@@ -49,9 +49,9 @@
#define tor_assert(expr) STMT_BEGIN \
if (PREDICT_UNLIKELY(!(expr))) { \
log_err(LD_BUG, "%s:%d: %s: Assertion %s failed; aborting.", \
- _SHORT_FILE_, __LINE__, __func__, #expr); \
+ SHORT_FILE__, __LINE__, __func__, #expr); \
fprintf(stderr,"%s:%d %s: Assertion %s failed; aborting.\n", \
- _SHORT_FILE_, __LINE__, __func__, #expr); \
+ SHORT_FILE__, __LINE__, __func__, #expr); \
abort(); \
} STMT_END
@@ -62,7 +62,7 @@
* to calls. */
#ifdef USE_DMALLOC
#define DMALLOC_PARAMS , const char *file, const int line
-#define DMALLOC_ARGS , _SHORT_FILE_, __LINE__
+#define DMALLOC_ARGS , SHORT_FILE__, __LINE__
#else
#define DMALLOC_PARAMS
#define DMALLOC_ARGS
@@ -74,23 +74,24 @@
#define tor_fragile_assert()
/* Memory management */
-void *_tor_malloc(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
-void *_tor_malloc_zero(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
-void *_tor_malloc_roundup(size_t *size DMALLOC_PARAMS) ATTR_MALLOC;
-void *_tor_calloc(size_t nmemb, size_t size DMALLOC_PARAMS) ATTR_MALLOC;
-void *_tor_realloc(void *ptr, size_t size DMALLOC_PARAMS);
-char *_tor_strdup(const char *s DMALLOC_PARAMS) ATTR_MALLOC ATTR_NONNULL((1));
-char *_tor_strndup(const char *s, size_t n DMALLOC_PARAMS)
+void *tor_malloc_(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
+void *tor_malloc_zero_(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
+void *tor_calloc_(size_t nmemb, size_t size DMALLOC_PARAMS) ATTR_MALLOC;
+void *tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS);
+char *tor_strdup_(const char *s DMALLOC_PARAMS) ATTR_MALLOC ATTR_NONNULL((1));
+char *tor_strndup_(const char *s, size_t n DMALLOC_PARAMS)
ATTR_MALLOC ATTR_NONNULL((1));
-void *_tor_memdup(const void *mem, size_t len DMALLOC_PARAMS)
+void *tor_memdup_(const void *mem, size_t len DMALLOC_PARAMS)
ATTR_MALLOC ATTR_NONNULL((1));
-void _tor_free(void *mem);
+void *tor_memdup_nulterm_(const void *mem, size_t len DMALLOC_PARAMS)
+ ATTR_MALLOC ATTR_NONNULL((1));
+void tor_free_(void *mem);
#ifdef USE_DMALLOC
extern int dmalloc_free(const char *file, const int line, void *pnt,
const int func_id);
#define tor_free(p) STMT_BEGIN \
if (PREDICT_LIKELY((p)!=NULL)) { \
- dmalloc_free(_SHORT_FILE_, __LINE__, (p), 0); \
+ dmalloc_free(SHORT_FILE__, __LINE__, (p), 0); \
(p)=NULL; \
} \
STMT_END
@@ -100,7 +101,7 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
* and it sets the pointer value to NULL after freeing it.
*
* This is a macro. If you need a function pointer to release memory from
- * tor_malloc(), use _tor_free().
+ * tor_malloc(), use tor_free_().
*/
#define tor_free(p) STMT_BEGIN \
if (PREDICT_LIKELY((p)!=NULL)) { \
@@ -110,14 +111,14 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
STMT_END
#endif
-#define tor_malloc(size) _tor_malloc(size DMALLOC_ARGS)
-#define tor_malloc_zero(size) _tor_malloc_zero(size DMALLOC_ARGS)
-#define tor_calloc(nmemb,size) _tor_calloc(nmemb, size DMALLOC_ARGS)
-#define tor_malloc_roundup(szp) _tor_malloc_roundup(szp DMALLOC_ARGS)
-#define tor_realloc(ptr, size) _tor_realloc(ptr, size DMALLOC_ARGS)
-#define tor_strdup(s) _tor_strdup(s DMALLOC_ARGS)
-#define tor_strndup(s, n) _tor_strndup(s, n DMALLOC_ARGS)
-#define tor_memdup(s, n) _tor_memdup(s, n DMALLOC_ARGS)
+#define tor_malloc(size) tor_malloc_(size DMALLOC_ARGS)
+#define tor_malloc_zero(size) tor_malloc_zero_(size DMALLOC_ARGS)
+#define tor_calloc(nmemb,size) tor_calloc_(nmemb, size DMALLOC_ARGS)
+#define tor_realloc(ptr, size) tor_realloc_(ptr, size DMALLOC_ARGS)
+#define tor_strdup(s) tor_strdup_(s DMALLOC_ARGS)
+#define tor_strndup(s, n) tor_strndup_(s, n DMALLOC_ARGS)
+#define tor_memdup(s, n) tor_memdup_(s, n DMALLOC_ARGS)
+#define tor_memdup_nulterm(s, n) tor_memdup_nulterm_(s, n DMALLOC_ARGS)
void tor_log_mallinfo(int severity);
@@ -161,6 +162,7 @@ void tor_log_mallinfo(int severity);
/* Math functions */
double tor_mathlog(double d) ATTR_CONST;
long tor_lround(double d) ATTR_CONST;
+int64_t tor_llround(double d) ATTR_CONST;
int tor_log2(uint64_t u64) ATTR_CONST;
uint64_t round_to_power_of_2(uint64_t u64);
unsigned round_to_next_multiple_of(unsigned number, unsigned divisor);
@@ -173,6 +175,17 @@ int n_bits_set_u8(uint8_t v);
* overflow. */
#define CEIL_DIV(a,b) (((a)+(b)-1)/(b))
+/* Return <b>v</b> if it's between <b>min</b> and <b>max</b>. Otherwise
+ * return <b>min</b> if <b>v</b> is smaller than <b>min</b>, or <b>max</b> if
+ * <b>b</b> is larger than <b>max</b>.
+ *
+ * Requires that <b>min</b> is no more than <b>max</b>. May evaluate any of
+ * its arguments more than once! */
+#define CLAMP(min,v,max) \
+ ( ((v) < (min)) ? (min) : \
+ ((v) > (max)) ? (max) : \
+ (v) )
+
/* String manipulation */
/** Allowable characters in a hexadecimal string. */
@@ -188,6 +201,7 @@ int strcasecmpstart(const char *s1, const char *s2) ATTR_NONNULL((1,2));
int strcmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2));
int strcasecmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2));
int fast_memcmpstart(const void *mem, size_t memlen, const char *prefix);
+void tor_strclear(char *s);
void tor_strstrip(char *s, const char *strip) ATTR_NONNULL((1,2));
long tor_parse_long(const char *s, int base, long min,
@@ -215,8 +229,6 @@ int tor_digest256_is_zero(const char *digest);
char *esc_for_log(const char *string) ATTR_MALLOC;
const char *escaped(const char *string);
struct smartlist_t;
-void wrap_string(struct smartlist_t *out, const char *string, size_t width,
- const char *prefix0, const char *prefixRest);
int tor_vsscanf(const char *buf, const char *pattern, va_list ap)
#ifdef __GNUC__
__attribute__((format(scanf, 2, 0)))
@@ -239,11 +251,9 @@ void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen);
int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen);
/* Time helpers */
-double tv_to_double(const struct timeval *tv);
-int64_t tv_to_msec(const struct timeval *tv);
-int64_t tv_to_usec(const struct timeval *tv);
long tv_udiff(const struct timeval *start, const struct timeval *end);
long tv_mdiff(const struct timeval *start, const struct timeval *end);
+int64_t tv_to_msec(const struct timeval *tv);
int tor_timegm(const struct tm *tm, time_t *time_out);
#define RFC1123_TIME_LEN 29
void format_rfc1123_time(char *buf, time_t t);
@@ -283,6 +293,15 @@ void update_approx_time(time_t now);
}
}
</pre>
+
+ As a convenience wrapper for logging, you can replace the above with:
+ <pre>
+ if (possibly_very_frequent_event()) {
+ static ratelim_t warning_limit = RATELIM_INIT(300);
+ log_fn_ratelim(&warning_limit, LOG_WARN, LD_GENERAL,
+ "The event occurred!");
+ }
+ </pre>
*/
typedef struct ratelim_t {
int rate;
@@ -306,6 +325,8 @@ enum stream_status {
IO_STREAM_CLOSED
};
+const char *stream_status_to_string(enum stream_status stream_status);
+
enum stream_status get_string_from_pipe(FILE *stream, char *buf, size_t count);
/** Return values from file_status(); see that function's documentation
@@ -360,8 +381,14 @@ struct stat;
#endif
char *read_file_to_str(const char *filename, int flags, struct stat *stat_out)
ATTR_MALLOC;
-const char *parse_config_line_from_str(const char *line,
- char **key_out, char **value_out);
+char *read_file_to_str_until_eof(int fd, size_t max_bytes_to_read,
+ size_t *sz_out)
+ ATTR_MALLOC;
+const char *parse_config_line_from_str_verbose(const char *line,
+ char **key_out, char **value_out,
+ const char **err_out);
+#define parse_config_line_from_str(line,key_out,value_out) \
+ parse_config_line_from_str_verbose((line),(key_out),(value_out),NULL)
char *expand_filename(const char *filename);
struct smartlist_t *tor_listdir(const char *dirname);
int path_is_relative(const char *filename);
@@ -373,7 +400,8 @@ void write_pidfile(char *filename);
/* Port forwarding */
void tor_check_port_forwarding(const char *filename,
- int dir_port, int or_port, time_t now);
+ struct smartlist_t *ports_to_forward,
+ time_t now);
typedef struct process_handle_t process_handle_t;
typedef struct process_environment_t process_environment_t;
@@ -464,10 +492,34 @@ HANDLE tor_process_get_stdout_pipe(process_handle_t *process_handle);
FILE *tor_process_get_stdout_pipe(process_handle_t *process_handle);
#endif
+#ifdef _WIN32
+struct smartlist_t *
+tor_get_lines_from_handle(HANDLE *handle,
+ enum stream_status *stream_status);
+#else
+struct smartlist_t *
+tor_get_lines_from_handle(FILE *handle,
+ enum stream_status *stream_status);
+#endif
+
int tor_terminate_process(process_handle_t *process_handle);
void tor_process_handle_destroy(process_handle_t *process_handle,
int also_terminate_process);
+/* ===== Insecure rng */
+typedef struct tor_weak_rng_t {
+ uint32_t state;
+} tor_weak_rng_t;
+
+#define TOR_WEAK_RNG_INIT {383745623}
+#define TOR_WEAK_RANDOM_MAX (INT_MAX)
+void tor_init_weak_random(tor_weak_rng_t *weak_rng, unsigned seed);
+int32_t tor_weak_random(tor_weak_rng_t *weak_rng);
+int32_t tor_weak_random_range(tor_weak_rng_t *rng, int32_t top);
+/** Randomly return true according to <b>rng</b> with probability 1 in
+ * <b>n</b> */
+#define tor_weak_random_one_in_n(rng, n) (0==tor_weak_random_range((rng),(n)))
+
#ifdef UTIL_PRIVATE
/* Prototypes for private functions only used by util.c (and unit tests) */