diff options
-rw-r--r-- | changes/bug1240 | 8 | ||||
-rw-r--r-- | changes/bug3825b | 7 | ||||
-rw-r--r-- | changes/bug4531_take2 | 5 | ||||
-rw-r--r-- | changes/portability_01_haiku | 14 | ||||
-rw-r--r-- | configure.in | 16 | ||||
-rw-r--r-- | src/or/Makefile.am | 2 | ||||
-rw-r--r-- | src/or/config.c | 30 | ||||
-rw-r--r-- | src/or/config.h | 2 | ||||
-rw-r--r-- | src/or/connection.c | 37 | ||||
-rw-r--r-- | src/or/connection_or.c | 5 | ||||
-rw-r--r-- | src/or/main.c | 7 | ||||
-rw-r--r-- | src/or/or.h | 5 | ||||
-rw-r--r-- | src/or/rendservice.c | 128 | ||||
-rw-r--r-- | src/or/transports.c | 7 | ||||
-rw-r--r-- | src/test/Makefile.am | 8 | ||||
-rw-r--r-- | src/tools/Makefile.am | 8 |
16 files changed, 237 insertions, 52 deletions
diff --git a/changes/bug1240 b/changes/bug1240 new file mode 100644 index 0000000000..657066491c --- /dev/null +++ b/changes/bug1240 @@ -0,0 +1,8 @@ + o Minor bugfixes: + - When running with an older Linux kernel that erroneously responds + to strange nmap behavior by having accept() return successfully + with a zero-length socket, just close the connection. Previously, + we would try harder to learn the remote address: but there was no + such remote address to learn, and our method for trying to learn + it was incorrect. Fixes bugs #1240, #4745, and #4747. Bugfix on + 0.1.0.3-rc. Reported and diagnosed by "r1eo". diff --git a/changes/bug3825b b/changes/bug3825b new file mode 100644 index 0000000000..08c0c2de73 --- /dev/null +++ b/changes/bug3825b @@ -0,0 +1,7 @@ + o Major features: + + - Adjust the number of introduction points that a hidden service + will try to maintain based on how long its introduction points + remain in use and how many introductions they handle. Fixes + part of bug 3825. + diff --git a/changes/bug4531_take2 b/changes/bug4531_take2 new file mode 100644 index 0000000000..fd4f5f0c46 --- /dev/null +++ b/changes/bug4531_take2 @@ -0,0 +1,5 @@ + o Minor bugfixes: + - Fix null-pointer access that could occur if TLS allocation failed. + Fixes bug 4531; bugfix on 0.2.0.20-rc. Found by "troll_un". This was + erroneously listed as fixed in 0.2.3.9-alpha, but the fix had + accidentally been reverted. diff --git a/changes/portability_01_haiku b/changes/portability_01_haiku new file mode 100644 index 0000000000..74887fe0c3 --- /dev/null +++ b/changes/portability_01_haiku @@ -0,0 +1,14 @@ + o Minor buxfixes: + - During configure, search for library containing cos function as + libm lives in libcore on some platforms (BeOS/Haiku). + Linking against libm was hard-coded before. Bugfix on + 0.2.2.2-alpha, fixes the first part of bug 4727. Patch and + analysis by Martin Hebnes Pedersen. + - Preprocessor directives should not be put inside the arguments + of a macro. This would break compilation with GCC releases prior + to version 3.3. We would never recommend such an old GCC + version, but it is apparently required for binary compatibility + on some platforms (namely, certain builds of Haiku). Bugfix on + 0.2.3.3-alpha, fixes the other part of bug 4727. Patch and + analysis by Martin Hebnes Pedersen. + diff --git a/configure.in b/configure.in index b05e935343..1f045f1349 100644 --- a/configure.in +++ b/configure.in @@ -279,7 +279,7 @@ fi AC_C_BIGENDIAN -AC_SEARCH_LIBS(socket, [socket]) +AC_SEARCH_LIBS(socket, [socket network]) AC_SEARCH_LIBS(gethostbyname, [nsl]) AC_SEARCH_LIBS(dlopen, [dl]) AC_SEARCH_LIBS(inet_aton, [resolv]) @@ -483,6 +483,20 @@ fi AC_SUBST(TOR_LIBEVENT_LIBS) dnl ------------------------------------------------------ +dnl Where do you live, libm? + +dnl On some platforms (Haiku/BeOS) the math library is +dnl part of libroot. In which case don't link against lm +TOR_LIB_MATH="" +save_LIBS="$LIBS" +AC_SEARCH_LIBS(pow, [m], , AC_MSG_ERROR([Could not find pow in libm or libc.])) +if test "$ac_cv_search_pow" != "none required"; then + TOR_LIB_MATH="$ac_cv_search_pow" +fi +LIBS="$save_LIBS" +AC_SUBST(TOR_LIB_MATH) + +dnl ------------------------------------------------------ dnl Where do you live, openssl? And how do we call you? tor_openssl_pkg_redhat="openssl" diff --git a/src/or/Makefile.am b/src/or/Makefile.am index a5682081ae..57f5dd65e4 100644 --- a/src/or/Makefile.am +++ b/src/or/Makefile.am @@ -74,7 +74,7 @@ AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \ tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@ tor_LDADD = ./libtor.a ../common/libor.a ../common/libor-crypto.a \ ../common/libor-event.a \ - @TOR_ZLIB_LIBS@ -lm @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \ + @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \ @TOR_LIB_WS32@ @TOR_LIB_GDI@ noinst_HEADERS = \ diff --git a/src/or/config.c b/src/or/config.c index 073b44d5e6..521f760051 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -6828,21 +6828,29 @@ get_transport_bindaddr(const char *line, const char *transport) return NULL; } -/** Return a static string containing the address:port a proxy - * transport should bind on. */ -const char * +/** Return a string containing the address:port that a proxy transport + * should bind on. The string is stored on the heap and must be freed + * by the caller of this function. */ +char * get_bindaddr_for_transport(const char *transport) { - static const char default_addrport[] = "127.0.0.1:0"; - const char *bindaddr = NULL; + char *default_addrport = NULL; + const char *stored_bindaddr = NULL; config_line_t *line = get_transport_in_state_by_name(transport); - if (!line) - return default_addrport; - - bindaddr = get_transport_bindaddr(line->value, transport); - - return bindaddr ? bindaddr : default_addrport; + if (!line) /* Found no references in state for this transport. */ + goto no_bindaddr_found; + + stored_bindaddr = get_transport_bindaddr(line->value, transport); + if (stored_bindaddr) /* found stored bindaddr in state file. */ + return tor_strdup(stored_bindaddr); + + no_bindaddr_found: + /** If we didn't find references for this pluggable transport in the + state file, we should instruct the pluggable transport proxy to + listen on INADDR_ANY on a random ephemeral port. */ + tor_asprintf(&default_addrport, "%s:%s", fmt_addr32(INADDR_ANY), "0"); + return default_addrport; } /** Save <b>transport</b> listening on <b>addr</b>:<b>port</b> to diff --git a/src/or/config.h b/src/or/config.h index 2d94192d3b..88258c133e 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -77,7 +77,7 @@ int options_need_geoip_info(const or_options_t *options, void save_transport_to_state(const char *transport_name, const tor_addr_t *addr, uint16_t port); -const char *get_bindaddr_for_transport(const char *transport); +char *get_bindaddr_for_transport(const char *transport); int getinfo_helper_config(control_connection_t *conn, const char *question, char **answer, diff --git a/src/or/connection.c b/src/or/connection.c index 9283c98589..a6d5d8f1e4 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -1051,7 +1051,12 @@ connection_create_listener(const struct sockaddr *listensockaddr, } /** Do basic sanity checking on a newly received socket. Return 0 - * if it looks ok, else return -1. */ + * if it looks ok, else return -1. + * + * Notably, some TCP stacks can erroneously have accept() return successfully + * with socklen 0, when the client sends an RST before the accept call (as + * nmap does). We want to detect that, and not go on with the connection. + */ static int check_sockaddr(struct sockaddr *sa, int len, int level) { @@ -1117,14 +1122,14 @@ connection_handle_listener_read(connection_t *conn, int new_type) tor_socket_t news; /* the new socket */ connection_t *newconn; /* information about the remote peer when connecting to other routers */ - char addrbuf[256]; - struct sockaddr *remote = (struct sockaddr*)addrbuf; + struct sockaddr_storage addrbuf; + struct sockaddr *remote = (struct sockaddr*)&addrbuf; /* length of the remote address. Must be whatever accept() needs. */ socklen_t remotelen = (socklen_t)sizeof(addrbuf); const or_options_t *options = get_options(); tor_assert((size_t)remotelen >= sizeof(struct sockaddr_in)); - memset(addrbuf, 0, sizeof(addrbuf)); + memset(&addrbuf, 0, sizeof(addrbuf)); news = tor_accept_socket(conn->s,remote,&remotelen); if (!SOCKET_OK(news)) { /* accept() error */ @@ -1161,21 +1166,9 @@ connection_handle_listener_read(connection_t *conn, int new_type) uint16_t port; if (check_sockaddr(remote, remotelen, LOG_INFO)<0) { log_info(LD_NET, - "accept() returned a strange address; trying getsockname()."); - remotelen=sizeof(addrbuf); - memset(addrbuf, 0, sizeof(addrbuf)); - if (getsockname(news, remote, &remotelen)<0) { - int e = tor_socket_errno(news); - log_warn(LD_NET, "getsockname() for new connection failed: %s", - tor_socket_strerror(e)); - } else { - if (check_sockaddr((struct sockaddr*)addrbuf, remotelen, - LOG_WARN) < 0) { - log_warn(LD_NET,"Something's wrong with this conn. Closing it."); - tor_close_socket(news); - return 0; - } - } + "accept() returned a strange address; closing connection."); + tor_close_socket(news); + return 0; } if (check_sockaddr_family_match(remote->sa_family, conn) < 0) { @@ -1303,7 +1296,7 @@ connection_connect(connection_t *conn, const char *address, { tor_socket_t s; int inprogress = 0; - char addrbuf[256]; + struct sockaddr_storage addrbuf; struct sockaddr *dest_addr; int dest_addr_len; const or_options_t *options = get_options(); @@ -1371,8 +1364,8 @@ connection_connect(connection_t *conn, const char *address, if (options->ConstrainedSockets) set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize); - memset(addrbuf,0,sizeof(addrbuf)); - dest_addr = (struct sockaddr*) addrbuf; + memset(&addrbuf,0,sizeof(addrbuf)); + dest_addr = (struct sockaddr*) &addrbuf; dest_addr_len = tor_addr_to_sockaddr(addr, port, dest_addr, sizeof(addrbuf)); tor_assert(dest_addr_len > 0); diff --git a/src/or/connection_or.c b/src/or/connection_or.c index cbe678d6cf..7609138e68 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -1099,12 +1099,13 @@ connection_tls_start_handshake(or_connection_t *conn, int receiving) conn->_base.state = OR_CONN_STATE_TLS_HANDSHAKING; tor_assert(!conn->tls); conn->tls = tor_tls_new(conn->_base.s, receiving); - tor_tls_set_logged_address(conn->tls, // XXX client and relay? - escaped_safe_str(conn->_base.address)); if (!conn->tls) { log_warn(LD_BUG,"tor_tls_new failed. Closing."); return -1; } + tor_tls_set_logged_address(conn->tls, // XXX client and relay? + escaped_safe_str(conn->_base.address)); + #ifdef USE_BUFFEREVENTS if (connection_type_uses_bufferevent(TO_CONN(conn))) { const int filtering = get_options()->_UseFilteringSSLBufferevents; diff --git a/src/or/main.c b/src/or/main.c index 74583b2ea0..1ba33957a6 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -2268,13 +2268,12 @@ tor_init(int argc, char *argv[]) { const char *version = get_version(); - log_notice(LD_GENERAL, "Tor v%s%s running on %s.", version, #ifdef USE_BUFFEREVENTS - " (with bufferevents)", + log_notice(LD_GENERAL, "Tor v%s (with bufferevents) running on %s.", + version, get_uname()); #else - "", + log_notice(LD_GENERAL, "Tor v%s running on %s.", version, get_uname()); #endif - get_uname()); log_notice(LD_GENERAL, "Tor can't help you if you use it wrong! " "Learn how to be safe at " diff --git a/src/or/or.h b/src/or/or.h index 6ff02ee36c..63ff5c4b31 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -4114,6 +4114,11 @@ typedef struct rend_intro_point_t { * included in the last HS descriptor we generated. */ unsigned int listed_in_last_desc : 1; + /** (Service side only) Flag indicating that + * rend_service_note_removing_intro_point has been called for this + * intro point. */ + unsigned int rend_service_note_removing_intro_point_called : 1; + /** (Service side only) A digestmap recording the INTRODUCE2 cells * this intro point's circuit has received. Each key is the digest * of the RSA-encrypted part of a received INTRODUCE2 cell; each diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 177f3bf23c..76caeffd0f 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -28,6 +28,7 @@ static origin_circuit_t *find_intro_circuit(rend_intro_point_t *intro, const char *pk_digest); static rend_intro_point_t *find_intro_point(origin_circuit_t *circ); +static int intro_point_accepted_intro_count(rend_intro_point_t *intro); static int intro_point_should_expire_now(rend_intro_point_t *intro, time_t now); @@ -115,6 +116,17 @@ num_rend_services(void) return smartlist_len(rend_service_list); } +/** Return a string identifying <b>service</b>, suitable for use in a + * log message. The result does not need to be freed, but may be + * overwritten by the next call to this function. */ +static const char * +rend_service_describe_for_log(rend_service_t *service) +{ + /* XXX024 Use this function throughout rendservice.c. */ + /* XXX024 Return a more useful description? */ + return safe_str_client(service->service_id); +} + /** Helper: free storage held by a single service authorized client entry. */ static void rend_authorized_client_free(rend_authorized_client_t *client) @@ -914,6 +926,104 @@ clean_accepted_intro_dh_parts(rend_service_t *service, time_t now) } DIGESTMAP_FOREACH_END; } +/** Called when <b>intro</b> will soon be removed from + * <b>service</b>'s list of intro points. */ +static void +rend_service_note_removing_intro_point(rend_service_t *service, + rend_intro_point_t *intro) +{ + time_t now = time(NULL); + + /* Don't process an intro point twice here. */ + if (intro->rend_service_note_removing_intro_point_called) { + return; + } else { + intro->rend_service_note_removing_intro_point_called = 1; + } + + /* Update service->n_intro_points_wanted based on how long intro + * lasted and how many introductions it handled. */ + if (intro->time_published == -1) { + /* This intro point was never used. Don't change + * n_intro_points_wanted. */ + } else { + /* We want to increase the number of introduction points service + * operates if intro was heavily used, or decrease the number of + * intro points if intro was lightly used. + * + * We consider an intro point's target 'usage' to be + * INTRO_POINT_LIFETIME_INTRODUCTIONS introductions in + * INTRO_POINT_LIFETIME_MIN_SECONDS seconds. To calculate intro's + * fraction of target usage, we divide the fraction of + * _LIFETIME_INTRODUCTIONS introductions that it has handled by + * the fraction of _LIFETIME_MIN_SECONDS for which it existed. + * + * Then we take the reciprocal of that fraction of desired usage, + * then multiply by a fudge factor of 1.5, to decide how many new + * introduction points should ideally replace intro (which is now + * closed or soon to be closed). In theory, assuming that + * introduction load is distributed equally across all intro + * points and ignoring the fact that different intro points are + * established and closed at different times, that number of intro + * points should bring all of our intro points exactly to our + * target usage. + * + * Then we clamp that number to a number of intro points we might + * be willing to replace this intro point with and turn it into an + * integer. then we clamp it again to the number of new intro + * points we could establish now, then we adjust + * service->n_intro_points_wanted and let rend_services_introduce + * create the new intro points we want (if any). + */ + double fractional_n_intro_points_wanted_to_replace_this_one = + ((((double)now - intro->time_published) / + INTRO_POINT_LIFETIME_MIN_SECONDS) * + ((intro_point_accepted_intro_count(intro)) / + INTRO_POINT_LIFETIME_INTRODUCTIONS)) * 1.5; + unsigned int n_intro_points_wanted_to_replace_this_one; + unsigned int n_intro_points_wanted_now; + unsigned int n_intro_points_really_wanted_now; + int n_intro_points_really_replacing_this_one; + + if (fractional_n_intro_points_wanted_to_replace_this_one > + NUM_INTRO_POINTS_MAX) { + n_intro_points_wanted_to_replace_this_one = NUM_INTRO_POINTS_MAX; + } else if (fractional_n_intro_points_wanted_to_replace_this_one < 0) { + n_intro_points_wanted_to_replace_this_one = 0; + } else { + n_intro_points_wanted_to_replace_this_one = (unsigned) + fractional_n_intro_points_wanted_to_replace_this_one; + } + + n_intro_points_wanted_now = + service->n_intro_points_wanted + + n_intro_points_wanted_to_replace_this_one - 1; + + if (n_intro_points_wanted_now < NUM_INTRO_POINTS_DEFAULT) { + /* XXXX This should be NUM_INTRO_POINTS_MIN instead. Perhaps + * another use of NUM_INTRO_POINTS_DEFAULT should be, too. */ + n_intro_points_really_wanted_now = NUM_INTRO_POINTS_DEFAULT; + } else if (n_intro_points_wanted_now > NUM_INTRO_POINTS_MAX) { + n_intro_points_really_wanted_now = NUM_INTRO_POINTS_MAX; + } else { + n_intro_points_really_wanted_now = n_intro_points_wanted_now; + } + + n_intro_points_really_replacing_this_one = + n_intro_points_really_wanted_now - service->n_intro_points_wanted + 1; + + log_info(LD_REND, "Replacing closing intro point for service %s " + "with %d new intro points (wanted %g replacements); " + "service will now try to have %u intro points", + rend_service_describe_for_log(service), + n_intro_points_really_replacing_this_one, + fractional_n_intro_points_wanted_to_replace_this_one, + n_intro_points_really_wanted_now); + + service->n_intro_points_wanted = n_intro_points_really_wanted_now; + } +} + /****** * Handle cells ******/ @@ -1937,6 +2047,18 @@ upload_service_descriptor(rend_service_t *service) service->desc_is_dirty = 0; } +/** Return the number of INTRODUCE2 cells an intro point has + * received. */ +static int +intro_point_accepted_intro_count(rend_intro_point_t *intro) +{ + if (intro->accepted_intro_rsa_parts == NULL) { + return 0; + } else { + return digestmap_size(intro->accepted_intro_rsa_parts); + } +} + /** Return non-zero iff <b>intro</b> should 'expire' now (i.e. we * should stop publishing it in new descriptors and eventually close * it). */ @@ -1957,8 +2079,7 @@ intro_point_should_expire_now(rend_intro_point_t *intro, return 1; } - if (intro->accepted_intro_rsa_parts != NULL && - digestmap_size(intro->accepted_intro_rsa_parts) >= + if (intro_point_accepted_intro_count(intro) >= INTRO_POINT_LIFETIME_INTRODUCTIONS) { /* This intro point has been used too many times. Expire it now. */ return 1; @@ -2061,6 +2182,7 @@ rend_services_introduce(void) " (circuit disappeared).", safe_str_client(extend_info_describe(intro->extend_info)), safe_str_client(service->service_id)); + rend_service_note_removing_intro_point(service, intro); if (intro->time_expiring != -1) { log_info(LD_REND, "We were already expiring the intro point; " "no need to mark the HS descriptor as dirty over this."); @@ -2083,6 +2205,8 @@ rend_services_introduce(void) safe_str_client(extend_info_describe(intro->extend_info)), safe_str_client(service->service_id)); + rend_service_note_removing_intro_point(service, intro); + /* The polite (and generally Right) way to expire an intro * point is to establish a new one to replace it, publish a * new descriptor that doesn't list any expiring intro points, diff --git a/src/or/transports.c b/src/or/transports.c index 6ee4878689..abf9d884f7 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -919,13 +919,18 @@ static char * get_bindaddr_for_proxy(const managed_proxy_t *mp) { char *bindaddr = NULL; + char *bindaddr_tmp = NULL; smartlist_t *string_tmp = smartlist_create(); tor_assert(mp->is_server); SMARTLIST_FOREACH_BEGIN(mp->transports_to_launch, char *, t) { - tor_asprintf(&bindaddr, "%s-%s", t, get_bindaddr_for_transport(t)); + bindaddr_tmp = get_bindaddr_for_transport(t); + + tor_asprintf(&bindaddr, "%s-%s", t, bindaddr_tmp); smartlist_add(string_tmp, bindaddr); + + tor_free(bindaddr_tmp); } SMARTLIST_FOREACH_END(t); bindaddr = smartlist_join_strings(string_tmp, ",", 0, NULL); diff --git a/src/test/Makefile.am b/src/test/Makefile.am index 73de300719..31a464ee7a 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -31,15 +31,15 @@ test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ @TOR_LDFLAGS_libevent@ test_LDADD = ../or/libtor.a ../common/libor.a ../common/libor-crypto.a \ ../common/libor-event.a \ - @TOR_ZLIB_LIBS@ -lm @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \ - @TOR_LIB_WS32@ @TOR_LIB_GDI@ + @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ + @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ @TOR_LDFLAGS_libevent@ bench_LDADD = ../or/libtor.a ../common/libor.a ../common/libor-crypto.a \ ../common/libor-event.a \ - @TOR_ZLIB_LIBS@ -lm @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \ - @TOR_LIB_WS32@ @TOR_LIB_GDI@ + @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ + @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ noinst_HEADERS = \ tinytest.h \ diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am index a9a619757a..35b0a41f53 100644 --- a/src/tools/Makefile.am +++ b/src/tools/Makefile.am @@ -3,17 +3,19 @@ noinst_PROGRAMS = tor-checkkey tor_resolve_SOURCES = tor-resolve.c tor_resolve_LDFLAGS = -tor_resolve_LDADD = ../common/libor.a -lm @TOR_LIB_WS32@ +tor_resolve_LDADD = ../common/libor.a @TOR_LIB_MATH@ @TOR_LIB_WS32@ tor_gencert_SOURCES = tor-gencert.c tor_gencert_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ tor_gencert_LDADD = ../common/libor.a ../common/libor-crypto.a \ - -lm @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ + @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \ + @TOR_LIB_WS32@ @TOR_LIB_GDI@ tor_checkkey_SOURCES = tor-checkkey.c tor_checkkey_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ tor_checkkey_LDADD = ../common/libor.a ../common/libor-crypto.a \ - -lm @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ + @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \ + @TOR_LIB_WS32@ @TOR_LIB_GDI@ SUBDIRS = tor-fw-helper DIST_SUBDIRS = tor-fw-helper |