1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539 |
- const char circuitbuild_c_id[] =
- "$Id$";
- #include "or.h"
- extern circuit_t *global_circuitlist;
- typedef struct {
- char nickname[MAX_NICKNAME_LEN+1];
- char identity[DIGEST_LEN];
- uint8_t made_contact;
- time_t bad_since;
- time_t unreachable_since;
- time_t last_attempted;
- } entry_guard_t;
- static smartlist_t *entry_guards = NULL;
- static int entry_guards_dirty = 0;
- static int circuit_deliver_create_cell(circuit_t *circ,
- uint8_t cell_type, char *payload);
- static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit);
- static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath);
- static int onion_extend_cpath(origin_circuit_t *circ);
- static int count_acceptable_routers(smartlist_t *routers);
- static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
- static routerinfo_t *choose_random_entry(cpath_build_state_t *state);
- static void entry_guards_changed(void);
- static uint16_t
- get_unique_circ_id_by_conn(or_connection_t *conn)
- {
- uint16_t test_circ_id;
- uint16_t attempts=0;
- uint16_t high_bit;
- tor_assert(conn);
- high_bit = (conn->circ_id_type == CIRC_ID_TYPE_HIGHER) ? 1<<15 : 0;
- do {
-
- test_circ_id = conn->next_circ_id++;
- if (test_circ_id == 0 || test_circ_id >= 1<<15) {
- test_circ_id = 1;
- conn->next_circ_id = 2;
- }
- if (++attempts > 1<<15) {
-
- log_warn(LD_CIRC,"No unused circ IDs. Failing.");
- return 0;
- }
- test_circ_id |= high_bit;
- } while (circuit_get_by_circid_orconn(test_circ_id, conn));
- return test_circ_id;
- }
- static char *
- circuit_list_path_impl(origin_circuit_t *circ, int verbose, int verbose_names)
- {
- crypt_path_t *hop;
- smartlist_t *elements;
- const char *states[] = {"closed", "waiting for keys", "open"};
- char buf[128];
- char *s;
- elements = smartlist_create();
- if (verbose) {
- const char *nickname = build_state_get_exit_nickname(circ->build_state);
- tor_snprintf(buf, sizeof(buf), "%s%s circ (length %d%s%s):",
- circ->build_state->is_internal ? "internal" : "exit",
- circ->build_state->need_uptime ? " (high-uptime)" : "",
- circ->build_state->desired_path_len,
- circ->_base.state == CIRCUIT_STATE_OPEN ? "" : ", exit ",
- circ->_base.state == CIRCUIT_STATE_OPEN ? "" :
- (nickname?nickname:"*unnamed*"));
- smartlist_add(elements, tor_strdup(buf));
- }
- hop = circ->cpath;
- do {
- routerinfo_t *ri;
- char *elt;
- if (!hop)
- break;
- if (!verbose && hop->state != CPATH_STATE_OPEN)
- break;
- if (!hop->extend_info)
- break;
- if (verbose_names) {
- elt = tor_malloc(MAX_VERBOSE_NICKNAME_LEN+1);
- if ((ri = router_get_by_digest(hop->extend_info->identity_digest))) {
- router_get_verbose_nickname(elt, ri);
- } else if (hop->extend_info->nickname &&
- is_legal_nickname(hop->extend_info->nickname)) {
- elt[0] = '$';
- base16_encode(elt+1, HEX_DIGEST_LEN+1,
- hop->extend_info->identity_digest, DIGEST_LEN);
- elt[HEX_DIGEST_LEN+1]= '~';
- strlcpy(elt+HEX_DIGEST_LEN+2,
- hop->extend_info->nickname, MAX_NICKNAME_LEN+1);
- } else {
- elt[0] = '$';
- base16_encode(elt+1, HEX_DIGEST_LEN+1,
- hop->extend_info->identity_digest, DIGEST_LEN);
- }
- } else {
- if ((ri = router_get_by_digest(hop->extend_info->identity_digest)) &&
- ri->is_named) {
- elt = tor_strdup(hop->extend_info->nickname);
- } else {
- elt = tor_malloc(HEX_DIGEST_LEN+2);
- elt[0] = '$';
- base16_encode(elt+1, HEX_DIGEST_LEN+1,
- hop->extend_info->identity_digest, DIGEST_LEN);
- }
- }
- tor_assert(elt);
- if (verbose) {
- size_t len = strlen(elt)+2+strlen(states[hop->state])+1;
- char *v = tor_malloc(len);
- tor_assert(hop->state <= 2);
- tor_snprintf(v,len,"%s(%s)",elt,states[hop->state]);
- smartlist_add(elements, v);
- tor_free(elt);
- } else {
- smartlist_add(elements, elt);
- }
- hop = hop->next;
- } while (hop != circ->cpath);
- s = smartlist_join_strings(elements, verbose?" ":",", 0, NULL);
- SMARTLIST_FOREACH(elements, char*, cp, tor_free(cp));
- smartlist_free(elements);
- return s;
- }
- char *
- circuit_list_path(origin_circuit_t *circ, int verbose)
- {
- return circuit_list_path_impl(circ, verbose, 0);
- }
- char *
- circuit_list_path_for_controller(origin_circuit_t *circ)
- {
- return circuit_list_path_impl(circ, 0, 1);
- }
- void
- circuit_log_path(int severity, unsigned int domain, origin_circuit_t *circ)
- {
- char *s = circuit_list_path(circ,1);
- log(severity,domain,"%s",s);
- tor_free(s);
- }
- void
- circuit_rep_hist_note_result(origin_circuit_t *circ)
- {
- crypt_path_t *hop;
- char *prev_digest = NULL;
- routerinfo_t *router;
- hop = circ->cpath;
- if (!hop)
- return;
- if (server_mode(get_options())) {
- routerinfo_t *me = router_get_my_routerinfo();
- if (!me)
- return;
- prev_digest = me->cache_info.identity_digest;
- }
- do {
- router = router_get_by_digest(hop->extend_info->identity_digest);
- if (router) {
- if (prev_digest) {
- if (hop->state == CPATH_STATE_OPEN)
- rep_hist_note_extend_succeeded(prev_digest,
- router->cache_info.identity_digest);
- else {
- rep_hist_note_extend_failed(prev_digest,
- router->cache_info.identity_digest);
- break;
- }
- }
- prev_digest = router->cache_info.identity_digest;
- } else {
- prev_digest = NULL;
- }
- hop=hop->next;
- } while (hop!=circ->cpath);
- }
- static int
- onion_populate_cpath(origin_circuit_t *circ)
- {
- int r;
- again:
- r = onion_extend_cpath(circ);
- if (r < 0) {
- log_info(LD_CIRC,"Generating cpath hop failed.");
- return -1;
- }
- if (r == 0)
- goto again;
- return 0;
- }
- origin_circuit_t *
- origin_circuit_init(uint8_t purpose, int onehop_tunnel,
- int need_uptime, int need_capacity, int internal)
- {
-
- origin_circuit_t *circ = origin_circuit_new();
- circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OR_WAIT);
- circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
- circ->build_state->onehop_tunnel = onehop_tunnel;
- circ->build_state->need_uptime = need_uptime;
- circ->build_state->need_capacity = need_capacity;
- circ->build_state->is_internal = internal;
- circ->_base.purpose = purpose;
- return circ;
- }
- origin_circuit_t *
- circuit_establish_circuit(uint8_t purpose, int onehop_tunnel,
- extend_info_t *info,
- int need_uptime, int need_capacity, int internal)
- {
- origin_circuit_t *circ;
- int err_reason = 0;
- circ = origin_circuit_init(purpose, onehop_tunnel,
- need_uptime, need_capacity, internal);
- if (onion_pick_cpath_exit(circ, info) < 0 ||
- onion_populate_cpath(circ) < 0) {
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_NOPATH);
- return NULL;
- }
- control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED, 0);
- if ((err_reason = circuit_handle_first_hop(circ)) < 0) {
- circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason);
- return NULL;
- }
- return circ;
- }
- int
- circuit_handle_first_hop(origin_circuit_t *circ)
- {
- crypt_path_t *firsthop;
- or_connection_t *n_conn;
- char tmpbuf[INET_NTOA_BUF_LEN];
- struct in_addr in;
- int err_reason = 0;
- firsthop = onion_next_hop_in_cpath(circ->cpath);
- tor_assert(firsthop);
- tor_assert(firsthop->extend_info);
-
- in.s_addr = htonl(firsthop->extend_info->addr);
- tor_inet_ntoa(&in, tmpbuf, sizeof(tmpbuf));
- log_debug(LD_CIRC,"Looking for firsthop '%s:%u'",tmpbuf,
- firsthop->extend_info->port);
-
- memcpy(circ->_base.n_conn_id_digest, firsthop->extend_info->identity_digest,
- DIGEST_LEN);
- n_conn = connection_or_get_by_identity_digest(
- firsthop->extend_info->identity_digest);
-
- if (!n_conn || n_conn->_base.state != OR_CONN_STATE_OPEN ||
- (n_conn->_base.or_is_obsolete &&
- router_digest_version_as_new_as(firsthop->extend_info->identity_digest,
- "0.1.1.9-alpha-cvs"))) {
-
- circ->_base.n_addr = firsthop->extend_info->addr;
- circ->_base.n_port = firsthop->extend_info->port;
- if (!n_conn || n_conn->_base.or_is_obsolete) {
- n_conn = connection_or_connect(firsthop->extend_info->addr,
- firsthop->extend_info->port,
- firsthop->extend_info->identity_digest);
- if (!n_conn) {
- log_info(LD_CIRC,"connect to firsthop failed. Closing.");
- return -END_CIRC_REASON_CONNECTFAILED;
- }
- }
- log_debug(LD_CIRC,"connecting in progress (or finished). Good.");
-
- return 0;
- } else {
- circ->_base.n_addr = n_conn->_base.addr;
- circ->_base.n_port = n_conn->_base.port;
- circ->_base.n_conn = n_conn;
- log_debug(LD_CIRC,"Conn open. Delivering first onion skin.");
- if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) {
- log_info(LD_CIRC,"circuit_send_next_onion_skin failed.");
- return err_reason;
- }
- }
- return 0;
- }
- extern smartlist_t *circuits_pending_or_conns;
- void
- circuit_n_conn_done(or_connection_t *or_conn, int status)
- {
- smartlist_t *changed_circs;
- int err_reason = 0;
- log_debug(LD_CIRC,"or_conn to %s, status=%d",
- or_conn->nickname ? or_conn->nickname : "NULL", status);
- if (!circuits_pending_or_conns)
- return;
- changed_circs = smartlist_create();
- SMARTLIST_FOREACH(circuits_pending_or_conns, circuit_t *, circ,
- {
- if (circ->marked_for_close)
- continue;
- tor_assert(circ->state == CIRCUIT_STATE_OR_WAIT);
- if (!circ->n_conn &&
- !memcmp(or_conn->identity_digest, circ->n_conn_id_digest,
- DIGEST_LEN)) {
- if (!status) {
- log_info(LD_CIRC,"or_conn failed. Closing circ.");
- circuit_mark_for_close(circ, END_CIRC_REASON_OR_CONN_CLOSED);
- continue;
- }
- log_debug(LD_CIRC, "Found circ, sending create cell.");
-
- circ->n_conn = or_conn;
- if (CIRCUIT_IS_ORIGIN(circ)) {
- if ((err_reason =
- circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ))) < 0) {
- log_info(LD_CIRC,
- "send_next_onion_skin failed; circuit marked for closing.");
- circuit_mark_for_close(circ, -err_reason);
- continue;
-
- }
- } else {
-
- tor_assert(circ->onionskin);
- if (circuit_deliver_create_cell(circ,CELL_CREATE,circ->onionskin)<0) {
- circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
- continue;
- }
- tor_free(circ->onionskin);
-
- smartlist_add(changed_circs, circ);
- }
- }
- });
- SMARTLIST_FOREACH(changed_circs, circuit_t *, circ,
- circuit_set_state(circ, CIRCUIT_STATE_OPEN));
- smartlist_free(changed_circs);
- }
- static int
- circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type,
- char *payload)
- {
- cell_t cell;
- uint16_t id;
- tor_assert(circ);
- tor_assert(circ->n_conn);
- tor_assert(payload);
- tor_assert(cell_type == CELL_CREATE || cell_type == CELL_CREATE_FAST);
- id = get_unique_circ_id_by_conn(circ->n_conn);
- if (!id) {
- log_warn(LD_CIRC,"failed to get unique circID.");
- return -1;
- }
- log_debug(LD_CIRC,"Chosen circID %u.", id);
- circuit_set_n_circid_orconn(circ, id, circ->n_conn);
- memset(&cell, 0, sizeof(cell_t));
- cell.command = cell_type;
- cell.circ_id = circ->n_circ_id;
- memcpy(cell.payload, payload, ONIONSKIN_CHALLENGE_LEN);
- connection_or_write_cell_to_buf(&cell, circ->n_conn);
- return 0;
- }
- int
- inform_testing_reachability(void)
- {
- char dirbuf[128];
- routerinfo_t *me = router_get_my_routerinfo();
- if (!me)
- return 0;
- if (me->dir_port)
- tor_snprintf(dirbuf, sizeof(dirbuf), " and DirPort %s:%d",
- me->address, me->dir_port);
- log(LOG_NOTICE, LD_OR, "Now checking whether ORPort %s:%d%s %s reachable... "
- "(this may take up to %d minutes -- look for log "
- "messages indicating success)",
- me->address, me->or_port,
- me->dir_port ? dirbuf : "",
- me->dir_port ? "are" : "is",
- TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60);
- return 1;
- }
- static INLINE int
- should_use_create_fast_for_router(routerinfo_t *router)
- {
- or_options_t *options = get_options();
- if (!options->FastFirstHopPK || server_mode(options))
- return 0;
- else if (!router || !router->platform ||
- !tor_version_as_new_as(router->platform, "0.1.0.6-rc"))
- return 0;
- else
- return 1;
- }
- int
- circuit_send_next_onion_skin(origin_circuit_t *circ)
- {
- crypt_path_t *hop;
- routerinfo_t *router;
- char payload[2+4+DIGEST_LEN+ONIONSKIN_CHALLENGE_LEN];
- char *onionskin;
- size_t payload_len;
- tor_assert(circ);
- if (circ->cpath->state == CPATH_STATE_CLOSED) {
- int fast;
- uint8_t cell_type;
- log_debug(LD_CIRC,"First skin; sending create cell.");
- router = router_get_by_digest(circ->_base.n_conn->identity_digest);
- fast = should_use_create_fast_for_router(router);
- if (! fast) {
-
- cell_type = CELL_CREATE;
- if (onion_skin_create(circ->cpath->extend_info->onion_key,
- &(circ->cpath->dh_handshake_state),
- payload) < 0) {
- log_warn(LD_CIRC,"onion_skin_create (first hop) failed.");
- return - END_CIRC_REASON_INTERNAL;
- }
- } else {
-
- cell_type = CELL_CREATE_FAST;
- memset(payload, 0, sizeof(payload));
- crypto_rand(circ->cpath->fast_handshake_state,
- sizeof(circ->cpath->fast_handshake_state));
- memcpy(payload, circ->cpath->fast_handshake_state,
- sizeof(circ->cpath->fast_handshake_state));
- }
- if (circuit_deliver_create_cell(TO_CIRCUIT(circ), cell_type, payload) < 0)
- return - END_CIRC_REASON_RESOURCELIMIT;
- circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
- circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
- log_info(LD_CIRC,"First hop: finished sending %s cell to '%s'",
- fast ? "CREATE_FAST" : "CREATE",
- router ? router->nickname : "<unnamed>");
- } else {
- tor_assert(circ->cpath->state == CPATH_STATE_OPEN);
- tor_assert(circ->_base.state == CIRCUIT_STATE_BUILDING);
- log_debug(LD_CIRC,"starting to send subsequent skin.");
- hop = onion_next_hop_in_cpath(circ->cpath);
- if (!hop) {
-
- circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
- log_info(LD_CIRC,"circuit built!");
- circuit_reset_failure_count(0);
- if (!has_completed_circuit && !circ->build_state->onehop_tunnel) {
- or_options_t *options = get_options();
- has_completed_circuit=1;
-
- log(LOG_NOTICE, LD_GENERAL,
- "Tor has successfully opened a circuit. "
- "Looks like client functionality is working.");
- control_event_client_status(LOG_NOTICE, "CIRCUIT_ESTABLISHED");
- if (server_mode(options) && !check_whether_orport_reachable()) {
- inform_testing_reachability();
- consider_testing_reachability(1, 1);
- }
- }
- circuit_rep_hist_note_result(circ);
- circuit_has_opened(circ);
- return 0;
- }
- *(uint32_t*)payload = htonl(hop->extend_info->addr);
- *(uint16_t*)(payload+4) = htons(hop->extend_info->port);
- onionskin = payload+2+4;
- memcpy(payload+2+4+ONIONSKIN_CHALLENGE_LEN,
- hop->extend_info->identity_digest, DIGEST_LEN);
- payload_len = 2+4+ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN;
- if (onion_skin_create(hop->extend_info->onion_key,
- &(hop->dh_handshake_state), onionskin) < 0) {
- log_warn(LD_CIRC,"onion_skin_create failed.");
- return - END_CIRC_REASON_INTERNAL;
- }
- log_debug(LD_CIRC,"Sending extend relay cell.");
-
- if (connection_edge_send_command(NULL, TO_CIRCUIT(circ),
- RELAY_COMMAND_EXTEND,
- payload, payload_len, hop->prev) < 0)
- return 0;
- hop->state = CPATH_STATE_AWAITING_KEYS;
- }
- return 0;
- }
- void
- circuit_note_clock_jumped(int seconds_elapsed)
- {
- int severity = server_mode(get_options()) ? LOG_WARN : LOG_NOTICE;
- log(severity, LD_GENERAL, "Your clock just jumped %d seconds %s; "
- "assuming established circuits no longer work.",
- seconds_elapsed >=0 ? seconds_elapsed : -seconds_elapsed,
- seconds_elapsed >=0 ? "forward" : "backward");
- control_event_general_status(LOG_WARN, "CLOCK_JUMPED TIME=%d",
- seconds_elapsed);
- has_completed_circuit=0;
- control_event_client_status(severity, "CIRCUIT_NOT_ESTABLISHED REASON=%s",
- "CLOCK_JUMPED");
- circuit_mark_all_unused_circs();
- circuit_expire_all_dirty_circs();
- }
- int
- circuit_extend(cell_t *cell, circuit_t *circ)
- {
- or_connection_t *n_conn;
- relay_header_t rh;
- char *onionskin;
- char *id_digest=NULL;
- if (circ->n_conn) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "n_conn already set. Bug/attack. Closing.");
- return -1;
- }
- if (!server_mode(get_options())) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Got an extend cell, but running as a client. Closing.");
- return -1;
- }
- relay_header_unpack(&rh, cell->payload);
- if (rh.length < 4+2+ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Wrong length %d on extend cell. Closing circuit.",
- rh.length);
- return -1;
- }
- circ->n_addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE));
- circ->n_port = ntohs(get_uint16(cell->payload+RELAY_HEADER_SIZE+4));
- onionskin = cell->payload+RELAY_HEADER_SIZE+4+2;
- id_digest = cell->payload+RELAY_HEADER_SIZE+4+2+ONIONSKIN_CHALLENGE_LEN;
- n_conn = connection_or_get_by_identity_digest(id_digest);
-
- if (!n_conn || n_conn->_base.state != OR_CONN_STATE_OPEN ||
- (n_conn->_base.or_is_obsolete &&
- router_digest_version_as_new_as(id_digest,"0.1.1.9-alpha-cvs"))) {
- struct in_addr in;
- char tmpbuf[INET_NTOA_BUF_LEN];
- in.s_addr = htonl(circ->n_addr);
- tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf));
- log_info(LD_CIRC|LD_OR,"Next router (%s:%d) not connected. Connecting.",
- tmpbuf, circ->n_port);
- circ->onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
- memcpy(circ->onionskin, onionskin, ONIONSKIN_CHALLENGE_LEN);
- circuit_set_state(circ, CIRCUIT_STATE_OR_WAIT);
-
- memcpy(circ->n_conn_id_digest, id_digest, DIGEST_LEN);
- if (n_conn && !n_conn->_base.or_is_obsolete) {
- circ->n_addr = n_conn->_base.addr;
- circ->n_port = n_conn->_base.port;
- } else {
-
- n_conn = connection_or_connect(circ->n_addr, circ->n_port, id_digest);
- if (!n_conn) {
- log_info(LD_CIRC,"Launching n_conn failed. Closing circuit.");
- circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
- return 0;
- }
- log_debug(LD_CIRC,"connecting in progress (or finished). Good.");
- }
-
- return 0;
- }
-
- circ->n_addr = n_conn->_base.addr;
- circ->n_port = n_conn->_base.port;
- circ->n_conn = n_conn;
- memcpy(circ->n_conn_id_digest, n_conn->identity_digest, DIGEST_LEN);
- log_debug(LD_CIRC,"n_conn is %s:%u",
- n_conn->_base.address,n_conn->_base.port);
- if (circuit_deliver_create_cell(circ, CELL_CREATE, onionskin) < 0)
- return -1;
- return 0;
- }
- int
- circuit_init_cpath_crypto(crypt_path_t *cpath, char *key_data, int reverse)
- {
- crypto_digest_env_t *tmp_digest;
- crypto_cipher_env_t *tmp_crypto;
- tor_assert(cpath);
- tor_assert(key_data);
- tor_assert(!(cpath->f_crypto || cpath->b_crypto ||
- cpath->f_digest || cpath->b_digest));
- cpath->f_digest = crypto_new_digest_env();
- crypto_digest_add_bytes(cpath->f_digest, key_data, DIGEST_LEN);
- cpath->b_digest = crypto_new_digest_env();
- crypto_digest_add_bytes(cpath->b_digest, key_data+DIGEST_LEN, DIGEST_LEN);
- if (!(cpath->f_crypto =
- crypto_create_init_cipher(key_data+(2*DIGEST_LEN),1))) {
- log_warn(LD_BUG,"Bug: forward cipher initialization failed.");
- return -1;
- }
- if (!(cpath->b_crypto =
- crypto_create_init_cipher(key_data+(2*DIGEST_LEN)+CIPHER_KEY_LEN,0))) {
- log_warn(LD_BUG,"Bug: backward cipher initialization failed.");
- return -1;
- }
- if (reverse) {
- tmp_digest = cpath->f_digest;
- cpath->f_digest = cpath->b_digest;
- cpath->b_digest = tmp_digest;
- tmp_crypto = cpath->f_crypto;
- cpath->f_crypto = cpath->b_crypto;
- cpath->b_crypto = tmp_crypto;
- }
- return 0;
- }
- int
- circuit_finish_handshake(origin_circuit_t *circ, uint8_t reply_type,
- char *reply)
- {
- char keys[CPATH_KEY_MATERIAL_LEN];
- crypt_path_t *hop;
- if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS)
- hop = circ->cpath;
- else {
- hop = onion_next_hop_in_cpath(circ->cpath);
- if (!hop) {
- log_warn(LD_PROTOCOL,"got extended when circ already built? Closing.");
- return - END_CIRC_REASON_TORPROTOCOL;
- }
- }
- tor_assert(hop->state == CPATH_STATE_AWAITING_KEYS);
- if (reply_type == CELL_CREATED && hop->dh_handshake_state) {
- if (onion_skin_client_handshake(hop->dh_handshake_state, reply, keys,
- DIGEST_LEN*2+CIPHER_KEY_LEN*2) < 0) {
- log_warn(LD_CIRC,"onion_skin_client_handshake failed.");
- return -END_CIRC_REASON_TORPROTOCOL;
- }
-
- memcpy(hop->handshake_digest, reply+DH_KEY_LEN, DIGEST_LEN);
- } else if (reply_type == CELL_CREATED_FAST && !hop->dh_handshake_state) {
- if (fast_client_handshake(hop->fast_handshake_state, reply, keys,
- DIGEST_LEN*2+CIPHER_KEY_LEN*2) < 0) {
- log_warn(LD_CIRC,"fast_client_handshake failed.");
- return -END_CIRC_REASON_TORPROTOCOL;
- }
- memcpy(hop->handshake_digest, reply+DIGEST_LEN, DIGEST_LEN);
- } else {
- log_warn(LD_PROTOCOL,"CREATED cell type did not match CREATE cell type.");
- return -END_CIRC_REASON_TORPROTOCOL;
- }
- if (hop->dh_handshake_state) {
- crypto_dh_free(hop->dh_handshake_state);
- hop->dh_handshake_state = NULL;
- }
- memset(hop->fast_handshake_state, 0, sizeof(hop->fast_handshake_state));
- if (circuit_init_cpath_crypto(hop, keys, 0)<0) {
- return -END_CIRC_REASON_TORPROTOCOL;
- }
- hop->state = CPATH_STATE_OPEN;
- log_info(LD_CIRC,"Finished building %scircuit hop:",
- (reply_type == CELL_CREATED_FAST) ? "fast " : "");
- circuit_log_path(LOG_INFO,LD_CIRC,circ);
- control_event_circuit_status(circ, CIRC_EVENT_EXTENDED, 0);
- return 0;
- }
- int
- circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer)
- {
- tor_assert(circ);
- tor_assert(layer);
-
- circuit_mark_for_close(TO_CIRCUIT(circ),
- END_CIRC_REASON_FLAG_REMOTE|END_CIRC_REASON_OR_CONN_CLOSED);
- return 0;
- #if 0
- while (layer->next != circ->cpath) {
-
- victim = layer->next;
- log_debug(LD_CIRC, "Killing a layer of the cpath.");
- for (stream = circ->p_streams; stream; stream=stream->next_stream) {
- if (stream->cpath_layer == victim) {
- log_info(LD_APP, "Marking stream %d for close because of truncate.",
- stream->stream_id);
-
- connection_mark_unattached_ap(stream, END_STREAM_REASON_DESTROY);
- }
- }
- layer->next = victim->next;
- circuit_free_cpath_node(victim);
- }
- log_info(LD_CIRC, "finished");
- return 0;
- #endif
- }
- int
- onionskin_answer(or_circuit_t *circ, uint8_t cell_type, char *payload,
- char *keys)
- {
- cell_t cell;
- crypt_path_t *tmp_cpath;
- tmp_cpath = tor_malloc_zero(sizeof(crypt_path_t));
- tmp_cpath->magic = CRYPT_PATH_MAGIC;
- memset(&cell, 0, sizeof(cell_t));
- cell.command = cell_type;
- cell.circ_id = circ->p_circ_id;
- circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
- memcpy(cell.payload, payload,
- cell_type == CELL_CREATED ? ONIONSKIN_REPLY_LEN : DIGEST_LEN*2);
- log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.",
- (unsigned int)*(uint32_t*)(keys),
- (unsigned int)*(uint32_t*)(keys+20));
- if (circuit_init_cpath_crypto(tmp_cpath, keys, 0)<0) {
- log_warn(LD_BUG,"Circuit initialization failed");
- tor_free(tmp_cpath);
- return -1;
- }
- circ->n_digest = tmp_cpath->f_digest;
- circ->n_crypto = tmp_cpath->f_crypto;
- circ->p_digest = tmp_cpath->b_digest;
- circ->p_crypto = tmp_cpath->b_crypto;
- tmp_cpath->magic = 0;
- tor_free(tmp_cpath);
- if (cell_type == CELL_CREATED)
- memcpy(circ->handshake_digest, cell.payload+DH_KEY_LEN, DIGEST_LEN);
- else
- memcpy(circ->handshake_digest, cell.payload+DIGEST_LEN, DIGEST_LEN);
- circ->is_first_hop = (cell_type == CELL_CREATED_FAST);
- connection_or_write_cell_to_buf(&cell, circ->p_conn);
- log_debug(LD_CIRC,"Finished sending 'created' cell.");
- if (!is_local_IP(circ->p_conn->_base.addr) &&
- !connection_or_nonopen_was_started_here(circ->p_conn)) {
-
- router_orport_found_reachable();
- }
- return 0;
- }
- static int
- new_route_len(double cw, uint8_t purpose, extend_info_t *exit,
- smartlist_t *routers)
- {
- int num_acceptable_routers;
- int routelen;
- tor_assert(cw >= 0.);
- tor_assert(cw < 1.);
- tor_assert(routers);
- #ifdef TOR_PERF
- routelen = 2;
- #else
- routelen = 3;
- if (exit &&
- purpose != CIRCUIT_PURPOSE_TESTING &&
- purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO)
- routelen++;
- #endif
- log_debug(LD_CIRC,"Chosen route length %d (%d routers available).",
- routelen, smartlist_len(routers));
- num_acceptable_routers = count_acceptable_routers(routers);
- if (num_acceptable_routers < 2) {
- log_info(LD_CIRC,
- "Not enough acceptable routers (%d). Discarding this circuit.",
- num_acceptable_routers);
- return -1;
- }
- if (num_acceptable_routers < routelen) {
- log_info(LD_CIRC,"Not enough routers: cutting routelen from %d to %d.",
- routelen, num_acceptable_routers);
- routelen = num_acceptable_routers;
- }
- return routelen;
- }
- static smartlist_t *
- circuit_get_unhandled_ports(time_t now)
- {
- smartlist_t *source = rep_hist_get_predicted_ports(now);
- smartlist_t *dest = smartlist_create();
- uint16_t *tmp;
- int i;
- for (i = 0; i < smartlist_len(source); ++i) {
- tmp = tor_malloc(sizeof(uint16_t));
- memcpy(tmp, smartlist_get(source, i), sizeof(uint16_t));
- smartlist_add(dest, tmp);
- }
- circuit_remove_handled_ports(dest);
- return dest;
- }
- int
- circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
- int *need_capacity)
- {
- int i, enough;
- uint16_t *port;
- smartlist_t *sl = circuit_get_unhandled_ports(now);
- smartlist_t *LongLivedServices = get_options()->LongLivedPorts;
- tor_assert(need_uptime);
- tor_assert(need_capacity);
- enough = (smartlist_len(sl) == 0);
- for (i = 0; i < smartlist_len(sl); ++i) {
- port = smartlist_get(sl, i);
- if (smartlist_string_num_isin(LongLivedServices, *port))
- *need_uptime = 1;
- tor_free(port);
- }
- smartlist_free(sl);
- return enough;
- }
- static int
- router_handles_some_port(routerinfo_t *router, smartlist_t *needed_ports)
- {
- int i;
- uint16_t port;
- for (i = 0; i < smartlist_len(needed_ports); ++i) {
- addr_policy_result_t r;
- port = *(uint16_t *)smartlist_get(needed_ports, i);
- tor_assert(port);
- r = compare_addr_to_addr_policy(0, port, router->exit_policy);
- if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED)
- return 1;
- }
- return 0;
- }
- static int
- ap_stream_wants_exit_attention(connection_t *conn)
- {
- if (conn->type == CONN_TYPE_AP &&
- conn->state == AP_CONN_STATE_CIRCUIT_WAIT &&
- !conn->marked_for_close &&
- !connection_edge_is_rendezvous_stream(TO_EDGE_CONN(conn)) &&
- !circuit_stream_is_being_handled(TO_EDGE_CONN(conn), 0,
- MIN_CIRCUITS_HANDLING_STREAM))
- return 1;
- return 0;
- }
- static routerinfo_t *
- choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
- int need_capacity)
- {
- int *n_supported;
- int i, j;
- int n_pending_connections = 0;
- connection_t **carray;
- int n_connections;
- int best_support = -1;
- int n_best_support=0;
- smartlist_t *sl, *preferredexits, *excludedexits;
- routerinfo_t *router;
- or_options_t *options = get_options();
- get_connection_array(&carray, &n_connections);
-
- for (i = 0; i < n_connections; ++i) {
- if (ap_stream_wants_exit_attention(carray[i]))
- ++n_pending_connections;
- }
-
- n_supported = tor_malloc(sizeof(int)*smartlist_len(dir->routers));
- for (i = 0; i < smartlist_len(dir->routers); ++i) {
- router = smartlist_get(dir->routers, i);
- if (router_is_me(router)) {
- n_supported[i] = -1;
-
- continue;
- }
- if (!router->is_running || router->is_bad_exit) {
- n_supported[i] = -1;
- continue;
- }
- if (router_is_unreliable(router, need_uptime, need_capacity, 0)) {
- n_supported[i] = -1;
- continue;
- }
- if (!router->is_valid &&
- (!(options->_AllowInvalid & ALLOW_INVALID_EXIT) ||
- router_is_unreliable(router, 1, 1, 0))) {
-
- n_supported[i] = -1;
- continue;
- }
- if (router_exit_policy_rejects_all(router)) {
- n_supported[i] = -1;
- continue;
- }
- n_supported[i] = 0;
- for (j = 0; j < n_connections; ++j) {
- if (!ap_stream_wants_exit_attention(carray[j]))
- continue;
- if (connection_ap_can_use_exit(TO_EDGE_CONN(carray[j]), router)) {
- ++n_supported[i];
- } else {
- }
- }
- if (n_supported[i] > best_support) {
-
- best_support = n_supported[i]; n_best_support=1;
- } else if (n_supported[i] == best_support) {
-
- ++n_best_support;
- }
- }
- log_info(LD_CIRC,
- "Found %d servers that might support %d/%d pending connections.",
- n_best_support, best_support >= 0 ? best_support : 0,
- n_pending_connections);
- preferredexits = smartlist_create();
- add_nickname_list_to_smartlist(preferredexits,options->ExitNodes,1,1,1);
- excludedexits = smartlist_create();
- add_nickname_list_to_smartlist(excludedexits,options->ExcludeNodes,0,0,1);
- sl = smartlist_create();
-
- if (best_support > 0) {
- for (i = 0; i < smartlist_len(dir->routers); i++)
- if (n_supported[i] == best_support)
- smartlist_add(sl, smartlist_get(dir->routers, i));
- smartlist_subtract(sl,excludedexits);
- if (options->StrictExitNodes || smartlist_overlap(sl,preferredexits))
- smartlist_intersect(sl,preferredexits);
- router = routerlist_sl_choose_by_bandwidth(sl, 1);
- } else {
-
- int try;
- smartlist_t *needed_ports = circuit_get_unhandled_ports(time(NULL));
- if (best_support == -1) {
- if (need_uptime || need_capacity) {
- log_info(LD_CIRC,
- "We couldn't find any live%s%s routers; falling back "
- "to list of all routers.",
- need_capacity?", fast":"",
- need_uptime?", stable":"");
- smartlist_free(preferredexits);
- smartlist_free(excludedexits);
- smartlist_free(sl);
- tor_free(n_supported);
- return choose_good_exit_server_general(dir, 0, 0);
- }
- log_notice(LD_CIRC, "All routers are down or won't exit -- choosing a "
- "doomed exit at random.");
- }
- for (try = 0; try < 2; try++) {
-
- for (i = 0; i < smartlist_len(dir->routers); i++) {
- router = smartlist_get(dir->routers, i);
- if (n_supported[i] != -1 &&
- (try || router_handles_some_port(router, needed_ports))) {
- smartlist_add(sl, router);
- }
- }
- smartlist_subtract(sl,excludedexits);
- if (options->StrictExitNodes || smartlist_overlap(sl,preferredexits))
- smartlist_intersect(sl,preferredexits);
-
- router = routerlist_sl_choose_by_bandwidth(sl, 1);
- if (router)
- break;
- }
- SMARTLIST_FOREACH(needed_ports, uint16_t *, cp, tor_free(cp));
- smartlist_free(needed_ports);
- }
- smartlist_free(preferredexits);
- smartlist_free(excludedexits);
- smartlist_free(sl);
- tor_free(n_supported);
- if (router) {
- log_info(LD_CIRC, "Chose exit server '%s'", router->nickname);
- return router;
- }
- if (options->StrictExitNodes) {
- log_warn(LD_CIRC,
- "No specified exit routers seem to be running, and "
- "StrictExitNodes is set: can't choose an exit.");
- }
- return NULL;
- }
- static routerinfo_t *
- choose_good_exit_server(uint8_t purpose, routerlist_t *dir,
- int need_uptime, int need_capacity, int is_internal)
- {
- or_options_t *options = get_options();
- switch (purpose) {
- case CIRCUIT_PURPOSE_C_GENERAL:
- if (is_internal)
- return router_choose_random_node(NULL, get_options()->ExcludeNodes,
- NULL, need_uptime, need_capacity, 0,
- get_options()->_AllowInvalid & ALLOW_INVALID_MIDDLE, 0, 0);
- else
- return choose_good_exit_server_general(dir,need_uptime,need_capacity);
- case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
- return router_choose_random_node(
- options->RendNodes, options->RendExcludeNodes,
- NULL, need_uptime, need_capacity, 0,
- options->_AllowInvalid & ALLOW_INVALID_RENDEZVOUS, 0, 0);
- }
- log_warn(LD_BUG,"Bug: unhandled purpose %d", purpose);
- tor_fragile_assert();
- return NULL;
- }
- static int
- onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit)
- {
- cpath_build_state_t *state = circ->build_state;
- routerlist_t *rl = router_get_routerlist();
- if (state->onehop_tunnel) {
- log_debug(LD_CIRC, "Launching a one-hop circuit for dir tunnel.");
- state->desired_path_len = 1;
- } else {
- int r = new_route_len(get_options()->PathlenCoinWeight,
- circ->_base.purpose, exit, rl->routers);
- if (r < 1)
- return -1;
- state->desired_path_len = r;
- }
- if (exit) {
- log_info(LD_CIRC,"Using requested exit node '%s'", exit->nickname);
- exit = extend_info_dup(exit);
- } else {
- routerinfo_t *router =
- choose_good_exit_server(circ->_base.purpose, rl, state->need_uptime,
- state->need_capacity, state->is_internal);
- if (!router) {
- log_warn(LD_CIRC,"failed to choose an exit server");
- return -1;
- }
- exit = extend_info_from_router(router);
- }
- state->chosen_exit = exit;
- return 0;
- }
- int
- circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info)
- {
- cpath_build_state_t *state;
- tor_assert(info);
- tor_assert(circ);
- state = circ->build_state;
- tor_assert(state);
- if (state->chosen_exit)
- extend_info_free(state->chosen_exit);
- state->chosen_exit = extend_info_dup(info);
- ++circ->build_state->desired_path_len;
- onion_append_hop(&circ->cpath, info);
- return 0;
- }
- int
- circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info)
- {
- int err_reason = 0;
- circuit_append_new_exit(circ, info);
- circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
- if ((err_reason = circuit_send_next_onion_skin(circ))<0) {
- log_warn(LD_CIRC, "Couldn't extend circuit to new point '%s'.",
- info->nickname);
- circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason);
- return -1;
- }
- return 0;
- }
- static int
- count_acceptable_routers(smartlist_t *routers)
- {
- int i, n;
- int num=0;
- routerinfo_t *r;
- n = smartlist_len(routers);
- for (i=0;i<n;i++) {
- r = smartlist_get(routers, i);
- if (r->is_running == 0) {
- goto next_i_loop;
- }
- if (r->is_valid == 0) {
- goto next_i_loop;
-
- }
- num++;
- next_i_loop:
- ;
- }
- return num;
- }
- void
- onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop)
- {
- if (*head_ptr) {
- new_hop->next = (*head_ptr);
- new_hop->prev = (*head_ptr)->prev;
- (*head_ptr)->prev->next = new_hop;
- (*head_ptr)->prev = new_hop;
- } else {
- *head_ptr = new_hop;
- new_hop->prev = new_hop->next = new_hop;
- }
- }
- static char *
- compute_preferred_testing_list(const char *answer)
- {
- smartlist_t *choices;
- routerlist_t *rl = router_get_routerlist();
- routerinfo_t *router;
- char *s;
- if (answer)
- return tor_strdup(answer);
- choices = smartlist_create();
-
- SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r,
- if (r->is_running && r->is_valid &&
- ((tor_version_as_new_as(r->platform,"0.1.1.21-cvs") &&
- !tor_version_as_new_as(r->platform,"0.1.2.0-alpha-cvs")) ||
- tor_version_as_new_as(r->platform,"0.1.2.1-alpha")) &&
- !is_local_IP(r->addr) &&
- !router_get_trusteddirserver_by_digest(r->cache_info.identity_digest))
- smartlist_add(choices, r));
- router = smartlist_choose(choices);
- smartlist_free(choices);
- if (!router) {
- log_info(LD_CIRC, "Looking for middle server that doesn't have the "
- "reachability bug, but didn't find one. Oh well.");
- return NULL;
- }
- log_info(LD_CIRC, "Looking for middle server that doesn't have the "
- "reachability bug, and chose '%s'. Great.", router->nickname);
- s = tor_malloc(HEX_DIGEST_LEN+2);
- s[0] = '$';
- base16_encode(s+1, HEX_DIGEST_LEN+1,
- router->cache_info.identity_digest, DIGEST_LEN);
- return s;
- }
- static routerinfo_t *
- choose_good_middle_server(uint8_t purpose,
- cpath_build_state_t *state,
- crypt_path_t *head,
- int cur_len)
- {
- int i;
- routerinfo_t *r, *choice;
- crypt_path_t *cpath;
- smartlist_t *excluded;
- or_options_t *options = get_options();
- char *preferred = NULL;
- tor_assert(_CIRCUIT_PURPOSE_MIN <= purpose &&
- purpose <= _CIRCUIT_PURPOSE_MAX);
- log_debug(LD_CIRC, "Contemplating intermediate hop: random choice.");
- excluded = smartlist_create();
- if ((r = build_state_get_exit_router(state))) {
- smartlist_add(excluded, r);
- routerlist_add_family(excluded, r);
- }
- if ((r = routerlist_find_my_routerinfo())) {
- smartlist_add(excluded, r);
- routerlist_add_family(excluded, r);
- }
- for (i = 0, cpath = head; i < cur_len; ++i, cpath=cpath->next) {
- if ((r = router_get_by_digest(cpath->extend_info->identity_digest))) {
- smartlist_add(excluded, r);
- routerlist_add_family(excluded, r);
- }
- }
- if (purpose == CIRCUIT_PURPOSE_TESTING)
- preferred = compute_preferred_testing_list(options->TestVia);
- choice = router_choose_random_node(preferred,
- options->ExcludeNodes, excluded,
- state->need_uptime, state->need_capacity, 0,
- options->_AllowInvalid & ALLOW_INVALID_MIDDLE, 0, 0);
- if (preferred)
- tor_free(preferred);
- smartlist_free(excluded);
- return choice;
- }
- static routerinfo_t *
- choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
- {
- routerinfo_t *r, *choice;
- smartlist_t *excluded;
- or_options_t *options = get_options();
- (void)purpose;
- if (state && options->UseEntryGuards) {
- return choose_random_entry(state);
- }
- excluded = smartlist_create();
- if (state && (r = build_state_get_exit_router(state))) {
- smartlist_add(excluded, r);
- routerlist_add_family(excluded, r);
- }
- if ((r = routerlist_find_my_routerinfo())) {
- smartlist_add(excluded, r);
- routerlist_add_family(excluded, r);
- }
- if (firewall_is_fascist_or()) {
-
- routerlist_t *rl = router_get_routerlist();
- int i;
- for (i=0; i < smartlist_len(rl->routers); i++) {
- r = smartlist_get(rl->routers, i);
- if (!fascist_firewall_allows_address_or(r->addr,r->or_port))
- smartlist_add(excluded, r);
- }
- }
-
- if (options->UseEntryGuards && entry_guards) {
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
- {
- if ((r = router_get_by_digest(entry->identity)))
- smartlist_add(excluded, r);
- });
- }
- choice = router_choose_random_node(
- NULL, options->ExcludeNodes,
- excluded, state ? state->need_uptime : 0,
- state ? state->need_capacity : 0,
- state ? 0 : 1,
- options->_AllowInvalid & ALLOW_INVALID_ENTRY, 0, 0);
- smartlist_free(excluded);
- return choice;
- }
- static crypt_path_t *
- onion_next_hop_in_cpath(crypt_path_t *cpath)
- {
- crypt_path_t *hop = cpath;
- do {
- if (hop->state != CPATH_STATE_OPEN)
- return hop;
- hop = hop->next;
- } while (hop != cpath);
- return NULL;
- }
- static int
- onion_extend_cpath(origin_circuit_t *circ)
- {
- uint8_t purpose = circ->_base.purpose;
- cpath_build_state_t *state = circ->build_state;
- int cur_len = circuit_get_cpath_len(circ);
- extend_info_t *info = NULL;
- if (cur_len >= state->desired_path_len) {
- log_debug(LD_CIRC, "Path is complete: %d steps long",
- state->desired_path_len);
- return 1;
- }
- log_debug(LD_CIRC, "Path is %d long; we want %d", cur_len,
- state->desired_path_len);
- if (cur_len == state->desired_path_len - 1) {
- info = extend_info_dup(state->chosen_exit);
- } else if (cur_len == 0) {
- routerinfo_t *r = choose_good_entry_server(purpose, state);
- if (r)
- info = extend_info_from_router(r);
- } else {
- routerinfo_t *r =
- choose_good_middle_server(purpose, state, circ->cpath, cur_len);
- if (r)
- info = extend_info_from_router(r);
- }
- if (!info) {
- log_warn(LD_CIRC,"Failed to find node for hop %d of our path. Discarding "
- "this circuit.", cur_len);
- return -1;
- }
- log_debug(LD_CIRC,"Chose router %s for hop %d (exit is %s)",
- info->nickname, cur_len+1, build_state_get_exit_nickname(state));
- onion_append_hop(&circ->cpath, info);
- extend_info_free(info);
- return 0;
- }
- static int
- onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice)
- {
- crypt_path_t *hop = tor_malloc_zero(sizeof(crypt_path_t));
-
- onion_append_to_cpath(head_ptr, hop);
- hop->magic = CRYPT_PATH_MAGIC;
- hop->state = CPATH_STATE_CLOSED;
- hop->extend_info = extend_info_dup(choice);
- hop->package_window = CIRCWINDOW_START;
- hop->deliver_window = CIRCWINDOW_START;
- return 0;
- }
- extend_info_t *
- extend_info_from_router(routerinfo_t *r)
- {
- extend_info_t *info;
- tor_assert(r);
- info = tor_malloc_zero(sizeof(extend_info_t));
- strlcpy(info->nickname, r->nickname, sizeof(info->nickname));
- memcpy(info->identity_digest, r->cache_info.identity_digest, DIGEST_LEN);
- info->onion_key = crypto_pk_dup_key(r->onion_pkey);
- info->addr = r->addr;
- info->port = r->or_port;
- return info;
- }
- void
- extend_info_free(extend_info_t *info)
- {
- tor_assert(info);
- crypto_free_pk_env(info->onion_key);
- tor_free(info);
- }
- extend_info_t *
- extend_info_dup(extend_info_t *info)
- {
- extend_info_t *newinfo;
- tor_assert(info);
- newinfo = tor_malloc(sizeof(extend_info_t));
- memcpy(newinfo, info, sizeof(extend_info_t));
- newinfo->onion_key = crypto_pk_dup_key(info->onion_key);
- return newinfo;
- }
- routerinfo_t *
- build_state_get_exit_router(cpath_build_state_t *state)
- {
- if (!state || !state->chosen_exit)
- return NULL;
- return router_get_by_digest(state->chosen_exit->identity_digest);
- }
- const char *
- build_state_get_exit_nickname(cpath_build_state_t *state)
- {
- if (!state || !state->chosen_exit)
- return NULL;
- return state->chosen_exit->nickname;
- }
- static int
- entry_guard_set_status(entry_guard_t *e, routerinfo_t *ri,
- time_t now, or_options_t *options)
- {
- const char *reason = NULL;
- char buf[HEX_DIGEST_LEN+1];
- int changed = 0;
- tor_assert(options);
-
- if (!ri)
- reason = "unlisted";
- else if (!ri->is_running)
- reason = "down";
- else if (!ri->is_possible_guard &&
- !router_nickname_is_in_list(ri, options->EntryNodes))
- reason = "not recommended as a guard";
- else if (router_nickname_is_in_list(ri, options->ExcludeNodes))
- reason = "excluded";
- if (reason && ! e->bad_since) {
-
- base16_encode(buf, sizeof(buf), e->identity, DIGEST_LEN);
- log_info(LD_CIRC, "Entry guard %s (%s) is %s: marking as unusable.",
- e->nickname, buf, reason);
- e->bad_since = now;
- control_event_guard(e->nickname, e->identity, "BAD");
- changed = 1;
- } else if (!reason && e->bad_since) {
-
- base16_encode(buf, sizeof(buf), e->identity, DIGEST_LEN);
- log_info(LD_CIRC, "Entry guard %s (%s) is no longer unusable: "
- "marking as ok.", e->nickname, buf);
- e->bad_since = 0;
- control_event_guard(e->nickname, e->identity, "GOOD");
- changed = 1;
- }
- return changed;
- }
- static int
- entry_is_time_to_retry(entry_guard_t *e, time_t now)
- {
- long diff;
- if (e->last_attempted < e->unreachable_since)
- return 1;
- diff = now - e->unreachable_since;
- if (diff < 6*60*60)
- return now > (e->last_attempted + 60*60);
- else if (diff < 3*24*60*60)
- return now > (e->last_attempted + 4*60*60);
- else if (diff < 7*24*60*60)
- return now > (e->last_attempted + 18*60*60);
- else
- return now > (e->last_attempted + 36*60*60);
- }
- static INLINE routerinfo_t *
- entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity,
- int assume_reachable)
- {
- routerinfo_t *r;
- if (e->bad_since)
- return NULL;
- if (!assume_reachable &&
- e->unreachable_since && !entry_is_time_to_retry(e, time(NULL)))
- return NULL;
- r = router_get_by_digest(e->identity);
- if (!r)
- return NULL;
- if (router_is_unreliable(r, need_uptime, need_capacity, 0))
- return NULL;
- if (firewall_is_fascist_or() &&
- !fascist_firewall_allows_address_or(r->addr,r->or_port))
- return NULL;
- return r;
- }
- static int
- num_live_entry_guards(void)
- {
- int n = 0;
- if (! entry_guards)
- return 0;
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
- {
- if (entry_is_live(entry, 0, 1, 0))
- ++n;
- });
- return n;
- }
- static INLINE int
- is_an_entry_guard(char *digest)
- {
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
- if (!memcmp(digest, entry->identity, DIGEST_LEN))
- return 1;
- );
- return 0;
- }
- static void
- log_entry_guards(int severity)
- {
- smartlist_t *elements = smartlist_create();
- char buf[1024];
- char *s;
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e,
- {
- tor_snprintf(buf, sizeof(buf), "%s (%s%s)",
- e->nickname,
- e->bad_since ? "down " : "up ",
- e->made_contact ? "made-contact" : "never-contacted");
- smartlist_add(elements, tor_strdup(buf));
- });
- s = smartlist_join_strings(elements, ",", 0, NULL);
- SMARTLIST_FOREACH(elements, char*, cp, tor_free(cp));
- smartlist_free(elements);
- log_fn(severity,LD_CIRC,"%s",s);
- tor_free(s);
- }
- static void
- control_event_guard_deferred(void)
- {
- #if 0
- int n = 0;
- or_options_t *options = get_options();
- if (!entry_guards)
- return;
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
- {
- if (entry_is_live(entry, 0, 1, 0)) {
- if (n++ == options->NumEntryGuards) {
- control_event_guard(entry->nickname, entry->identity, "DEFERRED");
- return;
- }
- }
- });
- #endif
- }
- #define NUM_ENTRY_PICK_TRIES 100
- static routerinfo_t *
- add_an_entry_guard(routerinfo_t *chosen)
- {
- routerinfo_t *router;
- entry_guard_t *entry;
- if (chosen) {
- router = chosen;
- if (is_an_entry_guard(router->cache_info.identity_digest))
- return NULL;
- } else {
- router = choose_good_entry_server(CIRCUIT_PURPOSE_C_GENERAL, NULL);
- if (!router)
- return NULL;
- }
- entry = tor_malloc_zero(sizeof(entry_guard_t));
- log_info(LD_CIRC, "Chose '%s' as new entry guard.", router->nickname);
- strlcpy(entry->nickname, router->nickname, sizeof(entry->nickname));
- memcpy(entry->identity, router->cache_info.identity_digest, DIGEST_LEN);
- if (chosen)
- smartlist_insert(entry_guards, 0, entry);
- else
- smartlist_add(entry_guards, entry);
- control_event_guard(entry->nickname, entry->identity, "NEW");
- control_event_guard_deferred();
- log_entry_guards(LOG_INFO);
- return router;
- }
- static void
- pick_entry_guards(void)
- {
- or_options_t *options = get_options();
- int changed = 0;
- tor_assert(entry_guards);
- while (num_live_entry_guards() < options->NumEntryGuards) {
- if (!add_an_entry_guard(NULL))
- break;
- changed = 1;
- }
- if (changed)
- entry_guards_changed();
- }
- void
- entry_guards_free_all(void)
- {
- if (entry_guards) {
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, tor_free(e));
- smartlist_free(entry_guards);
- entry_guards = NULL;
- }
- }
- #define ENTRY_GUARD_REMOVE_AFTER (30*24*60*60)
- static int
- remove_dead_entries(void)
- {
- char dbuf[HEX_DIGEST_LEN+1];
- char tbuf[ISO_TIME_LEN+1];
- time_t now = time(NULL);
- int i;
- int changed = 0;
- for (i = 0; i < smartlist_len(entry_guards); ) {
- entry_guard_t *entry = smartlist_get(entry_guards, i);
- if (entry->bad_since &&
- entry->bad_since + ENTRY_GUARD_REMOVE_AFTER < now) {
- base16_encode(dbuf, sizeof(dbuf), entry->identity, DIGEST_LEN);
- format_local_iso_time(tbuf, entry->bad_since);
- log_info(LD_CIRC, "Entry guard '%s' (%s) has been down or unlisted "
- "since %s local time; removing.",
- entry->nickname, dbuf, tbuf);
- control_event_guard(entry->nickname, entry->identity, "DROPPED");
- tor_free(entry);
- smartlist_del_keeporder(entry_guards, i);
- log_entry_guards(LOG_INFO);
- changed = 1;
- } else
- ++i;
- }
- return changed ? 1 : 0;
- }
- void
- entry_guards_compute_status(void)
- {
-
- time_t now;
- int changed = 0;
- int severity = LOG_INFO;
- or_options_t *options;
- if (! entry_guards)
- return;
- options = get_options();
- now = time(NULL);
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
- {
- routerinfo_t *r = router_get_by_digest(entry->identity);
- if (entry_guard_set_status(entry, r, now, options))
- changed = 1;
- log_info(LD_CIRC, "Summary: Entry '%s' is %s, %s and %s.",
- entry->nickname,
- entry->unreachable_since ? "unreachable" : "reachable",
- entry->bad_since ? "unusable" : "usable",
- entry_is_live(entry, 0, 1, 0) ? "live" : "not live");
- });
- if (remove_dead_entries())
- changed = 1;
- if (changed) {
- log_fn(severity, LD_CIRC, " (%d/%d entry guards are usable/new)",
- num_live_entry_guards(), smartlist_len(entry_guards));
- log_entry_guards(LOG_INFO);
- entry_guards_changed();
- }
- }
- int
- entry_guard_register_connect_status(const char *digest, int succeeded,
- time_t now)
- {
- int changed = 0;
- int refuse_conn = 0;
- int first_contact = 0;
- entry_guard_t *entry = NULL;
- int idx = -1;
- char buf[HEX_DIGEST_LEN+1];
- if (! entry_guards)
- return 0;
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e,
- {
- if (!memcmp(e->identity, digest, DIGEST_LEN)) {
- entry = e;
- idx = e_sl_idx;
- break;
- }
- });
- if (!entry)
- return 0;
- base16_encode(buf, sizeof(buf), entry->identity, DIGEST_LEN);
- if (succeeded) {
- if (entry->unreachable_since) {
- log_info(LD_CIRC, "Entry guard '%s' (%s) is now reachable again. Good.",
- entry->nickname, buf);
- entry->unreachable_since = 0;
- entry->last_attempted = now;
- control_event_guard(entry->nickname, entry->identity, "UP");
- changed = 1;
- }
- if (!entry->made_contact) {
- entry->made_contact = 1;
- first_contact = changed = 1;
- }
- } else {
- if (!entry->made_contact) {
-
- log_info(LD_CIRC,
- "Connection to never-contacted entry guard '%s' (%s) failed. "
- "Removing from the list. %d/%d entry guards usable/new.",
- entry->nickname, buf,
- num_live_entry_guards()-1, smartlist_len(entry_guards)-1);
- tor_free(entry);
- smartlist_del_keeporder(entry_guards, idx);
- log_entry_guards(LOG_INFO);
- changed = 1;
- } else if (!entry->unreachable_since) {
- log_info(LD_CIRC, "Unable to connect to entry guard '%s' (%s). "
- "Marking as unreachable.", entry->nickname, buf);
- entry->unreachable_since = entry->last_attempted = now;
- control_event_guard(entry->nickname, entry->identity, "DOWN");
- changed = 1;
- } else {
- char tbuf[ISO_TIME_LEN+1];
- format_iso_time(tbuf, entry->unreachable_since);
- log_debug(LD_CIRC, "Failed to connect to unreachable entry guard "
- "'%s' (%s). It has been unreachable since %s.",
- entry->nickname, buf, tbuf);
- entry->last_attempted = now;
- }
- }
- if (first_contact) {
-
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, {
- routerinfo_t *r;
- if (e == entry)
- break;
- if (e->made_contact) {
- r = entry_is_live(e, 0, 1, 1);
- if (r && !r->is_running) {
- refuse_conn = 1;
- r->is_running = 1;
- }
- }
- });
- if (refuse_conn) {
- log_info(LD_CIRC,
- "Connected to new entry guard '%s' (%s). Marking earlier "
- "entry guards up. %d/%d entry guards usable/new.",
- entry->nickname, buf,
- num_live_entry_guards(), smartlist_len(entry_guards));
- log_entry_guards(LOG_INFO);
- changed = 1;
- }
- }
- if (changed)
- entry_guards_changed();
- return refuse_conn ? -1 : 0;
- }
- static int should_add_entry_nodes = 0;
- void
- entry_nodes_should_be_added(void)
- {
- log_info(LD_CIRC, "New EntryNodes config option detected. Will use.");
- should_add_entry_nodes = 1;
- }
- void
- entry_guards_prepend_from_config(void)
- {
- int missed_some = 0;
- int idx;
- or_options_t *options = get_options();
- smartlist_t *routers = smartlist_create();
- smartlist_t *tmp = smartlist_create();
- tor_assert(entry_guards);
- tor_assert(options->EntryNodes);
- if (options->StrictEntryNodes) {
- log_info(LD_CIRC,"Clearing old entry guards");
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, tor_free(e));
- smartlist_clear(entry_guards);
- entry_guards_changed();
- }
- add_nickname_list_to_smartlist(routers, options->EntryNodes,
- 0, 1, 1);
-
- log_info(LD_CIRC,"Adding configured EntryNodes '%s'.",
- options->EntryNodes);
- smartlist_split_string(tmp, options->EntryNodes, ",",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- missed_some = smartlist_len(routers) != smartlist_len(tmp);
- SMARTLIST_FOREACH(tmp, char *, nick, tor_free(nick));
- smartlist_free(tmp);
- for (idx = smartlist_len(routers)-1 ; idx >= 0; idx--) {
-
- routerinfo_t *r = smartlist_get(routers, idx);
- add_an_entry_guard(r);
- }
- if (!missed_some)
- should_add_entry_nodes = 0;
- smartlist_free(routers);
- }
- static routerinfo_t *
- choose_random_entry(cpath_build_state_t *state)
- {
- or_options_t *options = get_options();
- smartlist_t *live_entry_guards = smartlist_create();
- routerinfo_t *chosen_exit = build_state_get_exit_router(state);
- routerinfo_t *r = NULL;
- int need_uptime = state->need_uptime;
- int need_capacity = state->need_capacity;
- if (!entry_guards)
- entry_guards = smartlist_create();
- if (should_add_entry_nodes)
- entry_guards_prepend_from_config();
- if (!options->StrictEntryNodes &&
- (! entry_guards ||
- smartlist_len(entry_guards) < options->NumEntryGuards))
- pick_entry_guards();
- retry:
- smartlist_clear(live_entry_guards);
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
- {
- r = entry_is_live(entry, need_uptime, need_capacity, 0);
- if (r && r != chosen_exit) {
- smartlist_add(live_entry_guards, r);
- if (smartlist_len(live_entry_guards) >= options->NumEntryGuards)
- break;
- }
- });
-
- if (smartlist_len(live_entry_guards) < 2) {
- if (!options->StrictEntryNodes) {
-
-
- r = add_an_entry_guard(NULL);
- if (r) {
- smartlist_add(live_entry_guards, r);
- entry_guards_changed();
- }
- }
- if (!r && need_uptime) {
- need_uptime = 0;
- goto retry;
- }
- if (!r && need_capacity) {
-
- need_capacity = 0;
- goto retry;
- }
-
- }
- r = smartlist_choose(live_entry_guards);
- smartlist_free(live_entry_guards);
- return r;
- }
- int
- entry_guards_parse_state(or_state_t *state, int set, char **msg)
- {
- entry_guard_t *node = NULL;
- smartlist_t *new_entry_guards = smartlist_create();
- config_line_t *line;
- *msg = NULL;
- for (line = state->EntryGuards; line; line = line->next) {
- if (!strcasecmp(line->key, "EntryGuard")) {
- smartlist_t *args = smartlist_create();
- node = tor_malloc_zero(sizeof(entry_guard_t));
-
- node->made_contact = 1;
- smartlist_add(new_entry_guards, node);
- smartlist_split_string(args, line->value, " ",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- if (smartlist_len(args)<2) {
- *msg = tor_strdup("Unable to parse entry nodes: "
- "Too few arguments to EntryGuard");
- } else if (!is_legal_nickname(smartlist_get(args,0))) {
- *msg = tor_strdup("Unable to parse entry nodes: "
- "Bad nickname for EntryGuard");
- } else {
- strlcpy(node->nickname, smartlist_get(args,0), MAX_NICKNAME_LEN+1);
- if (base16_decode(node->identity, DIGEST_LEN, smartlist_get(args,1),
- strlen(smartlist_get(args,1)))<0) {
- *msg = tor_strdup("Unable to parse entry nodes: "
- "Bad hex digest for EntryGuard");
- }
- }
- SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
- smartlist_free(args);
- if (*msg)
- break;
- } else {
- time_t when;
- time_t last_try = 0;
- if (!node) {
- *msg = tor_strdup("Unable to parse entry nodes: "
- "EntryGuardDownSince/UnlistedSince without EntryGuard");
- break;
- }
- if (parse_iso_time(line->value, &when)<0) {
- *msg = tor_strdup("Unable to parse entry nodes: "
- "Bad time in EntryGuardDownSince/UnlistedSince");
- break;
- }
- if (strlen(line->value) >= ISO_TIME_LEN+ISO_TIME_LEN+1) {
-
- parse_iso_time(line->value+ISO_TIME_LEN+1, &last_try);
- }
- if (!strcasecmp(line->key, "EntryGuardDownSince")) {
- node->unreachable_since = when;
- node->last_attempted = last_try;
- } else {
- node->bad_since = when;
- }
- }
- }
- if (*msg || !set) {
- SMARTLIST_FOREACH(new_entry_guards, entry_guard_t *, e, tor_free(e));
- smartlist_free(new_entry_guards);
- } else {
- if (entry_guards) {
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, tor_free(e));
- smartlist_free(entry_guards);
- }
- entry_guards = new_entry_guards;
- entry_guards_dirty = 0;
- }
- return *msg ? -1 : 0;
- }
- static void
- entry_guards_changed(void)
- {
- time_t when;
- entry_guards_dirty = 1;
-
- when = get_options()->AvoidDiskWrites ? time(NULL) + 3600 : time(NULL)+600;
- or_state_mark_dirty(get_or_state(), when);
- }
- void
- entry_guards_update_state(or_state_t *state)
- {
- config_line_t **next, *line;
- if (! entry_guards_dirty)
- return;
- config_free_lines(state->EntryGuards);
- next = &state->EntryGuards;
- *next = NULL;
- if (!entry_guards)
- entry_guards = smartlist_create();
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e,
- {
- char dbuf[HEX_DIGEST_LEN+1];
- if (!e->made_contact)
- continue;
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("EntryGuard");
- line->value = tor_malloc(HEX_DIGEST_LEN+MAX_NICKNAME_LEN+2);
- base16_encode(dbuf, sizeof(dbuf), e->identity, DIGEST_LEN);
- tor_snprintf(line->value,HEX_DIGEST_LEN+MAX_NICKNAME_LEN+2,
- "%s %s", e->nickname, dbuf);
- next = &(line->next);
- if (e->unreachable_since) {
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("EntryGuardDownSince");
- line->value = tor_malloc(ISO_TIME_LEN+1+ISO_TIME_LEN+1);
- format_iso_time(line->value, e->unreachable_since);
- if (e->last_attempted) {
- line->value[ISO_TIME_LEN] = ' ';
- format_iso_time(line->value+ISO_TIME_LEN+1, e->last_attempted);
- }
- next = &(line->next);
- }
- if (e->bad_since) {
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("EntryGuardUnlistedSince");
- line->value = tor_malloc(ISO_TIME_LEN+1);
- format_iso_time(line->value, e->bad_since);
- next = &(line->next);
- }
- });
- if (!get_options()->AvoidDiskWrites)
- or_state_mark_dirty(get_or_state(), 0);
- entry_guards_dirty = 0;
- }
- int
- getinfo_helper_entry_guards(control_connection_t *conn,
- const char *question, char **answer)
- {
- int use_long_names = conn->use_long_names;
- if (!strcmp(question,"entry-guards") ||
- !strcmp(question,"helper-nodes")) {
- smartlist_t *sl = smartlist_create();
- char tbuf[ISO_TIME_LEN+1];
- char nbuf[MAX_VERBOSE_NICKNAME_LEN+1];
- if (!entry_guards)
- entry_guards = smartlist_create();
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e,
- {
- size_t len = MAX_VERBOSE_NICKNAME_LEN+ISO_TIME_LEN+32;
- char *c = tor_malloc(len);
- const char *status = NULL;
- time_t when = 0;
- if (!e->made_contact) {
- status = "never-connected";
- } else if (e->bad_since) {
- when = e->bad_since;
- status = "unusable";
- } else {
- status = "up";
- }
- if (use_long_names) {
- routerinfo_t *ri = router_get_by_digest(e->identity);
- if (ri) {
- router_get_verbose_nickname(nbuf, ri);
- } else {
- nbuf[0] = '$';
- base16_encode(nbuf+1, sizeof(nbuf)-1, e->identity, DIGEST_LEN);
-
- }
- } else {
- base16_encode(nbuf, sizeof(nbuf), e->identity, DIGEST_LEN);
- }
- if (when) {
- format_iso_time(tbuf, when);
- tor_snprintf(c, len, "%s %s %s\n", nbuf, status, tbuf);
- } else {
- tor_snprintf(c, len, "%s %s\n", nbuf, status);
- }
- smartlist_add(sl, c);
- });
- *answer = smartlist_join_strings(sl, "", 0, NULL);
- SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
- smartlist_free(sl);
- }
- return 0;
- }
|