summaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2006-09-23 22:06:09 +0000
committerNick Mathewson <nickm@torproject.org>2006-09-23 22:06:09 +0000
commitbf738d30808190fcd20e8bcb3e75b17f7b730105 (patch)
tree4cfb162ee476acb4620d1d8195bd9ca850afe530 /src/or
parentaef0c26cb125f69113fc8ae37d4c3a8c062525e9 (diff)
downloadtor-bf738d30808190fcd20e8bcb3e75b17f7b730105.tar.gz
tor-bf738d30808190fcd20e8bcb3e75b17f7b730105.zip
r6362@totoro (orig r6361): arma | 2006-04-10 05:43:30 -0400
another todo item we ought to do r6363@totoro (orig r6362): weasel | 2006-04-10 06:03:47 -0400 New upstream version r6364@totoro (orig r6363): phobos | 2006-04-10 10:12:29 -0400 Remove a dependency on dist and assume a tarball is in ".." for dist-rpm. r6365@totoro (orig r6364): weasel | 2006-04-10 15:39:26 -0400 Remove redundant includes. They are all hanled in torint.h which we already do include. r6370@totoro (orig r6369): arma | 2006-04-10 16:00:31 -0400 be willing to add our own routerinfo into the routerlist. this means authorities will include themselves in their directories and network-statuses. r6373@totoro (orig r6372): arma | 2006-04-10 16:08:12 -0400 and forward-port the man page change r6374@totoro (orig r6373): arma | 2006-04-10 16:16:46 -0400 make DirFetchPeriod and StatusFetchPeriod truly obsolete. r6376@totoro (orig r6375): arma | 2006-04-10 16:21:55 -0400 0.1.2.0-alpha-cvs! r6377@totoro (orig r6376): nickm | 2006-04-10 17:23:00 -0400 Remove DER64 functions in trunk: they will never be used again unless the directory authorities switch back to 0.0.9tooearly. r6378@totoro (orig r6377): weasel | 2006-04-10 17:29:29 -0400 Stop assuming every authority is a v1 authority r6381@totoro (orig r6380): weasel | 2006-04-10 17:37:20 -0400 [forward port] Update the list of documentation files in tor.nsi and package_nsis-weasel.sh r6382@totoro (orig r6381): arma | 2006-04-10 17:40:43 -0400 drop moria1 from the list of authorities. r6383@totoro (orig r6382): arma | 2006-04-11 10:12:04 -0400 ok, put moria1 back in, since it's v1 and thus we need to send our rendezvous descriptors to it. eventually we might make a 'v1only' tag that explains it's only for rendezvous descriptors. r6384@totoro (orig r6383): phobos | 2006-04-12 21:46:27 -0400 Temporary hacks to ensure make dist-rpm works from cvs until a better solution can be found. r6386@totoro (orig r6385): arma | 2006-04-14 16:19:33 -0400 forward-port the n_named log severity downgrade. r6388@totoro (orig r6387): arma | 2006-04-15 03:15:23 -0400 if the bottom eighth of the servers by bandwidth is really crummy, try the bottom quartile instead. r6389@totoro (orig r6388): arma | 2006-04-15 19:53:58 -0400 update spec to reflect the downgraded loglevel for naming complaints. r6390@totoro (orig r6389): arma | 2006-04-16 18:34:00 -0400 no need to escape the address for our connections -- they are always IP addresses. r6391@totoro (orig r6390): arma | 2006-04-16 18:44:08 -0400 better error checking for torify, contributed by jacob appelbaum. r6392@totoro (orig r6391): arma | 2006-04-16 18:48:41 -0400 and remove the 'debugging' flag for torify r6393@totoro (orig r6392): weasel | 2006-04-16 22:46:14 -0400 Add an XXX to torify.in - "which" is evil, quote a few variables do -h and --help add (c) and license ("Same as tor") print an error message if exec falls through r6394@totoro (orig r6393): arma | 2006-04-17 02:43:27 -0400 slightly clearer log message when you use a nickname rather than a key for an unnamed server. r6395@totoro (orig r6394): arma | 2006-04-17 02:46:20 -0400 note another bug: we complain that a router doesn't exist, because it's down so we never fetched it so it doesn't exist. r6397@totoro (orig r6396): nickm | 2006-04-17 23:07:24 -0400 forward-port: "Resolve" all XXX011 items, mostly by marking them non-011. r6399@totoro (orig r6398): nickm | 2006-04-17 23:36:28 -0400 [forward-port] Implement an option, VirtualAddrMask, to set which addresses get handed out in response to mapaddress requests. Needs testing and docs! r6401@totoro (orig r6400): nickm | 2006-04-17 23:51:18 -0400 [Forward-port ]Test and document last patch. r6402@totoro (orig r6401): nickm | 2006-04-17 23:58:42 -0400 mainline branch. Remove some more dead XXXs. r6403@totoro (orig r6402): nickm | 2006-04-18 00:57:07 -0400 require at least 2**16 assignable virtual addresses r6405@totoro (orig r6404): arma | 2006-04-18 01:03:09 -0400 class B really means /16 here r6407@totoro (orig r6406): arma | 2006-04-18 15:48:06 -0400 Raise the timeout for complaining about wedged cpuworkers. This value is high because some servers with low memory/cpu sometimes spend an hour or more swapping, and Tor starves. r6408@totoro (orig r6407): weasel | 2006-04-21 11:52:49 -0400 Add add-tor helper script to contrib r6409@totoro (orig r6408): weasel | 2006-04-21 11:57:09 -0400 Remove test values from add-tor r6410@totoro (orig r6409): nickm | 2006-04-23 17:36:52 -0400 Prioritize items for 0.1.2 r6411@totoro (orig r6410): nickm | 2006-04-23 17:40:15 -0400 And another 0.1.2 item r6412@totoro (orig r6411): arma | 2006-04-23 19:05:34 -0400 make more hibernate log messages use local time. we should audit to see what other log messages keep switching back and forth between GMT and local. r6413@totoro (orig r6412): arma | 2006-04-23 19:09:03 -0400 Regenerate our local descriptor if it's dirty and some local function asks for it. This may resolve bug 286. r6414@totoro (orig r6413): nickm | 2006-04-24 12:29:06 -0400 Add a stub of a "path-spec", containing only the helper-node emails from arma. whee. r6415@totoro (orig r6414): nickm | 2006-04-24 13:51:31 -0400 Possible partial fix for 285; needs review r6416@totoro (orig r6415): arma | 2006-04-24 17:11:56 -0400 resolve typos in add-tor contrib script r6417@totoro (orig r6416): nickm | 2006-04-25 01:42:09 -0400 Add some bullet points to write up r6418@totoro (orig r6417): nickm | 2006-04-25 01:59:31 -0400 fix a segfault in last bug-285-related commit. r6419@totoro (orig r6418): nickm | 2006-04-25 02:02:46 -0400 you wanted it spelled properly too? And me not even funded! r6420@totoro (orig r6419): arma | 2006-04-25 02:16:38 -0400 list some more items to remember in path-building r6421@totoro (orig r6420): nickm | 2006-04-25 02:20:47 -0400 Only warn about a down node once r6422@totoro (orig r6421): arma | 2006-04-25 03:00:04 -0400 petty cleanups r6423@totoro (orig r6422): arma | 2006-04-25 03:06:48 -0400 put one of the XXX's back in r6427@totoro (orig r6426): nickm | 2006-04-29 13:44:31 -0400 shorten some too-wide lines r6428@totoro (orig r6427): nickm | 2006-04-29 14:42:26 -0400 Start remembering *where* we are storing routerdescs. This will make us easier to move from a RAM-mirrors-disk model to a RAM-caches-disk model, and save maybe around 10MB on a directory server. r6429@totoro (orig r6428): nickm | 2006-04-29 14:43:05 -0400 Note some subtasks and difficulties involved with reducing RAM usage on dirservers r6431@totoro (orig r6430): arma | 2006-05-03 14:29:44 -0400 forward-port the ORPort==0 patch r6434@totoro (orig r6433): arma | 2006-05-03 14:32:15 -0400 forward-port the changelog r6438@totoro (orig r6437): phobos | 2006-05-03 20:34:51 -0400 Reworked dist-rpm in order to duplicate what dist used to do, but don't actually require dist. r6444@totoro (orig r6443): weasel | 2006-05-05 11:40:54 -0400 Merge differences between debian_version_0_1_1_18-rc-1 and debian_version_0_1_1_19-rc-1 from tor-0_1_1-patches into head r6445@totoro (orig r6444): weasel | 2006-05-05 12:58:38 -0400 Handle website/* in tor.nsi r6448@totoro (orig r6447): arma | 2006-05-08 00:28:49 -0400 stop telling people that "tor -h" will help them in any way. r6449@totoro (orig r6448): arma | 2006-05-09 05:47:47 -0400 Tor servers are also giving spurious "you're invalid" warnings. This is because we get a lot of network statuses that don't list us at all, and we conclude that they all think we're invalid. The long-term fix is to get better logic, and the short-term fix is to downgrade the log severity. r6451@totoro (orig r6450): arma | 2006-05-10 03:35:03 -0400 another piece of doing tor over udp that i am concerned about. r6452@totoro (orig r6451): arma | 2006-05-10 03:35:33 -0400 a few more tweaks to the faq. r6453@totoro (orig r6452): weasel | 2006-05-10 06:24:17 -0400 All these headers we get via torint.h r6455@totoro (orig r6454): phobos | 2006-05-16 01:48:08 -0400 Fixed //Library/Tor in Tor.loc for osx r6456@totoro (orig r6455): nickm | 2006-05-16 22:18:35 -0400 finally write some comments on tor-spec-udp.txt r6457@totoro (orig r6456): nickm | 2006-05-21 16:01:13 -0400 apply control-spec patch from Matt Edman: Circuit status only has a path when it has been extended one or more hops. r6458@totoro (orig r6457): arma | 2006-05-22 00:44:57 -0400 add a few items it would be smart todo r6459@totoro (orig r6458): arma | 2006-05-22 15:56:32 -0400 remove all the interim changelog stuff for 0.1.1.x r6460@totoro (orig r6459): arma | 2006-05-22 16:00:12 -0400 my current notes on a 0.1.1.20 changelog r6461@totoro (orig r6460): arma | 2006-05-22 16:16:18 -0400 other todo tweaks r6462@totoro (orig r6461): arma | 2006-05-22 16:26:30 -0400 shuffle the todo items some more r6464@totoro (orig r6463): nickm | 2006-05-22 19:24:06 -0400 Remove string size limit on NEWDESC messages; solve bug 291. r6466@totoro (orig r6465): arma | 2006-05-22 23:08:30 -0400 add a few more debugging lines to help mikec track down his 11 minute jump into the future. r6467@totoro (orig r6466): arma | 2006-05-22 23:27:39 -0400 two more todo items that need to be solved during the wsaenobufs quest. r6468@totoro (orig r6467): arma | 2006-05-23 00:05:45 -0400 claim a few of the todo items. i guess that means i'm hoping nick does the rest. ;) r6469@totoro (orig r6468): arma | 2006-05-23 02:20:35 -0400 continue messing with the changelog. it's getting better now. r6470@totoro (orig r6469): arma | 2006-05-23 03:03:30 -0400 document that runasdaemon has no effect on windows. r6472@totoro (orig r6471): arma | 2006-05-23 03:04:55 -0400 ignore RunAsDaemon more thoroughly when we're running on windows. r6474@totoro (orig r6473): nickm | 2006-05-23 04:23:03 -0400 Throw out this UNALIGNED_INT_ACCESS_OK nonsense. Even where it works, it is often way way slower than doing the right thing. Backport candidate. r6475@totoro (orig r6474): nickm | 2006-05-23 04:38:18 -0400 Patch from Michael Mohr to fix cross-compilation. Backport candidate. Tweaked to use sensible defaults for NULL_REP_IS_ZERO_BYTES and TIME_T_IS_SIGNED. r6476@totoro (orig r6475): nickm | 2006-05-23 04:50:39 -0400 Add cross.sh cross-compilation script from Michael Mohr. Trivial backport candidate, since adding a new script cannot possibly break anything. r6477@totoro (orig r6476): nickm | 2006-05-23 04:54:26 -0400 Mark cross-compilation as solved in TODO. r6478@totoro (orig r6477): arma | 2006-05-23 11:06:05 -0400 trim out the parts of cross.sh that don't make sense now that we've applied cross-path directly. also, now we can run cross.sh from the tarball, not just from cvs. r6479@totoro (orig r6478): arma | 2006-05-23 11:26:51 -0400 another todo item that will make goodell happy r6480@totoro (orig r6479): arma | 2006-05-23 13:00:49 -0400 final changelog for 0.1.1.20. it is done. r6487@totoro (orig r6486): weasel | 2006-05-23 14:19:36 -0400 Forward port changelog r6488@totoro (orig r6487): arma | 2006-05-23 16:15:51 -0400 fix spelling of VirtualAddrNetwork in man page (thanks tup) r6490@totoro (orig r6489): arma | 2006-05-23 20:21:55 -0400 Claim a commonname of Tor, rather than TOR, in tls handshakes. Maybe this will help us win the war of names. r6491@totoro (orig r6490): arma | 2006-05-23 20:37:38 -0400 Stop initializing the hardware accelerator engines simply because we overloaded the meaning of the argument to crypto_global_init(). r6492@totoro (orig r6491): phobos | 2006-05-24 01:01:29 -0400 Add in the key CFBundleIdentifier required by XCode 2.x and beyond. r6493@totoro (orig r6492): arma | 2006-05-24 07:13:03 -0400 make options->RedirectExit work again; resolve bug 293. r6495@totoro (orig r6494): arma | 2006-05-24 19:03:28 -0400 make cookie authentication for the controller work again, maybe. it sure doesn't now. r6497@totoro (orig r6496): arma | 2006-05-25 16:06:09 -0400 Stop being picky about what the arguments to mapaddress look like. we were refusing names that had $ in them, which people who specify $key.exit will be sad about. There are likely other examples. If people can think of reasons why we should be picky, let me know. r6500@totoro (orig r6499): phobos | 2006-05-26 09:22:20 -0400 SUSEisms to enable "make dist-rpm" functionality in SuSe r6501@totoro (orig r6500): phobos | 2006-05-26 09:32:56 -0400 Use macros in place of details. r6502@totoro (orig r6501): phobos | 2006-05-26 09:42:28 -0400 Let AC_OUTPUT know about contrib/suse/tor.sh and we only need tor.sh from contrib/suse r6503@totoro (orig r6502): arma | 2006-05-26 09:51:20 -0400 build the Makefile in contrib/suse/ too r6504@totoro (orig r6503): arma | 2006-05-26 09:51:45 -0400 resolve an unused variable r6506@totoro (orig r6505): arma | 2006-05-26 12:29:20 -0400 correct a false log message, since we actually reset all our downloading stats every hour, and sometimes more often. r6507@totoro (orig r6506): arma | 2006-05-26 12:29:33 -0400 be more verbose about testing reachability of our ORPort. r6508@totoro (orig r6507): arma | 2006-05-26 12:32:16 -0400 if we're a server and some peer has a broken tls certificate, don't shout about it unless we want to hear about protocol violations. r6509@totoro (orig r6508): arma | 2006-05-28 12:07:44 -0400 clean up a comment r6510@totoro (orig r6509): arma | 2006-05-28 12:14:26 -0400 directory authorities should be more tolerant of failed reachability tests before crying foul to the server operator. r6511@totoro (orig r6510): nickm | 2006-05-28 12:54:39 -0400 Add a basic mmap function, with a "fake-it" wrapper to do read_file_from_str instead. Based on code from Michael Mohr. r6512@totoro (orig r6511): arma | 2006-05-30 01:05:50 -0400 remove a few things from the 0.1.2 todo, and add one r6513@totoro (orig r6512): arma | 2006-05-30 01:29:03 -0400 simplify a log message r6514@totoro (orig r6513): arma | 2006-05-30 02:11:36 -0400 tentative change: if you have your dirport set, you are a directory mirror, whether or not your orport is set. r6515@totoro (orig r6514): arma | 2006-05-30 02:11:46 -0400 and clarify the spec to say this too. r6516@totoro (orig r6515): arma | 2006-05-30 02:17:28 -0400 END_CIRC_REASON_OR_IDENTITY apparently means that we were told to connect to a different OR than lives on the addr:port we connected to. we don't actually remember whether that was the case, currently. so call it END_CIRC_REASON_OR_CONN_CLOSED as a compromise. r6517@totoro (orig r6516): arma | 2006-05-30 02:19:06 -0400 stop fetching descriptors if we're not a dir mirror and we haven't tried to establish any circuits lately. r6518@totoro (orig r6517): arma | 2006-05-30 02:19:48 -0400 and get grammar right r6519@totoro (orig r6518): arma | 2006-05-30 02:23:44 -0400 connection_t kept the identity_pkey but all it did was store it and free it. perhaps we don't need it after all? r6520@totoro (orig r6519): arma | 2006-05-30 02:36:32 -0400 mark off a todo item. i'll put it back if it turns out it doesn't work. r6521@totoro (orig r6520): nickm | 2006-05-30 16:41:22 -0400 Rearrange TODO. r6522@totoro (orig r6521): arma | 2006-06-01 04:43:56 -0400 update the explanation for deprecating v0 control spec. r6523@totoro (orig r6522): arma | 2006-06-02 22:56:44 -0400 don't stop fetching server descriptors if we're a server and haven't found ourselves reachable yet. r6524@totoro (orig r6523): nickm | 2006-06-03 14:52:31 -0400 Patch based on post by Mike C to or-dev; special-case based on use of MSVC, rather than on MS_WINDOWS, so that mingw builds. r6525@totoro (orig r6524): nickm | 2006-06-03 15:49:42 -0400 Add async dns code from Adam Langley, tweaked to build on OSX. Long-term, we may want to switch to libevnet/c-ares, if they ever handle 10k fd situations properly. This one still needs work too, but at least it is small. This code is disabled by default, and not integrated with dns.c. r6526@totoro (orig r6525): nickm | 2006-06-03 16:52:24 -0400 Make dns.c use eventdns.c -- but only when you pass the --enable-eventdns argument to configure.in. This will *so* not work on Windows yet. r6527@totoro (orig r6526): nickm | 2006-06-03 17:41:14 -0400 More DNS fixes. Send meaningful TTLs back to the client when possible. Cache at the server side independently from the TTL, to prevent attackers from probing the server to see who has been asking for what hostnames. (Hi, Dan Kaminski!) Also, clean some whitespace. r6528@totoro (orig r6527): nickm | 2006-06-03 17:47:26 -0400 Oops. When we dont get a TTL, we should default to the default, not to the minimum. r6529@totoro (orig r6528): nickm | 2006-06-03 18:05:23 -0400 Make eventdns.[ch] into good C90; remove signed/unsigned comparisons. r6530@totoro (orig r6529): arma | 2006-06-04 02:16:20 -0400 punctuation and spelling r6531@totoro (orig r6530): arma | 2006-06-04 02:17:32 -0400 if we insist on printing pointer values, at least make it stop complaining on (my particular) 64 bit platform. r6533@totoro (orig r6532): nickm | 2006-06-04 18:42:13 -0400 Add a new warning to our "warn a lot" list: unused parameters. This means we have to explicitly "use" unuseds, but it can catch bugs. (It caught two coding mistakes so far.) r6534@totoro (orig r6533): nickm | 2006-06-04 19:23:53 -0400 Some eventdns.c fixes for windows correctness. More will doubtless be needed, especially around the #includes. r6535@totoro (orig r6534): nickm | 2006-06-04 20:32:31 -0400 Hm. Where did we put that ntohl the last time we were juggling it? (hoop-lah). r6536@totoro (orig r6535): nickm | 2006-06-04 21:59:12 -0400 More eventdns.c patches: use HAVE_ALLOCA_H; print IP addrs as dotted quads. r6537@totoro (orig r6536): arma | 2006-06-05 00:29:03 -0400 bandaid for bug 299. this is still a bug, since we don't initialize for hardware acceleration in certain configurations; but not critical until that is supported. r6539@totoro (orig r6538): arma | 2006-06-05 03:27:48 -0400 Note a bug that causes servers to sometimes never send the pending create cell. Nick, is this a bug? If so, is my fix right? r6540@totoro (orig r6539): arma | 2006-06-05 04:02:04 -0400 remove some unused code (i think) r6541@totoro (orig r6540): arma | 2006-06-05 04:25:02 -0400 simplify some code, since circuit_build_failed() is only called on non-open circuits. r6542@totoro (orig r6541): arma | 2006-06-05 04:58:18 -0400 bugfix: if we are making our first ever connection to any entry guard, then don't mark it down at first. we had this implemented but it was disabled due to a bug. r6544@totoro (orig r6543): arma | 2006-06-05 05:08:10 -0400 simplify code now that libevent considers all sockets pollable. what we really mean now is ">= 0", which is clearer to test for. r6545@totoro (orig r6544): arma | 2006-06-05 05:47:19 -0400 scream louder if you've got a pending circuit for a given addr/port but the intended n_conn digest is wrong. r6546@totoro (orig r6545): arma | 2006-06-05 05:51:29 -0400 whoops, add a man page entry for ProtocolWarnings r6547@totoro (orig r6546): arma | 2006-06-05 06:01:52 -0400 don't tell people that the testing circuit failed if we already consider ourselves reachable. this just confuses them. r6548@totoro (orig r6547): nickm | 2006-06-05 19:01:22 -0400 Try to log useful messages at info and debug about what we are resolving and what answers we are getting wrt eventdns. r6549@totoro (orig r6548): arma | 2006-06-05 20:04:52 -0400 ship the event*.h files too. perhaps this will make my 'make dist' produce a tarball that i can build. r6550@totoro (orig r6549): arma | 2006-06-05 20:05:39 -0400 fix typo r6551@totoro (orig r6550): arma | 2006-06-05 20:06:52 -0400 We got an obscure report of an assert error on a windows Tor server with connection_add being called with socket = -1. The only places I can see where that happen would be if our tor_socketpair succeeds but it hands back negative values for some of its file descriptors. Perhaps this will produce more useful assert errors next time. r6552@totoro (orig r6551): nickm | 2006-06-05 20:12:22 -0400 Also, add a temporary hack to make sure eventdns.c is distributd. r6553@totoro (orig r6552): arma | 2006-06-05 23:33:24 -0400 fix the bug where we sometimes would fail to send some create cells once we'd connected to a(nother) tor server. r6557@totoro (orig r6556): arma | 2006-06-06 22:57:23 -0400 looks like we missed a piece of the 0.1.1.9 paranoia code. hopefully this change is a no-op. r6558@totoro (orig r6557): arma | 2006-06-07 02:10:54 -0400 simplify the tortls api: we only support being a "server", that is, even tor clients do the same sort of handshake. this has been true for years, so it's best to get rid of the stale code. r6559@totoro (orig r6558): arma | 2006-06-07 02:21:11 -0400 and now the exciting part: there is now no such thing as doing a client-only tls, that is, one with no certs. r6560@totoro (orig r6559): arma | 2006-06-07 02:53:43 -0400 the CookieAuthentication section in our spec seems to assume we're still using the v0 control protocol. r6561@totoro (orig r6560): arma | 2006-06-07 03:11:42 -0400 make connection_or_nonopen_was_started_here() based on something less voodooey. it turns out we already do keep a flag like that around. r6562@totoro (orig r6561): arma | 2006-06-07 04:42:24 -0400 put a bandaid in place so servers will have an easier time believing that they're reachable. this may help resolve the servers-on-dynamic-ip-addresses problem. r6564@totoro (orig r6563): arma | 2006-06-07 05:18:53 -0400 re-enable per-connection rate limiting. get rid of the "OP bandwidth" concept. lay groundwork for "bandwidth classes" -- separate global buckets that apply depending on what sort of conn it is. r6566@totoro (orig r6565): arma | 2006-06-08 05:20:58 -0400 ah, that explains why we weren't going dormant with respect to descriptor fetches. maybe now it will work. r6567@totoro (orig r6566): arma | 2006-06-08 05:35:20 -0400 remove a bit more obsolete code r6569@totoro (orig r6568): arma | 2006-06-08 18:36:13 -0400 ok, ok, maybe *this* time my rep_hist_circbuilding_dormant() will work. r6570@totoro (orig r6569): arma | 2006-06-08 22:20:42 -0400 try a better string at the top of torrc's autogenerated torrc. r6571@totoro (orig r6570): arma | 2006-06-08 22:45:39 -0400 fix a bootstrapping check we ignored that prevents us from running with only one dir authority. r6572@totoro (orig r6571): arma | 2006-06-09 02:35:45 -0400 Bandaid for a seg fault i just got in 0.1.1.20. More generally, i reopened bug 222. Whee. r6574@totoro (orig r6573): arma | 2006-06-09 02:52:49 -0400 and forward-port too. r6576@totoro (orig r6575): arma | 2006-06-09 05:02:32 -0400 when only one router is labelled as a guard, and we've already picked him, we would cycle endlessly picking him again, being unhappy about it, and so forth. now we specifically exclude guards when picking a new guard. r6577@totoro (orig r6576): arma | 2006-06-09 05:07:59 -0400 actually, don't fix it that far. we should still do some error checking. r6579@totoro (orig r6578): nickm | 2006-06-09 11:57:58 -0400 Override our notion of printability for esc_for_log. 127 and up are never printable. Take that, locales. r6580@totoro (orig r6579): nickm | 2006-06-09 13:07:22 -0400 Another escape() fix, for picky sprintfs. r6582@totoro (orig r6581): arma | 2006-06-09 20:26:39 -0400 Add a new config option TestVia, that lets you specify preferred middle hops to use for testing circuits. Perhaps this will let me debug the reachability problem better. r6583@totoro (orig r6582): arma | 2006-06-09 20:30:49 -0400 clean up formatting in the man page r6584@totoro (orig r6583): arma | 2006-06-09 20:32:14 -0400 add TestVia to the man page r6586@totoro (orig r6585): arma | 2006-06-09 20:57:12 -0400 take out the reachability bandaid in 0.1.2.x as well. maybe we will actually be able to fix it, instead. r6596@totoro (orig r6595): phobos | 2006-06-10 01:37:17 -0400 Remove echo -n to make start script slightly more readable on boot. r6600@totoro (orig r6599): arma | 2006-06-10 21:41:30 -0400 interim changelog for 0.1.2.1-alpha r6601@totoro (orig r6600): arma | 2006-06-10 21:42:21 -0400 forward-port the 0.1.1.21 changelog. r6604@totoro (orig r6603): weasel | 2006-06-11 20:49:07 -0400 Forward port changelog r6605@totoro (orig r6604): arma | 2006-06-12 02:03:15 -0400 allow people to start their tor with runasdaemon set but with no logs set at all. r6606@totoro (orig r6605): arma | 2006-06-12 06:44:00 -0400 typo, whitespace, and a clarification r6607@totoro (orig r6606): arma | 2006-06-12 07:59:19 -0400 Finally solve the "closing wedged cpuworkers" bug. Woo. This happened when we got two create cells in a row from the same TLS connection. It would hand one to the cpuworker, and then immediately handle the second one -- after it had registered that the first one was busy, but before it had updated the timestamp that we use to decide how *long* it's been busy. r6609@totoro (orig r6608): weasel | 2006-06-12 18:03:25 -0400 Make the Exit tag in status documents actually work in head too r6610@totoro (orig r6609): arma | 2006-06-12 22:48:06 -0400 reintroduce the logic to exit_policy_is_general_exit() to count how many ports are allowd. require two ports open, not just one. r6611@totoro (orig r6610): arma | 2006-06-13 01:36:35 -0400 Fix the bug that was causing servers to not find themselves reachable if they changed IP addresses. This happened because middle servers knew the old descriptor, and kept swapping the addr/port we asked for with the one they thought was right. So the create cell never got sent, because it was asking for a different addr/port than we believed we had connected to. r6614@totoro (orig r6613): arma | 2006-06-13 01:50:24 -0400 harmless typo r6615@totoro (orig r6614): arma | 2006-06-13 01:51:28 -0400 Defense in depth: fix the reachability bug a second way too. Now if we establish a connection with the right digest, regardless of what the addr/port is, and we have pending create cells, use it. r6616@totoro (orig r6615): arma | 2006-06-13 05:16:09 -0400 export the default exit policy via the control port, so controllers don't need to guess what it is / will be later. r6617@totoro (orig r6616): arma | 2006-06-13 06:25:22 -0400 first cut at a workaround for the reachability bug: explicitly find a server running the right version, if we can, and ask for that one. r6618@totoro (orig r6617): arma | 2006-06-13 06:48:26 -0400 bugfix in exit_policy_is_general_exit() that weasel found. this time for sure! r6619@totoro (orig r6618): arma | 2006-06-13 07:11:19 -0400 now we can tell dirserv_dump_directory_to_string() whether we want it to include down/invalid descriptors or not. r6620@totoro (orig r6619): arma | 2006-06-13 08:05:59 -0400 be more lax about recognizing valid hexdigests. r6621@totoro (orig r6620): arma | 2006-06-13 08:57:19 -0400 back off and add the $ at the beginning of the preferrednodes list we generate. r6622@totoro (orig r6621): nickm | 2006-06-13 17:49:56 -0400 eventdns: Apply a couple of patches from AGL; start working on windows compat; note some TODOs. r6623@totoro (orig r6622): arma | 2006-06-14 07:06:43 -0400 bugfix: discourage picking directory authorities as our TestVia hops, even if they're running the right versions, since we probably already have a connection established to them. r6624@totoro (orig r6623): arma | 2006-06-14 18:28:16 -0400 upgrade the severity of the 'clock jump' warn, and ask people to report if it occurs. r6625@totoro (orig r6624): arma | 2006-06-14 19:21:22 -0400 start checking for limits.h too. we should resume compiling on irix64 and other weird platforms now. r6626@totoro (orig r6625): arma | 2006-06-15 05:03:15 -0400 lower the number of seconds before we yell about clock jump. and make the yelling only happen if you're a server. r6627@totoro (orig r6626): arma | 2006-06-15 18:32:00 -0400 fix recommended url in torrc.sample for server sign-up r6628@totoro (orig r6627): weasel | 2006-06-15 18:52:56 -0400 Add a /tor/dir-all-weaselhack directory resource so I do not have to update my scripts r6629@totoro (orig r6628): arma | 2006-06-15 18:59:07 -0400 fix spacing r6630@totoro (orig r6629): weasel | 2006-06-15 19:14:01 -0400 And a minor bugfix to the weaselhack r6631@totoro (orig r6630): weasel | 2006-06-15 19:20:50 -0400 Forward port 07_log_to_file_by_default.dpatch r6632@totoro (orig r6631): arma | 2006-06-15 20:04:46 -0400 clean up man page. expand on contactinfo a bit. r6633@totoro (orig r6632): weasel | 2006-06-15 22:04:04 -0400 Fix configure.in to not produce broken configure files with more recent versions of autoconf. Thanks to Clint for his auto* voodoo. r6634@totoro (orig r6633): nickm | 2006-06-16 11:40:57 -0400 Clarify mmap and memory-use hacks. r6635@totoro (orig r6634): nickm | 2006-06-18 03:21:35 -0400 Add smartlist_reverse and smartlist_pop_last. r6636@totoro (orig r6635): nickm | 2006-06-18 03:22:36 -0400 Add a memdup function to util r6637@totoro (orig r6636): nickm | 2006-06-18 03:24:29 -0400 Add some incremental encryption wrappers to torgzip code r6638@totoro (orig r6637): nickm | 2006-06-18 03:27:47 -0400 Part of incremental encryption logic for buffers: there is a subtle yucky point documented in a comment. r6639@totoro (orig r6638): nickm | 2006-06-18 03:32:31 -0400 perhaps the reason I rail against cut-and-paste programming so vehemently is that I am so bad at it. r6640@totoro (orig r6639): nickm | 2006-06-18 03:35:10 -0400 Add tests for several of the more recently committed functions. r6641@totoro (orig r6640): nickm | 2006-06-18 03:37:21 -0400 remove non-germane comment r6642@totoro (orig r6641): nickm | 2006-06-18 03:38:55 -0400 Instead of adding servers and v1 directories to buffers en masse, directory servers add them on the fly as their outbufs are depleted. This will save ram on busy dirservers. r6643@totoro (orig r6642): nickm | 2006-06-18 03:55:04 -0400 Oops. conn->requested_resource is client only. r6644@totoro (orig r6643): nickm | 2006-06-18 03:57:47 -0400 add coverage for a default case r6645@totoro (orig r6644): nickm | 2006-06-18 04:07:16 -0400 Fix a couple of bugs in last patch. r6646@totoro (orig r6645): nickm | 2006-06-18 04:13:45 -0400 That dir_refresh_src fix will only work if I enable it. r6647@totoro (orig r6646): nickm | 2006-06-18 04:16:05 -0400 And actually check the url when it exists. that might work better. r6648@totoro (orig r6647): nickm | 2006-06-18 04:19:35 -0400 Stop trying to refresh when we are out of data. r6649@totoro (orig r6648): nickm | 2006-06-18 04:21:27 -0400 make zlib buffer function set buf_highwater properly r6650@totoro (orig r6649): nickm | 2006-06-18 04:44:34 -0400 Temporarily disable sentinels on buffers r6651@totoro (orig r6650): nickm | 2006-06-18 04:46:55 -0400 write_to_buf != connection_write_to_buf. Also, add a connection_write_to_buf_zlib wrapper that sucks. r6652@totoro (orig r6651): nickm | 2006-06-18 04:53:09 -0400 Make connection_write_to_buf_zlib set outbuf_flushlen right. r6653@totoro (orig r6652): nickm | 2006-06-18 05:03:48 -0400 Another _zlib fix. r6654@totoro (orig r6653): nickm | 2006-06-18 11:53:54 -0400 Re-enable buffer RAM guard values. r6655@totoro (orig r6654): nickm | 2006-06-18 12:05:54 -0400 Backport candidate: implement the "is this uptime change cosmetic" test properly. r6657@totoro (orig r6656): nickm | 2006-06-18 12:20:38 -0400 another write_to_buf_zlib fix. r6658@totoro (orig r6657): nickm | 2006-06-18 12:39:26 -0400 Ah. That seems to work. r6659@totoro (orig r6658): nickm | 2006-06-18 16:39:46 -0400 Resolve control flow warning. r6660@totoro (orig r6659): nickm | 2006-06-18 16:58:27 -0400 Become capable of noticing that we are done sending a directory. r6661@totoro (orig r6660): arma | 2006-06-18 17:07:45 -0400 correct a function comment in compute_preferred_testing_list() r6663@totoro (orig r6662): nickm | 2006-06-18 17:15:01 -0400 Fix an assert that still isnt the assert we are hunting. r6664@totoro (orig r6663): nickm | 2006-06-18 17:30:03 -0400 Fix a tricky crash: making the_directory heap-allocated (so we could refcount it and have multiple instances as neeeded) means that calls to dirserv_regenerate_directory could invalidate the auth_dir value passed to dirserv_pick_cached_dir_obj. Big fun. r6665@totoro (orig r6664): nickm | 2006-06-19 20:48:23 -0400 Start spooling v2 networkstatus docs as well. r6666@totoro (orig r6665): phobos | 2006-06-20 00:16:46 -0400 First crack at version checking for OSX installer. r6667@totoro (orig r6666): phobos | 2006-06-20 00:18:47 -0400 Minor fix to pre-instllation version check for OSX r6668@totoro (orig r6667): nickm | 2006-06-20 02:27:13 -0400 Ah. We need a new zlib_state for each networkstatus we spool out. r6669@totoro (orig r6668): arma | 2006-06-20 09:14:07 -0400 add a note for nick to fix r6670@totoro (orig r6669): nickm | 2006-06-20 12:48:32 -0400 Fishy, but harmless. r6671@totoro (orig r6670): nickm | 2006-06-20 19:06:52 -0400 Fix bug in networkstatus spooling: spool more than the first networkstatus. r6672@totoro (orig r6671): weasel | 2006-06-20 19:11:15 -0400 <nickm> ooh, that log shouldn't be there. can you take it out? r6673@totoro (orig r6672): phobos | 2006-06-20 22:27:18 -0400 Remove the osx version requirements on install due to a messy Installer situation between pre-panther, tiger and beyond, and metapackages. r6674@totoro (orig r6673): nickm | 2006-06-21 00:57:12 -0400 When requesting or serving resources via fingerprint/digest, request and respond in-order, removing duplicates. r6675@totoro (orig r6674): weasel | 2006-06-21 18:13:03 -0400 Fix 07_log_to_file_by_default in debian head r6676@totoro (orig r6675): nickm | 2006-06-22 03:01:54 -0400 Next batch of memory miserdom: mmap cached-routers file. This is sure to break somewhere. r6677@totoro (orig r6676): nickm | 2006-06-22 03:10:37 -0400 #if out test that was failing because of an extra newline. r6678@totoro (orig r6677): nickm | 2006-06-22 03:19:28 -0400 Set offset properly when parsing cache. r6679@totoro (orig r6678): nickm | 2006-06-22 03:25:15 -0400 Fix a bunch of spaces. r6680@totoro (orig r6679): nickm | 2006-06-22 03:29:14 -0400 Ooh, that could have been bad. Sort digests as digests, not strings. r6681@totoro (orig r6680): nickm | 2006-06-22 03:34:04 -0400 Make some more verbose gcc warnings go away. r6682@totoro (orig r6681): nickm | 2006-06-22 03:49:41 -0400 Mark some more TODO items done. r6683@totoro (orig r6682): nickm | 2006-06-23 22:06:52 -0400 Apparently, zlib sometimes reports Z_BUF_ERROR on input exhaustion as well as on running out of output space. This could well fix the assert bug reported by weasel and arma. r6684@totoro (orig r6683): nickm | 2006-06-23 22:10:21 -0400 Turn a while into a do/while; save a redundant test r6685@totoro (orig r6684): arma | 2006-06-24 00:57:59 -0400 refuse to write an iso_time which we can't parse, when dumping bandwidth state. this fixes the particular incident in bug 308, but the general issue remains. r6686@totoro (orig r6685): phobos | 2006-06-25 00:02:43 -0400 Create binary osx un-installer, update perms on install so anyone can run the uninstaller. r6689@totoro (orig r6688): phobos | 2006-06-25 00:07:24 -0400 Fix the messed up commit. r6690@totoro (orig r6689): phobos | 2006-06-25 00:08:21 -0400 And, commit it correctly. r6693@totoro (orig r6692): arma | 2006-06-27 07:23:10 -0400 specify the dir spec better (suggested by lexi) r6694@totoro (orig r6693): nickm | 2006-06-27 11:52:51 -0400 Likely fix for bug 309: when we calculate offsets after rebuilding the descriptor cache, do not reset the offset pointer half-way through. r6695@totoro (orig r6694): nickm | 2006-06-28 04:54:32 -0400 Actually enable mmap. That should improve matters. r6696@totoro (orig r6695): nickm | 2006-06-28 04:55:53 -0400 Make sure that our calculated offsets for routers is correct; again. This time bug 309 may be gone gone gone. r6697@totoro (orig r6696): nickm | 2006-06-28 04:57:41 -0400 Aaand re-disable the bogus test in get_body() r6698@totoro (orig r6697): nickm | 2006-06-28 07:03:34 -0400 Add a check to try to make cache rebuild fail fast if it is going to fail r6699@totoro (orig r6698): nickm | 2006-06-28 11:36:28 -0400 Fix another idiot bug causing symptom 309. Why cant I program? r6700@totoro (orig r6699): arma | 2006-06-28 11:39:02 -0400 tab-man strikes again r6701@totoro (orig r6700): nickm | 2006-06-29 07:04:42 -0400 complete_only == !allow_partial. This enables useful use of partial desc downloads. Backport candidate r6702@totoro (orig r6701): nickm | 2006-06-29 07:17:36 -0400 Harmless: Z_OK is not an acceptable answer to Z_FINISH. r6703@totoro (orig r6702): nickm | 2006-06-29 07:19:52 -0400 Apparent 311 fix: apparently passing Z_FINISH an empty string is problematic. r6704@totoro (orig r6703): arma | 2006-06-29 09:10:08 -0400 remove the word 'middleman' from the sample torrc r6705@totoro (orig r6704): arma | 2006-06-29 09:11:23 -0400 also remove word 'middleman' from a log notice r6706@totoro (orig r6705): nickm | 2006-06-30 06:50:43 -0400 Unify HTTP response code into one place so it is easier to add headers. Add an X-You-Are header, which we should probably rename. NOTE that we should not use this field for things where it matters if dirs lie. r6707@totoro (orig r6706): nickm | 2006-06-30 06:52:12 -0400 Add a .cvsignore file for contrib/suse/ r6708@totoro (orig r6707): nickm | 2006-07-01 17:51:21 -0400 Oops. Headers work better when named right. r6710@totoro (orig r6709): arma | 2006-07-03 23:19:59 -0400 minor fixes r6711@totoro (orig r6710): arma | 2006-07-03 23:25:07 -0400 minor fixes r6712@totoro (orig r6711): arma | 2006-07-03 23:27:09 -0400 No longer permit create cells to have the wrong circ_id_type. No running Tors should still have this bug. r6713@totoro (orig r6712): arma | 2006-07-03 23:31:27 -0400 Get rid of the router_retry_connections notion. Now routers no longer try to rebuild long-term connections to directory authorities, and directory authorities no longer try to rebuild long-term connections to all servers. We still don't hang up connections in these two cases though -- we need to look at it more carefully to avoid flapping, and we likely need to wait til 0.1.1.x is obsolete. r6714@totoro (orig r6713): arma | 2006-07-03 23:33:17 -0400 touch up the TODO and HACKING files r6715@totoro (orig r6714): arma | 2006-07-03 23:39:01 -0400 mention in the tor dmg instructions that you may need to remove your old shared library libevent, lest your linker get confused. r6716@totoro (orig r6715): arma | 2006-07-03 23:40:45 -0400 a first attempt at specifying HELLO cells. plus general cleanup on tor-spec. r6717@totoro (orig r6716): arma | 2006-07-04 11:51:59 -0400 if we're the server-side of the tls and there are problems, don't yell as loudly. r6718@totoro (orig r6717): arma | 2006-07-04 11:52:22 -0400 fix a misleading function comment r6720@totoro (orig r6719): arma | 2006-07-04 12:07:49 -0400 name the HELLO version the "link version" r6721@totoro (orig r6720): arma | 2006-07-04 12:11:35 -0400 ok, i'm not allowed to say that there. oh well. r6723@totoro (orig r6722): arma | 2006-07-04 14:18:08 -0400 Make the X-You-Are header more accurate when there's a proxy in the middle. r6727@totoro (orig r6726): arma | 2006-07-04 16:25:17 -0400 oops, we were ignoring options->ExcludeNodes when picking entry guards. it is still the case that we ignore it with respect to entry guards that we've already picked. r6728@totoro (orig r6727): arma | 2006-07-05 14:19:42 -0400 actually, that excludenodes fix was redundant. take it out. r6729@totoro (orig r6728): nickm | 2006-07-05 17:28:37 -0400 Add plausile logging support to eventdns; stop putting stuff onto stdout. r6730@totoro (orig r6729): nickm | 2006-07-05 17:33:46 -0400 Spelling fix. r6731@totoro (orig r6730): nickm | 2006-07-05 17:42:18 -0400 Clean up eventdns messages. r6734@totoro (orig r6733): arma | 2006-07-05 22:44:07 -0400 when an exit node gets a malformed begin cell, don't complain to the node operator, since he can't do anything about it. r6735@totoro (orig r6734): arma | 2006-07-05 22:45:46 -0400 whitespace/tab fixes r6736@totoro (orig r6735): arma | 2006-07-05 23:05:01 -0400 rename X-You-Are to something slightly better. r6737@totoro (orig r6736): phobos | 2006-07-06 11:51:07 -0400 Update osx binary un-installer naming, remove invalid osx binary un-installer app r6739@totoro (orig r6738): arma | 2006-07-06 12:19:00 -0400 forward-port the 0.1.1.22 changelog, minus the line about the osx uninstaller. r6740@totoro (orig r6739): phobos | 2006-07-06 12:28:19 -0400 Remove osx binary uninstaller changes. Tiger and Panther won't play nice in the same way. r6742@totoro (orig r6741): phobos | 2006-07-06 20:54:39 -0400 Binary OSX un-installer tarball r6743@totoro (orig r6742): phobos | 2006-07-06 20:55:12 -0400 Updated OSX binary un-installer for testing. r6744@totoro (orig r6743): nickm | 2006-07-07 13:31:56 -0400 eventdns: check for malloc() failures. r6745@totoro (orig r6744): nickm | 2006-07-07 13:33:30 -0400 When using eventdns: suppress logging of addresses when SafeLogging is active, and make set of nameservers configurable from torrc. r6746@totoro (orig r6745): nickm | 2006-07-07 15:08:44 -0400 Spellcheck and remove spurious include in eventdns.c r6747@totoro (orig r6746): arma | 2006-07-08 13:38:46 -0400 Fix a crash if you enable FascistFirewall but not FirewallPorts. Reported by Frediano Ziglio. r6749@totoro (orig r6748): nickm | 2006-07-09 18:28:12 -0400 First part of making mmap-based stuff work on win32: save descriptors as "binary" (no LF->CRLF tanslation) so that we can mmap them properly later. Patch from Frediano Ziglio. r6750@totoro (orig r6749): nickm | 2006-07-09 18:29:12 -0400 Make compilation work on old MSVCs without GetVertsionEx magic. Patch from Frediano Ziglio. r6751@totoro (orig r6750): nickm | 2006-07-09 18:33:21 -0400 Fix project file for MSVC6 (!). Patch from Frediano Ziglio. r6752@totoro (orig r6751): nickm | 2006-07-10 14:38:57 -0400 Add a const; fix a (probably harmless) bug when storing a resolve we forgot we asked for. r6753@totoro (orig r6752): nickm | 2006-07-10 23:33:16 -0400 OR_CONN_EVENT_NEW: we should probably handle that , should we not? Especially since 23:26 < phobos> nickm: grep -c "Unrecognized status code 4" tor.log r6754@totoro (orig r6753): phobos | 2006-07-11 00:27:12 -0400 First crack at launchd plist for Tor r6755@totoro (orig r6754): phobos | 2006-07-11 00:37:05 -0400 Add in start parameters. Perhaps we should ship these set correct in the default torrc. r6756@totoro (orig r6755): phobos | 2006-07-11 16:51:06 -0400 Move cmd line parameters into the config file, remove chroot, and satisfy the requirement of a ProgramArgument array r6757@totoro (orig r6756): nickm | 2006-07-11 16:51:58 -0400 Add some debugging asserts to dns.c; these are too expensive to leave in permanently. r6758@totoro (orig r6757): phobos | 2006-07-12 18:09:21 -0400 Update config to redirect output to the tor log file for now. r6759@totoro (orig r6758): arma | 2006-07-13 23:14:02 -0400 Avoid an integer underflow when the dir authority decides whether a router is stable: we might wrongly label it stable, and compute a slightly wrong median stability, when a descriptor is published later than now. Inspired by Matt's Vidalia checkin: http://trac.vidalia-project.net/changeset/1074 r6761@totoro (orig r6760): arma | 2006-07-15 01:49:57 -0400 minor tweak on the dir spec r6762@totoro (orig r6761): arma | 2006-07-15 01:50:22 -0400 mention the existence of dir-spec in tor-spec, and note that we need to update it. r6763@totoro (orig r6762): arma | 2006-07-15 01:53:41 -0400 add a whole lot more work to the todo. r6764@totoro (orig r6763): arma | 2006-07-15 15:21:30 -0400 stick to nick's nul/null convention r6765@totoro (orig r6764): arma | 2006-07-15 16:26:05 -0400 parameterize the loudness of resolve_my_address(), and call things IP addresses, not IPs. r6766@totoro (orig r6765): arma | 2006-07-16 01:57:11 -0400 whitespace/etc cleanups r6767@totoro (orig r6766): phobos | 2006-07-16 09:58:10 -0400 Change the way Tor starts on OSX 10.4 vs pre-10.4. 10.4 Tor now uses launchd for current and forward compatibility. r6768@totoro (orig r6767): phobos | 2006-07-16 14:18:40 -0400 Remove a merged if-then from line 85 r6769@totoro (orig r6768): nickm | 2006-07-16 20:39:05 -0400 MSVC6 is apparently terrified of unnatural cross-breeding between uint64_t and double, and needs more persuasion than usual to cast one to the other. Issue identified by Frediano Ziglio; patch revised for minimal impact on non-MSVC6 compilers. r6770@totoro (orig r6769): phobos | 2006-07-16 23:57:21 -0400 Added net.freehaven.tor.plist to AC_OUTPUT r6771@totoro (orig r6770): phobos | 2006-07-17 00:31:22 -0400 Minor fixed for launchd xml plist r6772@totoro (orig r6771): arma | 2006-07-17 01:12:54 -0400 nick suggests that the hello cell should have both server IP and client IP. he's right. r6773@totoro (orig r6772): arma | 2006-07-17 02:20:09 -0400 fix wordo r6774@totoro (orig r6773): arma | 2006-07-17 02:26:19 -0400 we are constrained more than we realized, on what g^x values we can accept or refuse. r6775@totoro (orig r6774): arma | 2006-07-17 02:35:06 -0400 Allow servers with no hostname or IP address to learn their IP address by asking the directory authorities. This code only kicks in when you would normally have exited with a "no address" error. This design is flawed, though, since the X-Your-Address-Is header is not authenticated, and doing it this way introduces too many new attacks. The right answer is to give IP address hints inside the HELLO cell; much of this code can be reused when we switch. r6776@totoro (orig r6775): arma | 2006-07-17 02:54:28 -0400 fix some more places where we shouldn't crash if we can't build our own descriptor yet. r6778@totoro (orig r6777): arma | 2006-07-17 02:59:56 -0400 and don't try to build the descriptor every second, if it's dirty but we don't have a known address. r6779@totoro (orig r6778): arma | 2006-07-17 04:11:27 -0400 huge bugfix: we weren't ever writing an http header when sending out network statuses! so clients were downloading the whole thing, and then discarding them because they're malformed. r6780@totoro (orig r6779): arma | 2006-07-17 04:17:51 -0400 Make a louder statement the first time we learn a guessed IP address. r6781@totoro (orig r6780): arma | 2006-07-17 15:33:54 -0400 parameterize the loudness of log_addr_has_changed(), since it's the only place where we inform the user of a new IP address, if we're guessing it from external sources. r6782@totoro (orig r6781): arma | 2006-07-17 15:42:22 -0400 shuffle todo items r6783@totoro (orig r6782): arma | 2006-07-17 20:01:12 -0400 pick a log domain; resolve an xxxx r6784@totoro (orig r6783): arma | 2006-07-17 20:59:46 -0400 If we are using an exit enclave and we can't connect, e.g. because its webserver is misconfigured to not listen on localhost, then back off and try connecting from somewhere else before we fail. r6785@totoro (orig r6784): nickm | 2006-07-17 22:01:32 -0400 Hm. We probably should define INT64_MAX if we really want it. (Especially since we only want it on one platform, where, coincidentally, it is not defined.) r6786@totoro (orig r6785): nickm | 2006-07-17 22:24:01 -0400 Oh. And apparently, msvc6 doesnt think very much of doing u64-and-double arithmetic either. r6787@totoro (orig r6786): arma | 2006-07-17 23:06:12 -0400 Start publishing one minute or so after we find our ORPort to be reachable. This will help reduce the number of descriptors we have for ourselves floating around, since it's quite likely other things (e.g. DirPort) will change during that minute too. r6788@totoro (orig r6787): arma | 2006-07-17 23:06:55 -0400 when we find our dirport to be reachable, mark our descriptor dirty so we'll tell the world. (fixes bug 306 reported by pnx) r6789@totoro (orig r6788): phobos | 2006-07-18 00:37:43 -0400 Add the output of OSX arch into the package name in preparation for ppc vs x86 packages. r6790@totoro (orig r6789): phobos | 2006-07-18 00:40:02 -0400 Load and start tor in launchd at end of installation r6791@totoro (orig r6790): arma | 2006-07-18 00:42:32 -0400 Define a schedule for how long to wait between retrying application connections. Rather than waiting a fixed amount of time between each retry, we wait only 5 seconds for the first, 10 seconds for the second, and 15 seconds for each retry after that. Hopefully this will improve the expected experience. Addresses bug 297. r6792@totoro (orig r6791): arma | 2006-07-18 00:48:59 -0400 don't squeal if the first few retries fail. r6793@totoro (orig r6792): nickm | 2006-07-20 12:47:35 -0400 Fork off v0 of the protocol spec; we are going to add versioning soon so we can make backward-incompatible changes without breaking the whole network. Also, fork the v0 directory protocol into its own document, and turn dir-spec.txt into the present tense. r6794@totoro (orig r6793): nickm | 2006-07-20 12:48:02 -0400 Add a few more paragraphs to path-spec.txt r6795@totoro (orig r6794): nickm | 2006-07-20 13:35:54 -0400 Document HELLO cells and proposed connection protocol versioning scheme. NOTE: This will not work as documented; see notes. r6796@totoro (orig r6795): arma | 2006-07-20 19:33:11 -0400 tweak r6797@totoro (orig r6796): arma | 2006-07-20 19:45:26 -0400 tweak r6798@totoro (orig r6797): phobos | 2006-07-21 00:30:19 -0400 Grammar fixes for clarity. r6799@totoro (orig r6798): arma | 2006-07-21 03:06:18 -0400 an entry guard that is "unlisted", as well as not known to be "down", is not therefore "up". r6800@totoro (orig r6799): arma | 2006-07-21 03:53:21 -0400 tweak r6801@totoro (orig r6800): arma | 2006-07-21 03:55:35 -0400 bugfix: if you find yourself reachable, then don't ever make any client requests (so you stop predicting circuits), then hup, then later your IP changes, you won't think circuits are working so you won't try to test reachability, so you won't publish. r6803@totoro (orig r6802): nickm | 2006-07-21 10:53:23 -0400 Another MSVC6 fix. Grnk. r6804@totoro (orig r6803): nickm | 2006-07-21 18:02:58 -0400 These asserts will either cause spurious crashes or help debug the pend->conn->s == -1 issue. r6805@totoro (orig r6804): arma | 2006-07-22 01:29:31 -0400 more bulletproof reachability testing r6806@totoro (orig r6805): arma | 2006-07-22 03:15:34 -0400 i lied, that won't work at all. maybe this will. r6807@totoro (orig r6806): arma | 2006-07-22 03:19:11 -0400 think harder about my logic r6809@totoro (orig r6808): arma | 2006-07-23 01:18:29 -0400 whitespace and docs r6810@totoro (orig r6809): arma | 2006-07-23 01:19:31 -0400 more todo items r6811@totoro (orig r6810): nickm | 2006-07-23 01:32:35 -0400 Add a mem_is_zero function (I think we will need this) and a STRUCT_OFFSET macro (we already need this). r6812@totoro (orig r6811): nickm | 2006-07-23 01:33:10 -0400 Remove STRUCT_OFFSET from config.c r6813@totoro (orig r6812): nickm | 2006-07-23 01:39:37 -0400 Add (void) lines for unused parameters in eventdns.c r6814@totoro (orig r6813): nickm | 2006-07-23 01:40:24 -0400 Delete trailing whitespace in eventdns.c r6815@totoro (orig r6814): arma | 2006-07-23 01:52:27 -0400 use tor_mem_is_zero() in more places. r6816@totoro (orig r6815): arma | 2006-07-23 02:41:02 -0400 rewrite conn->address for GET commands as well as POST commands. r6817@totoro (orig r6816): nickm | 2006-07-23 03:19:49 -0400 Whitespace fix r6818@totoro (orig r6817): nickm | 2006-07-23 03:37:35 -0400 Don't tell anybody, but we're going OO here. This patch splits circuit_t into origin_circuit_t and or_circuit_t. I fixed some segaults; there may be more. We still need to move more rendezvous stuff into subtypes. This is a trial run for splitting up connection_t; if the approach is insane, please say so soon so we can do something smarter. Also, this discards the old HALF_OPEN code, which nobody seems to want. r6819@totoro (orig r6818): nickm | 2006-07-23 04:13:45 -0400 Fix another segfault in assert_circuit_ok. r6820@totoro (orig r6819): arma | 2006-07-23 07:50:03 -0400 publish a new descriptor after we hup. this is important if our config has changed such that we'll want to start advertising our dirport now, etc. r6821@totoro (orig r6820): phobos | 2006-07-23 08:52:06 -0400 These settings are required for those using launchd in OSX 10.4. This is a crude but functional way to insert them for now. r6822@totoro (orig r6821): weasel | 2006-07-23 23:24:25 -0400 Previously our defaults for DataDirectory, PidFile, RunAsDaemon, and Log differed from upstreams. Now Tor behaves just like before (with our own DataDirectory and all) only when run as the debian-tor user. If invoked as any other user, Tor will behave just like the pristine upstream version. r6823@totoro (orig r6822): weasel | 2006-07-23 23:38:26 -0400 Tell users about the init script when they try to run Tor as root. Should we also do this when they try to run their Tor as any other (non root, non debian-tor) user? - add 11_tor_as_root_more_helpful r6892@totoro (orig r6891): weasel | 2006-07-24 21:00:48 -0400 Remove .cvsignore files from trunk r6894@totoro (orig r6893): nickm | 2006-07-24 21:13:04 -0400 Add an item to the TODO. r6899@totoro (orig r6898): nickm | 2006-07-25 00:34:14 -0400 Remove code to special-case "-cvs" ending, since it has not actually mattered since 0.0.9. Perhaps we can special-case even more... r6900@totoro (orig r6899): nickm | 2006-07-25 18:26:42 -0400 Add libor.a and libor-crypto.a to svn:ignore r6901@totoro (orig r6900): nickm | 2006-07-25 18:30:50 -0400 Allow wide lines if they have svn id tags in them. (This matters for svk: those tags can be *big*.) r6902@totoro (orig r6901): nickm | 2006-07-25 18:33:57 -0400 Apply checkSpace.pl to checkSpace.pl. r6903@totoro (orig r6902): nickm | 2006-07-25 18:51:51 -0400 Clarify a TODO, and test tweaked commit-email.pl script. r6904@totoro (orig r6903): nickm | 2006-07-26 15:05:34 -0400 r6902@Kushana: nickm | 2006-07-25 17:30:27 -0400 Move rend_query to origin_circuit_t where it belongs; save another 17 bytes per OR circuit. r6905@totoro (orig r6904): nickm | 2006-07-26 15:05:41 -0400 r6903@Kushana: nickm | 2006-07-25 18:22:48 -0400 No circuit can be both an intro point and a rend point, so we can merge both the cookie and the pk digest into one "rend_token" field for or circuits. This saves another 20 bytes per or circuit. r6906@totoro (orig r6905): nickm | 2006-07-26 15:07:23 -0400 r6907@Kushana: nickm | 2006-07-25 19:03:43 -0400 Realign circuit structs to avoid wasted space. r6907@totoro (orig r6906): nickm | 2006-07-26 15:07:26 -0400 r6908@Kushana: nickm | 2006-07-26 12:38:52 -0400 Refactor connection_t into edge, or, dir, control, and base subtypes. This might save some RAM on busy exit servers, but really matters most in terms of correctness. r6908@totoro (orig r6907): nickm | 2006-07-26 15:07:37 -0400 r6909@Kushana: nickm | 2006-07-26 13:05:58 -0400 Clean up wide lines from last patch. r6909@totoro (orig r6908): nickm | 2006-07-26 15:29:30 -0400 r6918@Kushana: nickm | 2006-07-26 15:22:28 -0400 Fix compilation for eventdns dns.c with split structs. r6910@totoro (orig r6909): nickm | 2006-07-26 15:39:47 -0400 r6920@Kushana: nickm | 2006-07-26 15:39:40 -0400 Mark some TODO items done r6911@totoro (orig r6910): phobos | 2006-07-26 17:50:27 -0400 Set Soft & Hard resource limits to appease launchd. r6912@totoro (orig r6911): phobos | 2006-07-26 19:52:59 -0400 OSX pre-install script to clean up Tor and force a fresh install, but save the server keys if they exist. r6913@totoro (orig r6912): phobos | 2006-07-26 20:19:36 -0400 Be better at finding the Tor install path, backup all of Tor just in case, then blow Tor away r6914@totoro (orig r6913): phobos | 2006-07-26 21:20:02 -0400 Backup only what is needed, write the file we created to a temp file for TorPostFlight to restore the data and remove the temp files r6915@totoro (orig r6914): phobos | 2006-07-26 23:02:47 -0400 The whole process works from preflight to postflight creating a clean Tor install with proper config file edits r6916@totoro (orig r6915): phobos | 2006-07-26 23:10:23 -0400 OSX gets confused when you have two ways to start the same program. r6917@totoro (orig r6916): phobos | 2006-07-26 23:17:50 -0400 Oops, forgot the all important 'r' r6919@totoro (orig r6918): nickm | 2006-07-27 00:10:51 -0400 Fix comments that implied that only dir connections had a purpose field, and the code that believed in those comments. r6920@totoro (orig r6919): nickm | 2006-07-27 01:03:57 -0400 r6922@Kushana: nickm | 2006-07-26 16:32:24 -0400 Rename some fields, compress a bitfield, and document some structs and fields r6923@totoro (orig r6922): nickm | 2006-07-27 13:16:10 -0400 Add more asserts in dns_found_answer. This may confirm my theory that dns_purge_resolve is the culprit. r6924@totoro (orig r6923): phobos | 2006-07-27 13:19:32 -0400 Far better test and handling of existing torrc r6925@totoro (orig r6924): nickm | 2006-07-27 13:37:37 -0400 Get better numbers out of HT_REP_OK r6926@totoro (orig r6925): nickm | 2006-07-27 14:35:25 -0400 Fix a bug in HT_REMOVE. r6927@totoro (orig r6926): nickm | 2006-07-27 14:35:56 -0400 More asserts in dns.c r6928@totoro (orig r6927): arma | 2006-07-27 15:35:11 -0400 resolve typo r6929@totoro (orig r6928): phobos | 2006-07-27 16:03:09 -0400 fi, fy fo fum, if-then- doesn't work without one r6930@totoro (orig r6929): phobos | 2006-07-27 16:24:53 -0400 Forget leopard. r6933@totoro (orig r6932): phobos | 2006-07-28 09:52:36 -0400 So long, farewell, auf Wiedersehen, adieu, launchd r6934@totoro (orig r6933): nickm | 2006-07-28 11:11:11 -0400 r6948@Kushana: nickm | 2006-07-28 10:10:35 -0400 Identify some likely target fields for lowering; lower global_identifier (since we only use it for AP streams and origin circs). r6935@totoro (orig r6934): nickm | 2006-07-28 11:11:20 -0400 r6949@Kushana: nickm | 2006-07-28 10:17:38 -0400 Shave another 8 bytes from connection_t: turn inbuf_reached_eof into a bit, and lower timestamp_lastempty to or_connection_t r6936@totoro (orig r6935): nickm | 2006-07-28 11:11:28 -0400 r6950@Kushana: nickm | 2006-07-28 10:32:08 -0400 Document split fields better. Now, I think we can take a break from type splitting for a bit. r6937@totoro (orig r6936): phobos | 2006-07-29 23:32:54 -0400 Remove the launchd plist file. r6938@totoro (orig r6937): arma | 2006-07-29 23:34:44 -0400 a bit more debugging for phobos r6939@totoro (orig r6938): phobos | 2006-07-29 23:53:18 -0400 Remove the last vestiges of launchd plist. r6940@totoro (orig r6939): arma | 2006-07-30 00:32:58 -0400 defense in depth r6945@totoro (orig r6944): arma | 2006-07-30 00:45:59 -0400 forward-port the website hack. note that with svn, our build system seems to build in-place, so the website/ and img/ directories actually get created in my sandbox. poo. r6946@totoro (orig r6945): arma | 2006-07-30 00:54:13 -0400 fix assert found by DreadWingKnight: now that rendezvous streams are attached to p_streams, the p_streams list can consist of both AP and EXIT conns. r6947@totoro (orig r6946): arma | 2006-07-30 01:36:17 -0400 forward-port the 0.1.1.23 changelog. r6953@totoro (orig r6952): nickm | 2006-07-31 13:59:11 -0400 r6952@Kushana: nickm | 2006-07-28 11:09:37 -0400 Add completely untested find-my-nameservers code for win32. r6954@totoro (orig r6953): nickm | 2006-07-31 13:59:37 -0400 r6958@Kushana: nickm | 2006-07-29 18:54:15 -0400 Looks like we might need a priority queue. r6955@totoro (orig r6954): nickm | 2006-07-31 14:00:18 -0400 r6959@Kushana: nickm | 2006-07-29 22:33:18 -0400 start restructuring dns to use priority queues for expiring entries. r6956@totoro (orig r6955): nickm | 2006-07-31 14:00:47 -0400 r6957@totoro (orig r6956): nickm | 2006-07-31 14:01:18 -0400 r6977@Kushana: nickm | 2006-07-31 13:01:28 -0400 Solve timing-out pending connections. Add pending resolves to expiry queue; when we find an answer, change the pending resolve to "done" and stick the actual answer in the expiry queue as a new entry. This uses a little more memory, but makes the code simpler than other solutions. r6958@totoro (orig r6957): nickm | 2006-07-31 14:01:22 -0400 r6978@Kushana: nickm | 2006-07-31 13:16:14 -0400 Add isupper and islower wrappers to compat.h r6959@totoro (orig r6958): nickm | 2006-07-31 14:01:27 -0400 r6979@Kushana: nickm | 2006-07-31 13:16:58 -0400 Add assert_ok functions for strmap and digestmap; use them in unit test code. r6960@totoro (orig r6959): nickm | 2006-07-31 14:01:37 -0400 r6980@Kushana: nickm | 2006-07-31 13:18:22 -0400 Add a utility function to verify that a string has been through strlower. r6961@totoro (orig r6960): nickm | 2006-07-31 14:01:45 -0400 r6981@Kushana: nickm | 2006-07-31 13:23:26 -0400 More asserts for cache correctness. r6962@totoro (orig r6961): nickm | 2006-07-31 14:01:49 -0400 r6982@Kushana: nickm | 2006-07-31 13:47:19 -0400 documentation and naming tweaks in dns.c r6963@totoro (orig r6962): nickm | 2006-07-31 16:19:58 -0400 r6993@Kushana: nickm | 2006-07-31 16:19:21 -0400 Interesting how much a ! can change the behavior of an assert. r6964@totoro (orig r6963): arma | 2006-07-31 16:25:57 -0400 more compile options mean more codepaths r6965@totoro (orig r6964): arma | 2006-08-01 00:08:15 -0400 man, our sample torrc sucked. r6966@totoro (orig r6965): arma | 2006-08-02 01:17:22 -0400 explain that the exitlist isn't perfect, because some tor exit nodes don't exit on their advertised address. r6969@totoro (orig r6968): weasel | 2006-08-02 21:50:10 -0400 r8207@galaxy: weasel | 2006-08-03 03:22:17 +0200 Merge in local revisions 7944, 8205, and 8206: Forward port 0.1.1.x changelog to trunk r6970@totoro (orig r6969): arma | 2006-08-03 00:22:25 -0400 fix a seg fault on exit for clients; and fix a comment. r6971@totoro (orig r6970): arma | 2006-08-03 00:23:45 -0400 turn future seg faults into asserts r6972@totoro (orig r6971): nickm | 2006-08-03 03:46:25 -0400 Patch from Frediano Ziglio: Windows compilation fixes on eventdns.c. r6973@totoro (orig r6972): nickm | 2006-08-04 14:23:56 -0400 r6995@Kushana: nickm | 2006-07-31 13:30:42 -0700 Avoid segfault if we exit before we get our first dns answer. r6974@totoro (orig r6973): nickm | 2006-08-04 14:24:13 -0400 r6975@totoro (orig r6974): nickm | 2006-08-04 14:24:25 -0400 r7007@Kushana: nickm | 2006-08-03 09:58:30 -0700 Export and use eventdns_config_windows_nameservers(); clean up some comments and log messages. r6976@totoro (orig r6975): nickm | 2006-08-04 14:24:41 -0400 r7008@Kushana: nickm | 2006-08-03 10:03:39 -0700 Oops. We shouldnt initialize eventdns when we are not being a server and not resolving anything. r6977@totoro (orig r6976): nickm | 2006-08-04 14:26:13 -0400 r7009@Kushana: nickm | 2006-08-03 10:44:58 -0700 Add functions to eventdns to allow detecting whether we have any nameservers configured, and to change the list of nameservers after initial configuration. r6978@totoro (orig r6977): nickm | 2006-08-04 14:26:40 -0400 r7010@Kushana: nickm | 2006-08-03 10:47:36 -0700 Enable log message format checking in eventdns.c when __GNUC__ is defined. r6979@totoro (orig r6978): nickm | 2006-08-04 14:27:10 -0400 r7011@Kushana: nickm | 2006-08-03 13:26:34 -0700 eventdns: Document functions added to API; make suspended requests go to the front of the queue; check (or explicitly ignore) return values on libevent functions. r6980@totoro (orig r6979): nickm | 2006-08-04 14:31:13 -0400 r6981@totoro (orig r6980): nickm | 2006-08-04 14:32:43 -0400 r7012@Kushana: nickm | 2006-08-03 19:21:25 -0700 Add an "mmap handle" type to encapsulate bookkeeping elements of mmap issues; add prelim win32 impl r6982@totoro (orig r6981): nickm | 2006-08-04 15:03:40 -0400 r7025@Kushana: nickm | 2006-08-04 12:03:22 -0700 Finish (I hope) windows mmap impl. r6983@totoro (orig r6982): arma | 2006-08-04 16:30:45 -0400 make svn trunk link again. nick can fix this if it's wrong. r6985@totoro (orig r6984): arma | 2006-08-04 23:08:56 -0400 a potential fix on the HELLO protocol design r6986@totoro (orig r6985): nickm | 2006-08-05 13:52:51 -0400 r7027@Kushana: nickm | 2006-08-04 13:06:48 -0700 Oops. Fix downcast macro. r6987@totoro (orig r6986): nickm | 2006-08-05 13:53:08 -0400 r7028@Kushana: nickm | 2006-08-04 13:10:16 -0700 Make data and size fields visible in tor_mmap_t; hide win magic differently. r6988@totoro (orig r6987): nickm | 2006-08-05 13:53:21 -0400 r7029@Kushana: nickm | 2006-08-04 14:08:41 -0700 Remove now-spurious size and data arguments from tor_mmap_file r6989@totoro (orig r6988): nickm | 2006-08-05 13:53:32 -0400 r7030@Kushana: nickm | 2006-08-04 14:46:52 -0700 Close an fd leak on failed mmap() r6990@totoro (orig r6989): phobos | 2006-08-07 21:42:52 -0400 Update preflight to save Privoxy configs as well r6991@totoro (orig r6990): arma | 2006-08-08 02:21:52 -0400 three more todo items r6992@totoro (orig r6991): arma | 2006-08-08 18:56:26 -0400 change the dir-spec to say that it's version 2 of the dir spec, and move the v0 file to v1. r6996@totoro (orig r6995): nickm | 2006-08-08 20:58:27 -0400 Say more about reverse DNS r6999@totoro (orig r6996): nickm | 2006-08-09 02:41:29 -0400 r7056@Kushana: nickm | 2006-08-08 23:40:53 -0700 Add a comment about v0 fallback approach. Why did we dislike discriminating on X.509 certs again? r7000@totoro (orig r6997): nickm | 2006-08-09 02:54:02 -0400 r7058@Kushana: nickm | 2006-08-08 23:53:46 -0700 Clarify point about certs. We have been over this before, but it seems simpler than what we are considering now. r7001@totoro (orig r6998): nickm | 2006-08-09 04:23:27 -0400 r7285@Kushana: nickm | 2006-08-09 01:23:11 -0700 Claim a TODO item (and test commit signing.) r7002@totoro (orig r6999): nickm | 2006-08-09 04:30:11 -0400 r7286@Kushana: nickm | 2006-08-09 01:28:27 -0700 Claim another TODO item (and test commit signing.) r7003@totoro (orig r7000): weasel | 2006-08-09 06:25:01 -0400 r8245@danube: weasel | 2006-08-09 12:24:00 +0200 Add a few comments so I find the rationale for the autoconf --build/--host split in the future when I need it again r7006@totoro (orig r7001): nickm | 2006-08-09 17:42:38 -0400 r7005@totoro: nickm | 2006-08-09 17:42:18 -0400 Begin committing violence against the spec; add some TODO items at the top. Arma, if you disagree, better say so. r7228@totoro (orig r7002): phobos | 2006-08-09 22:06:35 -0400 Update for universal binaries for OSX. r7229@totoro (orig r7003): nickm | 2006-08-10 03:39:47 -0400 Recommend libevent 1.1b for kqueue and win32 methods; deprecate libevent 1.0b harder; make libevent recommendation system saner. r7230@totoro (orig r7004): nickm | 2006-08-10 04:00:13 -0400 Experimentally re-enable kqueue on OSX when using libevent 1.1b or later. Log when we are doing this, so we can diagnose it when it fails. r7231@totoro (orig r7005): arma | 2006-08-10 04:00:54 -0400 a way to make tor more stable in crummy situations r7232@totoro (orig r7006): arma | 2006-08-10 04:13:41 -0400 initial skeleton for issues to resolve re: blocking resistance. r7233@totoro (orig r7007): nickm | 2006-08-10 05:01:37 -0400 r7299@Kushana: nickm | 2006-08-10 01:08:58 -0700 Patch from Tup to add support for transparent AP connections: this basically bundles the functionality of trans-proxy-tor into the tor mainline. Now hosts with compliant pf/netfilter implementations can redirect TCP connections straight to Tor without diverting through SOCKS. r7234@totoro (orig r7008): nickm | 2006-08-10 05:01:46 -0400 r7300@Kushana: nickm | 2006-08-10 01:36:40 -0700 Distinguish netfilter vs pf at configure time based on headers, not on OS. r7235@totoro (orig r7009): nickm | 2006-08-10 05:01:54 -0400 r7301@Kushana: nickm | 2006-08-10 01:41:27 -0700 Only open /dev/pf once. r7236@totoro (orig r7010): nickm | 2006-08-10 05:02:02 -0400 r7302@Kushana: nickm | 2006-08-10 01:48:44 -0700 Warn about open TransListenAddress values. r7237@totoro (orig r7011): nickm | 2006-08-10 05:02:12 -0400 r7303@Kushana: nickm | 2006-08-10 01:52:19 -0700 whitespace fixes r7238@totoro (orig r7012): nickm | 2006-08-10 05:02:26 -0400 r7304@Kushana: nickm | 2006-08-10 01:58:05 -0700 Fix verbose compilation errors; make sure transparent proxy fails when no method is configured. r7240@totoro (orig r7013): nickm | 2006-08-10 05:14:57 -0400 r7313@Kushana: nickm | 2006-08-10 02:13:35 -0700 Add missing .h to header file name. My bad. r7243@totoro (orig r7015): nickm | 2006-08-10 05:30:25 -0400 r7315@Kushana: nickm | 2006-08-10 02:30:13 -0700 add missing "test" and missing include. r7248@totoro (orig r7018): nickm | 2006-08-10 15:56:10 -0400 Fix crash in first-time option validation. Oops. r7249@totoro (orig r7019): nickm | 2006-08-11 03:09:09 -0400 r7323@Kushana: nickm | 2006-08-10 22:04:57 -0700 Add sys/socket.h prereq for net/if.h and net/pfvar.h r7250@totoro (orig r7020): nickm | 2006-08-11 03:09:17 -0400 r7324@Kushana: nickm | 2006-08-10 23:23:15 -0700 Add more warnings to the list of those we tolerate. Start using GCC attributes more, for better error checking and better code generation. r7251@totoro (orig r7021): nickm | 2006-08-11 03:09:28 -0400 r7325@Kushana: nickm | 2006-08-10 23:37:31 -0700 Use gcc offsetof where available. r7252@totoro (orig r7022): nickm | 2006-08-11 03:09:35 -0400 r7326@Kushana: nickm | 2006-08-10 23:50:49 -0700 And another GCC change: predict that tor_frees() are usually real frees, and tor_asserts() usually wont happen. Other test should wait till -fprofile-arcs r7253@totoro (orig r7023): nickm | 2006-08-11 03:09:45 -0400 r7327@Kushana: nickm | 2006-08-11 00:00:36 -0700 Fix a pedantic warning r7254@totoro (orig r7024): nickm | 2006-08-11 03:09:52 -0400 r7328@Kushana: nickm | 2006-08-11 00:04:26 -0700 remove an assert that can never be false (an array in a non-null struct cannot be null). r7255@totoro (orig r7025): nickm | 2006-08-11 03:17:16 -0400 r7335@Kushana: nickm | 2006-08-11 00:13:03 -0700 fix wide lines r7256@totoro (orig r7026): arma | 2006-08-11 03:31:16 -0400 fix typo, add explanatory comment r7257@totoro (orig r7027): arma | 2006-08-11 03:41:21 -0400 fix funny-looking assignment that crashes unit tests r7258@totoro (orig r7028): nickm | 2006-08-11 03:42:11 -0400 r7337@Kushana: nickm | 2006-08-11 00:42:04 -0700 Only use __builtin_offsetof with gcc 4 or later r7259@totoro (orig r7029): nickm | 2006-08-11 03:51:34 -0400 r7341@Kushana: nickm | 2006-08-11 00:51:05 -0700 Amazing how much difference adding a ! to all your asserts can make. r7260@totoro (orig r7030): nickm | 2006-08-11 03:51:42 -0400 r7342@Kushana: nickm | 2006-08-11 00:51:25 -0700 Remove braindeadism. r7262@totoro (orig r7032): arma | 2006-08-11 20:30:07 -0400 more todo items r7263@totoro (orig r7033): arma | 2006-08-11 20:38:38 -0400 mark out the two biggest bugs r7264@totoro (orig r7034): arma | 2006-08-12 03:44:13 -0400 two more thoughts to consider for blocking resistance r7266@totoro (orig r7036): weasel | 2006-08-12 19:26:54 -0400 r8290@danube: weasel | 2006-08-13 01:26:01 +0200 Merge local r8289 into trunk: Update debian/copyright r7267@totoro (orig r7037): phobos | 2006-08-12 20:13:55 -0400 Updated details on how to check for universal binary. r7269@totoro (orig r7039): phobos | 2006-08-12 20:29:56 -0400 Apparently not everyone wants to build Universal binaries. Return valid Archictecture detection for inclusion into final dmg naming. r7272@totoro (orig r7042): arma | 2006-08-13 19:38:30 -0400 simplify the connection_write_to_buf_zlib() wrapper. r7273@totoro (orig r7043): arma | 2006-08-13 20:28:44 -0400 note three more bugs we should resolve r7274@totoro (orig r7044): arma | 2006-08-14 01:53:57 -0400 save 3-7 bytes per edge connection r7275@totoro (orig r7045): nickm | 2006-08-14 02:03:26 -0400 r7369@Kushana: nickm | 2006-08-14 02:03:10 -0400 Shortening fields is only one part of making structs shorter. You must also consider alignment padding. Whee. r7276@totoro (orig r7046): arma | 2006-08-14 02:27:39 -0400 two more todo's, plus a cleanup r7277@totoro (orig r7047): arma | 2006-08-14 02:29:40 -0400 this is what i really meant r7278@totoro (orig r7048): arma | 2006-08-14 03:08:29 -0400 simplify compare_cached_resolves_by_expiry() to make it match the idioms of other compare functions. hopefully i didn't break it? r7279@totoro (orig r7049): arma | 2006-08-14 04:55:41 -0400 fix typos and stuff r7280@totoro (orig r7050): arma | 2006-08-14 05:03:16 -0400 clarify that some old versions used an organizationName of "Tor", and others used "TOR". We should avoid both now. r7281@totoro (orig r7051): arma | 2006-08-14 05:04:27 -0400 rename HELLO cells to VERSIONS cells. r7282@totoro (orig r7052): arma | 2006-08-14 05:44:54 -0400 note a compile warning that we should investigate one day. r7283@totoro (orig r7053): arma | 2006-08-14 06:00:15 -0400 avoid complaining about our SOCKS proxy proxy. r7284@totoro (orig r7054): arma | 2006-08-14 06:16:42 -0400 checkpoint in-progress changelog notes r7287@totoro (orig r7057): nickm | 2006-08-14 16:16:21 -0400 r7383@Kushana: nickm | 2006-08-14 16:16:03 -0400 Stop walking entire dns cache for every request, now that we found our hash table bug. r7288@totoro (orig r7058): nickm | 2006-08-14 17:44:29 -0400 r7045@Kushana: nickm | 2006-08-05 13:56:44 -0400 mess with the TODO a little. r7289@totoro (orig r7059): nickm | 2006-08-14 17:44:34 -0400 r7046@Kushana: nickm | 2006-08-05 13:57:04 -0400 Make it possible for dns_init() to fail; note failure of eventdns configuratoin. r7290@totoro (orig r7060): nickm | 2006-08-14 17:44:39 -0400 r7291@totoro (orig r7061): nickm | 2006-08-14 17:44:45 -0400 r7386@Kushana: nickm | 2006-08-14 17:43:44 -0400 Patch from Adam Langley. * I meant getaddrinfo_a, not getaddrinfo_r - fixed * Added more checks to the parsing code. * It seems you switched an alloca to a malloc, but didn't add any frees r7292@totoro (orig r7062): nickm | 2006-08-14 23:54:09 -0400 r7392@Kushana: nickm | 2006-08-14 23:50:32 -0400 Only do the expensive version of router_have_minimum_dir_info() when the dir info has changed. Backport candidate, since oprofile suggests that this function and ones it calls account for 25-35% of oprofile samples. r7293@totoro (orig r7063): nickm | 2006-08-14 23:54:13 -0400 r7393@Kushana: nickm | 2006-08-14 23:51:07 -0400 remove extraneous #endif r7305@totoro (orig r7064): nickm | 2006-08-15 00:50:17 -0400 r7397@Kushana: nickm | 2006-08-15 00:46:18 -0400 Fix eventdns version of dns.c. Man, we need to get rid of this eventdns/dnsworker split. r7306@totoro (orig r7065): nickm | 2006-08-15 00:50:33 -0400 r7398@Kushana: nickm | 2006-08-15 00:49:50 -0400 Add missing backslash r7308@totoro (orig r7067): arma | 2006-08-15 22:18:55 -0400 dns.c:173: warning: control reaches end of non-void function r7309@totoro (orig r7068): arma | 2006-08-15 23:44:13 -0400 automatically avoid picking more than one node from the same /16 network when constructing a circuit. r7310@totoro (orig r7069): nickm | 2006-08-16 14:47:19 -0400 r7404@Kushana: nickm | 2006-08-16 09:32:19 -0400 Pass hints to getaddrinfo; fix bug 280 (?) r7311@totoro (orig r7070): nickm | 2006-08-16 14:47:24 -0400 r7405@Kushana: nickm | 2006-08-16 14:38:46 -0400 Implement reverse DNS lookup in eventdns: add new entry point; rename old entry point; revise TODO a little; add facility for parsing dns names. r7313@totoro (orig r7072): nickm | 2006-08-17 19:00:32 -0400 r7411@Kushana: nickm | 2006-08-17 19:00:25 -0400 patch suggested by Karsten Loesing: respond to SIGNAL command before we execute the signal, in case the signal shuts us down. r7314@totoro (orig r7073): arma | 2006-08-18 13:46:14 -0400 clean up AllowInvalidNodes man page entry. r7315@totoro (orig r7074): arma | 2006-08-18 14:19:35 -0400 fix typo pointed out by paul r8455@totoro (orig r8214): nickm | 2006-08-22 02:10:53 -0400 r8556@Kushana: nickm | 2006-08-22 01:22:46 -0400 Enable eventdns by default on platforms where we autoconf. This should be everything but windows. r8456@totoro (orig r8215): nickm | 2006-08-22 02:10:58 -0400 r8557@Kushana: nickm | 2006-08-22 02:10:12 -0400 dns-related TODO changes. r8462@totoro (orig r8221): arma | 2006-08-23 19:45:03 -0400 tor --verify-config now exits with -1(255) or 0 depending on whether the config options are bad or good. r8463@totoro (orig r8222): arma | 2006-08-23 20:54:18 -0400 clean up logging conventions in do_list_fingerprint() r8464@totoro (orig r8223): arma | 2006-08-24 00:51:55 -0400 make our socks5 handling more robust to broken socks clients: throw out everything waiting on the buffer in between socks handshake phases, since they can't possibly (so the theory goes) have predicted what we plan to respond to them. r8465@totoro (orig r8224): nickm | 2006-08-25 17:01:56 -0400 r8572@Kushana: nickm | 2006-08-25 16:35:49 -0400 Fix for bug 308: When we have a state file we cannot parse, tell the user, and move it aside. r8466@totoro (orig r8225): nickm | 2006-08-25 17:02:01 -0400 r8573@Kushana: nickm | 2006-08-25 16:55:19 -0400 Resolve bug 321 when using dnsworkers: append a period to every address we resolve at the exit node, so that we do not accidentally pick up local addresses, and so that failing searches are retried in the resolver search domains. (This is already solved for eventdns.) r8467@totoro (orig r8226): nickm | 2006-08-25 17:16:22 -0400 r8576@Kushana: nickm | 2006-08-25 17:16:01 -0400 Fix bug 314: Instead of checking address_in_virtualrange, check addressmap_have_mapping(). This should be more accurate. [Rename to addressmap_have_mapping() from addressmap_already_mapped().] r8468@totoro (orig r8227): arma | 2006-08-26 00:48:50 -0400 fix a log level -- err is for things that kill tor, warn is for things that tor can recover from. also, avoid situations where people who don't read their logs accumulate ten thousand useless files in their datadir. r8469@totoro (orig r8228): arma | 2006-08-26 00:52:22 -0400 more todo items when we avoid putting /16 servers into the same circuit r8470@totoro (orig r8229): arma | 2006-08-26 02:51:02 -0400 remove some more vestiges of cvs r8471@totoro (orig r8230): arma | 2006-08-26 02:56:16 -0400 complete an item, abandon an item, defer an item. r8472@totoro (orig r8231): arma | 2006-08-26 02:57:48 -0400 remove more completed items r8473@totoro (orig r8232): arma | 2006-08-26 03:13:54 -0400 make a 'real soon now' section of the todo, to point out what's more urgent r8474@totoro (orig r8233): arma | 2006-08-26 21:33:35 -0400 fix typo r8475@totoro (orig r8234): arma | 2006-08-26 21:41:08 -0400 i'm guessing nick meant to check the return value of dns_init. and revise some log severities to match the convention. r8476@totoro (orig r8235): arma | 2006-08-26 22:07:54 -0400 stop three memory leaks. nick, fix these if i'm wrong. r8477@totoro (orig r8236): arma | 2006-08-26 22:12:12 -0400 stop a big memory leak: we were leaking the whole contents of cached-routers.new every time we read it. r8478@totoro (orig r8237): arma | 2006-08-27 02:49:33 -0400 typo and whitespace r8479@totoro (orig r8238): arma | 2006-08-27 02:49:51 -0400 a usability improvement i just thought of r8480@totoro (orig r8239): arma | 2006-08-27 02:51:19 -0400 0.1.2.1-alpha will break blossom exit node functionality; put that on the todo list. r8481@totoro (orig r8240): arma | 2006-08-27 02:55:48 -0400 clean up the 0.1.2.1-alpha changelog r8482@totoro (orig r8241): arma | 2006-08-27 02:58:30 -0400 comment out an unused variable; nick, feel free to excise it further. r8483@totoro (orig r8242): arma | 2006-08-27 03:02:41 -0400 bump the doxyfile version number, since i made a doxygen ref man last week. r8484@totoro (orig r8243): arma | 2006-08-27 03:03:05 -0400 fix typo r8485@totoro (orig r8244): arma | 2006-08-27 03:03:17 -0400 bump to 0.1.2.1-alpha (does it work?) r8486@totoro (orig r8245): arma | 2006-08-27 03:26:00 -0400 turn eventdns off by default until we can get some more useful log messages into it. no use learning that it's broken without being able to learn what is broken too. r8488@totoro (orig r8247): phobos | 2006-08-27 20:40:11 -0400 Update rpms to require libevent 1.1b. r8490@totoro (orig r8249): phobos | 2006-08-27 21:06:44 -0400 Remove architecture from builds. The official builds are universal binaries. r8491@totoro (orig r8250): phobos | 2006-08-27 22:20:35 -0400 Replace nickm as packager of rpms. r8492@totoro (orig r8251): arma | 2006-08-27 23:01:07 -0400 bump trunk to 0.1.2.1-alpha-dev r8493@totoro (orig r8252): nickm | 2006-08-27 23:15:38 -0400 r8605@Kushana: nickm | 2006-08-27 14:01:11 -0400 divide eventdns log messages into warn and info messages. r8494@totoro (orig r8253): nickm | 2006-08-27 23:15:47 -0400 r8606@Kushana: nickm | 2006-08-27 14:04:19 -0400 Now that 0.1.2.1-alpha is out, make eventdns on-by-default again. (Hoop-lah.) r8495@totoro (orig r8254): nickm | 2006-08-27 23:15:50 -0400 r8607@Kushana: nickm | 2006-08-27 15:45:42 -0400 Change configuration strategy for eventdns. Instead of elaborate option set, just allow the user to specify another resolv.conf to use. r8496@totoro (orig r8255): nickm | 2006-08-27 23:15:55 -0400 r8608@Kushana: nickm | 2006-08-27 16:57:47 -0400 Make it possible to change nameserver options while Tor is running. r8497@totoro (orig r8256): nickm | 2006-08-27 23:16:02 -0400 r8609@Kushana: nickm | 2006-08-27 17:24:27 -0400 Add some doxygen, concentrated in dns.c r8499@totoro (orig r8258): nickm | 2006-08-27 23:29:51 -0400 Kill some SVK branches that I am done with. r8500@totoro (orig r8259): nickm | 2006-08-27 23:46:21 -0400 r8626@Kushana: nickm | 2006-08-27 23:45:46 -0400 Aw, crap. Non-gcc bug. We need regular windows builds. r8511@totoro (orig r8270): arma | 2006-08-28 04:24:36 -0400 put some symbols on the eventdns logging. leave the haphazard formatting alone. r8512@totoro (orig r8271): arma | 2006-08-28 14:51:36 -0400 fix bug found by Adam J. Richter: directory clients shouldn't hang up five minutes after they begin. but directory servers should still hang up after 5 minutes of failing to deliver any bytes. r8513@totoro (orig r8272): arma | 2006-08-28 15:00:17 -0400 an even better check -- now servers hang up if they can't write for a while, and clients hang up if they can't read for a while. r8514@totoro (orig r8273): arma | 2006-08-28 15:02:57 -0400 and make the comment better, while i'm at it r8518@totoro (orig r8277): nickm | 2006-08-28 16:42:14 -0400 r8652@Kushana: nickm | 2006-08-28 16:41:44 -0400 Resolve bug 324: strdup the right variable. r8519@totoro (orig r8278): nickm | 2006-08-28 16:50:47 -0400 r8654@Kushana: nickm | 2006-08-28 16:50:36 -0400 I bet real programmers even have programs that compile. r8521@totoro (orig r8280): nickm | 2006-08-29 00:22:51 -0400 r8657@Kushana: nickm | 2006-08-29 00:22:31 -0400 Mark an item complete; test new commit-email.pl script. r8539@totoro (orig r8298): weasel | 2006-08-29 16:43:52 -0400 r9565@galaxy: weasel | 2006-08-29 22:20:38 +0200 Do not reload or start when our config is known to be broken r8540@totoro (orig r8299): weasel | 2006-08-29 16:43:59 -0400 r9566@galaxy: weasel | 2006-08-29 22:32:26 +0200 Unnest all those nested if blocks r8541@totoro (orig r8300): weasel | 2006-08-29 16:44:05 -0400 r9567@galaxy: weasel | 2006-08-29 22:32:46 +0200 Prepare 0.1.2.1-alpha-1 r8542@totoro (orig r8301): weasel | 2006-08-29 16:44:11 -0400 r9568@galaxy: weasel | 2006-08-29 22:34:36 +0200 Upload target is experimental, not unstable r8543@totoro (orig r8302): weasel | 2006-08-29 16:44:17 -0400 r9569@galaxy: weasel | 2006-08-29 22:38:54 +0200 Change Standards-Version to 3.7.2. No changes required. r8544@totoro (orig r8303): nickm | 2006-08-29 17:59:20 -0400 r8682@Kushana: nickm | 2006-08-29 17:58:59 -0400 Fix compilation on GCC2 by disabling fun attributes unless __GNUC_MAJOR__ >= 3. r8548@totoro (orig r8307): nickm | 2006-08-30 19:34:49 -0400 r8686@Kushana: nickm | 2006-08-30 18:01:35 -0400 Remove bogus whitespace r8549@totoro (orig r8308): nickm | 2006-08-30 19:34:56 -0400 r8687@Kushana: nickm | 2006-08-30 19:33:28 -0400 Apply patch from Adam Langley: fix assert() in eventdns.c. [Fuzzing, apparently, is cool.] r8550@totoro (orig r8309): nickm | 2006-08-31 13:39:47 -0400 r8691@Kushana: nickm | 2006-08-31 13:30:46 -0400 Fix bug 327 (part 1): Use correct macro to test for GCC 3 or later. r8551@totoro (orig r8310): nickm | 2006-08-31 13:39:51 -0400 r8692@Kushana: nickm | 2006-08-31 13:38:07 -0400 Fix bug 327 (part 2): Cast char to unsigned char before passing to toupper/tolower. (Follow the same idiom as with isupper and friends, in case we run into the same problem on SGI or whereever it was.) r8552@totoro (orig r8311): nickm | 2006-08-31 14:46:46 -0400 r8695@Kushana: nickm | 2006-08-31 14:35:36 -0400 Fix two corner cases in router_dir_info_changed(). This should have no observable effect. r8553@totoro (orig r8312): nickm | 2006-08-31 14:47:54 -0400 r8696@Kushana: nickm | 2006-08-31 14:43:44 -0400 Try to appease some warnings with newer gccs that believe that ignoring a return value is okay, but casting a return value and then ignoring it is a sign of madness. r8556@totoro (orig r8315): phobos | 2006-08-31 19:52:41 -0400 Remove old TODO that I can't remember the details of it. r8557@totoro (orig r8316): nickm | 2006-09-02 01:33:11 -0400 r8704@Kushana: nickm | 2006-09-02 01:32:34 -0400 correct includes for net/if.h and net/pfvar.h on openbsd (from Tup) r8558@totoro (orig r8317): arma | 2006-09-02 19:26:42 -0400 Tor is more than code these days. r8559@totoro (orig r8318): nickm | 2006-09-02 22:13:52 -0400 r8708@Kushana: nickm | 2006-09-02 20:34:15 -0400 Fix warnings reported by weasel when compiling Tor on Debian woody. r8560@totoro (orig r8319): nickm | 2006-09-02 22:13:56 -0400 r8709@Kushana: nickm | 2006-09-02 20:59:54 -0400 Remove unused autoconf checks. r8561@totoro (orig r8320): weasel | 2006-09-03 16:19:35 -0400 r9648@danube: weasel | 2006-09-03 19:54:42 +0200 Document minor update of debian/copyright by arma in debian changelog r8562@totoro (orig r8321): arma | 2006-09-05 10:30:06 -0400 patch from tup r8563@totoro (orig r8322): chiussi | 2006-09-05 21:49:55 -0400 - made configure check if we are building for win32 - made configure link to required system dll's if building for win32 - added diffs for libevent 1.1b - forced user to turn off eventdns if win32 is set - cleaned up tor_mmap_file()_win32 (not sure if it's stable) - cleaned up some warnings and typos r8564@totoro (orig r8323): chiussi | 2006-09-05 21:58:55 -0400 - removed windows line endings r8565@totoro (orig r8324): weasel | 2006-09-05 22:08:52 -0400 r9665@danube: weasel | 2006-09-06 04:08:12 +0200 Remove svn:executable properties from all files in Win32Build r8566@totoro (orig r8325): nickm | 2006-09-06 04:42:12 -0400 r8723@Kushana: nickm | 2006-09-06 04:24:54 -0400 Clean up configure.in spaces, and make it work on Mac OS X again (for me). r8567@totoro (orig r8326): nickm | 2006-09-06 04:42:16 -0400 r8724@Kushana: nickm | 2006-09-06 04:32:28 -0400 Fix spaces; restore support for mapping files over 4GB on win32 (?) r8568@totoro (orig r8327): nickm | 2006-09-06 04:42:20 -0400 r8725@Kushana: nickm | 2006-09-06 04:39:29 -0400 spawn_func fixes: have cpuworker_main and dnsworker_main confirm to the right interfaces [casting func to void* is icky]. Also, make pthread_create() build without warnings. r8569@totoro (orig r8328): nickm | 2006-09-06 16:22:05 -0400 r8729@Kushana: nickm | 2006-09-06 16:20:40 -0400 Fix dns_cancel_pending_resolve() to realize pending resolves have expiry times, and should not be freed except when they fall off the pqueue. r8570@totoro (orig r8329): nickm | 2006-09-06 16:33:28 -0400 r8731@Kushana: nickm | 2006-09-06 16:33:19 -0400 Try to fix eventdns.c build on windows. r8571@totoro (orig r8330): nickm | 2006-09-06 17:35:30 -0400 r8733@Kushana: nickm | 2006-09-06 17:35:22 -0400 Add some missing defines to eventdns.c for windows. r8572@totoro (orig r8331): arma | 2006-09-06 20:30:29 -0400 new config option AvoidDiskWrites for people running tors on usb keys and other media that degrades when you write. not implemented yet, so just a reminder. r8573@totoro (orig r8332): chiussi | 2006-09-06 20:51:20 -0400 - fixed up typos in eventdns.c - configure lets user build with eventdns on win32 r8574@totoro (orig r8333): chiussi | 2006-09-06 20:54:28 -0400 rm'ed a tab (sorry) r8575@totoro (orig r8334): arma | 2006-09-06 21:00:37 -0400 prefer calling it a client rather than an OP r8576@totoro (orig r8335): arma | 2006-09-06 21:01:11 -0400 flesh out TODO re: AvoidDiskWrites r8577@totoro (orig r8336): arma | 2006-09-06 21:02:23 -0400 clean up and correct the spec r8578@totoro (orig r8337): arma | 2006-09-06 21:22:55 -0400 another controller event we left out r8579@totoro (orig r8338): arma | 2006-09-06 21:23:15 -0400 clean up some comments r8580@totoro (orig r8339): arma | 2006-09-06 23:26:17 -0400 help the rpm spec file recognize development versions now that they're not called foo-cvs r8581@totoro (orig r8340): arma | 2006-09-06 23:40:23 -0400 packages now start including svn website docs (oops) r8583@totoro (orig r8342): chiussi | 2006-09-06 23:53:14 -0400 - added some debugging lines to load_nameservers_from_registry() r8584@totoro (orig r8343): chiussi | 2006-09-06 23:58:46 -0400 - got rid of tabs (i think) r8585@totoro (orig r8344): chiussi | 2006-09-07 00:02:52 -0400 - got rid of tabs r8586@totoro (orig r8345): chiussi | 2006-09-07 02:34:20 -0400 fixed win32 eventdns snafu r8587@totoro (orig r8346): chiussi | 2006-09-07 02:36:22 -0400 undid whitespace changes to dns.c r8588@totoro (orig r8347): nickm | 2006-09-07 12:24:19 -0400 r8753@Kushana: nickm | 2006-09-07 12:23:25 -0400 Make eventdns spacing consistant r8589@totoro (orig r8348): nickm | 2006-09-07 12:32:06 -0400 r8755@Kushana: nickm | 2006-09-07 12:31:57 -0400 Tabify eventdns r8590@totoro (orig r8349): nickm | 2006-09-07 15:00:51 -0400 r8757@Kushana: nickm | 2006-09-07 13:07:46 -0400 Fix more compile warnings on Woody. r8591@totoro (orig r8350): chiussi | 2006-09-08 05:02:14 -0400 fixed typo in eventdns.c r8592@totoro (orig r8351): chiussi | 2006-09-08 05:05:07 -0400 another typo r8593@totoro (orig r8352): weasel | 2006-09-08 12:12:15 -0400 r9695@danube: weasel | 2006-09-08 18:11:53 +0200 Make tor build with -O0 r8594@totoro (orig r8353): arma | 2006-09-08 16:48:43 -0400 possibly make tor build and run on cygwin again. r8595@totoro (orig r8354): arma | 2006-09-08 23:18:39 -0400 add a "getinfo address" controller command. r8596@totoro (orig r8355): arma | 2006-09-08 23:38:03 -0400 fix encoding in "getinfo addr-mappings" response. fix error code when "getinfo dir/status/" fails. r8597@totoro (orig r8356): nickm | 2006-09-08 23:46:52 -0400 r8766@Kushana: nickm | 2006-09-08 23:46:12 -0400 Remove some completed items from TODO; defer a bunch of stuff from 0.1.2.x (which we want to have an RC for by the end of October) r8598@totoro (orig r8357): arma | 2006-09-09 15:16:07 -0400 fix typo, add log message r8599@totoro (orig r8358): arma | 2006-09-09 15:20:27 -0400 parameterize the loudness of get_interface_address() r8600@totoro (orig r8359): arma | 2006-09-09 15:36:51 -0400 start remembering X-Your-Address-Is hints even if you're a client, so you can become a server more smoothly. r8602@totoro (orig r8361): phobos | 2006-09-10 23:46:00 -0400 First attempt to document the process to build Win32 executables with mingw. Relies upon magic to actually work right now. r8611@totoro (orig r8370): nickm | 2006-09-11 22:50:14 -0400 r8776@Kushana: nickm | 2006-09-11 22:49:53 -0400 Avoid crash when telling controller stream-status and a stream is detached. Fixes bug 334. Backport candidate. r8612@totoro (orig r8371): phobos | 2006-09-11 22:58:33 -0400 Updates to win32-mingw. libevent1.1b builds. openssl doesn't. r8614@totoro (orig r8373): nickm | 2006-09-12 14:05:54 -0400 r8785@Kushana: nickm | 2006-09-12 14:05:46 -0400 Add non-dist utility for weasel r8615@totoro (orig r8374): weasel | 2006-09-12 14:11:19 -0400 r9734@danube: weasel | 2006-09-12 20:11:02 +0200 Set svn:keywords r8616@totoro (orig r8375): arma | 2006-09-12 14:31:03 -0400 avoid getting mail from ilja in 2008 about this. r8617@totoro (orig r8376): nickm | 2006-09-12 15:00:55 -0400 r8791@Kushana: nickm | 2006-09-12 15:00:48 -0400 As long as we are being pedantic, we may as well be extra-pedantic. r8624@totoro (orig r8383): nickm | 2006-09-13 13:34:59 -0400 r8795@Kushana: nickm | 2006-09-13 13:34:54 -0400 Try to split off the mingw portions of the libevent diff so we can send them to niels separately. Adding two patches: one that applies against 1.1b; one that applies against the libevent svn trunk. r8625@totoro (orig r8384): arma | 2006-09-13 18:24:05 -0400 two todo items we'll need for the blocking-resistance scheme r8626@totoro (orig r8385): arma | 2006-09-13 18:24:43 -0400 continue fleshing out the blocking-resistance design doc r8627@totoro (orig r8386): weasel | 2006-09-14 00:53:23 -0400 r9736@danube: weasel | 2006-09-14 05:53:06 +0200 Refactor dirserv_parse_fingerprint_file(fname) into dirserv_load_fingerprint_file(): There is not need to put together the path to the approved-routers file in more than one place. r8628@totoro (orig r8387): weasel | 2006-09-14 00:53:42 -0400 r9749@danube: weasel | 2006-09-14 06:53:12 +0200 Do not graciously increase the size to be mmaped if the current size already is at a page_size boundary. This is important since if a file has a size of zero and we mmap() it with length > 0, then accessing the mmaped memory area causes a bus error. However, if we pass a length of 0 to mmap() it will return with -1 and things work from there. r8629@totoro (orig r8388): nickm | 2006-09-14 01:00:02 -0400 r8808@senior-two-eighty: nickm | 2006-09-14 00:59:54 -0400 House style for no-args functions is old-style C, not C++ r8630@totoro (orig r8389): weasel | 2006-09-14 01:07:26 -0400 r9752@danube: weasel | 2006-09-14 07:06:49 +0200 Fix some dead code that is on occasion useful r8631@totoro (orig r8390): weasel | 2006-09-14 01:07:34 -0400 r9753@danube: weasel | 2006-09-14 07:07:02 +0200 Remove duplicates from MyFamily r8632@totoro (orig r8391): weasel | 2006-09-14 01:17:02 -0400 r9758@danube: weasel | 2006-09-14 07:10:12 +0200 Add a comment r8633@totoro (orig r8392): weasel | 2006-09-14 01:17:12 -0400 r9759@danube: weasel | 2006-09-14 07:14:37 +0200 Add smartlist_uniq() to TODO list r8634@totoro (orig r8393): arma | 2006-09-14 01:49:03 -0400 we should add a preamble to tor-design saying it's out of date. r8636@totoro (orig r8395): nickm | 2006-09-14 18:34:57 -0400 r8817@Kushana: nickm | 2006-09-14 18:31:29 -0400 Patch from steve hildrey: Generate network status correctly on non-versioning dirservers r8637@totoro (orig r8396): nickm | 2006-09-15 00:27:58 -0400 r8819@Kushana: nickm | 2006-09-15 00:27:45 -0400 Implement a smartlist_uniq() that will with luck not end the world. r8638@totoro (orig r8397): weasel | 2006-09-15 00:29:36 -0400 r9767@danube: weasel | 2006-09-15 06:27:48 +0200 Minor documentation fix r8639@totoro (orig r8398): weasel | 2006-09-15 01:20:16 -0400 r9770@danube: weasel | 2006-09-15 07:20:05 +0200 router_set_networkstatus() gets a list of status documents we asked for from connection_dir_client_reached_eof(). However, as a cache we (sometimes?) just ask for "all". router_set_networkstatus() would freak out over that, meaning it would log a warning and drop the status document instead of caching it as it is supposed to. Now we let router_set_networkstatus() know if the data comes from an all-request so it can do the right thing. r8640@totoro (orig r8399): arma | 2006-09-15 01:30:25 -0400 Send out a burst of long-range drop cells after we've established that we're reachable. Spread them over 4 circuits, so hopefully a few will be fast. This exercises our bandwidth and bootstraps us quicker. r8641@totoro (orig r8400): arma | 2006-09-15 01:53:00 -0400 make my bandwidth exercises actually happen r8642@totoro (orig r8401): arma | 2006-09-15 02:06:09 -0400 two todo items r8643@totoro (orig r8402): arma | 2006-09-15 14:03:53 -0400 avoid thrashing the bandwidth exercise when we change IPs a lot. (we avoid simply by not doing any new tests when we change IPs -- it looks like we retain our previous bandwidth estimates, so there's no need to do new exercise. though in some cases new exercises may still be useful. one day we'll do something smarter.) r8644@totoro (orig r8403): arma | 2006-09-15 14:07:11 -0400 actually, do the bandwidth test anyway, if you've been up at least 6 hours at your previous address. r8645@totoro (orig r8404): nickm | 2006-09-15 16:19:55 -0400 r8821@Kushana: nickm | 2006-09-15 16:19:16 -0400 Clean up libevent difmingw f problems noticed by mikec. r8647@totoro (orig r8406): phobos | 2006-09-16 15:54:03 -0400 Re-create symlinks through cp. r8648@totoro (orig r8407): arma | 2006-09-17 02:18:06 -0400 build testing circuits more rapidly. this has a failure mode where if circuits fail quickly, we'll fail a lot of them very quickly and not retry for a while. so be it. r8649@totoro (orig r8408): arma | 2006-09-17 13:57:56 -0400 a few more todo changes r8650@totoro (orig r8409): nickm | 2006-09-17 15:58:24 -0400 r8837@Kushana: nickm | 2006-09-17 15:58:04 -0400 More TODO work; tenatively mark assignments. r8651@totoro (orig r8410): nickm | 2006-09-17 16:12:10 -0400 r8839@Kushana: nickm | 2006-09-17 16:11:59 -0400 Add some client performance XXXXs; try to move some common case tests higher on their decision trees. r8652@totoro (orig r8411): nickm | 2006-09-17 16:20:23 -0400 r8841@Kushana: nickm | 2006-09-17 16:20:16 -0400 Move more todo items around r8653@totoro (orig r8412): arma | 2006-09-18 00:24:41 -0400 Fix two bugs: first, "extendcircuit" would crash if you gave it a purpose. Second, if you give an unknown purpose, it would say: 552 Unknown purpose "purpose=foo" Now it just says 552 Unknown purpose "foo" r8656@totoro (orig r8415): arma | 2006-09-18 00:59:15 -0400 good god, that was a bad idea. i've built 500 circuits in the past 5 minutes, trying to establish reachability of my unreachable server. r8657@totoro (orig r8416): phobos | 2006-09-18 01:35:08 -0400 Fix a mis-spelled Privoxy. r8668@totoro (orig r8427): nickm | 2006-09-19 16:41:31 -0400 Merge in some bsockets calls, all wrapped inside #if defined(USE_BSOCKETS) r8669@totoro (orig r8428): nickm | 2006-09-19 16:45:20 -0400 Fix a bogus free() in eventdns.c. Bug reported by xiando. r8670@totoro (orig r8429): arma | 2006-09-19 17:37:03 -0400 eventdns patch from Adam Langley r8671@totoro (orig r8430): nickm | 2006-09-19 18:20:09 -0400 Switch routerlist.c to using memcmp on digests rather than crypto_pk_cmp_keys(); speed up find_whitespace a lot (8x for me) by using a switch statement. This should speed parsing a lot of routers at once by a lot. r8672@totoro (orig r8431): nickm | 2006-09-19 18:36:48 -0400 Malloc and friends are critical-path: Thus, add an it-wont-happen branch prediction for NULL returns, and skip the malloc(0) check on platforms where malloc(0) returns a pointer. r8673@totoro (orig r8432): nickm | 2006-09-19 19:18:30 -0400 Stop searching routerlist for routers with the same identity as other routers (on router insert): we already have a map for that. (We need to add an index field to routerinfo_t so we can figure out which point in the routerlist to replace.) Also, add a comment to routerlist.c; arma, please advise? r8674@totoro (orig r8433): nickm | 2006-09-19 19:48:14 -0400 NEEDS REVIEW. Act on previous comment, and handle named servers differently: now, we allow multiple servers with the same name in the routerlist even if that name is reserved, but we check whether names are reserved when we try to look up routers by nickname. This is a minor security fix. This makes router_add_to_routerlist O(1). This is a backport candidate. r8675@totoro (orig r8434): nickm | 2006-09-19 19:55:35 -0400 Speed up eat_whitespace by a lot. r8678@totoro (orig r8437): nickm | 2006-09-21 17:48:06 -0400 r8872@Kushana: nickm | 2006-09-21 14:00:20 -0400 Implement server-side reverse DNS using eventdns. Add an option to routerdescs so we can tell which servers have eventdns enabled. r8679@totoro (orig r8438): nickm | 2006-09-21 17:48:11 -0400 r8873@Kushana: nickm | 2006-09-21 14:38:22 -0400 Fix a bug: Remember, each call to escaped() replaces the value returned from the last call to escaped(). r8680@totoro (orig r8439): nickm | 2006-09-21 17:48:16 -0400 r8874@Kushana: nickm | 2006-09-21 15:22:27 -0400 Rename and document SearchDomains and ResolvConf options; warn if ServerDNSResolvConfFile is given but eventdns isnt enabled. r8681@totoro (orig r8440): nickm | 2006-09-21 17:48:22 -0400 r8875@Kushana: nickm | 2006-09-21 16:46:28 -0400 Resolve bug 330: detect ISPs that want to hijack failing DNS requests and basically domain-squat the entire internet. r8682@totoro (orig r8441): nickm | 2006-09-21 17:48:37 -0400 r8876@Kushana: nickm | 2006-09-21 16:58:46 -0400 Trivial cleanup: !!x is a weird way to spell x != NULL. r8683@totoro (orig r8442): nickm | 2006-09-21 17:48:42 -0400 r8877@Kushana: nickm | 2006-09-21 17:12:33 -0400 Consider non-exit servers unsuitable for RESOLVE commands. r8684@totoro (orig r8443): nickm | 2006-09-21 17:48:55 -0400 r8878@Kushana: nickm | 2006-09-21 17:15:47 -0400 Trivial whitespace cleanups. r8685@totoro (orig r8444): nickm | 2006-09-21 17:49:03 -0400 r8879@Kushana: nickm | 2006-09-21 17:20:31 -0400 Oops from earlier patch; add "opt eventdns" to unittests, fix bug in routerdesc generation. r8686@totoro (orig r8445): nickm | 2006-09-21 17:49:15 -0400 r8880@Kushana: nickm | 2006-09-21 17:26:02 -0400 Trivial patch to appease warn-happy gcc: mark unused parameter r8687@totoro (orig r8446): nickm | 2006-09-21 17:49:36 -0400 r8881@Kushana: nickm | 2006-09-21 17:27:59 -0400 Allow resolve requests to non-exits when they are specifically requested (via resolve foo.bar.exit). r8688@totoro (orig r8447): nickm | 2006-09-21 18:24:45 -0400 Fix bug in r8440: base32 uses 5 bytes per char, not 4. r8689@totoro (orig r8448): nickm | 2006-09-21 18:57:07 -0400 Fix stupid C mistake. Glad I caught that one fast. r8690@totoro (orig r8449): nickm | 2006-09-21 20:10:26 -0400 Fix a couple of server-side reverse dns bugs r8691@totoro (orig r8450): arma | 2006-09-21 20:24:27 -0400 remove some loud log messages r8692@totoro (orig r8451): nickm | 2006-09-21 20:43:55 -0400 r8894@Kushana: nickm | 2006-09-21 18:30:42 -0400 Specify and implement SOCKS5 interface for reverse hostname lookup. r8693@totoro (orig r8452): nickm | 2006-09-21 20:44:07 -0400 r8895@Kushana: nickm | 2006-09-21 20:05:11 -0400 Debug client-side reverse dns code. r8694@totoro (orig r8453): nickm | 2006-09-21 20:44:21 -0400 r8695@totoro (orig r8454): nickm | 2006-09-21 20:45:08 -0400 r8901@Kushana: nickm | 2006-09-21 20:43:48 -0400 I tracked a bug in server-side reverse DNS to something concerning the caching code. Ive disabled server-side cacheing for reverse DNS answers for now, and I am noting the bug in the TODO. r8696@totoro (orig r8455): phobos | 2006-09-21 21:15:07 -0400 Removed verbose patch output. r8697@totoro (orig r8456): nickm | 2006-09-21 21:23:28 -0400 r8906@Kushana: nickm | 2006-09-21 21:23:22 -0400 Revise patch for libevent 1.1b to handle the "wait, I *do* have a gettimeofday()" case. r8698@totoro (orig r8457): phobos | 2006-09-22 11:08:05 -0400 Finally, valid tor.exe directions from scratch with mingw. r8699@totoro (orig r8458): phobos | 2006-09-22 11:37:52 -0400 One last change to openssl to get it to compile in mingw. r8702@totoro (orig r8461): arma | 2006-09-22 15:29:26 -0400 remove 8888 as a long lived port. i can't remember why it's on the list. r8703@totoro (orig r8462): nickm | 2006-09-22 16:18:58 -0400 r8843@Kushana: nickm | 2006-09-17 16:57:20 -0400 A couple of last minor TODO cleanup items r8704@totoro (orig r8463): nickm | 2006-09-22 16:19:34 -0400 r8912@Kushana: nickm | 2006-09-22 16:18:51 -0400 Write more of path-spec.txt r8705@totoro (orig r8464): nickm | 2006-09-22 16:20:21 -0400 r8909@Kushana: nickm | 2006-09-22 00:38:13 -0400 Consider changes to has_old_dnsworkers as noncosmetic r8706@totoro (orig r8465): nickm | 2006-09-22 16:20:26 -0400 r8910@Kushana: nickm | 2006-09-22 12:14:05 -0400 Instead of just checking known-invalid addresses for DNS hijacking, we now check randomly generated addresses, and if too many of them map to the same IP, we assume that IP is the destination of a DNS hijack attempt. A little bird tells me that some DNS hijackers think that declining to give an A record for RFC2606 addresses (like .invalid and .example) makes them more standards compliant. Standardswise, this is like an illicit brothel making sure that nobody has pulled the tags off the mattresss, but that doesn't get us out of working around it. r8707@totoro (orig r8466): nickm | 2006-09-22 16:20:35 -0400 r8911@Kushana: nickm | 2006-09-22 12:24:52 -0400 Make exitlist only output each result line once. r8708@totoro (orig r8467): phobos | 2006-09-22 22:18:18 -0400 Special mingw package_nsis and nsi scripts. r8713@totoro (orig r8472): phobos | 2006-09-23 15:17:08 -0400 Changes to doc as a result of creating a MinGW tor.exe on a bare system. Add two TODO items relating to MinGW instructions. svn:r8473
Diffstat (limited to 'src/or')
-rw-r--r--src/or/Makefile.am10
-rw-r--r--src/or/buffers.c114
-rw-r--r--src/or/circuitbuild.c293
-rw-r--r--src/or/circuitlist.c589
-rw-r--r--src/or/circuituse.c417
-rw-r--r--src/or/command.c111
-rw-r--r--src/or/config.c516
-rw-r--r--src/or/connection.c536
-rw-r--r--src/or/connection_edge.c684
-rw-r--r--src/or/connection_or.c286
-rw-r--r--src/or/control.c472
-rw-r--r--src/or/cpuworker.c27
-rw-r--r--src/or/directory.c612
-rw-r--r--src/or/dirserv.c497
-rw-r--r--src/or/dns.c1308
-rw-r--r--src/or/eventdns.c2292
-rw-r--r--src/or/eventdns.h73
-rw-r--r--src/or/eventdns_tor.h13
-rw-r--r--src/or/hibernate.c20
-rw-r--r--src/or/main.c328
-rw-r--r--src/or/onion.c12
-rw-r--r--src/or/or.h837
-rw-r--r--src/or/policies.c38
-rw-r--r--src/or/relay.c333
-rw-r--r--src/or/rendclient.c108
-rw-r--r--src/or/rendcommon.c27
-rw-r--r--src/or/rendmid.c84
-rw-r--r--src/or/rendservice.c109
-rw-r--r--src/or/rephist.c91
-rw-r--r--src/or/router.c308
-rw-r--r--src/or/routerlist.c452
-rw-r--r--src/or/routerparse.c102
-rw-r--r--src/or/test.c157
33 files changed, 8473 insertions, 3383 deletions
diff --git a/src/or/Makefile.am b/src/or/Makefile.am
index 6a77adffaa..91ec1c057c 100644
--- a/src/or/Makefile.am
+++ b/src/or/Makefile.am
@@ -4,12 +4,19 @@ noinst_PROGRAMS = test
bin_PROGRAMS = tor
+if EVENTDNS
+EVDNSSRC = eventdns.c
+else
+EVDNSSRC =
+endif
+
tor_SOURCES = buffers.c circuitbuild.c circuitlist.c \
circuituse.c command.c config.c \
connection.c connection_edge.c connection_or.c control.c \
cpuworker.c directory.c dirserv.c dns.c hibernate.c main.c \
onion.c policies.c relay.c rendcommon.c rendclient.c rendmid.c \
rendservice.c rephist.c router.c routerlist.c routerparse.c \
+ $(EVDNSSRC) \
tor_main.c
tor_LDADD = ../common/libor.a ../common/libor-crypto.a -lz -lssl -lcrypto
@@ -20,9 +27,10 @@ test_SOURCES = buffers.c circuitbuild.c circuitlist.c \
cpuworker.c directory.c dirserv.c dns.c hibernate.c main.c \
onion.c policies.c relay.c rendcommon.c rendclient.c rendmid.c \
rendservice.c rephist.c router.c routerlist.c routerparse.c \
+ $(EVDNSSRC) \
test.c
test_LDADD = ../common/libor.a ../common/libor-crypto.a -lz -lssl -lcrypto
-noinst_HEADERS = or.h
+noinst_HEADERS = or.h eventdns.h eventdns_tor.h eventdns.c
diff --git a/src/or/buffers.c b/src/or/buffers.c
index f5dd19135b..290a81c8b2 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -58,10 +58,15 @@ struct buf_t {
char *cur; /**< The first byte used for storing data in the buffer. */
size_t highwater; /**< Largest observed datalen since last buf_shrink */
size_t len; /**< Maximum amount of data that <b>mem</b> can hold. */
+ size_t memsize; /**< How many bytes did we actually allocate? Can be less
+ * than 'len' if we shortened 'len' by a few bytes to make
+ * zlib wrap around more easily. */
size_t datalen; /**< Number of bytes currently in <b>mem</b>. */
};
+/** How many bytes, total, are used in all buffers? */
uint64_t buf_total_used = 0;
+/** How many bytes, total, are allocated in all buffers? */
uint64_t buf_total_alloc = 0;
/** Size, in bytes, for newly allocated buffers. Should be a power of 2. */
@@ -88,13 +93,14 @@ buf_normalize(buf_t *buf)
char *newmem, *oldmem;
size_t sz = (buf->mem+buf->len)-buf->cur;
log_warn(LD_BUG, "Unexpected non-normalized buffer.");
- newmem = GUARDED_MEM(tor_malloc(ALLOC_LEN(buf->len)));
- SET_GUARDS(newmem, buf->len);
+ newmem = GUARDED_MEM(tor_malloc(ALLOC_LEN(buf->memsize)));
+ SET_GUARDS(newmem, buf->memsize);
memcpy(newmem, buf->cur, sz);
memcpy(newmem+sz, buf->mem, buf->datalen-sz);
oldmem = RAW_MEM(buf->mem);
tor_free(oldmem); /* Can't use tor_free directly. */
buf->mem = buf->cur = newmem;
+ buf->len = buf->memsize;
check();
}
}
@@ -229,7 +235,7 @@ buf_resize(buf_t *buf, size_t new_capacity)
buf->len-offset);
buf->cur += new_capacity-buf->len;
}
- buf->len = new_capacity;
+ buf->memsize = buf->len = new_capacity;
#ifdef CHECK_AFTER_RESIZE
assert_buf_ok(buf);
@@ -249,15 +255,18 @@ buf_resize(buf_t *buf, size_t new_capacity)
static INLINE int
buf_ensure_capacity(buf_t *buf, size_t capacity)
{
- size_t new_len;
+ size_t new_len, min_len;
if (buf->len >= capacity) /* Don't grow if we're already big enough. */
return 0;
if (capacity > MAX_BUF_SIZE) /* Don't grow past the maximum. */
return -1;
- /* Find the smallest new_len equal to (2**X)*len for some X; such that
- * new_len is at least capacity.
+ /* Find the smallest new_len equal to (2**X) for some X; such that
+ * new_len is at least capacity, and at least 2*buf->len.
*/
- new_len = buf->len*2;
+ min_len = buf->len*2;
+ new_len = 16;
+ while (new_len < min_len)
+ new_len *= 2;
while (new_len < capacity)
new_len *= 2;
/* Resize the buffer. */
@@ -325,7 +334,7 @@ buf_new_with_capacity(size_t size)
buf->magic = BUFFER_MAGIC;
buf->cur = buf->mem = GUARDED_MEM(tor_malloc(ALLOC_LEN(size)));
SET_GUARDS(buf->mem, size);
- buf->len = size;
+ buf->len = buf->memsize = size;
buf_total_alloc += size;
assert_buf_ok(buf);
@@ -346,6 +355,7 @@ buf_clear(buf_t *buf)
buf_total_used -= buf->datalen;
buf->datalen = 0;
buf->cur = buf->mem;
+ buf->len = buf->memsize;
}
/** Return the number of bytes stored in <b>buf</b> */
@@ -398,7 +408,7 @@ read_to_buf_impl(int s, size_t at_most, buf_t *buf,
int read_result;
// log_fn(LOG_DEBUG,"reading at most %d bytes.",at_most);
- read_result = recv(s, pos, at_most, 0);
+ read_result = tor_socket_recv(s, pos, at_most, 0);
if (read_result < 0) {
int e = tor_socket_errno(s);
if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */
@@ -572,7 +582,7 @@ flush_buf_impl(int s, buf_t *buf, size_t sz, size_t *buf_flushlen)
{
int write_result;
- write_result = send(s, buf->cur, sz, 0);
+ write_result = tor_socket_send(s, buf->cur, sz, 0);
if (write_result < 0) {
int e = tor_socket_errno(s);
if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */
@@ -872,14 +882,14 @@ fetch_from_buf_http(buf_t *buf,
if (headers_out) {
*headers_out = tor_malloc(headerlen+1);
memcpy(*headers_out,buf->cur,headerlen);
- (*headers_out)[headerlen] = 0; /* null terminate it */
+ (*headers_out)[headerlen] = 0; /* nul terminate it */
}
if (body_out) {
tor_assert(body_used);
*body_used = bodylen;
*body_out = tor_malloc(bodylen+1);
memcpy(*body_out,buf->cur+headerlen,bodylen);
- (*body_out)[bodylen] = 0; /* null terminate it */
+ (*body_out)[bodylen] = 0; /* nul terminate it */
}
buf_remove_from_front(buf, headerlen+bodylen);
return 1;
@@ -947,7 +957,9 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
req->reply[1] = '\xFF'; /* reject all methods */
return -1;
}
- buf_remove_from_front(buf,2+nummethods); /* remove packet from buf */
+ /* remove packet from buf. also remove any other extraneous
+ * bytes, to support broken socks clients. */
+ buf_clear(buf);
req->replylen = 2; /* 2 bytes of response */
req->reply[0] = 5; /* socks5 reply */
@@ -962,8 +974,9 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
return 0; /* not yet */
req->command = (unsigned char) *(buf->cur+1);
if (req->command != SOCKS_COMMAND_CONNECT &&
- req->command != SOCKS_COMMAND_RESOLVE) {
- /* not a connect or resolve? we don't support it. */
+ req->command != SOCKS_COMMAND_RESOLVE &&
+ req->command != SOCKS_COMMAND_RESOLVE_PTR) {
+ /* not a connect or resolve or a resolve_ptr? we don't support it. */
log_warn(LD_APP,"socks5: command %d not recognized. Rejecting.",
req->command);
return -1;
@@ -987,7 +1000,8 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
strlcpy(req->address,tmpbuf,sizeof(req->address));
req->port = ntohs(*(uint16_t*)(buf->cur+8));
buf_remove_from_front(buf, 10);
- if (!address_is_in_virtual_range(req->address) &&
+ if (req->command != SOCKS_COMMAND_RESOLVE_PTR &&
+ !addressmap_have_mapping(req->address) &&
!have_warned_about_unsafe_socks) {
log_warn(LD_APP,
"Your application (using socks5 on port %d) is giving "
@@ -1013,6 +1027,11 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
"%d. Rejecting.", len+1,MAX_SOCKS_ADDR_LEN);
return -1;
}
+ if (req->command == SOCKS_COMMAND_RESOLVE_PTR) {
+ log_warn(LD_APP, "socks5 received RESOLVE_PTR command with "
+ "hostname type. Rejecting.");
+ return -1;
+ }
memcpy(req->address,buf->cur+5,len);
req->address[len] = 0;
req->port = ntohs(get_uint16(buf->cur+5+len));
@@ -1047,7 +1066,8 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
req->command = (unsigned char) *(buf->cur+1);
if (req->command != SOCKS_COMMAND_CONNECT &&
req->command != SOCKS_COMMAND_RESOLVE) {
- /* not a connect or resolve? we don't support it. */
+ /* not a connect or resolve? we don't support it. (No resolve_ptr with
+ * socks4.) */
log_warn(LD_APP,"socks4: command %d not recognized. Rejecting.",
req->command);
return -1;
@@ -1083,7 +1103,7 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
startaddr = NULL;
if (socks4_prot != socks4a &&
- !address_is_in_virtual_range(tmpbuf) &&
+ !addressmap_have_mapping(tmpbuf) &&
!have_warned_about_unsafe_socks) {
log_warn(LD_APP,
"Your application (using socks4 on port %d) is giving Tor "
@@ -1284,6 +1304,62 @@ fetch_from_buf_line(buf_t *buf, char *data_out, size_t *data_len)
return 1;
}
+/** Compress on uncompress the <b>data_len</b> bytes in <b>data</b> using the
+ * zlib state <b>state</b>, appending the result to <b>buf</b>. If
+ * <b>done</b> is true, flush the data in the state and finish the
+ * compression/uncompression. Return -1 on failure, 0 on success. */
+int
+write_to_buf_zlib(buf_t *buf, tor_zlib_state_t *state,
+ const char *data, size_t data_len,
+ int done)
+{
+ char *next;
+ size_t old_avail, avail;
+ int over = 0;
+ do {
+ buf_ensure_capacity(buf, buf->datalen + 1024);
+ next = _buf_end(buf);
+ if (next < buf->cur)
+ old_avail = avail = buf->cur - next;
+ else
+ old_avail = avail = (buf->mem + buf->len) - next;
+ switch (tor_zlib_process(state, &next, &avail, &data, &data_len, done)) {
+ case TOR_ZLIB_DONE:
+ over = 1;
+ break;
+ case TOR_ZLIB_ERR:
+ return -1;
+ case TOR_ZLIB_OK:
+ if (data_len == 0)
+ over = 1;
+ break;
+ case TOR_ZLIB_BUF_FULL:
+ if (avail && buf->len >= 1024 + buf->datalen) {
+ /* Zlib says we need more room (ZLIB_BUF_FULL), and we're not about
+ * to wrap around (avail != 0), and resizing won't actually make us
+ * un-full: we're at the end of the buffer, and zlib refuses to
+ * append more here, but there's a pile of free space at the start
+ * of the buffer (about 1K). So chop a few characters off the
+ * end of the buffer. This feels silly; anybody got a better hack?
+ *
+ * (We don't just want to expand the buffer nevertheless. Consider a
+ * 1/3 full buffer with a single byte free at the end. zlib will
+ * often refuse to append to that, and so we want to use the
+ * beginning, not double the buffer to be just 1/6 full.)
+ */
+ tor_assert(next >= buf->cur);
+ buf->len -= avail;
+ }
+ break;
+ }
+ buf->datalen += old_avail - avail;
+ if (buf->datalen > buf->highwater)
+ buf->highwater = buf->datalen;
+ buf_total_used += old_avail - avail;
+ } while (!over);
+ return 0;
+}
+
/** Log an error and exit if <b>buf</b> is corrupted.
*/
void
@@ -1298,7 +1374,7 @@ assert_buf_ok(buf_t *buf)
{
uint32_t u32 = get_uint32(buf->mem - 4);
tor_assert(u32 == START_MAGIC);
- u32 = get_uint32(buf->mem + buf->len);
+ u32 = get_uint32(buf->mem + buf->memsize);
tor_assert(u32 == END_MAGIC);
}
#endif
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 6a9ed3b16b..d23f21b704 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -43,7 +43,7 @@ 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(circuit_t *circ, extend_info_t *exit);
+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(uint8_t purpose, crypt_path_t **head_ptr,
cpath_build_state_t *state);
@@ -54,21 +54,19 @@ static routerinfo_t *choose_random_entry(cpath_build_state_t *state);
static void entry_guards_changed(void);
/** Iterate over values of circ_id, starting from conn-\>next_circ_id,
- * and with the high bit specified by circ_id_type (see
- * decide_circ_id_type()), until we get a circ_id that is not in use
- * by any other circuit on that conn.
+ * and with the high bit specified by conn-\>circ_id_type, until we get
+ * a circ_id that is not in use by any other circuit on that conn.
*
* Return it, or 0 if can't get a unique circ_id.
*/
static uint16_t
-get_unique_circ_id_by_conn(connection_t *conn)
+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);
- tor_assert(conn->type == CONN_TYPE_OR);
high_bit = (conn->circ_id_type == CIRC_ID_TYPE_HIGHER) ? 1<<15 : 0;
do {
/* Sequentially iterate over test_circ_id=1...1<<15-1 until we find a
@@ -96,14 +94,13 @@ get_unique_circ_id_by_conn(connection_t *conn)
* a more verbose format using spaces.
*/
char *
-circuit_list_path(circuit_t *circ, int verbose)
+circuit_list_path(origin_circuit_t *circ, int verbose)
{
crypt_path_t *hop;
smartlist_t *elements;
const char *states[] = {"closed", "waiting for keys", "open"};
char buf[128];
char *s;
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
elements = smartlist_create();
@@ -113,8 +110,8 @@ circuit_list_path(circuit_t *circ, int verbose)
circ->build_state->is_internal ? "internal" : "exit",
circ->build_state->need_uptime ? " (high-uptime)" : "",
circ->build_state->desired_path_len,
- circ->state == CIRCUIT_STATE_OPEN ? "" : ", exit ",
- circ->state == CIRCUIT_STATE_OPEN ? "" :
+ circ->_base.state == CIRCUIT_STATE_OPEN ? "" : ", exit ",
+ circ->_base.state == CIRCUIT_STATE_OPEN ? "" :
(nickname?nickname:"*unnamed*"));
smartlist_add(elements, tor_strdup(buf));
}
@@ -153,7 +150,7 @@ circuit_list_path(circuit_t *circ, int verbose)
* exit point.
*/
void
-circuit_log_path(int severity, unsigned int domain, circuit_t *circ)
+circuit_log_path(int severity, unsigned int domain, origin_circuit_t *circ)
{
char *s = circuit_list_path(circ,1);
log(severity,domain,"%s",s);
@@ -166,7 +163,7 @@ circuit_log_path(int severity, unsigned int domain, circuit_t *circ)
* unable to extend.
*/
void
-circuit_rep_hist_note_result(circuit_t *circ)
+circuit_rep_hist_note_result(origin_circuit_t *circ)
{
crypt_path_t *hop;
char *prev_digest = NULL;
@@ -207,74 +204,14 @@ circuit_rep_hist_note_result(circuit_t *circ)
} while (hop!=circ->cpath);
}
-/** A helper function for circuit_dump_by_conn() below. Log a bunch
- * of information about circuit <b>circ</b>.
- */
-static void
-circuit_dump_details(int severity, circuit_t *circ, int poll_index,
- const char *type, int this_circid, int other_circid)
-{
- log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d (other side %d), "
- "state %d (%s), born %d:",
- poll_index, type, this_circid, other_circid, circ->state,
- circuit_state_to_string(circ->state), (int)circ->timestamp_created);
- if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */
- circuit_log_path(severity, LD_CIRC, circ);
- }
-}
-
-/** Log, at severity <b>severity</b>, information about each circuit
- * that is connected to <b>conn</b>.
- */
-void
-circuit_dump_by_conn(connection_t *conn, int severity)
-{
- circuit_t *circ;
- connection_t *tmpconn;
-
- for (circ=global_circuitlist;circ;circ = circ->next) {
- if (circ->marked_for_close)
- continue;
- if (circ->p_conn == conn)
- circuit_dump_details(severity, circ, conn->poll_index, "App-ward",
- circ->p_circ_id, circ->n_circ_id);
- for (tmpconn=circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream) {
- if (tmpconn == conn) {
- circuit_dump_details(severity, circ, conn->poll_index, "App-ward",
- circ->p_circ_id, circ->n_circ_id);
- }
- }
- if (circ->n_conn == conn)
- circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward",
- circ->n_circ_id, circ->p_circ_id);
- for (tmpconn=circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream) {
- if (tmpconn == conn) {
- circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward",
- circ->n_circ_id, circ->p_circ_id);
- }
- }
- if (!circ->n_conn && circ->n_addr && circ->n_port &&
- circ->n_addr == conn->addr &&
- circ->n_port == conn->port &&
- !memcmp(conn->identity_digest, circ->n_conn_id_digest, DIGEST_LEN)) {
- circuit_dump_details(severity, circ, conn->poll_index,
- (circ->state == CIRCUIT_STATE_OPEN &&
- !CIRCUIT_IS_ORIGIN(circ)) ?
- "Endpoint" : "Pending",
- circ->n_circ_id, circ->p_circ_id);
- }
- }
-}
-
/** Pick all the entries in our cpath. Stop and return 0 when we're
* happy, or return -1 if an error occurs. */
static int
-onion_populate_cpath(circuit_t *circ)
+onion_populate_cpath(origin_circuit_t *circ)
{
int r;
again:
- r = onion_extend_cpath(circ->purpose, &circ->cpath, circ->build_state);
-// || !CIRCUIT_IS_ORIGIN(circ)) { // wtf? -rd
+ r = onion_extend_cpath(circ->_base.purpose, &circ->cpath, circ->build_state);
if (r < 0) {
log_info(LD_CIRC,"Generating cpath hop failed.");
return -1;
@@ -284,19 +221,20 @@ again:
return 0; /* if r == 1 */
}
-/** Create and return a new circuit. Initialize its purpose and
+/** Create and return a new origin circuit. Initialize its purpose and
* build-state based on our arguments. */
-circuit_t *
-circuit_init(uint8_t purpose, int need_uptime, int need_capacity, int internal)
+origin_circuit_t *
+origin_circuit_init(uint8_t purpose, int need_uptime, int need_capacity,
+ int internal)
{
/* sets circ->p_circ_id and circ->p_conn */
- circuit_t *circ = circuit_new(0, NULL);
- circuit_set_state(circ, CIRCUIT_STATE_OR_WAIT);
+ 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->need_uptime = need_uptime;
circ->build_state->need_capacity = need_capacity;
circ->build_state->is_internal = internal;
- circ->purpose = purpose;
+ circ->_base.purpose = purpose;
return circ;
}
@@ -307,24 +245,24 @@ circuit_init(uint8_t purpose, int need_uptime, int need_capacity, int internal)
* Also launch a connection to the first OR in the chosen path, if
* it's not open already.
*/
-circuit_t *
+origin_circuit_t *
circuit_establish_circuit(uint8_t purpose, extend_info_t *info,
int need_uptime, int need_capacity, int internal)
{
- circuit_t *circ;
+ origin_circuit_t *circ;
- circ = circuit_init(purpose, need_uptime, need_capacity, internal);
+ circ = origin_circuit_init(purpose, need_uptime, need_capacity, internal);
if (onion_pick_cpath_exit(circ, info) < 0 ||
onion_populate_cpath(circ) < 0) {
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return NULL;
}
control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED);
if (circuit_handle_first_hop(circ) < 0) {
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return NULL;
}
return circ;
@@ -335,10 +273,10 @@ circuit_establish_circuit(uint8_t purpose, extend_info_t *info,
* it. If we're already connected, then send the 'create' cell.
* Return 0 for ok, -1 if circ should be marked-for-close. */
int
-circuit_handle_first_hop(circuit_t *circ)
+circuit_handle_first_hop(origin_circuit_t *circ)
{
crypt_path_t *firsthop;
- connection_t *n_conn;
+ or_connection_t *n_conn;
char tmpbuf[INET_NTOA_BUF_LEN];
struct in_addr in;
@@ -352,22 +290,22 @@ circuit_handle_first_hop(circuit_t *circ)
log_debug(LD_CIRC,"Looking for firsthop '%s:%u'",tmpbuf,
firsthop->extend_info->port);
/* imprint the circuit with its future n_conn->id */
- memcpy(circ->n_conn_id_digest, firsthop->extend_info->identity_digest,
+ 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 we don't have an open conn, or the conn we have is obsolete
* (i.e. old or broken) and the other side will let us make a second
* connection without dropping it immediately... */
- if (!n_conn || n_conn->state != OR_CONN_STATE_OPEN ||
- (n_conn->is_obsolete &&
+ 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"))) {
/* not currently connected */
- circ->n_addr = firsthop->extend_info->addr;
- circ->n_port = firsthop->extend_info->port;
+ circ->_base.n_addr = firsthop->extend_info->addr;
+ circ->_base.n_port = firsthop->extend_info->port;
- if (!n_conn || n_conn->is_obsolete) { /* launch the connection */
+ if (!n_conn || n_conn->_base.or_is_obsolete) { /* launch the connection */
n_conn = connection_or_connect(firsthop->extend_info->addr,
firsthop->extend_info->port,
firsthop->extend_info->identity_digest);
@@ -384,9 +322,9 @@ circuit_handle_first_hop(circuit_t *circ)
*/
return 0;
} else { /* it's already open. use it. */
- circ->n_addr = n_conn->addr;
- circ->n_port = n_conn->port;
- circ->n_conn = n_conn;
+ 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 (circuit_send_next_onion_skin(circ) < 0) {
log_info(LD_CIRC,"circuit_send_next_onion_skin failed.");
@@ -396,15 +334,17 @@ circuit_handle_first_hop(circuit_t *circ)
return 0;
}
+extern smartlist_t *circuits_pending_or_conns;
+
/** Find any circuits that are waiting on <b>or_conn</b> to become
* open and get them to send their create cells forward.
*
* Status is 1 if connect succeeded, or 0 if connect failed.
*/
void
-circuit_n_conn_done(connection_t *or_conn, int status)
+circuit_n_conn_done(or_connection_t *or_conn, int status)
{
- extern smartlist_t *circuits_pending_or_conns;
+ smartlist_t *changed_circs;
smartlist_t *changed_circs;
log_debug(LD_CIRC,"or_conn to %s, status=%d",
@@ -428,14 +368,13 @@ circuit_n_conn_done(connection_t *or_conn, int status)
circuit_mark_for_close(circ, END_CIRC_REASON_OR_CONN_CLOSED);
continue;
}
- log_debug(LD_CIRC,
- "Found circ %d, sending create cell.", circ->n_circ_id);
+ log_debug(LD_CIRC, "Found circ, sending create cell.");
/* circuit_deliver_create_cell will set n_circ_id and add us to
* orconn_circuid_circuit_map, so we don't need to call
* set_circid_orconn here. */
circ->n_conn = or_conn;
if (CIRCUIT_IS_ORIGIN(circ)) {
- if (circuit_send_next_onion_skin(circ) < 0) {
+ if (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, END_CIRC_AT_ORIGIN);
@@ -473,14 +412,14 @@ circuit_n_conn_done(connection_t *or_conn, int status)
* Return -1 if we failed to find a suitable circid, else return 0.
*/
static int
-circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type, char *payload)
+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(circ->n_conn->type == CONN_TYPE_OR);
tor_assert(payload);
tor_assert(cell_type == CELL_CREATE || cell_type == CELL_CREATE_FAST);
@@ -490,7 +429,7 @@ circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type, char *payload)
return -1;
}
log_debug(LD_CIRC,"Chosen circID %u.", id);
- circuit_set_circid_orconn(circ, id, circ->n_conn, N_CONN_CHANGED);
+ circuit_set_n_circid_orconn(circ, id, circ->n_conn);
memset(&cell, 0, sizeof(cell_t));
cell.command = cell_type;
@@ -526,13 +465,13 @@ inform_testing_reachability(void)
/** Return true iff we should send a create_fast cell to build a circuit
* starting at <b>router</b>. (If <b>router</b> is NULL, we don't have
- * information on the router. */
+ * information on the router, so return false.) */
static INLINE int
should_use_create_fast_for_router(routerinfo_t *router)
{
or_options_t *options = get_options();
- if (!options->FastFirstHopPK || options->ORPort)
+ 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"))
@@ -541,8 +480,6 @@ should_use_create_fast_for_router(routerinfo_t *router)
return 1;
}
-extern int has_completed_circuit;
-
/** This is the backbone function for building circuits.
*
* If circ's first hop is closed, then we need to build a create
@@ -554,7 +491,7 @@ extern int has_completed_circuit;
* Return -reason if we want to tear down circ, else return 0.
*/
int
-circuit_send_next_onion_skin(circuit_t *circ)
+circuit_send_next_onion_skin(origin_circuit_t *circ)
{
crypt_path_t *hop;
routerinfo_t *router;
@@ -563,14 +500,13 @@ circuit_send_next_onion_skin(circuit_t *circ)
size_t payload_len;
tor_assert(circ);
- tor_assert(CIRCUIT_IS_ORIGIN(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->n_conn->identity_digest);
+ router = router_get_by_digest(circ->_base.n_conn->identity_digest);
fast = should_use_create_fast_for_router(router);
if (! fast) {
/* We are an OR, or we are connecting to an old Tor: we should
@@ -595,22 +531,22 @@ circuit_send_next_onion_skin(circuit_t *circ)
sizeof(circ->cpath->fast_handshake_state));
}
- if (circuit_deliver_create_cell(circ, cell_type, payload) < 0)
+ 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(circ, CIRCUIT_STATE_BUILDING);
+ 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>");
+ router ? router->nickname : "<unnamed>");
} else {
tor_assert(circ->cpath->state == CPATH_STATE_OPEN);
- tor_assert(circ->state == CIRCUIT_STATE_BUILDING);
+ 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) {
/* done building the circuit. whew. */
- circuit_set_state(circ, CIRCUIT_STATE_OPEN);
+ circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
log_info(LD_CIRC,"circuit built!");
circuit_reset_failure_count(0);
if (!has_completed_circuit) {
@@ -622,7 +558,7 @@ circuit_send_next_onion_skin(circuit_t *circ)
"Looks like client functionality is working.");
if (server_mode(options) && !check_whether_orport_reachable()) {
inform_testing_reachability();
- consider_testing_reachability();
+ consider_testing_reachability(1, 1);
}
}
circuit_rep_hist_note_result(circ);
@@ -647,7 +583,8 @@ circuit_send_next_onion_skin(circuit_t *circ)
log_debug(LD_CIRC,"Sending extend relay cell.");
/* send it to hop->prev, because it will transfer
* it to a create cell and then send to hop */
- if (connection_edge_send_command(NULL, circ, RELAY_COMMAND_EXTEND,
+ if (connection_edge_send_command(NULL, TO_CIRCUIT(circ),
+ RELAY_COMMAND_EXTEND,
payload, payload_len, hop->prev) < 0)
return 0; /* circuit is closed */
@@ -662,8 +599,13 @@ circuit_send_next_onion_skin(circuit_t *circ)
void
circuit_note_clock_jumped(int seconds_elapsed)
{
- log(LOG_NOTICE, LD_GENERAL,"Your clock just jumped %d seconds forward; "
- "assuming established circuits no longer work.", seconds_elapsed);
+ if (server_mode(get_options()))
+ log(LOG_WARN, LD_GENERAL,
+ "Please report: your clock just jumped %d seconds forward; "
+ "assuming established circuits no longer work.", seconds_elapsed);
+ else
+ log(LOG_NOTICE, LD_GENERAL, "Your clock just jumped %d seconds forward; "
+ "assuming established circuits no longer work.", seconds_elapsed);
has_completed_circuit=0; /* so it'll log when it works again */
circuit_mark_all_unused_circs();
circuit_expire_all_dirty_circs();
@@ -677,7 +619,7 @@ circuit_note_clock_jumped(int seconds_elapsed)
int
circuit_extend(cell_t *cell, circuit_t *circ)
{
- connection_t *n_conn;
+ or_connection_t *n_conn;
relay_header_t rh;
char *onionskin;
char *id_digest=NULL;
@@ -693,6 +635,12 @@ circuit_extend(cell_t *cell, circuit_t *circ)
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) {
@@ -712,12 +660,9 @@ circuit_extend(cell_t *cell, circuit_t *circ)
/* If we don't have an open conn, or the conn we have is obsolete
* (i.e. old or broken) and the other side will let us make a second
* connection without dropping it immediately... */
- if (!n_conn || n_conn->state != OR_CONN_STATE_OPEN ||
- (n_conn->is_obsolete &&
+ 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"))) {
- /* Note that this will close circuits where the onion has the same
- * router twice in a row in the path. I think that's ok.
- */
struct in_addr in;
char tmpbuf[INET_NTOA_BUF_LEN];
in.s_addr = htonl(circ->n_addr);
@@ -732,9 +677,9 @@ circuit_extend(cell_t *cell, circuit_t *circ)
/* imprint the circuit with its future n_conn->id */
memcpy(circ->n_conn_id_digest, id_digest, DIGEST_LEN);
- if (n_conn && !n_conn->is_obsolete) {
- circ->n_addr = n_conn->addr;
- circ->n_port = n_conn->port;
+ if (n_conn && !n_conn->_base.or_is_obsolete) {
+ circ->n_addr = n_conn->_base.addr;
+ circ->n_port = n_conn->_base.port;
} else {
/* we should try to open a connection */
n_conn = connection_or_connect(circ->n_addr, circ->n_port, id_digest);
@@ -753,12 +698,13 @@ circuit_extend(cell_t *cell, circuit_t *circ)
}
/* these may be different if the router connected to us from elsewhere */
- circ->n_addr = n_conn->addr;
- circ->n_port = n_conn->port;
+ 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->address,n_conn->port);
+ 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;
@@ -825,12 +771,12 @@ circuit_init_cpath_crypto(crypt_path_t *cpath, char *key_data, int reverse)
* Return - reason if we want to mark circ for close, else return 0.
*/
int
-circuit_finish_handshake(circuit_t *circ, uint8_t reply_type, char *reply)
+circuit_finish_handshake(origin_circuit_t *circ, uint8_t reply_type,
+ char *reply)
{
char keys[CPATH_KEY_MATERIAL_LEN];
crypt_path_t *hop;
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS)
hop = circ->cpath;
else {
@@ -888,20 +834,19 @@ circuit_finish_handshake(circuit_t *circ, uint8_t reply_type, char *reply)
* just give up: for circ to close, and return 0.
*/
int
-circuit_truncated(circuit_t *circ, crypt_path_t *layer)
+circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer)
{
// crypt_path_t *victim;
// connection_t *stream;
tor_assert(circ);
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
tor_assert(layer);
/* XXX Since we don't ask for truncates currently, getting a truncated
* means that a connection broke or an extend failed. For now,
* just give up.
*/
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return 0;
#if 0
@@ -934,7 +879,8 @@ circuit_truncated(circuit_t *circ, crypt_path_t *layer)
* cell back.
*/
int
-onionskin_answer(circuit_t *circ, uint8_t cell_type, char *payload, char *keys)
+onionskin_answer(or_circuit_t *circ, uint8_t cell_type, char *payload,
+ char *keys)
{
cell_t cell;
crypt_path_t *tmp_cpath;
@@ -946,7 +892,7 @@ onionskin_answer(circuit_t *circ, uint8_t cell_type, char *payload, char *keys)
cell.command = cell_type;
cell.circ_id = circ->p_circ_id;
- circuit_set_state(circ, CIRCUIT_STATE_OPEN);
+ circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
memcpy(cell.payload, payload,
cell_type == CELL_CREATED ? ONIONSKIN_REPLY_LEN : DIGEST_LEN*2);
@@ -974,8 +920,8 @@ onionskin_answer(circuit_t *circ, uint8_t cell_type, char *payload, char *keys)
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->addr) &&
- tor_tls_is_server(circ->p_conn->tls)) {
+ if (!is_local_IP(circ->p_conn->_base.addr) &&
+ !connection_or_nonopen_was_started_here(circ->p_conn)) {
/* record that we could process create cells from a non-local conn
* that we didn't initiate; presumably this means that create cells
* can reach us too. */
@@ -1112,8 +1058,9 @@ 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(conn) &&
- !circuit_stream_is_being_handled(conn, 0, MIN_CIRCUITS_HANDLING_STREAM))
+ !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;
}
@@ -1198,7 +1145,7 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
for (j = 0; j < n_connections; ++j) { /* iterate over connections */
if (!ap_stream_wants_exit_attention(carray[j]))
continue; /* Skip everything but APs in CIRCUIT_WAIT */
- if (connection_ap_can_use_exit(carray[j], router)) {
+ if (connection_ap_can_use_exit(TO_EDGE_CONN(carray[j]), router)) {
++n_supported[i];
// log_fn(LOG_DEBUG,"%s is supported. n_supported[%d] now %d.",
// router->nickname, i, n_supported[i]);
@@ -1260,7 +1207,7 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
need_uptime?", stable":"");
return choose_good_exit_server_general(dir, 0, 0);
}
- log_notice(LD_CIRC, "All routers are down or middleman -- choosing a "
+ log_notice(LD_CIRC, "All routers are down or won't exit -- choosing a "
"doomed exit at random.");
}
for (try = 0; try < 2; try++) {
@@ -1343,13 +1290,13 @@ choose_good_exit_server(uint8_t purpose, routerlist_t *dir,
* router (or use <b>exit</b> if provided). Store these in the
* cpath. Return 0 if ok, -1 if circuit should be closed. */
static int
-onion_pick_cpath_exit(circuit_t *circ, extend_info_t *exit)
+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();
int r;
- r = new_route_len(get_options()->PathlenCoinWeight, circ->purpose,
+ r = new_route_len(get_options()->PathlenCoinWeight, circ->_base.purpose,
exit, rl->routers);
if (r < 1) /* must be at least 1 */
return -1;
@@ -1360,8 +1307,8 @@ onion_pick_cpath_exit(circuit_t *circ, extend_info_t *exit)
exit = extend_info_dup(exit);
} else { /* we have to decide one */
routerinfo_t *router =
- choose_good_exit_server(circ->purpose, rl, state->need_uptime,
- state->need_capacity, state->is_internal);
+ 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;
@@ -1377,11 +1324,11 @@ onion_pick_cpath_exit(circuit_t *circ, extend_info_t *exit)
* the caller will do this if it wants to.
*/
int
-circuit_append_new_exit(circuit_t *circ, extend_info_t *info)
+circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info)
{
cpath_build_state_t *state;
tor_assert(info);
- tor_assert(circ && CIRCUIT_IS_ORIGIN(circ));
+ tor_assert(circ);
state = circ->build_state;
tor_assert(state);
@@ -1399,15 +1346,14 @@ circuit_append_new_exit(circuit_t *circ, extend_info_t *info)
* send the next extend cell to begin connecting to that hop.
*/
int
-circuit_extend_to_new_exit(circuit_t *circ, extend_info_t *info)
+circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info)
{
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
circuit_append_new_exit(circ, info);
- circuit_set_state(circ, CIRCUIT_STATE_BUILDING);
+ circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
if (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(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1;
}
return 0;
@@ -1436,6 +1382,10 @@ count_acceptable_routers(smartlist_t *routers)
if (r->is_valid == 0) {
// log_debug(LD_CIRC,"Nope, the directory says %d is not valid.",i);
goto next_i_loop;
+ /* XXX This clause makes us count incorrectly: if AllowInvalidRouters
+ * allows this node in some places, then we're getting an inaccurate
+ * count. For now, be conservative and don't count it. But later we
+ * should try to be smarter. */
}
num++;
// log_debug(LD_CIRC,"I like %d. num_acceptable_routers now %d.",i, num);
@@ -1472,7 +1422,7 @@ onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop)
* whole network has upgraded. */
static char *
compute_preferred_testing_list(const char *answer)
-{
+{
smartlist_t *choices;
routerlist_t *rl = router_get_routerlist();
routerinfo_t *router;
@@ -1569,6 +1519,7 @@ 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; /* not used yet. */
if (state && options->UseEntryGuards) {
return choose_random_entry(state);
@@ -1835,7 +1786,7 @@ log_entry_guards(int severity)
{
tor_snprintf(buf, sizeof(buf), "%s (%s%s%s)",
e->nickname,
- e->down_since ? "down " : "up ",
+ (e->down_since || e->unlisted_since) ? "down " : "up ",
e->unlisted_since ? "unlisted " : "listed ",
e->made_contact ? "made-contact" : "never-contacted");
smartlist_add(elements, tor_strdup(buf));
@@ -1850,7 +1801,7 @@ log_entry_guards(int severity)
#define NUM_ENTRY_PICK_TRIES 100
-/** Add a new (preferably stable and fast) entry to our
+/** Add a new (preferably stable and fast) router to our
* entry_guards list. Return a pointer to the router if we succeed,
* or NULL if we can't find any more suitable entries.
*
@@ -1862,33 +1813,23 @@ add_an_entry_guard(routerinfo_t *chosen)
{
routerinfo_t *router;
entry_guard_t *entry;
- int tries_left = NUM_ENTRY_PICK_TRIES;
-again:
- if (--tries_left <= 0) {
- log_warn(LD_CIRC, "Tried finding a new entry guard, but failed. "
- "Can you reach the Tor network?");
- return NULL;
- }
- if (chosen)
+ if (chosen) {
router = chosen;
- else
+ 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;
- /* make sure it's not already an entry */
- if (is_an_entry_guard(router->cache_info.identity_digest)) {
- if (chosen)
+ if (!router)
return NULL;
- goto again;
}
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)
+ if (chosen) /* prepend */
smartlist_insert(entry_guards, 0, entry);
- else
+ else /* append */
smartlist_add(entry_guards, entry);
log_entry_guards(LOG_INFO);
return router;
@@ -2032,7 +1973,7 @@ entry_guards_set_status_from_directory(void)
}
log_info(LD_CIRC, "Summary: Entry '%s' is %s, %s, and %s.",
entry->nickname,
- entry->down_since ? "down" : "up",
+ (entry->down_since || entry->unlisted_since) ? "down" : "up",
entry->unlisted_since ? "unlisted" : "listed",
entry_is_live(entry, 0, 1) ? "live" : "not live");
});
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index 73513c4030..dba7864861 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -33,7 +33,7 @@ static void circuit_free_cpath_node(crypt_path_t *victim);
* very important here, since we need to do it every time a cell arrives.) */
typedef struct orconn_circid_circuit_map_t {
HT_ENTRY(orconn_circid_circuit_map_t) node;
- connection_t *or_conn;
+ or_connection_t *or_conn;
uint16_t circ_id;
circuit_t *circuit;
} orconn_circid_circuit_map_t;
@@ -68,35 +68,14 @@ HT_GENERATE(orconn_circid_map, orconn_circid_circuit_map_t, node,
*/
orconn_circid_circuit_map_t *_last_circid_orconn_ent = NULL;
-/** Set the p_conn or n_conn field of a circuit <b>circ</b>, along
- * with the corresponding circuit ID, and add the circuit as appropriate
- * to the (orconn,id)-\>circuit map. */
-void
-circuit_set_circid_orconn(circuit_t *circ, uint16_t id,
- connection_t *conn,
- enum which_conn_changed_t which)
+static void
+circuit_set_circid_orconn_helper(circuit_t *circ, uint16_t id,
+ or_connection_t *conn,
+ uint16_t old_id, or_connection_t *old_conn)
{
- uint16_t old_id;
- connection_t *old_conn;
orconn_circid_circuit_map_t search;
orconn_circid_circuit_map_t *found;
- tor_assert(!conn || conn->type == CONN_TYPE_OR);
-
- if (which == P_CONN_CHANGED) {
- old_id = circ->p_circ_id;
- old_conn = circ->p_conn;
- circ->p_circ_id = id;
- circ->p_conn = conn;
- } else {
- old_id = circ->n_circ_id;
- old_conn = circ->n_conn;
- circ->n_circ_id = id;
- circ->n_conn = conn;
- }
- if (conn == old_conn && old_id == id)
- return;
-
if (_last_circid_orconn_ent &&
((old_id == _last_circid_orconn_ent->circ_id &&
old_conn == _last_circid_orconn_ent->or_conn) ||
@@ -106,7 +85,7 @@ circuit_set_circid_orconn(circuit_t *circ, uint16_t id,
}
if (old_conn) { /* we may need to remove it from the conn-circid map */
- tor_assert(old_conn->magic == CONNECTION_MAGIC);
+ tor_assert(old_conn->_base.magic == OR_CONNECTION_MAGIC);
search.circ_id = old_id;
search.or_conn = old_conn;
found = HT_REMOVE(orconn_circid_map, &orconn_circid_circuit_map, &search);
@@ -135,6 +114,47 @@ circuit_set_circid_orconn(circuit_t *circ, uint16_t id,
++conn->n_circuits;
}
+/** Set the p_conn field of a circuit <b>circ</b>, along
+ * with the corresponding circuit ID, and add the circuit as appropriate
+ * to the (orconn,id)-\>circuit map. */
+void
+circuit_set_p_circid_orconn(or_circuit_t *circ, uint16_t id,
+ or_connection_t *conn)
+{
+ uint16_t old_id;
+ or_connection_t *old_conn;
+
+ old_id = circ->p_circ_id;
+ old_conn = circ->p_conn;
+ circ->p_circ_id = id;
+ circ->p_conn = conn;
+
+ if (id == old_id && conn == old_conn)
+ return;
+ circuit_set_circid_orconn_helper(TO_CIRCUIT(circ), id, conn,
+ old_id, old_conn);
+}
+
+/** Set the n_conn field of a circuit <b>circ</b>, along
+ * with the corresponding circuit ID, and add the circuit as appropriate
+ * to the (orconn,id)-\>circuit map. */
+void
+circuit_set_n_circid_orconn(circuit_t *circ, uint16_t id,
+ or_connection_t *conn)
+{
+ uint16_t old_id;
+ or_connection_t *old_conn;
+
+ old_id = circ->n_circ_id;
+ old_conn = circ->n_conn;
+ circ->n_circ_id = id;
+ circ->n_conn = conn;
+
+ if (id == old_id && conn == old_conn)
+ return;
+ circuit_set_circid_orconn_helper(circ, id, conn, old_id, old_conn);
+}
+
/** Change the state of <b>circ</b> to <b>state</b>, adding it to or removing
* it from lists as appropriate. */
void
@@ -200,7 +220,7 @@ circuit_close_all_marked(void)
}
}
-/** Return the head of the global linked list of circuits. **/
+/** Return the head of the global linked list of circuits. */
circuit_t *
_circuit_get_global_list(void)
{
@@ -224,36 +244,53 @@ circuit_state_to_string(int state)
}
}
+/* DOCDOC */
+static void
+init_circuit_base(circuit_t *circ)
+{
+ circ->timestamp_created = time(NULL);
+
+ circ->package_window = CIRCWINDOW_START;
+ circ->deliver_window = CIRCWINDOW_START;
+
+ circuit_add(circ);
+}
+
/** Allocate space for a new circuit, initializing with <b>p_circ_id</b>
* and <b>p_conn</b>. Add it to the global circuit list.
*/
-circuit_t *
-circuit_new(uint16_t p_circ_id, connection_t *p_conn)
+origin_circuit_t *
+origin_circuit_new(void)
{
- circuit_t *circ;
- static uint32_t n_circuits_allocated = 1;
+ origin_circuit_t *circ;
/* never zero, since a global ID of 0 is treated specially by the
* controller */
+ static uint32_t n_circuits_allocated = 1;
- circ = tor_malloc_zero(sizeof(circuit_t));
- circ->magic = CIRCUIT_MAGIC;
+ circ = tor_malloc_zero(sizeof(origin_circuit_t));
+ circ->_base.magic = ORIGIN_CIRCUIT_MAGIC;
- circ->timestamp_created = time(NULL);
+ circ->next_stream_id = crypto_rand_int(1<<16);
+ circ->global_identifier = n_circuits_allocated++;
+ init_circuit_base(TO_CIRCUIT(circ));
+
+ return circ;
+}
+
+or_circuit_t *
+or_circuit_new(uint16_t p_circ_id, or_connection_t *p_conn)
+{
/* CircIDs */
- if (p_conn) {
- circuit_set_circid_orconn(circ, p_circ_id, p_conn, P_CONN_CHANGED);
- }
- /* circ->n_circ_id remains 0 because we haven't identified the next hop
- * yet */
+ or_circuit_t *circ;
- circ->package_window = CIRCWINDOW_START;
- circ->deliver_window = CIRCWINDOW_START;
+ circ = tor_malloc_zero(sizeof(or_circuit_t));
+ circ->_base.magic = OR_CIRCUIT_MAGIC;
- circ->next_stream_id = crypto_rand_int(1<<16);
- circ->global_identifier = n_circuits_allocated++;
+ if (p_conn)
+ circuit_set_p_circid_orconn(circ, p_circ_id, p_conn);
- circuit_add(circ);
+ init_circuit_base(TO_CIRCUIT(circ));
return circ;
}
@@ -263,35 +300,53 @@ circuit_new(uint16_t p_circ_id, connection_t *p_conn)
static void
circuit_free(circuit_t *circ)
{
+ void *mem;
tor_assert(circ);
- tor_assert(circ->magic == CIRCUIT_MAGIC);
- if (circ->n_crypto)
- crypto_free_cipher_env(circ->n_crypto);
- if (circ->p_crypto)
- crypto_free_cipher_env(circ->p_crypto);
- if (circ->n_digest)
- crypto_free_digest_env(circ->n_digest);
- if (circ->p_digest)
- crypto_free_digest_env(circ->p_digest);
- if (circ->build_state) {
- if (circ->build_state->chosen_exit)
- extend_info_free(circ->build_state->chosen_exit);
- if (circ->build_state->pending_final_cpath)
- circuit_free_cpath_node(circ->build_state->pending_final_cpath);
- }
- tor_free(circ->build_state);
- tor_free(circ->onionskin);
- circuit_free_cpath(circ->cpath);
- if (circ->rend_splice) {
- tor_assert(circ->rend_splice->magic == CIRCUIT_MAGIC);
- circ->rend_splice->rend_splice = NULL;
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
+ mem = ocirc;
+ tor_assert(circ->magic == ORIGIN_CIRCUIT_MAGIC);
+ if (ocirc->build_state) {
+ if (ocirc->build_state->chosen_exit)
+ extend_info_free(ocirc->build_state->chosen_exit);
+ if (ocirc->build_state->pending_final_cpath)
+ circuit_free_cpath_node(ocirc->build_state->pending_final_cpath);
+ }
+ tor_free(ocirc->build_state);
+
+ circuit_free_cpath(ocirc->cpath);
+
+ } else {
+ or_circuit_t *ocirc = TO_OR_CIRCUIT(circ);
+ mem = ocirc;
+ tor_assert(circ->magic == OR_CIRCUIT_MAGIC);
+
+ if (ocirc->p_crypto)
+ crypto_free_cipher_env(ocirc->p_crypto);
+ if (ocirc->p_digest)
+ crypto_free_digest_env(ocirc->p_digest);
+ if (ocirc->n_crypto)
+ crypto_free_cipher_env(ocirc->n_crypto);
+ if (ocirc->n_digest)
+ crypto_free_digest_env(ocirc->n_digest);
+
+ if (ocirc->rend_splice) {
+ or_circuit_t *other = ocirc->rend_splice;
+ tor_assert(other->_base.magic == OR_CIRCUIT_MAGIC);
+ other->rend_splice = NULL;
+ }
+
+ tor_free(circ->onionskin);
+
+ /* remove from map. */
+ circuit_set_p_circid_orconn(ocirc, 0, NULL);
}
+
/* Remove from map. */
- circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED);
- circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
+ circuit_set_n_circid_orconn(circ, 0, NULL);
memset(circ, 0xAA, sizeof(circuit_t)); /* poison memory */
- tor_free(circ);
+ tor_free(mem);
}
/** Deallocate space associated with the linked list <b>cpath</b>. */
@@ -321,11 +376,14 @@ circuit_free_all(void)
circuit_t *next;
while (global_circuitlist) {
next = global_circuitlist->next;
- while (global_circuitlist->resolving_streams) {
- connection_t *next;
- next = global_circuitlist->resolving_streams->next_stream;
- connection_free(global_circuitlist->resolving_streams);
- global_circuitlist->resolving_streams = next;
+ if (! CIRCUIT_IS_ORIGIN(global_circuitlist)) {
+ or_circuit_t *or_circ = TO_OR_CIRCUIT(global_circuitlist);
+ while (or_circ->resolving_streams) {
+ edge_connection_t *next;
+ next = or_circ->resolving_streams->next_stream;
+ connection_free(TO_CONN(or_circ->resolving_streams));
+ or_circ->resolving_streams = next;
+ }
}
circuit_free(global_circuitlist);
global_circuitlist = next;
@@ -358,18 +416,92 @@ circuit_free_cpath_node(crypt_path_t *victim)
tor_free(victim);
}
+/** A helper function for circuit_dump_by_conn() below. Log a bunch
+ * of information about circuit <b>circ</b>.
+ */
+static void
+circuit_dump_details(int severity, circuit_t *circ, int conn_array_index,
+ const char *type, int this_circid, int other_circid)
+{
+ log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d (other side %d), "
+ "state %d (%s), born %d:",
+ conn_array_index, type, this_circid, other_circid, circ->state,
+ circuit_state_to_string(circ->state), (int)circ->timestamp_created);
+ if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */
+ circuit_log_path(severity, LD_CIRC, TO_ORIGIN_CIRCUIT(circ));
+ }
+}
+
+/** Log, at severity <b>severity</b>, information about each circuit
+ * that is connected to <b>conn</b>.
+ */
+void
+circuit_dump_by_conn(connection_t *conn, int severity)
+{
+ circuit_t *circ;
+ edge_connection_t *tmpconn;
+
+ for (circ=global_circuitlist;circ;circ = circ->next) {
+ circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0;
+ if (circ->marked_for_close)
+ continue;
+
+ if (! CIRCUIT_IS_ORIGIN(circ))
+ p_circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
+
+ if (! CIRCUIT_IS_ORIGIN(circ) && TO_OR_CIRCUIT(circ)->p_conn &&
+ TO_CONN(TO_OR_CIRCUIT(circ)->p_conn) == conn)
+ circuit_dump_details(severity, circ, conn->conn_array_index, "App-ward",
+ p_circ_id, n_circ_id);
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ for (tmpconn=TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn;
+ tmpconn=tmpconn->next_stream) {
+ if (TO_CONN(tmpconn) == conn) {
+ circuit_dump_details(severity, circ, conn->conn_array_index,
+ "App-ward", p_circ_id, n_circ_id);
+ }
+ }
+ }
+ if (circ->n_conn && TO_CONN(circ->n_conn) == conn)
+ circuit_dump_details(severity, circ, conn->conn_array_index, "Exit-ward",
+ n_circ_id, p_circ_id);
+ if (! CIRCUIT_IS_ORIGIN(circ)) {
+ for (tmpconn=TO_OR_CIRCUIT(circ)->n_streams; tmpconn;
+ tmpconn=tmpconn->next_stream) {
+ if (TO_CONN(tmpconn) == conn) {
+ circuit_dump_details(severity, circ, conn->conn_array_index,
+ "Exit-ward", n_circ_id, p_circ_id);
+ }
+ }
+ }
+ if (!circ->n_conn && circ->n_addr && circ->n_port &&
+ circ->n_addr == conn->addr &&
+ circ->n_port == conn->port &&
+ conn->type == CONN_TYPE_OR &&
+ !memcmp(TO_OR_CONN(conn)->identity_digest, circ->n_conn_id_digest,
+ DIGEST_LEN)) {
+ circuit_dump_details(severity, circ, conn->conn_array_index,
+ (circ->state == CIRCUIT_STATE_OPEN &&
+ !CIRCUIT_IS_ORIGIN(circ)) ?
+ "Endpoint" : "Pending",
+ n_circ_id, p_circ_id);
+ }
+ }
+}
+
/** Return the circuit whose global ID is <b>id</b>, or NULL if no
* such circuit exists. */
-circuit_t *
+origin_circuit_t *
circuit_get_by_global_id(uint32_t id)
{
circuit_t *circ;
for (circ=global_circuitlist;circ;circ = circ->next) {
- if (circ->global_identifier == id) {
+ if (CIRCUIT_IS_ORIGIN(circ) &&
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier == id) {
if (circ->marked_for_close)
return NULL;
else
- return circ;
+ return TO_ORIGIN_CIRCUIT(circ);
}
}
return NULL;
@@ -381,13 +513,11 @@ circuit_get_by_global_id(uint32_t id)
* Return NULL if no such circuit exists.
*/
static INLINE circuit_t *
-circuit_get_by_circid_orconn_impl(uint16_t circ_id, connection_t *conn)
+circuit_get_by_circid_orconn_impl(uint16_t circ_id, or_connection_t *conn)
{
orconn_circid_circuit_map_t search;
orconn_circid_circuit_map_t *found;
- tor_assert(conn->type == CONN_TYPE_OR);
-
if (_last_circid_orconn_ent &&
circ_id == _last_circid_orconn_ent->circ_id &&
conn == _last_circid_orconn_ent->or_conn) {
@@ -407,10 +537,13 @@ circuit_get_by_circid_orconn_impl(uint16_t circ_id, connection_t *conn)
{
circuit_t *circ;
for (circ=global_circuitlist;circ;circ = circ->next) {
- if (circ->p_conn == conn && circ->p_circ_id == circ_id) {
- log_warn(LD_BUG,
- "circuit matches p_conn, but not in hash table (Bug!)");
- return circ;
+ if (! CIRCUIT_IS_ORIGIN(circ)) {
+ or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+ if (or_circ->p_conn == conn && or_circ->p_circ_id == circ_id) {
+ log_warn(LD_BUG,
+ "circuit matches p_conn, but not in hash table (Bug!)");
+ return circ;
+ }
}
if (circ->n_conn == conn && circ->n_circ_id == circ_id) {
log_warn(LD_BUG,
@@ -429,7 +562,7 @@ circuit_get_by_circid_orconn_impl(uint16_t circ_id, connection_t *conn)
* Return NULL if no such circuit exists.
*/
circuit_t *
-circuit_get_by_circid_orconn(uint16_t circ_id, connection_t *conn)
+circuit_get_by_circid_orconn(uint16_t circ_id, or_connection_t *conn)
{
circuit_t *circ = circuit_get_by_circid_orconn_impl(circ_id, conn);
if (!circ || circ->marked_for_close)
@@ -444,7 +577,7 @@ circuit_get_by_circid_orconn(uint16_t circ_id, connection_t *conn)
* Return NULL if no such circuit exists.
*/
int
-circuit_id_used_on_conn(uint16_t circ_id, connection_t *conn)
+circuit_id_used_on_conn(uint16_t circ_id, or_connection_t *conn)
{
circuit_t *circ = circuit_get_by_circid_orconn_impl(circ_id, conn);
if (circ && circ->marked_for_close)
@@ -456,13 +589,14 @@ circuit_id_used_on_conn(uint16_t circ_id, connection_t *conn)
/** Return the circuit that a given edge connection is using. */
circuit_t *
-circuit_get_by_edge_conn(connection_t *conn)
+circuit_get_by_edge_conn(edge_connection_t *conn)
{
circuit_t *circ;
- tor_assert(CONN_IS_EDGE(conn));
circ = conn->on_circuit;
- tor_assert(!circ || circ->magic == CIRCUIT_MAGIC);
+ tor_assert(!circ ||
+ (CIRCUIT_IS_ORIGIN(circ) ? circ->magic == ORIGIN_CIRCUIT_MAGIC
+ : circ->magic == OR_CIRCUIT_MAGIC));
return circ;
}
@@ -472,18 +606,24 @@ circuit_get_by_edge_conn(connection_t *conn)
* been marked already.
*/
void
-circuit_unlink_all_from_or_conn(connection_t *conn, int reason)
+circuit_unlink_all_from_or_conn(or_connection_t *conn, int reason)
{
circuit_t *circ;
for (circ = global_circuitlist; circ; circ = circ->next) {
- if (circ->n_conn == conn || circ->p_conn == conn) {
- if (circ->n_conn == conn)
- circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
- if (circ->p_conn == conn)
- circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED);
- if (!circ->marked_for_close)
- circuit_mark_for_close(circ, reason);
+ int mark = 0;
+ if (circ->n_conn == conn) {
+ circuit_set_n_circid_orconn(circ, 0, NULL);
+ mark = 1;
+ }
+ if (! CIRCUIT_IS_ORIGIN(circ)) {
+ or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+ if (or_circ->p_conn == conn) {
+ circuit_set_p_circid_orconn(or_circ, 0, NULL);
+ mark = 1;
+ }
}
+ if (mark && !circ->marked_for_close)
+ circuit_mark_for_close(circ, reason);
}
}
@@ -493,62 +633,91 @@ circuit_unlink_all_from_or_conn(connection_t *conn, int reason)
*
* Return NULL if no such circuit exists.
*/
-circuit_t *
+origin_circuit_t *
circuit_get_by_rend_query_and_purpose(const char *rend_query, uint8_t purpose)
{
circuit_t *circ;
+ tor_assert(CIRCUIT_PURPOSE_IS_ORIGIN(purpose));
+
for (circ = global_circuitlist; circ; circ = circ->next) {
if (!circ->marked_for_close &&
circ->purpose == purpose &&
- !rend_cmp_service_ids(rend_query, circ->rend_query))
- return circ;
+ !rend_cmp_service_ids(rend_query, TO_ORIGIN_CIRCUIT(circ)->rend_query))
+ return TO_ORIGIN_CIRCUIT(circ);
}
return NULL;
}
/** Return the first circuit in global_circuitlist after <b>start</b>
- * whose rend_pk_digest field is <b>digest</b> and whose purpose is
- * <b>purpose</b>. Returns NULL if no circuit is found.
+ * whose purpose is <b>purpose</b> is purpose, and (if set) whose
+ * <b>digest</b> matches the rend_pk_digest field. Return NULL if no
+ * circuit is found.
* If <b>start</b> is NULL, begin at the start of the list.
+ * DOCDOC origin.
*/
-circuit_t *
-circuit_get_next_by_pk_and_purpose(circuit_t *start,
+origin_circuit_t *
+circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
const char *digest, uint8_t purpose)
{
circuit_t *circ;
+ tor_assert(CIRCUIT_PURPOSE_IS_ORIGIN(purpose));
if (start == NULL)
circ = global_circuitlist;
else
- circ = start->next;
+ circ = TO_CIRCUIT(start)->next;
for ( ; circ; circ = circ->next) {
if (circ->marked_for_close)
continue;
if (circ->purpose != purpose)
continue;
- if (!memcmp(circ->rend_pk_digest, digest, DIGEST_LEN))
- return circ;
+ if (!digest)
+ return TO_ORIGIN_CIRCUIT(circ);
+ else if (!memcmp(TO_ORIGIN_CIRCUIT(circ)->rend_pk_digest,
+ digest, DIGEST_LEN))
+ return TO_ORIGIN_CIRCUIT(circ);
}
return NULL;
}
-/** Return the circuit waiting for a rendezvous with the provided cookie.
- * Return NULL if no such circuit is found.
- */
-circuit_t *
-circuit_get_rendezvous(const char *cookie)
+/* DOCDOC */
+static or_circuit_t *
+circuit_get_by_rend_token_and_purpose(uint8_t purpose, const char *token,
+ size_t len)
{
circuit_t *circ;
for (circ = global_circuitlist; circ; circ = circ->next) {
if (! circ->marked_for_close &&
- circ->purpose == CIRCUIT_PURPOSE_REND_POINT_WAITING &&
- ! memcmp(circ->rend_cookie, cookie, REND_COOKIE_LEN) )
- return circ;
+ circ->purpose == purpose &&
+ ! memcmp(TO_OR_CIRCUIT(circ)->rend_token, token, len))
+ return TO_OR_CIRCUIT(circ);
}
return NULL;
}
+/** Return the circuit waiting for a rendezvous with the provided cookie.
+ * Return NULL if no such circuit is found.
+ */
+or_circuit_t *
+circuit_get_rendezvous(const char *cookie)
+{
+ return circuit_get_by_rend_token_and_purpose(
+ CIRCUIT_PURPOSE_REND_POINT_WAITING,
+ cookie, REND_COOKIE_LEN);
+}
+
+/** Return the circuit waiting for intro cells of the given digest.
+ * Return NULL if no such circuit is found.
+ */
+or_circuit_t *
+circuit_get_intro_point(const char *digest)
+{
+ return circuit_get_by_rend_token_and_purpose(
+ CIRCUIT_PURPOSE_INTRO_POINT, digest,
+ DIGEST_LEN);
+}
+
/** Return a circuit that is open, has specified <b>purpose</b>,
* has a timestamp_dirty value of 0, is uptime/capacity/internal
* if required, and if info is defined, does not already use info
@@ -559,41 +728,43 @@ circuit_get_rendezvous(const char *cookie)
*
* Only return internal circuits if that is requested.
*/
-circuit_t *
+origin_circuit_t *
circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
int need_uptime,
int need_capacity, int internal)
{
- circuit_t *circ;
- circuit_t *best=NULL;
+ circuit_t *_circ;
+ origin_circuit_t *best=NULL;
log_debug(LD_CIRC,
"Hunting for a circ to cannibalize: purpose %d, uptime %d, "
"capacity %d, internal %d",
purpose, need_uptime, need_capacity, internal);
- for (circ=global_circuitlist; circ; circ = circ->next) {
- if (CIRCUIT_IS_ORIGIN(circ) &&
- circ->state == CIRCUIT_STATE_OPEN &&
- !circ->marked_for_close &&
- circ->purpose == purpose &&
- !circ->timestamp_dirty &&
- (!need_uptime || circ->build_state->need_uptime) &&
- (!need_capacity || circ->build_state->need_capacity) &&
- (internal == circ->build_state->is_internal)) {
- if (info) {
- /* need to make sure we don't duplicate hops */
- crypt_path_t *hop = circ->cpath;
- do {
- if (!memcmp(hop->extend_info->identity_digest,
- info->identity_digest, DIGEST_LEN))
- goto next;
- hop=hop->next;
- } while (hop!=circ->cpath);
- }
- if (!best || (best->build_state->need_uptime && !need_uptime))
- best = circ;
+ for (_circ=global_circuitlist; _circ; _circ = _circ->next) {
+ if (CIRCUIT_IS_ORIGIN(_circ) &&
+ _circ->state == CIRCUIT_STATE_OPEN &&
+ !_circ->marked_for_close &&
+ _circ->purpose == purpose &&
+ !_circ->timestamp_dirty) {
+ origin_circuit_t *circ = TO_ORIGIN_CIRCUIT(_circ);
+ if ((!need_uptime || circ->build_state->need_uptime) &&
+ (!need_capacity || circ->build_state->need_capacity) &&
+ (internal == circ->build_state->is_internal)) {
+ if (info) {
+ /* need to make sure we don't duplicate hops */
+ crypt_path_t *hop = circ->cpath;
+ do {
+ if (!memcmp(hop->extend_info->identity_digest,
+ info->identity_digest, DIGEST_LEN))
+ goto next;
+ hop=hop->next;
+ } while (hop!=circ->cpath);
+ }
+ if (!best || (best->build_state->need_uptime && !need_uptime))
+ best = circ;
next: ;
+ }
}
}
return best;
@@ -654,8 +825,6 @@ void
_circuit_mark_for_close(circuit_t *circ, int reason, int line,
const char *file)
{
- connection_t *conn;
-
assert_circuit_ok(circ);
tor_assert(line);
tor_assert(file);
@@ -685,7 +854,7 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
}
if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
- onion_pending_remove(circ);
+ onion_pending_remove(TO_OR_CIRCUIT(circ));
}
/* If the circuit ever became OPEN, we sent it to the reputation history
* module then. If it isn't OPEN, we send it there now to remember which
@@ -693,60 +862,74 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
*/
if (circ->state != CIRCUIT_STATE_OPEN) {
if (CIRCUIT_IS_ORIGIN(circ)) {
- circuit_build_failed(circ); /* take actions if necessary */
+ origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
+ circuit_build_failed(ocirc); /* take actions if necessary */
+ circuit_rep_hist_note_result(ocirc);
}
- circuit_rep_hist_note_result(circ);
}
if (circ->state == CIRCUIT_STATE_OR_WAIT) {
if (circuits_pending_or_conns)
smartlist_remove(circuits_pending_or_conns, circ);
}
if (CIRCUIT_IS_ORIGIN(circ)) {
- control_event_circuit_status(circ,
+ control_event_circuit_status(TO_ORIGIN_CIRCUIT(circ),
(circ->state == CIRCUIT_STATE_OPEN)?CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED);
}
if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
+ origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
tor_assert(circ->state == CIRCUIT_STATE_OPEN);
- tor_assert(circ->build_state->chosen_exit);
+ tor_assert(ocirc->build_state->chosen_exit);
/* treat this like getting a nack from it */
log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). "
"Removing from descriptor.",
- safe_str(circ->rend_query),
- safe_str(build_state_get_exit_nickname(circ->build_state)));
- rend_client_remove_intro_point(circ->build_state->chosen_exit,
- circ->rend_query);
+ safe_str(ocirc->rend_query),
+ safe_str(build_state_get_exit_nickname(ocirc->build_state)));
+ rend_client_remove_intro_point(ocirc->build_state->chosen_exit,
+ ocirc->rend_query);
}
-
if (circ->n_conn)
connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason);
- for (conn=circ->n_streams; conn; conn=conn->next_stream)
- connection_edge_destroy(circ->n_circ_id, conn);
- while (circ->resolving_streams) {
- conn = circ->resolving_streams;
- circ->resolving_streams = conn->next_stream;
- if (!conn->marked_for_close) {
- /* The other side will see a DESTROY, and infer that the connections
- * are closing because the circuit is getting torn down. No need
- * to send an end cell. */
- conn->has_sent_end = 1;
- connection_mark_for_close(conn);
+
+ if (! CIRCUIT_IS_ORIGIN(circ)) {
+ or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+ edge_connection_t *conn;
+ for (conn=or_circ->n_streams; conn; conn=conn->next_stream)
+ connection_edge_destroy(or_circ->p_circ_id, conn);
+
+ while (or_circ->resolving_streams) {
+ conn = or_circ->resolving_streams;
+ or_circ->resolving_streams = conn->next_stream;
+ if (!conn->_base.marked_for_close) {
+ /* The other side will see a DESTROY, and infer that the connections
+ * are closing because the circuit is getting torn down. No need
+ * to send an end cell. */
+ conn->_base.edge_has_sent_end = 1;
+ connection_mark_for_close(TO_CONN(conn));
+ }
+ conn->on_circuit = NULL;
}
- conn->on_circuit = NULL;
+
+ if (or_circ->p_conn)
+ connection_or_send_destroy(or_circ->p_circ_id, or_circ->p_conn, reason);
+ } else {
+ origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
+ edge_connection_t *conn;
+ for (conn=ocirc->p_streams; conn; conn=conn->next_stream)
+ connection_edge_destroy(circ->n_circ_id, conn);
}
- if (circ->p_conn)
- connection_or_send_destroy(circ->p_circ_id, circ->p_conn, reason);
- for (conn=circ->p_streams; conn; conn=conn->next_stream)
- connection_edge_destroy(circ->p_circ_id, conn);
circ->marked_for_close = line;
circ->marked_for_close_file = file;
- if (circ->rend_splice) {
- if (!circ->rend_splice->marked_for_close) {
- /* do this after marking this circuit, to avoid infinite recursion. */
- circuit_mark_for_close(circ->rend_splice, reason);
+ if (! CIRCUIT_IS_ORIGIN(circ)) {
+ or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+ if (or_circ->rend_splice) {
+ if (!or_circ->rend_splice->_base.marked_for_close) {
+ /* do this after marking this circuit, to avoid infinite recursion. */
+ circuit_mark_for_close(TO_CIRCUIT(or_circ->rend_splice), reason);
+ }
+ or_circ->rend_splice = NULL;
}
- circ->rend_splice = NULL;
}
}
@@ -809,46 +992,49 @@ assert_cpath_ok(const crypt_path_t *cp)
void
assert_circuit_ok(const circuit_t *c)
{
- connection_t *conn;
+ edge_connection_t *conn;
+ const or_circuit_t *or_circ = NULL;
+ const origin_circuit_t *origin_circ = NULL;
tor_assert(c);
- tor_assert(c->magic == CIRCUIT_MAGIC);
+ tor_assert(c->magic == ORIGIN_CIRCUIT_MAGIC || c->magic == OR_CIRCUIT_MAGIC);
tor_assert(c->purpose >= _CIRCUIT_PURPOSE_MIN &&
c->purpose <= _CIRCUIT_PURPOSE_MAX);
+ if (CIRCUIT_IS_ORIGIN(c))
+ origin_circ = TO_ORIGIN_CIRCUIT((circuit_t*)c);
+ else
+ or_circ = TO_OR_CIRCUIT((circuit_t*)c);
+
if (c->n_conn) {
- tor_assert(c->n_conn->type == CONN_TYPE_OR);
tor_assert(!memcmp(c->n_conn->identity_digest, c->n_conn_id_digest,
DIGEST_LEN));
if (c->n_circ_id)
tor_assert(c == circuit_get_by_circid_orconn(c->n_circ_id, c->n_conn));
}
- if (c->p_conn) {
- tor_assert(c->p_conn->type == CONN_TYPE_OR);
- if (c->p_circ_id)
- tor_assert(c == circuit_get_by_circid_orconn(c->p_circ_id, c->p_conn));
+ if (or_circ && or_circ->p_conn) {
+ if (or_circ->p_circ_id)
+ tor_assert(c == circuit_get_by_circid_orconn(or_circ->p_circ_id,
+ or_circ->p_conn));
}
- for (conn = c->p_streams; conn; conn = conn->next_stream)
- tor_assert(conn->type == CONN_TYPE_AP);
- for (conn = c->n_streams; conn; conn = conn->next_stream)
- tor_assert(conn->type == CONN_TYPE_EXIT);
+#if 0 /* false now that rendezvous exits are attached to p_streams */
+ if (origin_circ)
+ for (conn = origin_circ->p_streams; conn; conn = conn->next_stream)
+ tor_assert(conn->_base.type == CONN_TYPE_AP);
+#endif
+ if (or_circ)
+ for (conn = or_circ->n_streams; conn; conn = conn->next_stream)
+ tor_assert(conn->_base.type == CONN_TYPE_EXIT);
tor_assert(c->deliver_window >= 0);
tor_assert(c->package_window >= 0);
if (c->state == CIRCUIT_STATE_OPEN) {
tor_assert(!c->onionskin);
- if (c->cpath) {
- tor_assert(CIRCUIT_IS_ORIGIN(c));
- tor_assert(!c->n_crypto);
- tor_assert(!c->p_crypto);
- tor_assert(!c->n_digest);
- tor_assert(!c->p_digest);
- } else {
- tor_assert(!CIRCUIT_IS_ORIGIN(c));
- tor_assert(c->n_crypto);
- tor_assert(c->p_crypto);
- tor_assert(c->n_digest);
- tor_assert(c->p_digest);
+ if (or_circ) {
+ tor_assert(or_circ->n_crypto);
+ tor_assert(or_circ->p_crypto);
+ tor_assert(or_circ->n_digest);
+ tor_assert(or_circ->p_digest);
}
}
if (c->state == CIRCUIT_STATE_OR_WAIT && !c->marked_for_close) {
@@ -858,17 +1044,18 @@ assert_circuit_ok(const circuit_t *c)
tor_assert(!circuits_pending_or_conns ||
!smartlist_isin(circuits_pending_or_conns, c));
}
- if (c->cpath) {
- assert_cpath_ok(c->cpath);
+ if (origin_circ && origin_circ->cpath) {
+ assert_cpath_ok(origin_circ->cpath);
}
if (c->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED) {
+ tor_assert(or_circ);
if (!c->marked_for_close) {
- tor_assert(c->rend_splice);
- tor_assert(c->rend_splice->rend_splice == c);
+ tor_assert(or_circ->rend_splice);
+ tor_assert(or_circ->rend_splice->rend_splice == or_circ);
}
- tor_assert(c->rend_splice != c);
+ tor_assert(or_circ->rend_splice != or_circ);
} else {
- tor_assert(!c->rend_splice);
+ tor_assert(!or_circ || !or_circ->rend_splice);
}
}
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 2aec912c17..310e8278fb 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -26,12 +26,13 @@ static void circuit_increment_failure_count(void);
* Else return 0.
*/
static int
-circuit_is_acceptable(circuit_t *circ, connection_t *conn,
+circuit_is_acceptable(circuit_t *circ, edge_connection_t *conn,
int must_be_open, uint8_t purpose,
int need_uptime, int need_internal,
time_t now)
{
routerinfo_t *exitrouter;
+ cpath_build_state_t *build_state;
tor_assert(circ);
tor_assert(conn);
tor_assert(conn->socks_request);
@@ -71,11 +72,12 @@ circuit_is_acceptable(circuit_t *circ, connection_t *conn,
* circuit, it's the magical extra bob hop. so just check the nickname
* of the one we meant to finish at.
*/
- exitrouter = build_state_get_exit_router(circ->build_state);
+ build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
+ exitrouter = build_state_get_exit_router(build_state);
- if (need_uptime && !circ->build_state->need_uptime)
+ if (need_uptime && !build_state->need_uptime)
return 0;
- if (need_internal != circ->build_state->is_internal)
+ if (need_internal != build_state->is_internal)
return 0;
if (purpose == CIRCUIT_PURPOSE_C_GENERAL) {
@@ -89,7 +91,8 @@ circuit_is_acceptable(circuit_t *circ, connection_t *conn,
return 0;
}
} else { /* not general */
- if (rend_cmp_service_ids(conn->rend_query, circ->rend_query)) {
+ if (rend_cmp_service_ids(conn->rend_query,
+ TO_ORIGIN_CIRCUIT(circ)->rend_query)) {
/* this circ is not for this conn */
return 0;
}
@@ -114,9 +117,11 @@ circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose)
return 1;
} else {
if (a->timestamp_dirty ||
- b->build_state->is_internal ||
a->timestamp_created > b->timestamp_created)
return 1;
+ if (CIRCUIT_IS_ORIGIN(b) &&
+ TO_ORIGIN_CIRCUIT(b)->build_state->is_internal)
+ return 1;
}
break;
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
@@ -149,8 +154,8 @@ circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose)
* If it's INTRODUCE_ACK_WAIT and must_be_open==0, then return the
* closest introduce-purposed circuit that you can find.
*/
-static circuit_t *
-circuit_get_best(connection_t *conn, int must_be_open, uint8_t purpose,
+static origin_circuit_t *
+circuit_get_best(edge_connection_t *conn, int must_be_open, uint8_t purpose,
int need_uptime, int need_internal)
{
circuit_t *circ, *best=NULL;
@@ -163,6 +168,8 @@ circuit_get_best(connection_t *conn, int must_be_open, uint8_t purpose,
purpose == CIRCUIT_PURPOSE_C_REND_JOINED);
for (circ=global_circuitlist;circ;circ = circ->next) {
+ if (!CIRCUIT_IS_ORIGIN(circ))
+ continue;
if (!circuit_is_acceptable(circ,conn,must_be_open,purpose,
need_uptime,need_internal,now))
continue;
@@ -174,7 +181,7 @@ circuit_get_best(connection_t *conn, int must_be_open, uint8_t purpose,
best = circ;
}
- return best;
+ return best ? TO_ORIGIN_CIRCUIT(best) : NULL;
}
/** Close all circuits that start at us, aren't open, and were born
@@ -230,7 +237,8 @@ circuit_expire_building(time_t now)
/* c_rend_ready circs measure age since timestamp_dirty,
* because that's set when they switch purposes
*/
- if (!victim->rend_query[0] || victim->timestamp_dirty > cutoff)
+ if (TO_ORIGIN_CIRCUIT(victim)->rend_query[0] ||
+ victim->timestamp_dirty > cutoff)
continue;
break;
case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
@@ -247,7 +255,8 @@ circuit_expire_building(time_t now)
if (victim->n_conn)
log_info(LD_CIRC,"Abandoning circ %s:%d:%d (state %d:%s, purpose %d)",
- victim->n_conn->address, victim->n_port, victim->n_circ_id,
+ victim->n_conn->_base.address, victim->n_port,
+ victim->n_circ_id,
victim->state, circuit_state_to_string(victim->state),
victim->purpose);
else
@@ -255,7 +264,7 @@ circuit_expire_building(time_t now)
victim->n_circ_id, victim->state,
circuit_state_to_string(victim->state), victim->purpose);
- circuit_log_path(LOG_INFO,LD_CIRC,victim);
+ circuit_log_path(LOG_INFO,LD_CIRC,TO_ORIGIN_CIRCUIT(victim));
circuit_mark_for_close(victim, END_CIRC_AT_ORIGIN);
}
}
@@ -288,7 +297,8 @@ circuit_remove_handled_ports(smartlist_t *needed_ports)
* Else return 0.
*/
int
-circuit_stream_is_being_handled(connection_t *conn, uint16_t port, int min)
+circuit_stream_is_being_handled(edge_connection_t *conn,
+ uint16_t port, int min)
{
circuit_t *circ;
routerinfo_t *exitrouter;
@@ -301,12 +311,14 @@ circuit_stream_is_being_handled(connection_t *conn, uint16_t port, int min)
if (CIRCUIT_IS_ORIGIN(circ) &&
!circ->marked_for_close &&
circ->purpose == CIRCUIT_PURPOSE_C_GENERAL &&
- !circ->build_state->is_internal &&
(!circ->timestamp_dirty ||
circ->timestamp_dirty + get_options()->MaxCircuitDirtiness > now)) {
- exitrouter = build_state_get_exit_router(circ->build_state);
- if (exitrouter &&
- (!need_uptime || circ->build_state->need_uptime)) {
+ cpath_build_state_t *build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
+ if (build_state->is_internal)
+ continue;
+
+ exitrouter = build_state_get_exit_router(build_state);
+ if (exitrouter && (!need_uptime || build_state->need_uptime)) {
int ok;
if (conn) {
ok = connection_ap_can_use_exit(conn, exitrouter);
@@ -343,6 +355,7 @@ circuit_predict_and_launch_new(void)
/* First, count how many of each type of circuit we have already. */
for (circ=global_circuitlist;circ;circ = circ->next) {
+ cpath_build_state_t *build_state;
if (!CIRCUIT_IS_ORIGIN(circ))
continue;
if (circ->marked_for_close)
@@ -352,9 +365,10 @@ circuit_predict_and_launch_new(void)
if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL)
continue; /* only pay attention to general-purpose circs */
num++;
- if (circ->build_state->is_internal)
+ build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
+ if (build_state->is_internal)
num_internal++;
- if (circ->build_state->need_uptime && circ->build_state->is_internal)
+ if (build_state->need_uptime && build_state->is_internal)
num_uptime_internal++;
}
@@ -445,9 +459,9 @@ circuit_build_needed_circs(time_t now)
* lists of <b>circ</b>, then remove it from the list.
*/
void
-circuit_detach_stream(circuit_t *circ, connection_t *conn)
+circuit_detach_stream(circuit_t *circ, edge_connection_t *conn)
{
- connection_t *prevconn;
+ edge_connection_t *prevconn;
tor_assert(circ);
tor_assert(conn);
@@ -455,44 +469,49 @@ circuit_detach_stream(circuit_t *circ, connection_t *conn)
conn->cpath_layer = NULL; /* make sure we don't keep a stale pointer */
conn->on_circuit = NULL;
- if (conn == circ->p_streams) {
- circ->p_streams = conn->next_stream;
- return;
- }
- if (conn == circ->n_streams) {
- circ->n_streams = conn->next_stream;
- return;
- }
- if (conn == circ->resolving_streams) {
- circ->resolving_streams = conn->next_stream;
- return;
- }
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
+ if (conn == origin_circ->p_streams) {
+ origin_circ->p_streams = conn->next_stream;
+ return;
+ }
- for (prevconn = circ->p_streams;
- prevconn && prevconn->next_stream && prevconn->next_stream != conn;
- prevconn = prevconn->next_stream)
- ;
- if (prevconn && prevconn->next_stream) {
- prevconn->next_stream = conn->next_stream;
- return;
- }
+ for (prevconn = origin_circ->p_streams;
+ prevconn && prevconn->next_stream && prevconn->next_stream != conn;
+ prevconn = prevconn->next_stream)
+ ;
+ if (prevconn && prevconn->next_stream) {
+ prevconn->next_stream = conn->next_stream;
+ return;
+ }
+ } else {
+ or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+ if (conn == or_circ->n_streams) {
+ or_circ->n_streams = conn->next_stream;
+ return;
+ }
+ if (conn == or_circ->resolving_streams) {
+ or_circ->resolving_streams = conn->next_stream;
+ return;
+ }
- for (prevconn = circ->n_streams;
- prevconn && prevconn->next_stream && prevconn->next_stream != conn;
- prevconn = prevconn->next_stream)
- ;
- if (prevconn && prevconn->next_stream) {
- prevconn->next_stream = conn->next_stream;
- return;
- }
+ for (prevconn = or_circ->n_streams;
+ prevconn && prevconn->next_stream && prevconn->next_stream != conn;
+ prevconn = prevconn->next_stream)
+ ;
+ if (prevconn && prevconn->next_stream) {
+ prevconn->next_stream = conn->next_stream;
+ return;
+ }
- for (prevconn = circ->resolving_streams;
- prevconn && prevconn->next_stream && prevconn->next_stream != conn;
- prevconn = prevconn->next_stream)
- ;
- if (prevconn && prevconn->next_stream) {
- prevconn->next_stream = conn->next_stream;
- return;
+ for (prevconn = or_circ->resolving_streams;
+ prevconn && prevconn->next_stream && prevconn->next_stream != conn;
+ prevconn = prevconn->next_stream)
+ ;
+ if (prevconn && prevconn->next_stream) {
+ prevconn->next_stream = conn->next_stream;
+ return;
+ }
}
log_err(LD_BUG,"edge conn not in circuit's list?");
@@ -519,10 +538,11 @@ circuit_about_to_close_connection(connection_t *conn)
if (!connection_state_is_open(conn)) {
/* Inform any pending (not attached) circs that they should
* give up. */
- circuit_n_conn_done(conn, 0);
+ circuit_n_conn_done(TO_OR_CONN(conn), 0);
}
/* Now close all the attached circuits on it. */
- circuit_unlink_all_from_or_conn(conn, END_CIRC_REASON_OR_CONN_CLOSED);
+ circuit_unlink_all_from_or_conn(TO_OR_CONN(conn),
+ END_CIRC_REASON_OR_CONN_CLOSED);
return;
}
case CONN_TYPE_AP:
@@ -533,17 +553,17 @@ circuit_about_to_close_connection(connection_t *conn)
* been sent. But don't kill the circuit.
*/
- circ = circuit_get_by_edge_conn(conn);
+ circ = circuit_get_by_edge_conn(TO_EDGE_CONN(conn));
if (!circ)
return;
- circuit_detach_stream(circ, conn);
+ circuit_detach_stream(circ, TO_EDGE_CONN(conn));
}
} /* end switch */
}
-/** Find each circuit that has been dirty for too long, and has
- * no streams on it: mark it for close.
+/** Find each circuit that has been unused for too long, or dirty
+ * for too long and has no streax=ms on it: mark it for close.
*/
static void
circuit_expire_old_circuits(time_t now)
@@ -552,23 +572,19 @@ circuit_expire_old_circuits(time_t now)
time_t cutoff = now - get_options()->CircuitIdleTimeout;
for (circ = global_circuitlist; circ; circ = circ->next) {
- if (circ->marked_for_close)
+ if (circ->marked_for_close || ! CIRCUIT_IS_ORIGIN(circ))
continue;
/* If the circuit has been dirty for too long, and there are no streams
* on it, mark it for close.
*/
if (circ->timestamp_dirty &&
circ->timestamp_dirty + get_options()->MaxCircuitDirtiness < now &&
- CIRCUIT_IS_ORIGIN(circ) &&
- !circ->p_streams /* nothing attached */ ) {
+ !TO_ORIGIN_CIRCUIT(circ)->p_streams /* nothing attached */ ) {
log_debug(LD_CIRC, "Closing n_circ_id %d (dirty %d secs ago, purp %d)",
circ->n_circ_id, (int)(now - circ->timestamp_dirty),
circ->purpose);
- /* (only general and purpose_c circs can get dirty) */
- tor_assert(!circ->n_streams);
- tor_assert(circ->purpose <= CIRCUIT_PURPOSE_C_REND_JOINED);
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
- } else if (!circ->timestamp_dirty && CIRCUIT_IS_ORIGIN(circ) &&
+ } else if (!circ->timestamp_dirty &&
circ->state == CIRCUIT_STATE_OPEN &&
circ->purpose == CIRCUIT_PURPOSE_C_GENERAL) {
if (circ->timestamp_created < cutoff) {
@@ -581,30 +597,72 @@ circuit_expire_old_circuits(time_t now)
}
}
-/** A testing circuit has completed. Take whatever stats we want. */
+#define NUM_PARALLEL_TESTING_CIRCS 4
+
+static int have_performed_bandwidth_test = 0;
+
+/** Reset have_performed_bandwidth_test, so we'll start building
+ * testing circuits again so we can exercise our bandwidth. */
+void
+reset_bandwidth_test(void)
+{
+ have_performed_bandwidth_test = 0;
+}
+
+/** Return 1 if we've already exercised our bandwidth, or if we
+ * have fewer than NUM_PARALLEL_TESTING_CIRCS testing circuits
+ * established or on the way. Else return 0.
+ */
+int
+circuit_enough_testing_circs(void)
+{
+ circuit_t *circ;
+ int num = 0;
+
+ if (have_performed_bandwidth_test)
+ return 1;
+
+ for (circ = global_circuitlist; circ; circ = circ->next) {
+ if (!circ->marked_for_close && CIRCUIT_IS_ORIGIN(circ) &&
+ circ->purpose == CIRCUIT_PURPOSE_TESTING &&
+ circ->state == CIRCUIT_STATE_OPEN)
+ num++;
+ }
+ return num >= NUM_PARALLEL_TESTING_CIRCS;
+}
+
+/** A testing circuit has completed. Take whatever stats we want.
+ * Noticing reachability is taken care of in onionskin_answer(),
+ * so there's no need to record anything here. But if we still want
+ * to do the bandwidth test, and we now have enough testing circuits
+ * open, do it.
+ */
static void
-circuit_testing_opened(circuit_t *circ)
+circuit_testing_opened(origin_circuit_t *circ)
{
- /* For now, we only use testing circuits to see if our ORPort is
- reachable. But we remember reachability in onionskin_answer(),
- so there's no need to record anything here. Just close the circ. */
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ if (have_performed_bandwidth_test) {
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
+ } else if (circuit_enough_testing_circs()) {
+ router_perform_bandwidth_test(NUM_PARALLEL_TESTING_CIRCS, time(NULL));
+ have_performed_bandwidth_test = 1;
+ } else
+ consider_testing_reachability(1, 0);
}
/** A testing circuit has failed to build. Take whatever stats we want. */
static void
-circuit_testing_failed(circuit_t *circ, int at_last_hop)
+circuit_testing_failed(origin_circuit_t *circ, int at_last_hop)
{
-#if 0
- routerinfo_t *me = router_get_my_routerinfo();
+ if (server_mode(get_options()) && check_whether_orport_reachable())
+ return;
- if (!at_last_hop)
- circuit_launch_by_router(CIRCUIT_PURPOSE_TESTING, me, 0, 1, 1);
- else
-#endif
log_info(LD_GENERAL,
"Our testing circuit (to see if your ORPort is reachable) "
"has failed. I'll try again later.");
+
+ /* These aren't used yet. */
+ (void)circ;
+ (void)at_last_hop;
}
/** The circuit <b>circ</b> has just become open. Take the next
@@ -614,11 +672,11 @@ circuit_testing_failed(circuit_t *circ, int at_last_hop)
* that could use circ.
*/
void
-circuit_has_opened(circuit_t *circ)
+circuit_has_opened(origin_circuit_t *circ)
{
control_event_circuit_status(circ, CIRC_EVENT_BUILT);
- switch (circ->purpose) {
+ switch (TO_CIRCUIT(circ)->purpose) {
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
rend_client_rendcirc_has_opened(circ);
connection_ap_attach_pending();
@@ -643,7 +701,7 @@ circuit_has_opened(circuit_t *circ)
circuit_testing_opened(circ);
break;
default:
- log_err(LD_BUG,"unhandled purpose %d",circ->purpose);
+ log_err(LD_BUG,"unhandled purpose %d",circ->_base.purpose);
tor_assert(0);
}
}
@@ -651,7 +709,7 @@ circuit_has_opened(circuit_t *circ)
/** Called whenever a circuit could not be successfully built.
*/
void
-circuit_build_failed(circuit_t *circ)
+circuit_build_failed(origin_circuit_t *circ)
{
/* we should examine circ and see if it failed because of
* the last hop or an earlier hop. then use this info below.
@@ -668,38 +726,35 @@ circuit_build_failed(circuit_t *circ)
circ->cpath->state != CPATH_STATE_OPEN) {
/* We failed at the first hop. If there's an OR connection
to blame, blame it. */
- connection_t *n_conn = NULL;
- if (circ->n_conn) {
- n_conn = circ->n_conn;
- } else if (circ->state == CIRCUIT_STATE_OR_WAIT) {
+ or_connection_t *n_conn = NULL;
+ if (circ->_base.n_conn) {
+ n_conn = circ->_base.n_conn;
+ } else if (circ->_base.state == CIRCUIT_STATE_OR_WAIT) {
/* we have to hunt for it */
- n_conn = connection_or_get_by_identity_digest(circ->n_conn_id_digest);
+ n_conn = connection_or_get_by_identity_digest(
+ circ->_base.n_conn_id_digest);
}
if (n_conn) {
log_info(LD_OR,
"Our circuit failed to get a response from the first hop "
"(%s:%d). I'm going to try to rotate to a better connection.",
- n_conn->address, n_conn->port);
- n_conn->is_obsolete = 1;
+ n_conn->_base.address, n_conn->_base.port);
+ n_conn->_base.or_is_obsolete = 1;
entry_guard_set_status(n_conn->identity_digest, 0);
}
}
- switch (circ->purpose) {
+ switch (circ->_base.purpose) {
case CIRCUIT_PURPOSE_C_GENERAL:
- if (circ->state != CIRCUIT_STATE_OPEN) {
- /* If we never built the circuit, note it as a failure. */
- /* Note that we can't just check circ->cpath here, because if
- * circuit-building failed immediately, it won't be set yet. */
- circuit_increment_failure_count();
- }
+ /* If we never built the circuit, note it as a failure. */
+ circuit_increment_failure_count();
break;
case CIRCUIT_PURPOSE_TESTING:
circuit_testing_failed(circ, failed_at_last_hop);
break;
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
/* at Bob, waiting for introductions */
- if (circ->state != CIRCUIT_STATE_OPEN) {
+ if (circ->_base.state != CIRCUIT_STATE_OPEN) {
circuit_increment_failure_count();
}
/* no need to care here, because bob will rebuild intro
@@ -714,9 +769,7 @@ circuit_build_failed(circuit_t *circ)
break;
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
/* at Alice, waiting for Bob */
- if (circ->state != CIRCUIT_STATE_OPEN) {
- circuit_increment_failure_count();
- }
+ circuit_increment_failure_count();
/* Alice will pick a new rend point when this one dies, if
* the stream in question still cares. No need to act here. */
break;
@@ -750,11 +803,11 @@ static int did_circs_fail_last_period = 0;
/** Launch a new circuit; see circuit_launch_by_extend_info() for
* details on arguments. */
-circuit_t *
+origin_circuit_t *
circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit,
int need_uptime, int need_capacity, int internal)
{
- circuit_t *circ;
+ origin_circuit_t *circ;
extend_info_t *info = NULL;
if (exit)
info = extend_info_from_router(exit);
@@ -771,11 +824,11 @@ circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit,
* choose among routers with high bandwidth. If <b>internal</b> is true, the
* last hop need not be an exit node. Return the newly allocated circuit on
* success, or NULL on failure. */
-circuit_t *
+origin_circuit_t *
circuit_launch_by_extend_info(uint8_t purpose, extend_info_t *extend_info,
int need_uptime, int need_capacity, int internal)
{
- circuit_t *circ;
+ origin_circuit_t *circ;
if (!router_have_minimum_dir_info()) {
log_debug(LD_CIRC,"Haven't fetched enough directory info yet; canceling "
@@ -791,11 +844,11 @@ circuit_launch_by_extend_info(uint8_t purpose, extend_info_t *extend_info,
if (circ) {
log_info(LD_CIRC,"Cannibalizing circ '%s' for purpose %d",
build_state_get_exit_nickname(circ->build_state), purpose);
- circ->purpose = purpose;
+ circ->_base.purpose = purpose;
/* reset the birth date of this circ, else expire_building
* will see it and think it's been trying to build since it
* began. */
- circ->timestamp_created = time(NULL);
+ circ->_base.timestamp_created = time(NULL);
switch (purpose) {
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
@@ -835,7 +888,7 @@ circuit_launch_by_extend_info(uint8_t purpose, extend_info_t *extend_info,
/** Launch a new circuit; see circuit_launch_by_extend_info() for
* details on arguments. */
-circuit_t *
+origin_circuit_t *
circuit_launch_by_nickname(uint8_t purpose, const char *exit_nickname,
int need_uptime, int need_capacity, int internal)
{
@@ -876,25 +929,26 @@ circuit_reset_failure_count(int timeout)
n_circuit_failures = 0;
}
-/** Find an open circ that we're happy with: return 1. If there isn't
- * one, and there isn't one on the way, launch one and return 0. If it
- * will never work, return -1.
+/** Find an open circ that we're happy to use for <b>conn</b> and return 1. If
+ * there isn't one, and there isn't one on the way, launch one and return
+ * 0. If it will never work, return -1.
*
* Write the found or in-progress or launched circ into *circp.
*/
static int
-circuit_get_open_circ_or_launch(connection_t *conn,
+circuit_get_open_circ_or_launch(edge_connection_t *conn,
uint8_t desired_circuit_purpose,
- circuit_t **circp)
+ origin_circuit_t **circp)
{
- circuit_t *circ;
+ origin_circuit_t *circ;
int is_resolve;
int need_uptime, need_internal;
tor_assert(conn);
tor_assert(circp);
- tor_assert(conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
- is_resolve = conn->socks_request->command == SOCKS_COMMAND_RESOLVE;
+ tor_assert(conn->_base.state == AP_CONN_STATE_CIRCUIT_WAIT);
+ is_resolve = (conn->socks_request->command == SOCKS_COMMAND_RESOLVE ||
+ conn->socks_request->command == SOCKS_COMMAND_RESOLVE_PTR);
need_uptime = smartlist_string_num_isin(get_options()->LongLivedPorts,
conn->socks_request->port);
@@ -956,7 +1010,7 @@ circuit_get_open_circ_or_launch(connection_t *conn,
"No intro points for '%s': refetching service descriptor.",
safe_str(conn->rend_query));
rend_client_refetch_renddesc(conn->rend_query);
- conn->state = AP_CONN_STATE_RENDDESC_WAIT;
+ conn->_base.state = AP_CONN_STATE_RENDDESC_WAIT;
return 0;
}
log_info(LD_REND,"Chose '%s' as intro point for '%s'.",
@@ -969,11 +1023,16 @@ circuit_get_open_circ_or_launch(connection_t *conn,
if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_GENERAL) {
if (conn->chosen_exit_name) {
routerinfo_t *r;
+ int opt = conn->_base.chosen_exit_optional;
if (!(r = router_get_by_nickname(conn->chosen_exit_name, 1))) {
- /*XXXX NM domain? */
- log_notice(LD_CIRC,
- "Requested exit point '%s' is not known. Closing.",
- conn->chosen_exit_name);
+ log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP,
+ "Requested exit point '%s' is not known. %s.",
+ conn->chosen_exit_name, opt ? "Trying others" : "Closing");
+ if (opt) {
+ conn->_base.chosen_exit_optional = 0;
+ tor_free(conn->chosen_exit_name);
+ return 0;
+ }
return -1;
}
extend_info = extend_info_from_router(r);
@@ -998,8 +1057,8 @@ circuit_get_open_circ_or_launch(connection_t *conn,
if (circ) {
/* write the service_id into circ */
strlcpy(circ->rend_query, conn->rend_query, sizeof(circ->rend_query));
- if (circ->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND &&
- circ->state == CIRCUIT_STATE_OPEN)
+ if (circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND &&
+ circ->_base.state == CIRCUIT_STATE_OPEN)
rend_client_rendcirc_has_opened(circ);
}
}
@@ -1018,19 +1077,18 @@ circuit_get_open_circ_or_launch(connection_t *conn,
* circ's cpath.
*/
static void
-link_apconn_to_circ(connection_t *apconn, circuit_t *circ)
+link_apconn_to_circ(edge_connection_t *apconn, origin_circuit_t *circ)
{
/* add it into the linked list of streams on this circuit */
log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %d.",
- circ->n_circ_id);
+ circ->_base.n_circ_id);
/* reset it, so we can measure circ timeouts */
- apconn->timestamp_lastread = time(NULL);
+ apconn->_base.timestamp_lastread = time(NULL);
apconn->next_stream = circ->p_streams;
- apconn->on_circuit = circ;
+ apconn->on_circuit = TO_CIRCUIT(circ);
/* assert_connection_ok(conn, time(NULL)); */
circ->p_streams = apconn;
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
tor_assert(circ->cpath);
tor_assert(circ->cpath->prev);
tor_assert(circ->cpath->prev->state == CPATH_STATE_OPEN);
@@ -1040,7 +1098,7 @@ link_apconn_to_circ(connection_t *apconn, circuit_t *circ)
/** If an exit wasn't specifically chosen, save the history for future
* use. */
static void
-consider_recording_trackhost(connection_t *conn, circuit_t *circ)
+consider_recording_trackhost(edge_connection_t *conn, origin_circuit_t *circ)
{
int found_needle = 0;
char *str;
@@ -1052,7 +1110,7 @@ consider_recording_trackhost(connection_t *conn, circuit_t *circ)
/* Search the addressmap for this conn's destination. */
/* If he's not in the address map.. */
if (!options->TrackHostExits ||
- addressmap_already_mapped(conn->socks_request->address))
+ addressmap_have_mapping(conn->socks_request->address))
return; /* nothing to track, or already mapped */
SMARTLIST_FOREACH(options->TrackHostExits, const char *, cp, {
@@ -1094,21 +1152,20 @@ consider_recording_trackhost(connection_t *conn, circuit_t *circ)
* send a begin or resolve cell as appropriate. Return values are as
* for connection_ap_handshake_attach_circuit. */
int
-connection_ap_handshake_attach_chosen_circuit(connection_t *conn,
- circuit_t *circ)
+connection_ap_handshake_attach_chosen_circuit(edge_connection_t *conn,
+ origin_circuit_t *circ)
{
tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_AP);
- tor_assert(conn->state == AP_CONN_STATE_CIRCUIT_WAIT ||
- conn->state == AP_CONN_STATE_CONTROLLER_WAIT);
+ tor_assert(conn->_base.state == AP_CONN_STATE_CIRCUIT_WAIT ||
+ conn->_base.state == AP_CONN_STATE_CONTROLLER_WAIT);
tor_assert(conn->socks_request);
tor_assert(circ);
- tor_assert(circ->state == CIRCUIT_STATE_OPEN);
+ tor_assert(circ->_base.state == CIRCUIT_STATE_OPEN);
- conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
+ conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
- if (!circ->timestamp_dirty)
- circ->timestamp_dirty = time(NULL);
+ if (!circ->_base.timestamp_dirty)
+ circ->_base.timestamp_dirty = time(NULL);
link_apconn_to_circ(conn, circ);
tor_assert(conn->socks_request);
@@ -1132,19 +1189,18 @@ connection_ap_handshake_attach_chosen_circuit(connection_t *conn,
* right next step, and return 1.
*/
int
-connection_ap_handshake_attach_circuit(connection_t *conn)
+connection_ap_handshake_attach_circuit(edge_connection_t *conn)
{
int retval;
int conn_age;
int severity;
tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_AP);
- tor_assert(conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
+ tor_assert(conn->_base.state == AP_CONN_STATE_CIRCUIT_WAIT);
tor_assert(conn->socks_request);
- conn_age = time(NULL) - conn->timestamp_created;
- severity = (!conn->addr && !conn->port) ? LOG_INFO : LOG_NOTICE;
+ conn_age = time(NULL) - conn->_base.timestamp_created;
+ severity = (!conn->_base.addr && !conn->_base.port) ? LOG_INFO : LOG_NOTICE;
if (conn_age > get_options()->SocksTimeout) {
log_fn(severity, LD_APP,
"Tried for %d seconds to get a connection to %s:%d. Giving up.",
@@ -1154,20 +1210,32 @@ connection_ap_handshake_attach_circuit(connection_t *conn)
}
if (!connection_edge_is_rendezvous_stream(conn)) { /* we're a general conn */
- circuit_t *circ=NULL;
+ origin_circuit_t *circ=NULL;
if (conn->chosen_exit_name) {
routerinfo_t *router = router_get_by_nickname(conn->chosen_exit_name, 1);
+ int opt = conn->_base.chosen_exit_optional;
if (!router) {
- log_warn(LD_APP,
- "Requested exit point '%s' is not known. Closing.",
- conn->chosen_exit_name);
+ log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP,
+ "Requested exit point '%s' is not known. %s.",
+ conn->chosen_exit_name, opt ? "Trying others" : "Closing");
+ if (opt) {
+ conn->_base.chosen_exit_optional = 0;
+ tor_free(conn->chosen_exit_name);
+ return 0;
+ }
return -1;
}
- if (!connection_ap_can_use_exit(conn, router)) {
- log_warn(LD_APP,
- "Requested exit point '%s' would refuse request. Closing.",
- conn->chosen_exit_name);
+ if (conn->_base.purpose != EXIT_PURPOSE_RESOLVE &&
+ !connection_ap_can_use_exit(conn, router)) {
+ log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP,
+ "Requested exit point '%s' would refuse request. %s.",
+ conn->chosen_exit_name, opt ? "Trying others" : "Closing");
+ if (opt) {
+ conn->_base.chosen_exit_optional = 0;
+ tor_free(conn->chosen_exit_name);
+ return 0;
+ }
return -1;
}
}
@@ -1180,7 +1248,7 @@ connection_ap_handshake_attach_circuit(connection_t *conn)
log_debug(LD_APP|LD_CIRC,
"Attaching apconn to circ %d (stream %d sec old).",
- circ->n_circ_id, conn_age);
+ circ->_base.n_circ_id, conn_age);
/* here, print the circ's path. so people can figure out which circs are
* sucking. */
circuit_log_path(LOG_INFO,LD_APP|LD_CIRC,circ);
@@ -1189,7 +1257,7 @@ connection_ap_handshake_attach_circuit(connection_t *conn)
return connection_ap_handshake_attach_chosen_circuit(conn, circ);
} else { /* we're a rendezvous conn */
- circuit_t *rendcirc=NULL, *introcirc=NULL;
+ origin_circuit_t *rendcirc=NULL, *introcirc=NULL;
tor_assert(!conn->cpath_layer);
@@ -1205,25 +1273,25 @@ connection_ap_handshake_attach_circuit(connection_t *conn)
log_info(LD_REND,
"rend joined circ %d already here. attaching. "
"(stream %d sec old)",
- rendcirc->n_circ_id, conn_age);
+ rendcirc->_base.n_circ_id, conn_age);
/* Mark rendezvous circuits as 'newly dirty' every time you use
* them, since the process of rebuilding a rendezvous circ is so
* expensive. There is a tradeoffs between linkability and
* feasibility, at this point.
*/
- rendcirc->timestamp_dirty = time(NULL);
+ rendcirc->_base.timestamp_dirty = time(NULL);
link_apconn_to_circ(conn, rendcirc);
if (connection_ap_handshake_send_begin(conn, rendcirc) < 0)
return 0; /* already marked, let them fade away */
return 1;
}
- if (rendcirc && (rendcirc->purpose ==
+ if (rendcirc && (rendcirc->_base.purpose ==
CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)) {
log_info(LD_REND,
"pending-join circ %d already here, with intro ack. "
"Stalling. (stream %d sec old)",
- rendcirc->n_circ_id, conn_age);
+ rendcirc->_base.n_circ_id, conn_age);
return 0;
}
@@ -1237,7 +1305,8 @@ connection_ap_handshake_attach_circuit(connection_t *conn)
tor_assert(introcirc);
log_info(LD_REND, "Intro circ %d present and awaiting ack (rend %d). "
"Stalling. (stream %d sec old)",
- introcirc->n_circ_id, rendcirc ? rendcirc->n_circ_id : 0,
+ introcirc->_base.n_circ_id,
+ rendcirc ? rendcirc->_base.n_circ_id : 0,
conn_age);
return 0;
}
@@ -1245,32 +1314,34 @@ connection_ap_handshake_attach_circuit(connection_t *conn)
/* now rendcirc and introcirc are each either undefined or not finished */
if (rendcirc && introcirc &&
- rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY) {
+ rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY) {
log_info(LD_REND,
"ready rend circ %d already here (no intro-ack yet on "
"intro %d). (stream %d sec old)",
- rendcirc->n_circ_id, introcirc->n_circ_id, conn_age);
+ rendcirc->_base.n_circ_id,
+ introcirc->_base.n_circ_id, conn_age);
- tor_assert(introcirc->purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
- if (introcirc->state == CIRCUIT_STATE_OPEN) {
+ tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
+ if (introcirc->_base.state == CIRCUIT_STATE_OPEN) {
log_info(LD_REND,"found open intro circ %d (rend %d); sending "
"introduction. (stream %d sec old)",
- introcirc->n_circ_id, rendcirc->n_circ_id, conn_age);
+ introcirc->_base.n_circ_id, rendcirc->_base.n_circ_id,
+ conn_age);
if (rend_client_send_introduction(introcirc, rendcirc) < 0) {
return -1;
}
- rendcirc->timestamp_dirty = time(NULL);
- introcirc->timestamp_dirty = time(NULL);
- assert_circuit_ok(rendcirc);
- assert_circuit_ok(introcirc);
+ rendcirc->_base.timestamp_dirty = time(NULL);
+ introcirc->_base.timestamp_dirty = time(NULL);
+ assert_circuit_ok(TO_CIRCUIT(rendcirc));
+ assert_circuit_ok(TO_CIRCUIT(introcirc));
return 0;
}
}
log_info(LD_REND, "Intro (%d) and rend (%d) circs are not both ready. "
"Stalling conn. (%d sec old)",
- introcirc ? introcirc->n_circ_id : 0,
- rendcirc ? rendcirc->n_circ_id : 0, conn_age);
+ introcirc ? introcirc->_base.n_circ_id : 0,
+ rendcirc ? rendcirc->_base.n_circ_id : 0, conn_age);
return 0;
}
}
diff --git a/src/or/command.c b/src/or/command.c
index 6c55174772..f87b2b0554 100644
--- a/src/or/command.c
+++ b/src/or/command.c
@@ -27,10 +27,10 @@ uint64_t stats_n_relay_cells_processed = 0;
uint64_t stats_n_destroy_cells_processed = 0;
/* These are the main four functions for processing cells */
-static void command_process_create_cell(cell_t *cell, connection_t *conn);
-static void command_process_created_cell(cell_t *cell, connection_t *conn);
-static void command_process_relay_cell(cell_t *cell, connection_t *conn);
-static void command_process_destroy_cell(cell_t *cell, connection_t *conn);
+static void command_process_create_cell(cell_t *cell, or_connection_t *conn);
+static void command_process_created_cell(cell_t *cell, or_connection_t *conn);
+static void command_process_relay_cell(cell_t *cell, or_connection_t *conn);
+static void command_process_destroy_cell(cell_t *cell, or_connection_t *conn);
#ifdef KEEP_TIMING_STATS
/** This is a wrapper function around the actual function that processes the
@@ -38,8 +38,8 @@ static void command_process_destroy_cell(cell_t *cell, connection_t *conn);
* by the number of microseconds used by the call to <b>*func(cell, conn)</b>.
*/
static void
-command_time_process_cell(cell_t *cell, connection_t *conn, int *time,
- void (*func)(cell_t *, connection_t *))
+command_time_process_cell(cell_t *cell, or_connection_t *conn, int *time,
+ void (*func)(cell_t *, or_connection_t *))
{
struct timeval start, end;
long time_passed;
@@ -68,7 +68,7 @@ command_time_process_cell(cell_t *cell, connection_t *conn, int *time,
* process each type of cell.
*/
void
-command_process_cell(cell_t *cell, connection_t *conn)
+command_process_cell(cell_t *cell, or_connection_t *conn)
{
#ifdef KEEP_TIMING_STATS
/* how many of each cell have we seen so far this second? needs better
@@ -159,9 +159,9 @@ command_process_cell(cell_t *cell, connection_t *conn)
* picked up again when the cpuworker finishes decrypting it.
*/
static void
-command_process_create_cell(cell_t *cell, connection_t *conn)
+command_process_create_cell(cell_t *cell, or_connection_t *conn)
{
- circuit_t *circ;
+ or_circuit_t *circ;
int id_is_high;
if (we_are_hibernating()) {
@@ -182,33 +182,35 @@ command_process_create_cell(cell_t *cell, connection_t *conn)
return;
}
- /* If the high bit of the circuit ID is not as expected, then switch
- * which half of the space we'll use for our own CREATE cells.
- *
- * This can happen because Tor 0.0.9pre5 and earlier decide which
- * half to use based on nickname, and we now use identity keys.
- */
- id_is_high = cell->circ_id & (1<<15);
- if (id_is_high && conn->circ_id_type == CIRC_ID_TYPE_HIGHER) {
- log_info(LD_OR, "Got a high circuit ID from %s (%d); switching to "
- "low circuit IDs.",
- conn->nickname ? conn->nickname : "client", conn->s);
- conn->circ_id_type = CIRC_ID_TYPE_LOWER;
- } else if (!id_is_high && conn->circ_id_type == CIRC_ID_TYPE_LOWER) {
- log_info(LD_OR, "Got a low circuit ID from %s (%d); switching to "
- "high circuit IDs.",
- conn->nickname ? conn->nickname : "client", conn->s);
- conn->circ_id_type = CIRC_ID_TYPE_HIGHER;
+ if (!server_mode(get_options())) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received create cell (type %d) from %s:%d, but we're a client. "
+ "Sending back a destroy.",
+ (int)cell->command, conn->_base.address, conn->_base.port);
+ connection_or_send_destroy(cell->circ_id, conn,
+ END_CIRC_REASON_TORPROTOCOL);
+ return;
}
- circ = circuit_get_by_circid_orconn(cell->circ_id, conn);
+ /* If the high bit of the circuit ID is not as expected, close the
+ * circ. */
+ id_is_high = cell->circ_id & (1<<15);
+ if ((id_is_high && conn->circ_id_type == CIRC_ID_TYPE_HIGHER) ||
+ (!id_is_high && conn->circ_id_type == CIRC_ID_TYPE_LOWER)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received create cell with unexpected circ_id %d. Closing.",
+ cell->circ_id);
+ connection_or_send_destroy(cell->circ_id, conn,
+ END_CIRC_REASON_TORPROTOCOL);
+ return;
+ }
- if (circ) {
+ if (circuit_get_by_circid_orconn(cell->circ_id, conn)) {
routerinfo_t *router = router_get_by_digest(conn->identity_digest);
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "received CREATE cell (circID %d) for known circ. "
+ "Received CREATE cell (circID %d) for known circ. "
"Dropping (age %d).",
- cell->circ_id, (int)(time(NULL) - conn->timestamp_created));
+ cell->circ_id, (int)(time(NULL) - conn->_base.timestamp_created));
if (router)
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Details: nickname \"%s\", platform %s.",
@@ -216,34 +218,34 @@ command_process_create_cell(cell_t *cell, connection_t *conn)
return;
}
- circ = circuit_new(cell->circ_id, conn);
- circ->purpose = CIRCUIT_PURPOSE_OR;
- circuit_set_state(circ, CIRCUIT_STATE_ONIONSKIN_PENDING);
+ circ = or_circuit_new(cell->circ_id, conn);
+ circ->_base.purpose = CIRCUIT_PURPOSE_OR;
+ circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING);
if (cell->command == CELL_CREATE) {
- circ->onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
- memcpy(circ->onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN);
+ circ->_base.onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
+ memcpy(circ->_base.onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN);
- /* hand it off to the cpuworkers, and then return */
+ /* hand it off to the cpuworkers, and then return. */
if (assign_to_cpuworker(NULL, CPUWORKER_TASK_ONION, circ) < 0) {
log_warn(LD_GENERAL,"Failed to hand off onionskin. Closing.");
- circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
return;
}
log_debug(LD_OR,"success: handed off onionskin.");
} else {
/* This is a CREATE_FAST cell; we can handle it immediately without using
- * a CPU worker.*/
+ * a CPU worker. */
char keys[CPATH_KEY_MATERIAL_LEN];
char reply[DIGEST_LEN*2];
tor_assert(cell->command == CELL_CREATE_FAST);
if (fast_server_handshake(cell->payload, reply, keys, sizeof(keys))<0) {
log_warn(LD_OR,"Failed to generate key material. Closing.");
- circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
return;
}
if (onionskin_answer(circ, CELL_CREATED_FAST, reply, keys)<0) {
log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing.");
- circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
return;
}
}
@@ -258,7 +260,7 @@ command_process_create_cell(cell_t *cell, connection_t *conn)
* extend to the next hop in the circuit if necessary.
*/
static void
-command_process_created_cell(cell_t *cell, connection_t *conn)
+command_process_created_cell(cell_t *cell, or_connection_t *conn)
{
circuit_t *circ;
@@ -273,20 +275,22 @@ command_process_created_cell(cell_t *cell, connection_t *conn)
if (circ->n_circ_id != cell->circ_id) {
log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,
- "got created cell from OPward? Closing.");
+ "got created cell from Tor client? Closing.");
circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
return;
}
if (CIRCUIT_IS_ORIGIN(circ)) { /* we're the OP. Handshake this. */
+ origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
log_debug(LD_OR,"at OP. Finishing handshake.");
- if (circuit_finish_handshake(circ, cell->command, cell->payload) < 0) {
+ if (circuit_finish_handshake(origin_circ, cell->command,
+ cell->payload) < 0) {
log_warn(LD_OR,"circuit_finish_handshake failed.");
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
return;
}
log_debug(LD_OR,"Moving to next skin.");
- if (circuit_send_next_onion_skin(circ) < 0) {
+ if (circuit_send_next_onion_skin(origin_circ) < 0) {
log_info(LD_OR,"circuit_send_next_onion_skin failed.");
/* XXX push this circuit_close lower */
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
@@ -305,7 +309,7 @@ command_process_created_cell(cell_t *cell, connection_t *conn)
* circuit_receive_relay_cell() for actual processing.
*/
static void
-command_process_relay_cell(cell_t *cell, connection_t *conn)
+command_process_relay_cell(cell_t *cell, or_connection_t *conn)
{
circuit_t *circ;
int reason;
@@ -315,7 +319,7 @@ command_process_relay_cell(cell_t *cell, connection_t *conn)
if (!circ) {
log_debug(LD_OR,
"unknown circuit %d on connection from %s:%d. Dropping.",
- cell->circ_id, conn->address, conn->port);
+ cell->circ_id, conn->_base.address, conn->_base.port);
return;
}
@@ -325,7 +329,9 @@ command_process_relay_cell(cell_t *cell, connection_t *conn)
return;
}
- if (cell->circ_id == circ->p_circ_id) { /* it's an outgoing cell */
+ if (!CIRCUIT_IS_ORIGIN(circ) &&
+ cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id) {
+ /* it's an outgoing cell */
if ((reason = circuit_receive_relay_cell(cell, circ,
CELL_DIRECTION_OUT)) < 0) {
log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,"circuit_receive_relay_cell "
@@ -358,7 +364,7 @@ command_process_relay_cell(cell_t *cell, connection_t *conn)
* and passes the destroy cell onward if necessary).
*/
static void
-command_process_destroy_cell(cell_t *cell, connection_t *conn)
+command_process_destroy_cell(cell_t *cell, or_connection_t *conn)
{
circuit_t *circ;
uint8_t reason;
@@ -367,17 +373,18 @@ command_process_destroy_cell(cell_t *cell, connection_t *conn)
reason = (uint8_t)cell->payload[0];
if (!circ) {
log_info(LD_OR,"unknown circuit %d on connection from %s:%d. Dropping.",
- cell->circ_id, conn->address, conn->port);
+ cell->circ_id, conn->_base.address, conn->_base.port);
return;
}
log_debug(LD_OR,"Received for circID %d.",cell->circ_id);
- if (cell->circ_id == circ->p_circ_id) {
+ if (!CIRCUIT_IS_ORIGIN(circ) &&
+ cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id) {
/* the destroy came from behind */
- circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED);
+ circuit_set_p_circid_orconn(TO_OR_CIRCUIT(circ), 0, NULL);
circuit_mark_for_close(circ, reason);
} else { /* the destroy came from ahead */
- circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
+ circuit_set_n_circid_orconn(circ, 0, NULL);
if (CIRCUIT_IS_ORIGIN(circ)) {
circuit_mark_for_close(circ, reason);
} else {
diff --git a/src/or/config.c b/src/or/config.c
index d8ae9a47c2..523ec22bfe 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -76,6 +76,8 @@ static config_abbrev_t _option_abbrevs[] = {
{ "NumHelperNodes", "NumEntryGuards", 0, 0},
{ "UseEntryNodes", "UseEntryGuards", 0, 0},
{ "NumEntryNodes", "NumEntryGuards", 0, 0},
+ { "ResolvConf", "ServerDNSResolvConfFile", 0, 1},
+ { "SearchDomains", "ServerDNSSearchDomains", 0, 1},
{ NULL, NULL, 0, 0},
};
/* A list of state-file abbreviations, for compatibility. */
@@ -100,10 +102,6 @@ typedef struct config_var_t {
const char *initvalue; /**< String (or null) describing initial value. */
} config_var_t;
-/** Return the offset of <b>member</b> within the type <b>tp</b>, in bytes */
-#define STRUCT_OFFSET(tp, member) \
- ((off_t) (((char*)&((tp*)0)->member)-(char*)0))
-
#define STRUCT_VAR_P(st, off) \
((void*) ( ((char*)st) + off ) )
@@ -134,6 +132,7 @@ static config_var_t _option_vars[] = {
VAR("AuthDirReject", LINELIST, AuthDirReject, NULL),
VAR("AuthDirRejectUnlisted",BOOL, AuthDirRejectUnlisted,"0"),
VAR("AuthoritativeDirectory",BOOL, AuthoritativeDir, "0"),
+ VAR("AvoidDiskWrites", BOOL, AvoidDiskWrites, "0"),
VAR("BandwidthBurst", MEMUNIT, BandwidthBurst, "6 MB"),
VAR("BandwidthRate", MEMUNIT, BandwidthRate, "3 MB"),
VAR("CircuitBuildTimeout", INTERVAL, CircuitBuildTimeout, "1 minute"),
@@ -148,8 +147,7 @@ static config_var_t _option_vars[] = {
VAR("DebugLogFile", STRING, DebugLogFile, NULL),
VAR("DirAllowPrivateAddresses",BOOL, DirAllowPrivateAddresses, NULL),
VAR("DirListenAddress", LINELIST, DirListenAddress, NULL),
- /* if DirFetchPeriod is 0, see get_dir_fetch_period() in main.c */
- VAR("DirFetchPeriod", INTERVAL, DirFetchPeriod, "0 seconds"),
+ OBSOLETE("DirFetchPeriod"),
VAR("DirPolicy", LINELIST, DirPolicy, NULL),
VAR("DirPort", UINT, DirPort, "0"),
OBSOLETE("DirPostPeriod"),
@@ -184,7 +182,7 @@ static config_var_t _option_vars[] = {
VAR("LogFile", LINELIST_S, OldLogOptions, NULL),
VAR("LogLevel", LINELIST_S, OldLogOptions, NULL),
VAR("LongLivedPorts", CSV, LongLivedPorts,
- "21,22,706,1863,5050,5190,5222,5223,6667,8300,8888"),
+ "21,22,706,1863,5050,5190,5222,5223,6667,8300"),
VAR("MapAddress", LINELIST, AddressMap, NULL),
VAR("MaxAdvertisedBandwidth",MEMUNIT,MaxAdvertisedBandwidth,"128 TB"),
VAR("MaxCircuitDirtiness", INTERVAL, MaxCircuitDirtiness, "10 minutes"),
@@ -213,6 +211,8 @@ static config_var_t _option_vars[] = {
VAR("RecommendedClientVersions", LINELIST, RecommendedClientVersions, NULL),
VAR("RecommendedServerVersions", LINELIST, RecommendedServerVersions, NULL),
VAR("RedirectExit", LINELIST, RedirectExit, NULL),
+ VAR("RelayBandwidthBurst", MEMUNIT, RelayBandwidthBurst, "0"),
+ VAR("RelayBandwidthRate", MEMUNIT, RelayBandwidthRate, "0"),
VAR("RendExcludeNodes", STRING, RendExcludeNodes, NULL),
VAR("RendNodes", STRING, RendNodes, NULL),
VAR("RendPostPeriod", INTERVAL, RendPostPeriod, "1 hour"),
@@ -222,13 +222,15 @@ static config_var_t _option_vars[] = {
VAR("RunTesting", BOOL, RunTesting, "0"),
VAR("SafeLogging", BOOL, SafeLogging, "1"),
VAR("SafeSocks", BOOL, SafeSocks, "0"),
+ VAR("ServerDNSDetectHijacking",BOOL, ServerDNSDetectHijacking,"1"),
+ VAR("ServerDNSResolvConfFile", STRING, ServerDNSResolvConfFile, NULL),
+ VAR("ServerDNSSearchDomains", BOOL, ServerDNSSearchDomains, "0"),
VAR("ShutdownWaitLength", INTERVAL, ShutdownWaitLength, "30 seconds"),
VAR("SocksListenAddress", LINELIST, SocksListenAddress, NULL),
VAR("SocksPolicy", LINELIST, SocksPolicy, NULL),
VAR("SocksPort", UINT, SocksPort, "9050"),
VAR("SocksTimeout", INTERVAL, SocksTimeout, "2 minutes"),
- /* if StatusFetchPeriod is 0, see get_status_fetch_period() in main.c */
- VAR("StatusFetchPeriod", INTERVAL, StatusFetchPeriod, "0 seconds"),
+ OBSOLETE("StatusFetchPeriod"),
VAR("StrictEntryNodes", BOOL, StrictEntryNodes, "0"),
VAR("StrictExitNodes", BOOL, StrictExitNodes, "0"),
VAR("SysLog", LINELIST_S, OldLogOptions, NULL),
@@ -237,6 +239,8 @@ static config_var_t _option_vars[] = {
VAR("TrackHostExits", CSV, TrackHostExits, NULL),
VAR("TrackHostExitsExpire",INTERVAL, TrackHostExitsExpire, "30 minutes"),
OBSOLETE("TrafficShaping"),
+ VAR("TransListenAddress", LINELIST, TransListenAddress, NULL),
+ VAR("TransPort", UINT, TransPort, "0"),
VAR("UseEntryGuards", BOOL, UseEntryGuards, "1"),
VAR("User", STRING, User, NULL),
VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir, "0"),
@@ -391,11 +395,15 @@ static int or_state_validate(or_state_t *old_options, or_state_t *options,
static uint64_t config_parse_memunit(const char *s, int *ok);
static int config_parse_interval(const char *s, int *ok);
-static void print_cvs_version(void);
+static void print_svn_version(void);
static void init_libevent(void);
static int opt_streq(const char *s1, const char *s2);
+typedef enum {
+ LE_OLD=0, LE_10C, LE_10D, LE_10E, LE_11, LE_11A, LE_11B, LE_OTHER
+} le_version_t;
+static le_version_t decode_libevent_version(void);
#if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
-static void check_libevent_version(const char *m, const char *v, int server);
+static void check_libevent_version(const char *m, int server);
#endif
/*static*/ or_options_t *options_new(void);
@@ -445,7 +453,7 @@ static or_state_t *global_state = NULL;
static void *
config_alloc(config_format_t *fmt)
{
- void *opts = opts = tor_malloc_zero(fmt->size);
+ void *opts = tor_malloc_zero(fmt->size);
*(uint32_t*)STRUCT_VAR_P(opts, fmt->magic_offset) = fmt->magic;
CHECK(fmt, opts);
return opts;
@@ -514,7 +522,9 @@ safe_str(const char *address)
return address;
}
-/** Equivalent to escaped(safe_str(address)) */
+/** Equivalent to escaped(safe_str(address)). See reentrancy node on
+ * escaped(): don't use this outside the main thread, or twice in the same
+ * log statement. */
const char *
escaped_safe_str(const char *address)
{
@@ -530,6 +540,7 @@ add_default_trusted_dirservers(void)
{
int i;
const char *dirservers[] = {
+ /* eventually we should mark moria1 as "v1only" */
"moria1 v1 18.244.0.188:9031 "
"FFCB 46DB 1339 DA84 674C 70D7 CB58 6434 C437 0441",
"moria2 v1 18.244.0.114:80 "
@@ -787,18 +798,22 @@ options_act(or_options_t *old_options)
log_info(LD_GENERAL,
"Worker-related options changed. Rotating workers.");
if (server_mode(options) && !server_mode(old_options)) {
- extern int has_completed_circuit;
if (init_keys() < 0) {
log_err(LD_GENERAL,"Error initializing keys; exiting");
return -1;
}
server_has_changed_ip();
- if (has_completed_circuit)
+ if (has_completed_circuit || !any_predicted_circuits(time(NULL)))
inform_testing_reachability();
}
cpuworkers_rotate();
- dnsworkers_rotate();
+ dns_reset();
+ }
+#ifdef USE_EVENTDNS
+ else {
+ dns_reset();
}
+#endif
}
/* Check if we need to parse and add the EntryNodes config option. */
@@ -807,6 +822,12 @@ options_act(or_options_t *old_options)
!opt_streq(old_options->EntryNodes, options->EntryNodes)))
entry_nodes_should_be_added();
+ /* If the user wants to avoid certain nodes, make sure none of them
+ * are already entryguards */
+ if (options->ExcludeNodes) {
+ // XXX TODO
+ }
+
/* Since our options changed, we might need to regenerate and upload our
* server descriptor.
*/
@@ -1274,19 +1295,9 @@ get_assigned_option(config_format_t *fmt, or_options_t *options,
if (!var) {
log_warn(LD_CONFIG, "Unknown option '%s'. Failing.", key);
return NULL;
- } else if (var->type == CONFIG_TYPE_LINELIST_S) {
- log_warn(LD_CONFIG,
- "Can't return context-sensitive '%s' on its own", key);
- return NULL;
}
value = STRUCT_VAR_P(options, var->var_offset);
- if (var->type == CONFIG_TYPE_LINELIST ||
- var->type == CONFIG_TYPE_LINELIST_V) {
- /* Linelist requires special handling: we just copy and return it. */
- return config_lines_dup(*(const config_line_t**)value);
- }
-
result = tor_malloc_zero(sizeof(config_line_t));
result->key = tor_strdup(var->name);
switch (var->type)
@@ -1342,6 +1353,17 @@ get_assigned_option(config_format_t *fmt, or_options_t *options,
tor_free(result->key);
tor_free(result);
return NULL;
+ case CONFIG_TYPE_LINELIST_S:
+ log_warn(LD_CONFIG,
+ "Can't return context-sensitive '%s' on its own", key);
+ tor_free(result->key);
+ tor_free(result);
+ return NULL;
+ case CONFIG_TYPE_LINELIST:
+ case CONFIG_TYPE_LINELIST_V:
+ tor_free(result->key);
+ tor_free(result);
+ return config_lines_dup(*(const config_line_t**)value);
default:
tor_free(result->key);
tor_free(result);
@@ -1491,6 +1513,7 @@ static void
option_clear(config_format_t *fmt, or_options_t *options, config_var_t *var)
{
void *lvalue = STRUCT_VAR_P(options, var->var_offset);
+ (void)fmt; /* unused */
switch (var->type) {
case CONFIG_TYPE_STRING:
tor_free(*(char**)lvalue);
@@ -1573,8 +1596,8 @@ print_usage(void)
* public IP address.
*/
int
-resolve_my_address(or_options_t *options, uint32_t *addr_out,
- char **hostname_out)
+resolve_my_address(int warn_severity, or_options_t *options,
+ uint32_t *addr_out, char **hostname_out)
{
struct in_addr in;
struct hostent *rent;
@@ -1584,6 +1607,8 @@ resolve_my_address(or_options_t *options, uint32_t *addr_out,
char tmpbuf[INET_NTOA_BUF_LEN];
static uint32_t old_addr=0;
const char *address = options->Address;
+ int notice_severity = warn_severity <= LOG_NOTICE ?
+ LOG_NOTICE : warn_severity;
tor_assert(addr_out);
@@ -1594,13 +1619,13 @@ resolve_my_address(or_options_t *options, uint32_t *addr_out,
explicit_hostname = 0; /* it's implicit */
if (gethostname(hostname, sizeof(hostname)) < 0) {
- log_warn(LD_NET,"Error obtaining local hostname");
+ log_fn(warn_severity, LD_NET,"Error obtaining local hostname");
return -1;
}
log_debug(LD_CONFIG,"Guessed local host name as '%s'",hostname);
}
- /* now we know hostname. resolve it and keep only the IP */
+ /* now we know hostname. resolve it and keep only the IP address */
if (tor_inet_aton(hostname, &in) == 0) {
/* then we have to resolve it */
@@ -1610,21 +1635,22 @@ resolve_my_address(or_options_t *options, uint32_t *addr_out,
uint32_t interface_ip;
if (explicit_hostname) {
- log_warn(LD_CONFIG,"Could not resolve local Address '%s'. Failing.",
- hostname);
+ log_fn(warn_severity, LD_CONFIG,
+ "Could not resolve local Address '%s'. Failing.", hostname);
return -1;
}
- log_notice(LD_CONFIG, "Could not resolve guessed local hostname '%s'. "
- "Trying something else.", hostname);
- if (get_interface_address(&interface_ip)) {
- log_warn(LD_CONFIG, "Could not get local interface IP address. "
- "Failing.");
+ log_fn(notice_severity, LD_CONFIG,
+ "Could not resolve guessed local hostname '%s'. "
+ "Trying something else.", hostname);
+ if (get_interface_address(warn_severity, &interface_ip)) {
+ log_fn(warn_severity, LD_CONFIG,
+ "Could not get local interface IP address. Failing.");
return -1;
}
in.s_addr = htonl(interface_ip);
tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf));
- log_notice(LD_CONFIG, "Learned IP address '%s' for local interface."
- " Using that.", tmpbuf);
+ log_fn(notice_severity, LD_CONFIG, "Learned IP address '%s' for "
+ "local interface. Using that.", tmpbuf);
strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
} else {
tor_assert(rent->h_length == 4);
@@ -1635,24 +1661,26 @@ resolve_my_address(or_options_t *options, uint32_t *addr_out,
uint32_t interface_ip;
tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf));
- log_notice(LD_CONFIG, "Guessed local hostname '%s' resolves to a "
- "private IP address (%s). Trying something else.", hostname,
- tmpbuf);
+ log_fn(notice_severity, LD_CONFIG, "Guessed local hostname '%s' "
+ "resolves to a private IP address (%s). Trying something "
+ "else.", hostname, tmpbuf);
- if (get_interface_address(&interface_ip)) {
- log_warn(LD_CONFIG, "Could not get local interface IP address. "
- "Too bad.");
+ if (get_interface_address(warn_severity, &interface_ip)) {
+ log_fn(warn_severity, LD_CONFIG,
+ "Could not get local interface IP address. Too bad.");
} else if (is_internal_IP(interface_ip, 0)) {
struct in_addr in2;
in2.s_addr = htonl(interface_ip);
tor_inet_ntoa(&in2,tmpbuf,sizeof(tmpbuf));
- log_notice(LD_CONFIG, "Interface IP '%s' is a private address "
- "too. Ignoring.", tmpbuf);
+ log_fn(notice_severity, LD_CONFIG,
+ "Interface IP address '%s' is a private address too. "
+ "Ignoring.", tmpbuf);
} else {
in.s_addr = htonl(interface_ip);
tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf));
- log_notice(LD_CONFIG, "Learned IP address '%s' for local interface."
- " Using that.", tmpbuf);
+ log_fn(notice_severity, LD_CONFIG,
+ "Learned IP address '%s' for local interface."
+ " Using that.", tmpbuf);
strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
}
}
@@ -1666,18 +1694,18 @@ resolve_my_address(or_options_t *options, uint32_t *addr_out,
if (!options->DirServers) {
/* if they are using the default dirservers, disallow internal IPs
* always. */
- log_warn(LD_CONFIG,"Address '%s' resolves to private IP '%s'. "
- "Tor servers that use the default DirServers must have public "
- "IP addresses.",
- hostname, tmpbuf);
+ log_fn(warn_severity, LD_CONFIG,
+ "Address '%s' resolves to private IP address '%s'. "
+ "Tor servers that use the default DirServers must have public "
+ "IP addresses.", hostname, tmpbuf);
return -1;
}
if (!explicit_ip) {
/* even if they've set their own dirservers, require an explicit IP if
* they're using an internal address. */
- log_warn(LD_CONFIG,"Address '%s' resolves to private IP '%s'. Please "
- "set the Address config option to be the IP you want to use.",
- hostname, tmpbuf);
+ log_fn(warn_severity, LD_CONFIG, "Address '%s' resolves to private "
+ "IP address '%s'. Please set the Address config option to be "
+ "the IP address you want to use.", hostname, tmpbuf);
return -1;
}
}
@@ -1685,7 +1713,9 @@ resolve_my_address(or_options_t *options, uint32_t *addr_out,
log_debug(LD_CONFIG, "Resolved Address to '%s'.", tmpbuf);
*addr_out = ntohl(in.s_addr);
if (old_addr && old_addr != *addr_out) {
- log_notice(LD_NET, "Your IP seems to have changed. Updating.");
+ /* Leave this as a notice, regardless of the requested severity,
+ * at least until dynamic IP address support becomes bulletproof. */
+ log_notice(LD_NET, "Your IP address seems to have changed. Updating.");
server_has_changed_ip();
}
old_addr = *addr_out;
@@ -1963,23 +1993,40 @@ validate_ports_csv(smartlist_t *sl, const char *name, char **msg)
return 0;
}
-/** Lowest allowable value for DirFetchPeriod; if this is too low, clients can
- * overload the directory system. */
-#define MIN_DIR_FETCH_PERIOD (10*60)
+#if 0
+/* XXXX Unused. */
+/** Return 0 if every element of sl is a string holding an IP address, or if sl
+ * is NULL. Otherwise set *msg and return -1. */
+static int
+validate_ips_csv(smartlist_t *sl, const char *name, char **msg)
+{
+ char buf[1024];
+ tor_assert(name);
+
+ if (!sl)
+ return 0;
+
+ SMARTLIST_FOREACH(sl, const char *, cp,
+ {
+ struct in_addr in;
+ if (0 == tor_inet_aton(cp, &in)) {
+ int r = tor_snprintf(buf, sizeof(buf),
+ "Malformed address '%s' out of range in %s", cp, name);
+ *msg = tor_strdup(r >= 0 ? buf : "internal error");
+ return -1;
+ }
+ });
+ return 0;
+}
+#endif
+
/** Lowest allowable value for RendPostPeriod; if this is too low, hidden
* services can overload the directory system. */
#define MIN_REND_POST_PERIOD (5*60)
-/** Lowest allowable value for StatusFetchPeriod; if this is too low, clients
- * can overload the directory system. */
-#define MIN_STATUS_FETCH_PERIOD (5*60)
/** Highest allowable value for DirFetchPeriod, StatusFetchPeriod, and
* RendPostPeriod. */
#define MAX_DIR_PERIOD (MIN_ONION_KEY_LIFETIME/2)
-/** Highest allowable value for DirFetchPeriod for directory caches. */
-#define MAX_CACHE_DIR_FETCH_PERIOD (60*60)
-/** Highest allowable value for StatusFetchPeriod for directory caches. */
-#define MAX_CACHE_STATUS_FETCH_PERIOD (15*60)
/** Return 0 if every setting in <b>options</b> is reasonable, and a
* permissible transition from <b>old_options</b>. Else return -1.
@@ -2031,27 +2078,39 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->ControlPort == 0 && options->ControlListenAddress != NULL)
REJECT("ControlPort must be defined if ControlListenAddress is defined.");
+ if (options->TransPort == 0 && options->TransListenAddress != NULL)
+ REJECT("TransPort must be defined if TransListenAddress is defined.");
+
#if 0 /* don't complain, since a standard configuration does this! */
if (options->SocksPort == 0 && options->SocksListenAddress != NULL)
REJECT("SocksPort must be defined if SocksListenAddress is defined.");
#endif
- if (options->SocksListenAddress) {
- config_line_t *line = NULL;
- char *address = NULL;
- for (line = options->SocksListenAddress; line; line = line->next) {
+ for (i = 0; i < 2; ++i) {
+ int is_socks = i==0;
+ config_line_t *line, *opt, *old;
+ const char *tp = is_socks ? "SOCKS proxy" : "transparent proxy";
+ if (is_socks) {
+ opt = options->SocksListenAddress;
+ old = old_options ? old_options->SocksListenAddress : NULL;
+ } else {
+ opt = options->TransListenAddress;
+ old = old_options ? old_options->TransListenAddress : NULL;
+ }
+
+ for (line = opt; line; line = line->next) {
+ char *address = NULL;
uint16_t port;
uint32_t addr;
- if (parse_addr_port(line->value, &address, &addr, &port)<0)
+ if (parse_addr_port(LOG_WARN, line->value, &address, &addr, &port)<0)
continue; /* We'll warn about this later. */
if (!is_internal_IP(addr, 1) &&
- (!old_options || !config_lines_eq(old_options->SocksListenAddress,
- options->SocksListenAddress))) {
+ (!old_options || !config_lines_eq(old, opt))) {
log_warn(LD_CONFIG,
- "You specified a public address '%s' for a SOCKS listener. Other "
+ "You specified a public address '%s' for a %s. Other "
"people on the Internet might find your computer and use it as "
- "an open SOCKS proxy. Please don't allow this unless you have "
- "a good reason.", address);
+ "an open %s. Please don't allow this unless you have "
+ "a good reason.", address, tp, tp);
}
tor_free(address);
}
@@ -2098,10 +2157,10 @@ options_validate(or_options_t *old_options, or_options_t *options,
options->PublishServerDescriptor = 0;
}
- if (server_mode(options)) {
+ if (authdir_mode(options)) {
/* confirm that our address isn't broken, so we can complain now */
uint32_t tmp;
- if (resolve_my_address(options, &tmp, NULL) < 0)
+ if (resolve_my_address(LOG_WARN, options, &tmp, NULL) < 0)
REJECT("Failed to resolve/guess local address. See logs for details.");
}
@@ -2113,8 +2172,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->SocksPort < 0 || options->SocksPort > 65535)
REJECT("SocksPort option out of bounds.");
- if (options->SocksPort == 0 && options->ORPort == 0)
- REJECT("SocksPort and ORPort are both undefined? Quitting.");
+ if (options->TransPort < 0 || options->TransPort > 65535)
+ REJECT("TransPort option out of bounds.");
+
+ if (options->SocksPort == 0 && options->TransPort == 0 &&
+ options->ORPort == 0)
+ REJECT("SocksPort, TransPort, and ORPort are all undefined? Quitting.");
if (options->ControlPort < 0 || options->ControlPort > 65535)
REJECT("ControlPort option out of bounds.");
@@ -2122,6 +2185,11 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->DirPort < 0 || options->DirPort > 65535)
REJECT("DirPort option out of bounds.");
+#ifndef USE_TRANSPARENT
+ if (options->TransPort || options->TransListenAddress)
+ REJECT("TransPort and TransListenAddress are disabled in this build.");
+#endif
+
if (options->StrictExitNodes &&
(!options->ExitNodes || !strlen(options->ExitNodes)) &&
(!old_options ||
@@ -2296,51 +2364,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
(options->PathlenCoinWeight < 0.0 || options->PathlenCoinWeight >= 1.0))
REJECT("PathlenCoinWeight option must be >=0.0 and <1.0.");
- if (options->DirFetchPeriod &&
- options->DirFetchPeriod < MIN_DIR_FETCH_PERIOD) {
- log(LOG_WARN, LD_CONFIG,
- "DirFetchPeriod option must be at least %d seconds. Clipping.",
- MIN_DIR_FETCH_PERIOD);
- options->DirFetchPeriod = MIN_DIR_FETCH_PERIOD;
- }
- if (options->StatusFetchPeriod &&
- options->StatusFetchPeriod < MIN_STATUS_FETCH_PERIOD) {
- log(LOG_WARN, LD_CONFIG,
- "StatusFetchPeriod option must be at least %d seconds. Clipping.",
- MIN_STATUS_FETCH_PERIOD);
- options->StatusFetchPeriod = MIN_STATUS_FETCH_PERIOD;
- }
if (options->RendPostPeriod < MIN_REND_POST_PERIOD) {
log(LOG_WARN,LD_CONFIG,"RendPostPeriod option must be at least %d seconds."
" Clipping.", MIN_REND_POST_PERIOD);
options->RendPostPeriod = MIN_REND_POST_PERIOD;
}
- if (options->DirPort && ! options->AuthoritativeDir) {
- if (options->DirFetchPeriod > MAX_CACHE_DIR_FETCH_PERIOD) {
- log(LOG_WARN, LD_CONFIG, "Caching directory servers must have "
- "DirFetchPeriod less than %d seconds. Clipping.",
- MAX_CACHE_DIR_FETCH_PERIOD);
- options->DirFetchPeriod = MAX_CACHE_DIR_FETCH_PERIOD;
- }
- if (options->StatusFetchPeriod > MAX_CACHE_STATUS_FETCH_PERIOD) {
- log(LOG_WARN, LD_CONFIG, "Caching directory servers must have "
- "StatusFetchPeriod less than %d seconds. Clipping.",
- MAX_CACHE_STATUS_FETCH_PERIOD);
- options->StatusFetchPeriod = MAX_CACHE_STATUS_FETCH_PERIOD;
- }
- }
-
- if (options->DirFetchPeriod > MAX_DIR_PERIOD) {
- log(LOG_WARN, LD_CONFIG, "DirFetchPeriod is too large; clipping to %ds.",
- MAX_DIR_PERIOD);
- options->DirFetchPeriod = MAX_DIR_PERIOD;
- }
- if (options->StatusFetchPeriod > MAX_DIR_PERIOD) {
- log(LOG_WARN, LD_CONFIG,"StatusFetchPeriod is too large; clipping to %ds.",
- MAX_DIR_PERIOD);
- options->StatusFetchPeriod = MAX_DIR_PERIOD;
- }
if (options->RendPostPeriod > MAX_DIR_PERIOD) {
log(LOG_WARN, LD_CONFIG, "RendPostPeriod is too large; clipping to %ds.",
MAX_DIR_PERIOD);
@@ -2379,7 +2408,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("Failed to parse accounting options. See logs for details.");
if (options->HttpProxy) { /* parse it now */
- if (parse_addr_port(options->HttpProxy, NULL,
+ if (parse_addr_port(LOG_WARN, options->HttpProxy, NULL,
&options->HttpProxyAddr, &options->HttpProxyPort) < 0)
REJECT("HttpProxy failed to parse or resolve. Please fix.");
if (options->HttpProxyPort == 0) { /* give it a default */
@@ -2393,7 +2422,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (options->HttpsProxy) { /* parse it now */
- if (parse_addr_port(options->HttpsProxy, NULL,
+ if (parse_addr_port(LOG_WARN, options->HttpsProxy, NULL,
&options->HttpsProxyAddr, &options->HttpsProxyPort) <0)
REJECT("HttpsProxy failed to parse or resolve. Please fix.");
if (options->HttpsProxyPort == 0) { /* give it a default */
@@ -2416,6 +2445,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->UseEntryGuards && ! options->NumEntryGuards)
REJECT("Cannot enable UseEntryGuards with NumEntryGuards set to 0");
+#ifndef USE_EVENTDNS
+ if (options->ServerDNSResolvConfFile)
+ log(LOG_WARN, LD_CONFIG,
+ "ServerDNSResolvConfFile only works when eventdns support is enabled.");
+#endif
+
if (check_nickname_list(options->ExitNodes, "ExitNodes", msg))
return -1;
if (check_nickname_list(options->EntryNodes, "EntryNodes", msg))
@@ -2539,6 +2574,8 @@ options_transition_affects_workers(or_options_t *old_options,
if (!opt_streq(old_options->DataDirectory, new_options->DataDirectory) ||
old_options->NumCpus != new_options->NumCpus ||
old_options->ORPort != new_options->ORPort ||
+ old_options->ServerDNSSearchDomains !=
+ new_options->ServerDNSSearchDomains ||
old_options->SafeLogging != new_options->SafeLogging ||
!config_lines_eq(old_options->Logs, new_options->Logs))
return 1;
@@ -2697,7 +2734,7 @@ options_init_from_torrc(int argc, char **argv)
if (argc > 1 && (!strcmp(argv[1],"--version"))) {
printf("Tor version %s.\n",VERSION);
if (argc > 2 && (!strcmp(argv[2],"--version"))) {
- print_cvs_version();
+ print_svn_version();
}
exit(0);
}
@@ -2732,11 +2769,11 @@ options_init_from_torrc(int argc, char **argv)
if (using_default_torrc) {
/* didn't find one, try CONFDIR */
const char *dflt = get_default_conf_file();
- char *fn = NULL;
if (dflt && file_status(dflt) == FN_FILE) {
fname = tor_strdup(dflt);
} else {
#ifndef MS_WINDOWS
+ char *fn;
fn = expand_filename("~/.torrc");
if (fn && file_status(fn) == FN_FILE) {
fname = fn;
@@ -3168,8 +3205,8 @@ parse_redirect_line(smartlist_t *result, config_line_t *line, char **msg)
if (0==strcasecmp(smartlist_get(elements,1), "pass")) {
r->is_redirect = 0;
} else {
- if (parse_addr_port(smartlist_get(elements,1),NULL,&r->addr_dest,
- &r->port_dest)) {
+ if (parse_addr_port(LOG_WARN, smartlist_get(elements,1),NULL,
+ &r->addr_dest, &r->port_dest)) {
*msg = tor_strdup("Error parsing dest address in RedirectExit line");
goto err;
}
@@ -3234,7 +3271,7 @@ parse_dir_server_line(const char *line, int validate_only)
goto err;
}
addrport = smartlist_get(items, 0);
- if (parse_addr_port(addrport, &address, NULL, &port)<0) {
+ if (parse_addr_port(LOG_WARN, addrport, &address, NULL, &port)<0) {
log_warn(LD_CONFIG, "Error parsing DirServer address '%s'", addrport);
goto err;
}
@@ -3364,6 +3401,8 @@ write_configuration_file(const char *fname, or_options_t *options)
break;
case FN_NOENT:
break;
+ case FN_ERROR:
+ case FN_DIR:
default:
log_warn(LD_CONFIG,
"Config file \"%s\" is not a file? Failing.", fname);
@@ -3555,7 +3594,20 @@ init_libevent(void)
*/
suppress_libevent_log_msg("Function not implemented");
#ifdef __APPLE__
- setenv("EVENT_NOKQUEUE","1",1);
+ if (decode_libevent_version() < LE_11B) {
+ setenv("EVENT_NOKQUEUE","1",1);
+ } else if (!getenv("EVENT_NOKQUEUE")) {
+ const char *ver = NULL;
+#ifdef HAVE_EVENT_GET_VERSION
+ ver = event_get_version();
+#endif
+ /* If we're 1.1b or later, we'd better have get_version() */
+ tor_assert(ver);
+ log(LOG_NOTICE, LD_GENERAL, "Enabling experimental OS X kqueue support "
+ "with libevent %s. If this turns out to not work, "
+ "set the environment variable EVENT_NOKQUEUE, and tell the Tor "
+ "developers.", ver);
+ }
#endif
event_init();
suppress_libevent_log_msg(NULL);
@@ -3565,46 +3617,78 @@ init_libevent(void)
log(LOG_NOTICE, LD_GENERAL,
"Initialized libevent version %s using method %s. Good.",
event_get_version(), event_get_method());
- check_libevent_version(event_get_method(), event_get_version(),
- get_options()->ORPort != 0);
+ check_libevent_version(event_get_method(), get_options()->ORPort != 0);
#else
log(LOG_NOTICE, LD_GENERAL,
"Initialized old libevent (version 1.0b or earlier).");
log(LOG_WARN, LD_GENERAL,
- "You have a very old version of libevent. It is likely to be buggy; "
- "please consider building Tor with a more recent version.");
+ "You have a *VERY* old version of libevent. It is likely to be buggy; "
+ "please build Tor with a more recent version.");
#endif
}
#if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
+static const struct {
+ const char *name; le_version_t version;
+} le_version_table[] = {
+ /* earlier versions don't have get_version. */
+ { "1.0c", LE_10C },
+ { "1.0d", LE_10D },
+ { "1.0e", LE_10E },
+ { "1.1", LE_11 },
+ { "1.1a", LE_11A },
+ { "1.1b", LE_11B },
+ { NULL, 0 }
+};
+
+static le_version_t
+decode_libevent_version(void)
+{
+ const char *v = event_get_version();
+ int i;
+ for (i=0; le_version_table[i].name; ++i) {
+ if (!strcmp(le_version_table[i].name, v)) {
+ return le_version_table[i].version;
+ }
+ }
+ return LE_OTHER;
+}
+
/**
* Compare the given libevent method and version to a list of versions
* which are known not to work. Warn the user as appropriate.
*
*/
static void
-check_libevent_version(const char *m, const char *v, int server)
+check_libevent_version(const char *m, int server)
{
int buggy = 0, iffy = 0, slow = 0;
+ le_version_t version;
+ const char *v = event_get_version();
- tor_assert(m && v);
+ version = decode_libevent_version();
+ /* XXX Would it be worthwhile disabling the methods that we know
+ * are buggy, rather than just warning about them and then proceeding
+ * to use them? If so, we should probably not wrap this whole thing
+ * in HAVE_EVENT_GET_VERSION and HAVE_EVENT_GET_METHOD. -RD */
if (!strcmp(m, "kqueue")) {
- if (!strcmp(v, "1.0c") || !strcmp(v, "1.0d") || !strcmp(v, "1.0e") ||
- !strcmp(v, "1.1")) {
+ if (version < LE_11B)
buggy = 1;
- }
} else if (!strcmp(m, "epoll")) {
- if (!strcmp(v, "1.0c") || !strcmp(v, "1.0d") || !strcmp(v, "1.0e"))
+ if (version < LE_11)
iffy = 1;
} else if (!strcmp(m, "poll")) {
- if (!strcmp(v, "1.0c") || !strcmp(v, "1.0d"))
+ if (version < LE_10E)
buggy = 1;
- else if (!strcmp(v, "1.0e"))
+ else if (version < LE_11)
slow = 1;
} else if (!strcmp(m, "poll")) {
- if (!strcmp(v, "1.0c") || !strcmp(v, "1.0d") || !strcmp(v, "1.0e"))
+ if (version < LE_11)
slow = 1;
+ } else if (!strcmp(m, "win32")) {
+ if (version < LE_11B)
+ buggy = 1;
}
if (buggy) {
@@ -3623,6 +3707,12 @@ check_libevent_version(const char *m, const char *v, int server)
}
}
+#else
+static le_version_t
+decode_libevent_version(void)
+{
+ return LE_OLD;
+}
#endif
/** Return the persistent state struct for this Tor. */
@@ -3654,6 +3744,10 @@ static int
or_state_validate(or_state_t *old_state, or_state_t *state,
int from_setconf, char **msg)
{
+ /* We don't use these; only options do. Still, we need to match that
+ * signature. */
+ (void) from_setconf;
+ (void) old_state;
if (entry_guards_parse_state(state, 0, msg)<0) {
return -1;
}
@@ -3704,7 +3798,7 @@ or_state_load(void)
or_state_t *new_state = NULL;
char *contents = NULL, *fname;
char *errmsg = NULL;
- int r = -1;
+ int r = -1, badstate = 0;
fname = get_or_state_fname();
switch (file_status(fname)) {
@@ -3716,6 +3810,8 @@ or_state_load(void)
break;
case FN_NOENT:
break;
+ case FN_ERROR:
+ case FN_DIR:
default:
log_warn(LD_GENERAL,"State file \"%s\" is not a file? Failing.", fname);
goto done;
@@ -3732,30 +3828,68 @@ or_state_load(void)
lines, 0, 0, &errmsg);
config_free_lines(lines);
if (assign_retval<0)
- goto done;
+ badstate = 1;
+ if (errmsg) {
+ log_warn(LD_GENERAL, "%s", errmsg);
+ tor_free(errmsg);
+ }
}
- if (or_state_validate(NULL, new_state, 1, &errmsg) < 0) {
- goto done;
+ if (!badstate && or_state_validate(NULL, new_state, 1, &errmsg) < 0)
+ badstate = 1;
+
+ if (errmsg) {
+ log_warn(LD_GENERAL, "%s", errmsg);
+ tor_free(errmsg);
}
- if (contents)
+ if (badstate && !contents) {
+ log_warn(LD_BUG, "Uh oh. We couldn't even validate our own default state."
+ " This is a bug in Tor.");
+ goto done;
+ } else if (badstate && contents) {
+ int i;
+ file_status_t status;
+ size_t len = strlen(fname)+16;
+ char *fname2 = tor_malloc(len);
+ for (i = 0; i < 100; ++i) {
+ tor_snprintf(fname2, len, "%s.%d", fname, i);
+ status = file_status(fname2);
+ if (status == FN_NOENT)
+ break;
+ }
+ if (i == 100) {
+ log_warn(LD_BUG, "Unable to parse state in \"%s\"; too many saved bad "
+ "state files to move aside. Discarding the old state file.",
+ fname);
+ unlink(fname);
+ } else {
+ log_warn(LD_BUG, "Unable to parse state in \"%s\". Moving it aside "
+ "to \"%s\". This could be a bug in Tor; please tell "
+ "the developers.", fname, fname2);
+ rename(fname, fname2);
+ }
+ tor_free(fname2);
+ tor_free(contents);
+ config_free(&state_format, new_state);
+
+ new_state = tor_malloc_zero(sizeof(or_state_t));
+ new_state->_magic = OR_STATE_MAGIC;
+ config_init(&state_format, new_state);
+ } else if (contents) {
log_info(LD_GENERAL, "Loaded state from \"%s\"", fname);
- else
+ } else {
log_info(LD_GENERAL, "Initialized state");
+ }
or_state_set(new_state);
new_state = NULL;
if (!contents) {
global_state->dirty = 1;
or_state_save();
}
-
r = 0;
+
done:
- if (errmsg) {
- log_warn(LD_GENERAL, "%s", errmsg);
- tor_free(errmsg);
- }
tor_free(fname);
tor_free(contents);
if (new_state)
@@ -3862,47 +3996,47 @@ config_getinfo_helper(const char *question, char **answer)
#include "../common/ht.h"
#include "../common/test.h"
-/** Dump the version of every file to the log. */
-static void
-print_cvs_version(void)
-{
- extern const char aes_c_id[];
- extern const char compat_c_id[];
- extern const char container_c_id[];
- extern const char crypto_c_id[];
- extern const char log_c_id[];
- extern const char torgzip_c_id[];
- extern const char tortls_c_id[];
- extern const char util_c_id[];
-
- extern const char buffers_c_id[];
- extern const char circuitbuild_c_id[];
- extern const char circuitlist_c_id[];
- extern const char circuituse_c_id[];
- extern const char command_c_id[];
+extern const char aes_c_id[];
+extern const char compat_c_id[];
+extern const char container_c_id[];
+extern const char crypto_c_id[];
+extern const char log_c_id[];
+extern const char torgzip_c_id[];
+extern const char tortls_c_id[];
+extern const char util_c_id[];
+
+extern const char buffers_c_id[];
+extern const char circuitbuild_c_id[];
+extern const char circuitlist_c_id[];
+extern const char circuituse_c_id[];
+extern const char command_c_id[];
// extern const char config_c_id[];
- extern const char connection_c_id[];
- extern const char connection_edge_c_id[];
- extern const char connection_or_c_id[];
- extern const char control_c_id[];
- extern const char cpuworker_c_id[];
- extern const char directory_c_id[];
- extern const char dirserv_c_id[];
- extern const char dns_c_id[];
- extern const char hibernate_c_id[];
- extern const char main_c_id[];
- extern const char onion_c_id[];
- extern const char policies_c_id[];
- extern const char relay_c_id[];
- extern const char rendclient_c_id[];
- extern const char rendcommon_c_id[];
- extern const char rendmid_c_id[];
- extern const char rendservice_c_id[];
- extern const char rephist_c_id[];
- extern const char router_c_id[];
- extern const char routerlist_c_id[];
- extern const char routerparse_c_id[];
+extern const char connection_c_id[];
+extern const char connection_edge_c_id[];
+extern const char connection_or_c_id[];
+extern const char control_c_id[];
+extern const char cpuworker_c_id[];
+extern const char directory_c_id[];
+extern const char dirserv_c_id[];
+extern const char dns_c_id[];
+extern const char hibernate_c_id[];
+extern const char main_c_id[];
+extern const char onion_c_id[];
+extern const char policies_c_id[];
+extern const char relay_c_id[];
+extern const char rendclient_c_id[];
+extern const char rendcommon_c_id[];
+extern const char rendmid_c_id[];
+extern const char rendservice_c_id[];
+extern const char rephist_c_id[];
+extern const char router_c_id[];
+extern const char routerlist_c_id[];
+extern const char routerparse_c_id[];
+/** Dump the version of every file to the log. */
+static void
+print_svn_version(void)
+{
puts(AES_H_ID);
puts(COMPAT_H_ID);
puts(CONTAINER_H_ID);
diff --git a/src/or/connection.c b/src/or/connection.c
index 3135c61584..88346f8aad 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -16,10 +16,12 @@ const char connection_c_id[] =
static connection_t *connection_create_listener(const char *listenaddress,
uint16_t listenport, int type);
-static int connection_init_accepted_conn(connection_t *conn);
+static int connection_init_accepted_conn(connection_t *conn,
+ uint8_t listener_type);
static int connection_handle_listener_read(connection_t *conn, int new_type);
-static int connection_receiver_bucket_should_increase(connection_t *conn);
+static int connection_receiver_bucket_should_increase(or_connection_t *conn);
static int connection_finished_flushing(connection_t *conn);
+static int connection_flushed_some(connection_t *conn);
static int connection_finished_connecting(connection_t *conn);
static int connection_reached_eof(connection_t *conn);
static int connection_read_to_buf(connection_t *conn, int *max_to_read);
@@ -43,6 +45,7 @@ conn_type_to_string(int type)
case CONN_TYPE_OR: return "OR";
case CONN_TYPE_EXIT: return "Exit";
case CONN_TYPE_AP_LISTENER: return "Socks listener";
+ case CONN_TYPE_AP_TRANS_LISTENER: return "Transparent listener";
case CONN_TYPE_AP: return "Socks";
case CONN_TYPE_DIR_LISTENER: return "Directory listener";
case CONN_TYPE_DIR: return "Directory";
@@ -68,6 +71,7 @@ conn_state_to_string(int type, int state)
switch (type) {
case CONN_TYPE_OR_LISTENER:
case CONN_TYPE_AP_LISTENER:
+ case CONN_TYPE_AP_TRANS_LISTENER:
case CONN_TYPE_DIR_LISTENER:
case CONN_TYPE_CONTROL_LISTENER:
if (state == LISTENER_STATE_READY)
@@ -92,6 +96,7 @@ conn_state_to_string(int type, int state)
break;
case CONN_TYPE_AP:
switch (state) {
+ case AP_CONN_STATE_ORIGDST_WAIT:
case AP_CONN_STATE_SOCKS_WAIT: return "waiting for dest info";
case AP_CONN_STATE_RENDDESC_WAIT: return "waiting for rendezvous desc";
case AP_CONN_STATE_CONTROLLER_WAIT: return "waiting for controller";
@@ -144,7 +149,7 @@ conn_state_to_string(int type, int state)
/** Allocate space for a new connection_t. This function just initializes
* conn; you must call connection_add() to link it into the main array.
*
- * Set conn-\>type to <b>type</b>. Set conn-\>s and conn-\>poll_index to
+ * Set conn-\>type to <b>type</b>. Set conn-\>s and conn-\>conn_array_index to
* -1 to signify they are not yet assigned.
*
* If conn is not a listener type, allocate buffers for it. If it's
@@ -157,15 +162,40 @@ conn_state_to_string(int type, int state)
connection_t *
connection_new(int type)
{
- static uint32_t n_connections_allocated = 0;
+ static uint32_t n_connections_allocated = 1;
connection_t *conn;
time_t now = time(NULL);
+ size_t length;
+ uint32_t magic;
- conn = tor_malloc_zero(sizeof(connection_t));
- conn->magic = CONNECTION_MAGIC;
+ switch (type) {
+ case CONN_TYPE_OR:
+ length = sizeof(or_connection_t);
+ magic = OR_CONNECTION_MAGIC;
+ break;
+ case CONN_TYPE_EXIT:
+ case CONN_TYPE_AP:
+ length = sizeof(edge_connection_t);
+ magic = EDGE_CONNECTION_MAGIC;
+ break;
+ case CONN_TYPE_DIR:
+ length = sizeof(dir_connection_t);
+ magic = DIR_CONNECTION_MAGIC;
+ break;
+ case CONN_TYPE_CONTROL:
+ length = sizeof(control_connection_t);
+ magic = CONTROL_CONNECTION_MAGIC;
+ break;
+ default:
+ length = sizeof(connection_t);
+ magic = BASE_CONNECTION_MAGIC;
+ break;
+ }
+
+ conn = tor_malloc_zero(length);
+ conn->magic = magic;
conn->s = -1; /* give it a default of 'not used' */
- conn->poll_index = -1; /* also default to 'not used' */
- conn->global_identifier = n_connections_allocated++;
+ conn->conn_array_index = -1; /* also default to 'not used' */
conn->type = type;
if (!connection_is_listener(conn)) { /* listeners never use their buf */
@@ -173,10 +203,14 @@ connection_new(int type)
conn->outbuf = buf_new();
}
if (type == CONN_TYPE_AP) {
- conn->socks_request = tor_malloc_zero(sizeof(socks_request_t));
+ TO_EDGE_CONN(conn)->socks_request =
+ tor_malloc_zero(sizeof(socks_request_t));
}
-
- conn->next_circ_id = crypto_rand_int(1<<15);
+ if (CONN_IS_EDGE(conn)) {
+ TO_EDGE_CONN(conn)->global_identifier = n_connections_allocated++;
+ }
+ if (type == CONN_TYPE_OR)
+ TO_OR_CONN(conn)->next_circ_id = crypto_rand_int(1<<15);
conn->timestamp_created = now;
conn->timestamp_lastread = now;
@@ -208,30 +242,72 @@ connection_unregister(connection_t *conn)
static void
_connection_free(connection_t *conn)
{
- tor_assert(conn->magic == CONNECTION_MAGIC);
+ void *mem;
+ switch (conn->type) {
+ case CONN_TYPE_OR:
+ tor_assert(conn->magic == OR_CONNECTION_MAGIC);
+ mem = TO_OR_CONN(conn);
+ break;
+ case CONN_TYPE_AP:
+ case CONN_TYPE_EXIT:
+ tor_assert(conn->magic == EDGE_CONNECTION_MAGIC);
+ mem = TO_EDGE_CONN(conn);
+ break;
+ case CONN_TYPE_DIR:
+ tor_assert(conn->magic == DIR_CONNECTION_MAGIC);
+ mem = TO_DIR_CONN(conn);
+ break;
+ case CONN_TYPE_CONTROL:
+ tor_assert(conn->magic == CONTROL_CONNECTION_MAGIC);
+ mem = TO_CONTROL_CONN(conn);
+ break;
+ default:
+ tor_assert(conn->magic == BASE_CONNECTION_MAGIC);
+ mem = conn;
+ break;
+ }
if (!connection_is_listener(conn)) {
buf_free(conn->inbuf);
buf_free(conn->outbuf);
}
+
tor_free(conn->address);
- tor_free(conn->chosen_exit_name);
if (connection_speaks_cells(conn)) {
- if (conn->tls) {
- tor_tls_free(conn->tls);
- conn->tls = NULL;
+ or_connection_t *or_conn = TO_OR_CONN(conn);
+ if (or_conn->tls) {
+ tor_tls_free(or_conn->tls);
+ or_conn->tls = NULL;
}
+
+ tor_free(or_conn->nickname);
+ }
+ if (CONN_IS_EDGE(conn)) {
+ edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
+ tor_free(edge_conn->chosen_exit_name);
+ tor_free(edge_conn->socks_request);
+ }
+ if (conn->type == CONN_TYPE_CONTROL) {
+ control_connection_t *control_conn = TO_CONTROL_CONN(conn);
+ tor_free(control_conn->incoming_cmd);
}
- if (conn->identity_pkey)
- crypto_free_pk_env(conn->identity_pkey);
- tor_free(conn->nickname);
- tor_free(conn->socks_request);
- tor_free(conn->incoming_cmd);
tor_free(conn->read_event); /* Probably already freed by connection_free. */
tor_free(conn->write_event); /* Probably already freed by connection_free. */
- tor_free(conn->requested_resource);
+
+ if (conn->type == CONN_TYPE_DIR) {
+ dir_connection_t *dir_conn = TO_DIR_CONN(conn);
+ tor_free(dir_conn->requested_resource);
+ if (dir_conn->zlib_state)
+ tor_zlib_free(dir_conn->zlib_state);
+ if (dir_conn->fingerprint_stack) {
+ SMARTLIST_FOREACH(dir_conn->fingerprint_stack, char *, cp, tor_free(cp));
+ smartlist_free(dir_conn->fingerprint_stack);
+ }
+ if (dir_conn->cached_dir)
+ cached_dir_decref(dir_conn->cached_dir);
+ }
if (conn->s >= 0) {
log_debug(LD_NET,"closing fd %d.",conn->s);
@@ -239,13 +315,13 @@ _connection_free(connection_t *conn)
}
if (conn->type == CONN_TYPE_OR &&
- !tor_digest_is_zero(conn->identity_digest)) {
+ !tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest)) {
log_warn(LD_BUG, "called on OR conn with non-zeroed identity_digest");
- connection_or_remove_from_identity_map(conn);
+ connection_or_remove_from_identity_map(TO_OR_CONN(conn));
}
memset(conn, 0xAA, sizeof(connection_t)); /* poison memory */
- tor_free(conn);
+ tor_free(mem);
}
/** Make sure <b>conn</b> isn't in any of the global conn lists; then free it.
@@ -259,12 +335,12 @@ connection_free(connection_t *conn)
if (connection_speaks_cells(conn)) {
if (conn->state == OR_CONN_STATE_OPEN)
directory_set_dirty();
- if (!tor_digest_is_zero(conn->identity_digest)) {
- connection_or_remove_from_identity_map(conn);
+ if (!tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest)) {
+ connection_or_remove_from_identity_map(TO_OR_CONN(conn));
}
}
if (conn->type == CONN_TYPE_CONTROL) {
- conn->event_mask = 0;
+ TO_CONTROL_CONN(conn)->event_mask = 0;
control_update_global_event_mask();
}
connection_unregister(conn);
@@ -290,7 +366,7 @@ connection_free_all(void)
/* We don't want to log any messages to controllers. */
for (i=0;i<n;i++)
if (carray[i]->type == CONN_TYPE_CONTROL)
- carray[i]->event_mask = 0;
+ TO_CONTROL_CONN(carray[i])->event_mask = 0;
control_update_global_event_mask();
/* Unlink everything from the identity map. */
@@ -319,11 +395,14 @@ void
connection_about_to_close_connection(connection_t *conn)
{
circuit_t *circ;
+ dir_connection_t *dir_conn;
+ or_connection_t *or_conn;
+ edge_connection_t *edge_conn;
assert(conn->marked_for_close);
if (CONN_IS_EDGE(conn)) {
- if (!conn->has_sent_end) {
+ if (!conn->edge_has_sent_end) {
log_warn(LD_BUG, "Harmless bug: Edge connection (marked at %s:%d) "
"hasn't sent end yet?",
conn->marked_for_close_file, conn->marked_for_close);
@@ -333,23 +412,25 @@ connection_about_to_close_connection(connection_t *conn)
switch (conn->type) {
case CONN_TYPE_DIR:
+ dir_conn = TO_DIR_CONN(conn);
if (conn->state < DIR_CONN_STATE_CLIENT_FINISHED) {
/* It's a directory connection and connecting or fetching
* failed: forget about this router, and maybe try again. */
- connection_dir_request_failed(conn);
+ connection_dir_request_failed(dir_conn);
// XXX if it's rend desc we may want to retry -RD
}
if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC)
- rend_client_desc_here(conn->rend_query); /* give it a try */
+ rend_client_desc_here(dir_conn->rend_query); /* give it a try */
break;
case CONN_TYPE_OR:
+ or_conn = TO_OR_CONN(conn);
/* Remember why we're closing this connection. */
if (conn->state != OR_CONN_STATE_OPEN) {
- if (connection_or_nonopen_was_started_here(conn)) {
- rep_hist_note_connect_failed(conn->identity_digest, time(NULL));
- entry_guard_set_status(conn->identity_digest, 0);
- router_set_status(conn->identity_digest, 0);
- control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
+ if (connection_or_nonopen_was_started_here(or_conn)) {
+ rep_hist_note_connect_failed(or_conn->identity_digest, time(NULL));
+ entry_guard_set_status(or_conn->identity_digest, 0);
+ router_set_status(or_conn->identity_digest, 0);
+ control_event_or_conn_status(or_conn, OR_CONN_EVENT_FAILED);
}
} else if (conn->hold_open_until_flushed) {
/* XXXX009 We used to have an arg that told us whether we closed the
@@ -361,30 +442,32 @@ connection_about_to_close_connection(connection_t *conn)
* flushing still get noted as dead, not disconnected. But this is an
* improvement. -NM
*/
- rep_hist_note_disconnect(conn->identity_digest, time(NULL));
- control_event_or_conn_status(conn, OR_CONN_EVENT_CLOSED);
- } else if (conn->identity_digest) {
- rep_hist_note_connection_died(conn->identity_digest, time(NULL));
- control_event_or_conn_status(conn, OR_CONN_EVENT_CLOSED);
+ rep_hist_note_disconnect(or_conn->identity_digest, time(NULL));
+ control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED);
+ } else if (or_conn->identity_digest) {
+ rep_hist_note_connection_died(or_conn->identity_digest, time(NULL));
+ control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED);
}
break;
case CONN_TYPE_AP:
- if (conn->socks_request->has_finished == 0) {
+ edge_conn = TO_EDGE_CONN(conn);
+ if (edge_conn->socks_request->has_finished == 0) {
/* since conn gets removed right after this function finishes,
* there's no point trying to send back a reply at this point. */
log_warn(LD_BUG,"Bug: Closing stream (marked at %s:%d) without sending"
" back a socks reply.",
conn->marked_for_close_file, conn->marked_for_close);
} else {
- control_event_stream_status(conn, STREAM_EVENT_CLOSED);
+ control_event_stream_status(edge_conn, STREAM_EVENT_CLOSED);
}
break;
case CONN_TYPE_EXIT:
+ edge_conn = TO_EDGE_CONN(conn);
if (conn->state == EXIT_CONN_STATE_RESOLVING) {
- circ = circuit_get_by_edge_conn(conn);
+ circ = circuit_get_by_edge_conn(edge_conn);
if (circ)
- circuit_detach_stream(circ, conn);
- connection_dns_remove(conn);
+ circuit_detach_stream(circ, edge_conn);
+ connection_dns_remove(edge_conn);
}
break;
case CONN_TYPE_DNSWORKER:
@@ -515,7 +598,7 @@ connection_create_listener(const char *listenaddress, uint16_t listenport,
#endif
memset(&listenaddr,0,sizeof(struct sockaddr_in));
- if (parse_addr_port(listenaddress, &address, &addr, &usePort)<0) {
+ if (parse_addr_port(LOG_WARN, listenaddress, &address, &addr, &usePort)<0) {
log_warn(LD_CONFIG,
"Error parsing/resolving ListenAddress %s", listenaddress);
return NULL;
@@ -534,10 +617,6 @@ connection_create_listener(const char *listenaddress, uint16_t listenport,
if (s < 0) {
log_warn(LD_NET,"Socket creation failed.");
goto err;
- } else if (!SOCKET_IS_POLLABLE(s)) {
- log_warn(LD_NET,"Too many connections; can't create pollable listener.");
- tor_close_socket(s);
- goto err;
}
#ifndef MS_WINDOWS
@@ -637,16 +716,8 @@ connection_handle_listener_read(connection_t *conn, int new_type)
memset(addrbuf, 0, sizeof(addrbuf));
news = accept(conn->s,(struct sockaddr *)&addrbuf,&remotelen);
- if (!SOCKET_IS_POLLABLE(news)) {
- /* accept() error, or too many conns to poll */
- int e;
- if (news>=0) {
- /* Too many conns to poll. */
- log_warn(LD_NET,"Too many connections; couldn't accept connection.");
- tor_close_socket(news);
- return 0;
- }
- e = tor_socket_errno(conn->s);
+ if (news < 0) { /* accept() error */
+ int e = tor_socket_errno(conn->s);
if (ERRNO_IS_ACCEPT_EAGAIN(e)) {
return 0; /* he hung up before we could accept(). that's fine. */
} else if (ERRNO_IS_ACCEPT_RESOURCE_LIMIT(e)) {
@@ -719,7 +790,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
return 0; /* no need to tear down the parent */
}
- if (connection_init_accepted_conn(newconn) < 0) {
+ if (connection_init_accepted_conn(newconn, conn->type) < 0) {
connection_mark_for_close(newconn);
return 0;
}
@@ -730,16 +801,23 @@ connection_handle_listener_read(connection_t *conn, int new_type)
* If conn is an OR, start the tls handshake.
*/
static int
-connection_init_accepted_conn(connection_t *conn)
+connection_init_accepted_conn(connection_t *conn, uint8_t listener_type)
{
connection_start_reading(conn);
switch (conn->type) {
case CONN_TYPE_OR:
- control_event_or_conn_status(conn, OR_CONN_EVENT_NEW);
- return connection_tls_start_handshake(conn, 1);
+ control_event_or_conn_status(TO_OR_CONN(conn), OR_CONN_EVENT_NEW);
+ return connection_tls_start_handshake(TO_OR_CONN(conn), 1);
case CONN_TYPE_AP:
- conn->state = AP_CONN_STATE_SOCKS_WAIT;
+ switch (listener_type) {
+ case CONN_TYPE_AP_LISTENER:
+ conn->state = AP_CONN_STATE_SOCKS_WAIT;
+ break;
+ case CONN_TYPE_AP_TRANS_LISTENER:
+ conn->state = AP_CONN_STATE_ORIGDST_WAIT;
+ break;
+ }
break;
case CONN_TYPE_DIR:
conn->purpose = DIR_PURPOSE_SERVER;
@@ -773,12 +851,6 @@ connection_connect(connection_t *conn, char *address,
log_warn(LD_NET,"Error creating network socket: %s",
tor_socket_strerror(tor_socket_errno(-1)));
return -1;
- } else if (!SOCKET_IS_POLLABLE(s)) {
- log_warn(LD_NET,
- "Too many connections; can't create pollable connection to %s",
- escaped_safe_str(address));
- tor_close_socket(s);
- return -1;
}
if (options->OutboundBindAddress) {
@@ -903,7 +975,7 @@ retry_listeners(int type, config_line_t *cfg,
{
char *address=NULL;
uint16_t port;
- if (! parse_addr_port(wanted->value, &address, NULL, &port)) {
+ if (!parse_addr_port(LOG_WARN, wanted->value, &address, NULL, &port)) {
int addr_matches = !strcasecmp(address, conn->address);
tor_free(address);
if (! port)
@@ -985,6 +1057,10 @@ retry_all_listeners(int force, smartlist_t *replaced_conns,
options->SocksPort, "127.0.0.1", force,
replaced_conns, new_conns, 0)<0)
return -1;
+ if (retry_listeners(CONN_TYPE_AP_TRANS_LISTENER, options->TransListenAddress,
+ options->TransPort, "127.0.0.1", force,
+ replaced_conns, new_conns, 0)<0)
+ return -1;
if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
options->ControlListenAddress,
options->ControlPort, "127.0.0.1", force,
@@ -1017,9 +1093,11 @@ connection_bucket_read_limit(connection_t *conn)
if (at_most > global_read_bucket)
at_most = global_read_bucket;
- if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN)
- if (at_most > conn->receiver_bucket)
- at_most = conn->receiver_bucket;
+ if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN) {
+ or_connection_t *or_conn = TO_OR_CONN(conn);
+ if (at_most > or_conn->receiver_bucket)
+ at_most = or_conn->receiver_bucket;
+ }
if (at_most < 0)
return 0;
@@ -1062,10 +1140,8 @@ static void
connection_read_bucket_decrement(connection_t *conn, int num_read)
{
global_read_bucket -= num_read;
- //tor_assert(global_read_bucket >= 0);
if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN) {
- conn->receiver_bucket -= num_read;
- //tor_assert(conn->receiver_bucket >= 0);
+ TO_OR_CONN(conn)->receiver_bucket -= num_read;
}
}
@@ -1082,7 +1158,7 @@ connection_consider_empty_buckets(connection_t *conn)
}
if (connection_speaks_cells(conn) &&
conn->state == OR_CONN_STATE_OPEN &&
- conn->receiver_bucket <= 0) {
+ TO_OR_CONN(conn)->receiver_bucket <= 0) {
LOG_FN_CONN(conn,
(LOG_DEBUG,LD_NET,"receiver bucket exhausted. Pausing."));
conn->wants_to_read = 1;
@@ -1090,8 +1166,7 @@ connection_consider_empty_buckets(connection_t *conn)
}
}
-/** Initialize the global read bucket to options->BandwidthBurst,
- * and current_time to the current time. */
+/** Initialize the global read bucket to options->BandwidthBurst. */
void
connection_bucket_init(void)
{
@@ -1109,6 +1184,9 @@ connection_bucket_refill(struct timeval *now)
connection_t *conn;
connection_t **carray;
or_options_t *options = get_options();
+ /* Not used, but it should be! We might have rolled over more than one
+ * second! XXXX */
+ (void) now;
/* refill the global buckets */
if (global_read_bucket < (int)options->BandwidthBurst) {
@@ -1125,10 +1203,15 @@ connection_bucket_refill(struct timeval *now)
for (i=0;i<n;i++) {
conn = carray[i];
- if (connection_receiver_bucket_should_increase(conn)) {
- conn->receiver_bucket = conn->bandwidth;
- //log_fn(LOG_DEBUG,"Receiver bucket %d now %d.", i,
- // conn->receiver_bucket);
+ if (connection_speaks_cells(conn)) {
+ or_connection_t *or_conn = TO_OR_CONN(conn);
+ if (connection_receiver_bucket_should_increase(or_conn)) {
+ or_conn->receiver_bucket += or_conn->bandwidthrate;
+ if (or_conn->receiver_bucket > or_conn->bandwidthburst)
+ or_conn->receiver_bucket = or_conn->bandwidthburst;
+ //log_fn(LOG_DEBUG,"Receiver bucket %d now %d.", i,
+ // conn->receiver_bucket);
+ }
}
if (conn->wants_to_read == 1 /* it's marked to turn reading back on now */
@@ -1137,7 +1220,7 @@ connection_bucket_refill(struct timeval *now)
* not the best place to check this.) */
&& (!connection_speaks_cells(conn) ||
conn->state != OR_CONN_STATE_OPEN ||
- conn->receiver_bucket > 0)) {
+ TO_OR_CONN(conn)->receiver_bucket > 0)) {
/* and either a non-cell conn or a cell conn with non-empty bucket */
LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET,"waking up conn (fd %d)",conn->s));
conn->wants_to_read = 0;
@@ -1154,16 +1237,13 @@ connection_bucket_refill(struct timeval *now)
* should add another pile of tokens to it?
*/
static int
-connection_receiver_bucket_should_increase(connection_t *conn)
+connection_receiver_bucket_should_increase(or_connection_t *conn)
{
tor_assert(conn);
- if (!connection_speaks_cells(conn))
- return 0; /* edge connections don't use receiver_buckets */
- if (conn->state != OR_CONN_STATE_OPEN)
+ if (conn->_base.state != OR_CONN_STATE_OPEN)
return 0; /* only open connections play the rate limiting game */
-
- if (conn->receiver_bucket >= conn->bandwidth)
+ if (conn->receiver_bucket >= conn->bandwidthburst)
return 0;
return 1;
@@ -1195,6 +1275,7 @@ connection_handle_read(connection_t *conn)
case CONN_TYPE_OR_LISTENER:
return connection_handle_listener_read(conn, CONN_TYPE_OR);
case CONN_TYPE_AP_LISTENER:
+ case CONN_TYPE_AP_TRANS_LISTENER:
return connection_handle_listener_read(conn, CONN_TYPE_AP);
case CONN_TYPE_DIR_LISTENER:
return connection_handle_listener_read(conn, CONN_TYPE_DIR);
@@ -1209,15 +1290,15 @@ loop_again:
/* There's a read error; kill the connection.*/
connection_close_immediate(conn); /* Don't flush; connection is dead. */
if (CONN_IS_EDGE(conn)) {
- connection_edge_end_errno(conn, conn->cpath_layer);
- if (conn->socks_request) /* broken, so don't send a socks reply back */
- conn->socks_request->has_finished = 1;
+ edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
+ connection_edge_end_errno(edge_conn, edge_conn->cpath_layer);
+ if (edge_conn->socks_request) /* broken, don't send a socks reply back */
+ edge_conn->socks_request->has_finished = 1;
}
connection_mark_for_close(conn);
return -1;
}
- if (CONN_IS_EDGE(conn) &&
- try_to_read != max_to_read) {
+ if (CONN_IS_EDGE(conn) && try_to_read != max_to_read) {
/* instruct it not to try to package partial cells. */
if (connection_process_inbuf(conn, 0) < 0) {
return -1;
@@ -1274,29 +1355,32 @@ connection_read_to_buf(connection_t *conn, int *max_to_read)
if (connection_speaks_cells(conn) &&
conn->state > OR_CONN_STATE_PROXY_READING) {
int pending;
+ or_connection_t *or_conn = TO_OR_CONN(conn);
if (conn->state == OR_CONN_STATE_HANDSHAKING) {
/* continue handshaking even if global token bucket is empty */
- return connection_tls_continue_handshake(conn);
+ return connection_tls_continue_handshake(or_conn);
}
log_debug(LD_NET,
"%d: starting, inbuf_datalen %d (%d pending in tls object)."
" at_most %d.",
conn->s,(int)buf_datalen(conn->inbuf),
- tor_tls_get_pending_bytes(conn->tls), at_most);
+ tor_tls_get_pending_bytes(or_conn->tls), at_most);
/* else open, or closing */
- result = read_to_buf_tls(conn->tls, at_most, conn->inbuf);
+ result = read_to_buf_tls(or_conn->tls, at_most, conn->inbuf);
switch (result) {
case TOR_TLS_CLOSE:
log_info(LD_NET,"TLS connection closed on read. Closing. "
"(Nickname %s, address %s",
- conn->nickname ? conn->nickname : "not set", conn->address);
+ or_conn->nickname ? or_conn->nickname : "not set",
+ conn->address);
return -1;
case TOR_TLS_ERROR:
log_info(LD_NET,"tls error. breaking (nickname %s, address %s).",
- conn->nickname ? conn->nickname : "not set", conn->address);
+ or_conn->nickname ? or_conn->nickname : "not set",
+ conn->address);
return -1;
case TOR_TLS_WANTWRITE:
connection_start_writing(conn);
@@ -1308,12 +1392,12 @@ connection_read_to_buf(connection_t *conn, int *max_to_read)
default:
break;
}
- pending = tor_tls_get_pending_bytes(conn->tls);
+ pending = tor_tls_get_pending_bytes(or_conn->tls);
if (pending) {
/* XXXX If we have any pending bytes, read them now. This *can*
* take us over our read allotment, but really we shouldn't be
* believing that SSL bytes are the same as TCP bytes anyway. */
- int r2 = read_to_buf_tls(conn->tls, pending, conn->inbuf);
+ int r2 = read_to_buf_tls(or_conn->tls, pending, conn->inbuf);
if (r2<0) {
log_warn(LD_BUG, "Bug: apparently, reading pending bytes can fail.");
return -1;
@@ -1323,9 +1407,11 @@ connection_read_to_buf(connection_t *conn, int *max_to_read)
}
} else {
+ int reached_eof = 0;
CONN_LOG_PROTECT(conn,
- result = read_to_buf(conn->s, at_most, conn->inbuf,
- &conn->inbuf_reached_eof));
+ result = read_to_buf(conn->s, at_most, conn->inbuf, &reached_eof));
+ if (reached_eof)
+ conn->inbuf_reached_eof = 1;
// log_fn(LOG_DEBUG,"read_to_buf returned %d.",read_result);
@@ -1418,7 +1504,8 @@ connection_handle_write(connection_t *conn)
log_warn(LD_BUG,
"getsockopt() syscall failed?! Please report to tor-ops.");
if (CONN_IS_EDGE(conn))
- connection_edge_end_errno(conn, conn->cpath_layer);
+ connection_edge_end_errno(TO_EDGE_CONN(conn),
+ TO_EDGE_CONN(conn)->cpath_layer);
connection_mark_for_close(conn);
return -1;
}
@@ -1427,7 +1514,8 @@ connection_handle_write(connection_t *conn)
if (!ERRNO_IS_CONN_EINPROGRESS(e)) {
log_info(LD_NET,"in-progress connect failed. Removing.");
if (CONN_IS_EDGE(conn))
- connection_edge_end_errno(conn, conn->cpath_layer);
+ connection_edge_end_errno(TO_EDGE_CONN(conn),
+ TO_EDGE_CONN(conn)->cpath_layer);
connection_close_immediate(conn);
connection_mark_for_close(conn);
@@ -1435,7 +1523,7 @@ connection_handle_write(connection_t *conn)
* ignores unrecognized routers
*/
if (conn->type == CONN_TYPE_OR && !get_options()->HttpsProxy)
- router_set_status(conn->identity_digest, 0);
+ router_set_status(TO_OR_CONN(conn)->identity_digest, 0);
return -1;
} else {
return 0; /* no change, see if next time is better */
@@ -1450,9 +1538,10 @@ connection_handle_write(connection_t *conn)
if (connection_speaks_cells(conn) &&
conn->state > OR_CONN_STATE_PROXY_READING) {
+ or_connection_t *or_conn = TO_OR_CONN(conn);
if (conn->state == OR_CONN_STATE_HANDSHAKING) {
connection_stop_writing(conn);
- if (connection_tls_continue_handshake(conn) < 0) {
+ if (connection_tls_continue_handshake(or_conn) < 0) {
/* Don't flush; connection is dead. */
connection_close_immediate(conn);
connection_mark_for_close(conn);
@@ -1462,7 +1551,7 @@ connection_handle_write(connection_t *conn)
}
/* else open, or closing */
- result = flush_buf_tls(conn->tls, conn->outbuf,
+ result = flush_buf_tls(or_conn->tls, conn->outbuf,
max_to_write, &conn->outbuf_flushlen);
switch (result) {
case TOR_TLS_ERROR:
@@ -1500,7 +1589,8 @@ connection_handle_write(connection_t *conn)
max_to_write, &conn->outbuf_flushlen));
if (result < 0) {
if (CONN_IS_EDGE(conn))
- connection_edge_end_errno(conn, conn->cpath_layer);
+ connection_edge_end_errno(TO_EDGE_CONN(conn),
+ TO_EDGE_CONN(conn)->cpath_layer);
connection_close_immediate(conn); /* Don't flush; connection is dead. */
connection_mark_for_close(conn);
@@ -1508,9 +1598,13 @@ connection_handle_write(connection_t *conn)
}
}
- if (result > 0 && !is_local_IP(conn->addr)) { /* remember it */
- rep_hist_note_bytes_written(result, now);
- global_write_bucket -= result;
+ if (result > 0) {
+ if (!is_local_IP(conn->addr)) { /* remember it */
+ rep_hist_note_bytes_written(result, time(NULL));
+ global_write_bucket -= result;
+ }
+ if (connection_flushed_some(conn) < 0)
+ connection_mark_for_close(conn);
}
if (!connection_wants_to_flush(conn)) { /* it's done flushing */
@@ -1526,16 +1620,17 @@ connection_handle_write(connection_t *conn)
/* A controller event has just happened with such urgency that we
* need to write it onto controller <b>conn</b> immediately. */
void
-_connection_controller_force_write(connection_t *conn)
+_connection_controller_force_write(control_connection_t *control_conn)
{
/* XXX This is hideous code duplication, but raising it seems a little
* tricky for now. Think more about this one. We only call it for
* EVENT_ERR_MSG, so messing with buckets a little isn't such a big problem.
*/
int result;
- tor_assert(conn);
- tor_assert(!conn->tls);
- tor_assert(conn->type == CONN_TYPE_CONTROL);
+ connection_t *conn;
+ tor_assert(control_conn);
+ conn = TO_CONN(control_conn);
+
if (conn->marked_for_close || conn->s < 0)
return;
@@ -1548,9 +1643,13 @@ _connection_controller_force_write(connection_t *conn)
return;
}
- if (result > 0 && !is_local_IP(conn->addr)) { /* remember it */
- rep_hist_note_bytes_written(result, time(NULL));
- global_write_bucket -= result;
+ if (result > 0) {
+ if (!is_local_IP(conn->addr)) { /* remember it */
+ rep_hist_note_bytes_written(result, time(NULL));
+ global_write_bucket -= result;
+ }
+ if (connection_flushed_some(conn) < 0)
+ connection_mark_for_close(conn);
}
if (!connection_wants_to_flush(conn)) { /* it's done flushing */
@@ -1581,7 +1680,7 @@ connection_write_to_buf(const char *string, size_t len, connection_t *conn)
wrong compared to our max outbuf size. close the whole circuit. */
log_warn(LD_NET,
"write_to_buf failed. Closing circuit (fd %d).", conn->s);
- circuit_mark_for_close(circuit_get_by_edge_conn(conn),
+ circuit_mark_for_close(circuit_get_by_edge_conn(TO_EDGE_CONN(conn)),
END_CIRC_REASON_INTERNAL);
} else {
log_warn(LD_NET,
@@ -1595,13 +1694,45 @@ connection_write_to_buf(const char *string, size_t len, connection_t *conn)
conn->outbuf_flushlen += len;
}
+void
+connection_write_to_buf_zlib(dir_connection_t *dir_conn,
+ const char *data, size_t data_len,
+ int done)
+{
+ int r;
+ size_t old_datalen;
+ connection_t *conn;
+ if (!data_len)
+ return;
+ conn = TO_CONN(dir_conn);
+ /* if it's marked for close, only allow write if we mean to flush it */
+ if (conn->marked_for_close && !conn->hold_open_until_flushed)
+ return;
+
+ old_datalen = buf_datalen(conn->outbuf);
+ /* XXXX TOO much duplicate code! XXXX012NM */
+ CONN_LOG_PROTECT(conn, r = write_to_buf_zlib(
+ conn->outbuf, dir_conn->zlib_state,
+ data, data_len, done));
+ if (r < 0) {
+ log_warn(LD_NET,
+ "write_to_buf failed. Closing connection (fd %d).", conn->s);
+ connection_mark_for_close(conn);
+ return;
+ }
+
+ connection_start_writing(conn);
+ conn->outbuf_flushlen += buf_datalen(conn->outbuf) - old_datalen;
+}
+
/** Return the conn to addr/port that has the most recent
* timestamp_created, or NULL if no such conn exists. */
-connection_t *
+or_connection_t *
connection_or_exact_get_by_addr_port(uint32_t addr, uint16_t port)
{
int i, n;
- connection_t *conn, *best=NULL;
+ connection_t *conn;
+ or_connection_t *best=NULL;
connection_t **carray;
get_connection_array(&carray,&n);
@@ -1611,8 +1742,8 @@ connection_or_exact_get_by_addr_port(uint32_t addr, uint16_t port)
conn->addr == addr &&
conn->port == port &&
!conn->marked_for_close &&
- (!best || best->timestamp_created < conn->timestamp_created))
- best = conn;
+ (!best || best->_base.timestamp_created < conn->timestamp_created))
+ best = TO_OR_CONN(conn);
}
return best;
}
@@ -1644,7 +1775,7 @@ connection_get_by_type_addr_port_purpose(int type,
/** Return the connection with id <b>id</b> if it is not already marked for
* close.
*/
-connection_t *
+edge_connection_t *
connection_get_by_global_id(uint32_t id)
{
int i, n;
@@ -1654,9 +1785,9 @@ connection_get_by_global_id(uint32_t id)
get_connection_array(&carray,&n);
for (i=0;i<n;i++) {
conn = carray[i];
- if (conn->global_identifier == id) {
+ if (CONN_IS_EDGE(conn) && TO_EDGE_CONN(conn)->global_identifier == id) {
if (!conn->marked_for_close)
- return conn;
+ return TO_EDGE_CONN(conn);
else
return NULL;
}
@@ -1734,14 +1865,22 @@ connection_get_by_type_state_rendquery(int type, int state,
connection_t *conn;
connection_t **carray;
+ tor_assert(type == CONN_TYPE_DIR ||
+ type == CONN_TYPE_AP || type == CONN_TYPE_EXIT);
+
get_connection_array(&carray,&n);
for (i=0;i<n;i++) {
conn = carray[i];
if (conn->type == type &&
!conn->marked_for_close &&
- (!state || state == conn->state) &&
- !rend_cmp_service_ids(rendquery, conn->rend_query))
- return conn;
+ (!state || state == conn->state)) {
+ if (type == CONN_TYPE_DIR &&
+ rend_cmp_service_ids(rendquery, TO_DIR_CONN(conn)->rend_query))
+ return conn;
+ else if (CONN_IS_EDGE(conn) &&
+ rend_cmp_service_ids(rendquery, TO_EDGE_CONN(conn)->rend_query))
+ return conn;
+ }
}
return NULL;
}
@@ -1772,6 +1911,7 @@ connection_is_listener(connection_t *conn)
{
if (conn->type == CONN_TYPE_OR_LISTENER ||
conn->type == CONN_TYPE_AP_LISTENER ||
+ conn->type == CONN_TYPE_AP_TRANS_LISTENER ||
conn->type == CONN_TYPE_DIR_LISTENER ||
conn->type == CONN_TYPE_CONTROL_LISTENER)
return 1;
@@ -1859,7 +1999,7 @@ client_check_address_changed(int sock)
uint32_t *ip;
if (!last_interface_ip)
- get_interface_address(&last_interface_ip);
+ get_interface_address(LOG_INFO, &last_interface_ip);
if (!outgoing_addrs)
outgoing_addrs = smartlist_create();
@@ -1877,7 +2017,7 @@ client_check_address_changed(int sock)
/* Uh-oh. We haven't connected from this address before. Has the interface
* address changed? */
- if (get_interface_address(&iface_ip)<0)
+ if (get_interface_address(LOG_INFO, &iface_ip)<0)
return;
ip = tor_malloc(sizeof(uint32_t));
*ip = ip_out;
@@ -1911,18 +2051,19 @@ connection_process_inbuf(connection_t *conn, int package_partial)
switch (conn->type) {
case CONN_TYPE_OR:
- return connection_or_process_inbuf(conn);
+ return connection_or_process_inbuf(TO_OR_CONN(conn));
case CONN_TYPE_EXIT:
case CONN_TYPE_AP:
- return connection_edge_process_inbuf(conn, package_partial);
+ return connection_edge_process_inbuf(TO_EDGE_CONN(conn),
+ package_partial);
case CONN_TYPE_DIR:
- return connection_dir_process_inbuf(conn);
+ return connection_dir_process_inbuf(TO_DIR_CONN(conn));
case CONN_TYPE_DNSWORKER:
return connection_dns_process_inbuf(conn);
case CONN_TYPE_CPUWORKER:
return connection_cpu_process_inbuf(conn);
case CONN_TYPE_CONTROL:
- return connection_control_process_inbuf(conn);
+ return connection_control_process_inbuf(TO_CONTROL_CONN(conn));
default:
log_err(LD_BUG,"Bug: got unexpected conn type %d.", conn->type);
tor_fragile_assert();
@@ -1930,6 +2071,17 @@ connection_process_inbuf(connection_t *conn, int package_partial)
}
}
+/** Called whenever we've written data on a connection. */
+static int
+connection_flushed_some(connection_t *conn)
+{
+ if (conn->type == CONN_TYPE_DIR &&
+ conn->state == DIR_CONN_STATE_SERVER_WRITING)
+ return connection_dirserv_flushed_some(TO_DIR_CONN(conn));
+ else
+ return 0;
+}
+
/** We just finished flushing bytes from conn-\>outbuf, and there
* are no more bytes remaining.
*
@@ -1945,18 +2097,18 @@ connection_finished_flushing(connection_t *conn)
switch (conn->type) {
case CONN_TYPE_OR:
- return connection_or_finished_flushing(conn);
+ return connection_or_finished_flushing(TO_OR_CONN(conn));
case CONN_TYPE_AP:
case CONN_TYPE_EXIT:
- return connection_edge_finished_flushing(conn);
+ return connection_edge_finished_flushing(TO_EDGE_CONN(conn));
case CONN_TYPE_DIR:
- return connection_dir_finished_flushing(conn);
+ return connection_dir_finished_flushing(TO_DIR_CONN(conn));
case CONN_TYPE_DNSWORKER:
return connection_dns_finished_flushing(conn);
case CONN_TYPE_CPUWORKER:
return connection_cpu_finished_flushing(conn);
case CONN_TYPE_CONTROL:
- return connection_control_finished_flushing(conn);
+ return connection_control_finished_flushing(TO_CONTROL_CONN(conn));
default:
log_err(LD_BUG,"Bug: got unexpected conn type %d.", conn->type);
tor_fragile_assert();
@@ -1977,11 +2129,11 @@ connection_finished_connecting(connection_t *conn)
switch (conn->type)
{
case CONN_TYPE_OR:
- return connection_or_finished_connecting(conn);
+ return connection_or_finished_connecting(TO_OR_CONN(conn));
case CONN_TYPE_EXIT:
- return connection_edge_finished_connecting(conn);
+ return connection_edge_finished_connecting(TO_EDGE_CONN(conn));
case CONN_TYPE_DIR:
- return connection_dir_finished_connecting(conn);
+ return connection_dir_finished_connecting(TO_DIR_CONN(conn));
default:
log_err(LD_BUG,"Bug: got unexpected conn type %d.", conn->type);
tor_fragile_assert();
@@ -1995,18 +2147,18 @@ connection_reached_eof(connection_t *conn)
{
switch (conn->type) {
case CONN_TYPE_OR:
- return connection_or_reached_eof(conn);
+ return connection_or_reached_eof(TO_OR_CONN(conn));
case CONN_TYPE_AP:
case CONN_TYPE_EXIT:
- return connection_edge_reached_eof(conn);
+ return connection_edge_reached_eof(TO_EDGE_CONN(conn));
case CONN_TYPE_DIR:
- return connection_dir_reached_eof(conn);
+ return connection_dir_reached_eof(TO_DIR_CONN(conn));
case CONN_TYPE_DNSWORKER:
return connection_dns_reached_eof(conn);
case CONN_TYPE_CPUWORKER:
return connection_cpu_reached_eof(conn);
case CONN_TYPE_CONTROL:
- return connection_control_reached_eof(conn);
+ return connection_control_reached_eof(TO_CONTROL_CONN(conn));
default:
log_err(LD_BUG,"Bug: got unexpected conn type %d.", conn->type);
tor_fragile_assert();
@@ -2020,10 +2172,28 @@ connection_reached_eof(connection_t *conn)
void
assert_connection_ok(connection_t *conn, time_t now)
{
+ (void) now; /* XXXX unused. */
tor_assert(conn);
- tor_assert(conn->magic == CONNECTION_MAGIC);
tor_assert(conn->type >= _CONN_TYPE_MIN);
tor_assert(conn->type <= _CONN_TYPE_MAX);
+ switch (conn->type) {
+ case CONN_TYPE_OR:
+ tor_assert(conn->magic == OR_CONNECTION_MAGIC);
+ break;
+ case CONN_TYPE_AP:
+ case CONN_TYPE_EXIT:
+ tor_assert(conn->magic == EDGE_CONNECTION_MAGIC);
+ break;
+ case CONN_TYPE_DIR:
+ tor_assert(conn->magic == DIR_CONNECTION_MAGIC);
+ break;
+ case CONN_TYPE_CONTROL:
+ tor_assert(conn->magic == CONTROL_CONNECTION_MAGIC);
+ break;
+ default:
+ tor_assert(conn->magic == BASE_CONNECTION_MAGIC);
+ break;
+ }
if (conn->outbuf_flushlen > 0) {
tor_assert(connection_is_writing(conn) || conn->wants_to_write);
@@ -2032,7 +2202,7 @@ assert_connection_ok(connection_t *conn, time_t now)
if (conn->hold_open_until_flushed)
tor_assert(conn->marked_for_close);
- /* XXX check: wants_to_read, wants_to_write, s, poll_index,
+ /* XXX check: wants_to_read, wants_to_write, s, conn_array_index,
* marked_for_close. */
/* buffers */
@@ -2050,9 +2220,8 @@ assert_connection_ok(connection_t *conn, time_t now)
*/
#endif
- if (conn->type != CONN_TYPE_OR) {
- tor_assert(!conn->tls);
- } else {
+ if (conn->type == CONN_TYPE_OR) {
+ or_connection_t *or_conn = TO_OR_CONN(conn);
if (conn->state == OR_CONN_STATE_OPEN) {
/* tor_assert(conn->bandwidth > 0); */
/* the above isn't necessarily true: if we just did a TLS
@@ -2065,48 +2234,37 @@ assert_connection_ok(connection_t *conn, time_t now)
// tor_assert(conn->addr && conn->port);
tor_assert(conn->address);
if (conn->state > OR_CONN_STATE_PROXY_READING)
- tor_assert(conn->tls);
+ tor_assert(or_conn->tls);
}
- if (! CONN_IS_EDGE(conn)) {
- tor_assert(!conn->stream_id);
- tor_assert(!conn->next_stream);
- tor_assert(!conn->cpath_layer);
- tor_assert(!conn->package_window);
- tor_assert(!conn->deliver_window);
-#if 0
- tor_assert(!conn->done_sending);
- tor_assert(!conn->done_receiving);
-#endif
- } else {
+ if (CONN_IS_EDGE(conn)) {
+ edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
/* XXX unchecked: package window, deliver window. */
- }
- if (conn->type == CONN_TYPE_AP) {
- tor_assert(conn->socks_request);
- if (conn->state == AP_CONN_STATE_OPEN) {
- tor_assert(conn->socks_request->has_finished);
- if (!conn->marked_for_close) {
- tor_assert(conn->cpath_layer);
- assert_cpath_layer_ok(conn->cpath_layer);
+ if (conn->type == CONN_TYPE_AP) {
+
+ tor_assert(edge_conn->socks_request);
+ if (conn->state == AP_CONN_STATE_OPEN) {
+ tor_assert(edge_conn->socks_request->has_finished);
+ if (!conn->marked_for_close) {
+ tor_assert(edge_conn->cpath_layer);
+ assert_cpath_layer_ok(edge_conn->cpath_layer);
+ }
}
}
- } else {
- tor_assert(!conn->socks_request);
- }
- if (conn->type == CONN_TYPE_EXIT) {
- tor_assert(conn->purpose == EXIT_PURPOSE_CONNECT ||
- conn->purpose == EXIT_PURPOSE_RESOLVE);
+ if (conn->type == CONN_TYPE_EXIT) {
+ tor_assert(conn->purpose == EXIT_PURPOSE_CONNECT ||
+ conn->purpose == EXIT_PURPOSE_RESOLVE);
+ }
} else if (conn->type != CONN_TYPE_DIR) {
- tor_assert(!conn->purpose); /* only used for dir types currently */
- }
- if (conn->type != CONN_TYPE_DIR) {
- tor_assert(!conn->requested_resource);
+ /* Purpose is only used for dir and exit types currently */
+ tor_assert(!conn->purpose);
}
switch (conn->type)
{
case CONN_TYPE_OR_LISTENER:
case CONN_TYPE_AP_LISTENER:
+ case CONN_TYPE_AP_TRANS_LISTENER:
case CONN_TYPE_DIR_LISTENER:
case CONN_TYPE_CONTROL_LISTENER:
tor_assert(conn->state == LISTENER_STATE_READY);
@@ -2114,7 +2272,7 @@ assert_connection_ok(connection_t *conn, time_t now)
case CONN_TYPE_OR:
tor_assert(conn->state >= _OR_CONN_STATE_MIN);
tor_assert(conn->state <= _OR_CONN_STATE_MAX);
- tor_assert(conn->n_circuits >= 0);
+ tor_assert(TO_OR_CONN(conn)->n_circuits >= 0);
break;
case CONN_TYPE_EXIT:
tor_assert(conn->state >= _EXIT_CONN_STATE_MIN);
@@ -2125,7 +2283,7 @@ assert_connection_ok(connection_t *conn, time_t now)
case CONN_TYPE_AP:
tor_assert(conn->state >= _AP_CONN_STATE_MIN);
tor_assert(conn->state <= _AP_CONN_STATE_MAX);
- tor_assert(conn->socks_request);
+ tor_assert(TO_EDGE_CONN(conn)->socks_request);
break;
case CONN_TYPE_DIR:
tor_assert(conn->state >= _DIR_CONN_STATE_MIN);
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 902e0c009b..9ab672ff07 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -13,25 +13,37 @@ const char connection_edge_c_id[] =
#include "or.h"
+#ifdef HAVE_LINUX_NETFILTER_IPV4_H
+#include <linux/netfilter_ipv4.h>
+#define TRANS_NETFILTER
+#endif
+
+#if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H)
+#include <net/if.h>
+#include <net/pfvar.h>
+#define TRANS_PF
+#endif
+
/* List of exit_redirect_t */
static smartlist_t *redirect_exit_list = NULL;
-static int connection_ap_handshake_process_socks(connection_t *conn);
+static int connection_ap_handshake_process_socks(edge_connection_t *conn);
+static int connection_ap_process_transparent(edge_connection_t *conn);
/** An AP stream has failed/finished. If it hasn't already sent back
* a socks reply, send one now (based on endreason). Also set
* has_sent_end to 1, and mark the conn.
*/
void
-_connection_mark_unattached_ap(connection_t *conn, int endreason,
+_connection_mark_unattached_ap(edge_connection_t *conn, int endreason,
int line, const char *file)
{
- tor_assert(conn->type == CONN_TYPE_AP);
- conn->has_sent_end = 1; /* no circ yet */
+ tor_assert(conn->_base.type == CONN_TYPE_AP);
+ conn->_base.edge_has_sent_end = 1; /* no circ yet */
- if (conn->marked_for_close) {
+ if (conn->_base.marked_for_close) {
/* This call will warn as appropriate. */
- _connection_mark_for_close(conn, line, file);
+ _connection_mark_for_close(TO_CONN(conn), line, file);
return;
}
@@ -51,49 +63,36 @@ _connection_mark_unattached_ap(connection_t *conn, int endreason,
0, NULL, -1);
}
- _connection_mark_for_close(conn, line, file);
- conn->hold_open_until_flushed = 1;
+ _connection_mark_for_close(TO_CONN(conn), line, file);
+ conn->_base.hold_open_until_flushed = 1;
}
/** There was an EOF. Send an end and mark the connection for close.
*/
int
-connection_edge_reached_eof(connection_t *conn)
+connection_edge_reached_eof(edge_connection_t *conn)
{
-#ifdef HALF_OPEN
- /* eof reached; we're done reading, but we might want to write more. */
- conn->done_receiving = 1;
- shutdown(conn->s, 0); /* XXX check return, refactor NM */
- if (conn->done_sending) {
- connection_edge_end(conn, END_STREAM_REASON_DONE, conn->cpath_layer);
- connection_mark_for_close(conn);
- } else {
- connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
- RELAY_COMMAND_END,
- NULL, 0, conn->cpath_layer);
- }
- return 0;
-#else
- if (buf_datalen(conn->inbuf) && connection_state_is_open(conn)) {
+ if (buf_datalen(conn->_base.inbuf) &&
+ connection_state_is_open(TO_CONN(conn))) {
/* it still has stuff to process. don't let it die yet. */
return 0;
}
- log_info(LD_EDGE,"conn (fd %d) reached eof. Closing.", conn->s);
- if (!conn->marked_for_close) {
+ log_info(LD_EDGE,"conn (fd %d) reached eof. Closing.", conn->_base.s);
+ if (!conn->_base.marked_for_close) {
/* only mark it if not already marked. it's possible to
* get the 'end' right around when the client hangs up on us. */
connection_edge_end(conn, END_STREAM_REASON_DONE, conn->cpath_layer);
if (conn->socks_request) /* eof, so don't send a socks reply back */
conn->socks_request->has_finished = 1;
- connection_mark_for_close(conn);
+ connection_mark_for_close(TO_CONN(conn));
}
return 0;
-#endif
}
/** Handle new bytes on conn->inbuf based on state:
* - If it's waiting for socks info, try to read another step of the
* socks handshake out of conn->inbuf.
+ * - If it's waiting for the original destination, fetch it.
* - If it's open, then package more relay cells from the stream.
* - Else, leave the bytes on inbuf alone for now.
*
@@ -101,23 +100,28 @@ connection_edge_reached_eof(connection_t *conn)
* else return 0.
*/
int
-connection_edge_process_inbuf(connection_t *conn, int package_partial)
+connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
{
tor_assert(conn);
- tor_assert(CONN_IS_EDGE(conn));
- switch (conn->state) {
+ switch (conn->_base.state) {
case AP_CONN_STATE_SOCKS_WAIT:
if (connection_ap_handshake_process_socks(conn) < 0) {
/* already marked */
return -1;
}
return 0;
+ case AP_CONN_STATE_ORIGDST_WAIT:
+ if (connection_ap_process_transparent(conn) < 0) {
+ /* already marked */
+ return -1;
+ }
+ return 0;
case AP_CONN_STATE_OPEN:
case EXIT_CONN_STATE_OPEN:
if (connection_edge_package_raw_inbuf(conn, package_partial) < 0) {
/* (We already sent an end cell if possible) */
- connection_mark_for_close(conn);
+ connection_mark_for_close(TO_CONN(conn));
return -1;
}
return 0;
@@ -129,13 +133,13 @@ connection_edge_process_inbuf(connection_t *conn, int package_partial)
case AP_CONN_STATE_CONTROLLER_WAIT:
log_info(LD_EDGE,
"data from edge while in '%s' state. Leaving it on buffer.",
- conn_state_to_string(conn->type, conn->state));
+ conn_state_to_string(conn->_base.type, conn->_base.state));
return 0;
}
- log_warn(LD_BUG,"Bug: Got unexpected state %d. Closing.",conn->state);
+ log_warn(LD_BUG,"Bug: Got unexpected state %d. Closing.",conn->_base.state);
tor_fragile_assert();
connection_edge_end(conn, END_STREAM_REASON_INTERNAL, conn->cpath_layer);
- connection_mark_for_close(conn);
+ connection_mark_for_close(TO_CONN(conn));
return -1;
}
@@ -143,19 +147,18 @@ connection_edge_process_inbuf(connection_t *conn, int package_partial)
* Mark it for close and return 0.
*/
int
-connection_edge_destroy(uint16_t circ_id, connection_t *conn)
+connection_edge_destroy(uint16_t circ_id, edge_connection_t *conn)
{
- tor_assert(CONN_IS_EDGE(conn));
-
- if (!conn->marked_for_close) {
+ if (!conn->_base.marked_for_close) {
log_info(LD_EDGE,
"CircID %d: At an edge. Marking connection for close.", circ_id);
- if (conn->type == CONN_TYPE_AP) {
+ if (conn->_base.type == CONN_TYPE_AP) {
connection_mark_unattached_ap(conn, END_STREAM_REASON_DESTROY);
} else {
- conn->has_sent_end = 1; /* closing the circuit, nothing to send to */
- connection_mark_for_close(conn);
- conn->hold_open_until_flushed = 1;
+ /* closing the circuit, nothing to send an END to */
+ conn->_base.edge_has_sent_end = 1;
+ connection_mark_for_close(TO_CONN(conn));
+ conn->_base.hold_open_until_flushed = 1;
}
}
conn->cpath_layer = NULL;
@@ -172,45 +175,46 @@ connection_edge_destroy(uint16_t circ_id, connection_t *conn)
* else return 0.
*/
int
-connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_layer)
+connection_edge_end(edge_connection_t *conn, char reason,
+ crypt_path_t *cpath_layer)
{
char payload[RELAY_PAYLOAD_SIZE];
size_t payload_len=1;
circuit_t *circ;
- if (conn->has_sent_end) {
+ if (conn->_base.edge_has_sent_end) {
log_warn(LD_BUG,"Harmless bug: Calling connection_edge_end (reason %d) "
"on an already ended stream?", reason);
tor_fragile_assert();
return -1;
}
- if (conn->marked_for_close) {
+ if (conn->_base.marked_for_close) {
log_warn(LD_BUG,
"Bug: called on conn that's already marked for close at %s:%d.",
- conn->marked_for_close_file, conn->marked_for_close);
+ conn->_base.marked_for_close_file, conn->_base.marked_for_close);
return 0;
}
payload[0] = reason;
if (reason == END_STREAM_REASON_EXITPOLICY &&
!connection_edge_is_rendezvous_stream(conn)) {
- set_uint32(payload+1, htonl(conn->addr));
- /* XXXX fill with a real TTL! */
- set_uint32(payload+5, htonl(MAX_DNS_ENTRY_AGE));
+ set_uint32(payload+1, htonl(conn->_base.addr));
+ set_uint32(payload+5, htonl(dns_clip_ttl(conn->address_ttl)));
payload_len += 8;
}
circ = circuit_get_by_edge_conn(conn);
if (circ && !circ->marked_for_close) {
- log_debug(LD_EDGE,"Marking conn (fd %d) and sending end.",conn->s);
+ log_debug(LD_EDGE,"Marking conn (fd %d) and sending end.",conn->_base.s);
connection_edge_send_command(conn, circ, RELAY_COMMAND_END,
payload, payload_len, cpath_layer);
} else {
- log_debug(LD_EDGE,"Marking conn (fd %d); no circ to send end.",conn->s);
+ log_debug(LD_EDGE,"Marking conn (fd %d); no circ to send end.",
+ conn->_base.s);
}
- conn->has_sent_end = 1;
+ conn->_base.edge_has_sent_end = 1;
return 0;
}
@@ -219,11 +223,11 @@ connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_layer)
* an appropriate relay end cell to <b>cpath_layer</b>.
**/
int
-connection_edge_end_errno(connection_t *conn, crypt_path_t *cpath_layer)
+connection_edge_end_errno(edge_connection_t *conn, crypt_path_t *cpath_layer)
{
uint8_t reason;
tor_assert(conn);
- reason = (uint8_t)errno_to_end_reason(tor_socket_errno(conn->s));
+ reason = (uint8_t)errno_to_end_reason(tor_socket_errno(conn->_base.s));
return connection_edge_end(conn, reason, cpath_layer);
}
@@ -238,26 +242,26 @@ connection_edge_end_errno(connection_t *conn, crypt_path_t *cpath_layer)
* return 0.
*/
int
-connection_edge_finished_flushing(connection_t *conn)
+connection_edge_finished_flushing(edge_connection_t *conn)
{
tor_assert(conn);
- tor_assert(CONN_IS_EDGE(conn));
- switch (conn->state) {
+ switch (conn->_base.state) {
case AP_CONN_STATE_OPEN:
case EXIT_CONN_STATE_OPEN:
- connection_stop_writing(conn);
+ connection_stop_writing(TO_CONN(conn));
connection_edge_consider_sending_sendme(conn);
return 0;
case AP_CONN_STATE_SOCKS_WAIT:
+ case AP_CONN_STATE_ORIGDST_WAIT:
case AP_CONN_STATE_RENDDESC_WAIT:
case AP_CONN_STATE_CIRCUIT_WAIT:
case AP_CONN_STATE_CONNECT_WAIT:
case AP_CONN_STATE_CONTROLLER_WAIT:
- connection_stop_writing(conn);
+ connection_stop_writing(TO_CONN(conn));
return 0;
default:
- log_warn(LD_BUG,"BUG: called in unexpected state %d.", conn->state);
+ log_warn(LD_BUG,"BUG: called in unexpected state %d.",conn->_base.state);
tor_fragile_assert();
return -1;
}
@@ -268,13 +272,15 @@ connection_edge_finished_flushing(connection_t *conn)
* data, deliver 'CONNECTED' relay cells as appropriate, and check
* any pending data that may have been received. */
int
-connection_edge_finished_connecting(connection_t *conn)
+connection_edge_finished_connecting(edge_connection_t *edge_conn)
{
char valbuf[INET_NTOA_BUF_LEN];
+ connection_t *conn;
struct in_addr in;
- tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_EXIT);
+ tor_assert(edge_conn);
+ tor_assert(edge_conn->_base.type == CONN_TYPE_EXIT);
+ conn = TO_CONN(edge_conn);
tor_assert(conn->state == EXIT_CONN_STATE_CONNECTING);
in.s_addr = htonl(conn->addr);
@@ -288,23 +294,42 @@ connection_edge_finished_connecting(connection_t *conn)
* cells */
connection_start_writing(conn);
/* deliver a 'connected' relay cell back through the circuit. */
- if (connection_edge_is_rendezvous_stream(conn)) {
- if (connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
+ if (connection_edge_is_rendezvous_stream(edge_conn)) {
+ if (connection_edge_send_command(edge_conn,
+ circuit_get_by_edge_conn(edge_conn),
RELAY_COMMAND_CONNECTED, NULL, 0,
- conn->cpath_layer) < 0)
+ edge_conn->cpath_layer) < 0)
return 0; /* circuit is closed, don't continue */
} else {
char connected_payload[8];
set_uint32(connected_payload, htonl(conn->addr));
set_uint32(connected_payload+4,
- htonl(MAX_DNS_ENTRY_AGE)); /* XXXX fill with a real TTL */
- if (connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
- RELAY_COMMAND_CONNECTED, connected_payload, 8, conn->cpath_layer) < 0)
+ htonl(dns_clip_ttl(edge_conn->address_ttl)));
+ if (connection_edge_send_command(edge_conn,
+ circuit_get_by_edge_conn(edge_conn),
+ RELAY_COMMAND_CONNECTED,
+ connected_payload, 8,
+ edge_conn->cpath_layer) < 0)
return 0; /* circuit is closed, don't continue */
}
- tor_assert(conn->package_window > 0);
+ tor_assert(edge_conn->package_window > 0);
/* in case the server has written anything */
- return connection_edge_process_inbuf(conn, 1);
+ return connection_edge_process_inbuf(edge_conn, 1);
+}
+
+/** Define a schedule for how long to wait between retrying
+ * application connections. Rather than waiting a fixed amount of
+ * time between each retry, we wait only 5 seconds for the first,
+ * 10 seconds for the second, and 15 seconds for each retry after
+ * that. Hopefully this will improve the expected user experience. */
+static int
+compute_socks_timeout(edge_connection_t *conn)
+{
+ if (conn->num_socks_retries == 0)
+ return 5;
+ if (conn->num_socks_retries == 1)
+ return 10;
+ return 15;
}
/** Find all general-purpose AP streams waiting for a response that sent their
@@ -320,34 +345,37 @@ void
connection_ap_expire_beginning(void)
{
connection_t **carray;
- connection_t *conn;
+ edge_connection_t *conn;
circuit_t *circ;
const char *nickname;
int n, i;
time_t now = time(NULL);
or_options_t *options = get_options();
int severity;
+ int cutoff;
get_connection_array(&carray, &n);
for (i = 0; i < n; ++i) {
- conn = carray[i];
- if (conn->type != CONN_TYPE_AP)
+ if (carray[i]->type != CONN_TYPE_AP)
continue;
+ conn = TO_EDGE_CONN(carray[i]);
/* if it's an internal bridge connection, don't yell its status. */
- severity = (!conn->addr && !conn->port) ? LOG_INFO : LOG_NOTICE;
- if (conn->state == AP_CONN_STATE_CONTROLLER_WAIT) {
- if (now - conn->timestamp_lastread >= options->SocksTimeout) {
+ severity = (!conn->_base.addr && !conn->_base.port)
+ ? LOG_INFO : LOG_NOTICE;
+ if (conn->_base.state == AP_CONN_STATE_CONTROLLER_WAIT) {
+ if (now - conn->_base.timestamp_lastread >= options->SocksTimeout) {
log_fn(severity, LD_APP, "Closing unattached stream.");
connection_mark_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
}
continue;
}
- else if (conn->state != AP_CONN_STATE_RESOLVE_WAIT &&
- conn->state != AP_CONN_STATE_CONNECT_WAIT)
+ if (conn->_base.state != AP_CONN_STATE_RESOLVE_WAIT &&
+ conn->_base.state != AP_CONN_STATE_CONNECT_WAIT)
continue;
- if (now - conn->timestamp_lastread < 15)
+ cutoff = compute_socks_timeout(conn);
+ if (now - conn->_base.timestamp_lastread < cutoff)
continue;
circ = circuit_get_by_edge_conn(conn);
if (!circ) { /* it's vanished? */
@@ -357,11 +385,11 @@ connection_ap_expire_beginning(void)
continue;
}
if (circ->purpose == CIRCUIT_PURPOSE_C_REND_JOINED) {
- if (now - conn->timestamp_lastread > options->SocksTimeout) {
+ if (now - conn->_base.timestamp_lastread > options->SocksTimeout) {
log_fn(severity, LD_REND,
"Rend stream is %d seconds late. Giving up on address"
" '%s.onion'.",
- (int)(now - conn->timestamp_lastread),
+ (int)(now - conn->_base.timestamp_lastread),
safe_str(conn->socks_request->address));
connection_edge_end(conn, END_STREAM_REASON_TIMEOUT,
conn->cpath_layer);
@@ -370,26 +398,29 @@ connection_ap_expire_beginning(void)
continue;
}
tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL);
- nickname = build_state_get_exit_nickname(circ->build_state);
- log_fn(severity, LD_APP,
+ nickname = build_state_get_exit_nickname(
+ TO_ORIGIN_CIRCUIT(circ)->build_state);
+ log_fn(cutoff < 15 ? LOG_INFO : severity, LD_APP,
"We tried for %d seconds to connect to '%s' using exit '%s'."
" Retrying on a new circuit.",
- (int)(now - conn->timestamp_lastread),
+ (int)(now - conn->_base.timestamp_lastread),
safe_str(conn->socks_request->address),
nickname ? nickname : "*unnamed*");
/* send an end down the circuit */
connection_edge_end(conn, END_STREAM_REASON_TIMEOUT, conn->cpath_layer);
/* un-mark it as ending, since we're going to reuse it */
- conn->has_sent_end = 0;
+ conn->_base.edge_has_sent_end = 0;
/* kludge to make us not try this circuit again, yet to allow
* current streams on it to survive if they can: make it
* unattractive to use for new streams */
tor_assert(circ->timestamp_dirty);
circ->timestamp_dirty -= options->MaxCircuitDirtiness;
- /* give our stream another 15 seconds to try */
- conn->timestamp_lastread += 15;
+ /* give our stream another 'cutoff' seconds to try */
+ conn->_base.timestamp_lastread += cutoff;
+ if (conn->num_socks_retries < 250) /* avoid overflow */
+ conn->num_socks_retries++;
/* move it back into 'pending' state, and try to attach. */
- if (connection_ap_detach_retriable(conn, circ)<0) {
+ if (connection_ap_detach_retriable(conn, TO_ORIGIN_CIRCUIT(circ))<0) {
connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
}
} /* end for */
@@ -403,6 +434,7 @@ connection_ap_attach_pending(void)
{
connection_t **carray;
connection_t *conn;
+ edge_connection_t *edge_conn;
int n, i;
get_connection_array(&carray, &n);
@@ -413,8 +445,9 @@ connection_ap_attach_pending(void)
conn->type != CONN_TYPE_AP ||
conn->state != AP_CONN_STATE_CIRCUIT_WAIT)
continue;
- if (connection_ap_handshake_attach_circuit(conn) < 0) {
- connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
+ edge_conn = TO_EDGE_CONN(conn);
+ if (connection_ap_handshake_attach_circuit(edge_conn) < 0) {
+ connection_mark_unattached_ap(edge_conn, END_STREAM_REASON_CANT_ATTACH);
}
}
}
@@ -427,17 +460,17 @@ connection_ap_attach_pending(void)
* Returns -1 on err, 1 on success, 0 on not-yet-sure.
*/
int
-connection_ap_detach_retriable(connection_t *conn, circuit_t *circ)
+connection_ap_detach_retriable(edge_connection_t *conn, origin_circuit_t *circ)
{
control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE);
- conn->timestamp_lastread = time(NULL);
+ conn->_base.timestamp_lastread = time(NULL);
if (! get_options()->LeaveStreamsUnattached) {
- conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
- circuit_detach_stream(circ,conn);
+ conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
+ circuit_detach_stream(TO_CIRCUIT(circ),conn);
return connection_ap_handshake_attach_circuit(conn);
} else {
- conn->state = AP_CONN_STATE_CONTROLLER_WAIT;
- circuit_detach_stream(circ,conn);
+ conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
+ circuit_detach_stream(TO_CIRCUIT(circ),conn);
return 0;
}
}
@@ -612,9 +645,9 @@ addressmap_rewrite(char *address, size_t maxlen)
/** Return 1 if <b>address</b> is already registered, else return 0 */
int
-addressmap_already_mapped(const char *address)
+addressmap_have_mapping(const char *address)
{
- return strmap_get(addressmap, address) ? 1 : 0;
+ return strmap_get_lc(addressmap, address) ? 1 : 0;
}
/** Register a request to map <b>address</b> to <b>new_address</b>,
@@ -682,7 +715,7 @@ client_dns_incr_failures(const char *address)
addressmap_entry_t *ent = strmap_get(addressmap, address);
if (!ent) {
ent = tor_malloc_zero(sizeof(addressmap_entry_t));
- ent->expires = time(NULL)+MAX_DNS_ENTRY_AGE;
+ ent->expires = time(NULL) + MAX_DNS_ENTRY_AGE;
strmap_set(addressmap,address,ent);
}
++ent->num_resolve_failures;
@@ -712,7 +745,7 @@ client_dns_clear_failures(const char *address)
* ".exitname.exit" before registering the mapping.
*
* If <b>ttl</b> is nonnegative, the mapping will be valid for
- * <b>ttl</b>seconds.
+ * <b>ttl</b>seconds; otherwise, we use the default.
*/
void
client_dns_set_addressmap(const char *address, uint32_t val,
@@ -726,10 +759,13 @@ client_dns_set_addressmap(const char *address, uint32_t val,
char extendedval[INET_NTOA_BUF_LEN+MAX_HEX_NICKNAME_LEN+10];
char valbuf[INET_NTOA_BUF_LEN];
- tor_assert(address); tor_assert(val);
+ tor_assert(address);
+ tor_assert(val);
- if (ttl<0 || ttl>MAX_DNS_ENTRY_AGE)
- ttl = MAX_DNS_ENTRY_AGE;
+ if (ttl<0)
+ ttl = DEFAULT_DNS_TTL;
+ else
+ ttl = dns_clip_ttl(ttl);
if (tor_inet_aton(address, &in))
return; /* If address was an IP address already, don't add a mapping. */
@@ -1005,8 +1041,8 @@ addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
* rendezvous descriptor is already here and fresh enough).
*/
int
-connection_ap_handshake_rewrite_and_attach(connection_t *conn,
- circuit_t *circ)
+connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
+ origin_circuit_t *circ)
{
socks_request_t *socks = conn->socks_request;
hostname_type_t addresstype;
@@ -1105,7 +1141,7 @@ connection_ap_handshake_rewrite_and_attach(connection_t *conn,
return 0;
}
rep_hist_note_used_resolve(time(NULL)); /* help predict this next time */
- } else { /* socks->command == SOCKS_COMMAND_CONNECT */
+ } else if (socks->command == SOCKS_COMMAND_CONNECT) {
if (socks->port == 0) {
log_notice(LD_APP,"Application asked to connect to port 0. Refusing.");
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
@@ -1124,13 +1160,20 @@ connection_ap_handshake_rewrite_and_attach(connection_t *conn,
routers with this nickname */
conn->chosen_exit_name =
tor_strdup(hex_str(r->cache_info.identity_digest, DIGEST_LEN));
+ conn->_base.chosen_exit_optional = 1;
}
}
/* help predict this next time */
rep_hist_note_used_port(socks->port, time(NULL));
+ } else if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) {
+ // XXXX NM Do anything here?
+
+ rep_hist_note_used_resolve(time(NULL)); /* help predict this next time */
+ } else {
+ tor_fragile_assert();
}
- conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
+ conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
if ((circ &&
connection_ap_handshake_attach_chosen_circuit(conn, circ) < 0) ||
(!circ &&
@@ -1144,7 +1187,7 @@ connection_ap_handshake_rewrite_and_attach(connection_t *conn,
rend_cache_entry_t *entry;
int r;
- if (socks->command == SOCKS_COMMAND_RESOLVE) {
+ if (socks->command != SOCKS_COMMAND_CONNECT) {
/* if it's a resolve request, fail it right now, rather than
* building all the circuits and then realizing it won't work. */
log_warn(LD_APP,
@@ -1175,21 +1218,21 @@ connection_ap_handshake_rewrite_and_attach(connection_t *conn,
return -1;
}
if (r==0) {
- conn->state = AP_CONN_STATE_RENDDESC_WAIT;
+ conn->_base.state = AP_CONN_STATE_RENDDESC_WAIT;
log_info(LD_REND, "Unknown descriptor %s. Fetching.",
safe_str(conn->rend_query));
rend_client_refetch_renddesc(conn->rend_query);
} else { /* r > 0 */
#define NUM_SECONDS_BEFORE_REFETCH (60*15)
if (time(NULL) - entry->received < NUM_SECONDS_BEFORE_REFETCH) {
- conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
+ conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
log_info(LD_REND, "Descriptor is here and fresh enough. Great.");
if (connection_ap_handshake_attach_circuit(conn) < 0) {
connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
return -1;
}
} else {
- conn->state = AP_CONN_STATE_RENDDESC_WAIT;
+ conn->_base.state = AP_CONN_STATE_RENDDESC_WAIT;
log_info(LD_REND, "Stale descriptor %s. Refetching.",
safe_str(conn->rend_query));
rend_client_refetch_renddesc(conn->rend_query);
@@ -1200,6 +1243,108 @@ connection_ap_handshake_rewrite_and_attach(connection_t *conn,
return 0; /* unreached but keeps the compiler happy */
}
+#ifdef TRANS_PF
+static int pf_socket = -1;
+static int
+get_pf_socket(void)
+{
+ int pf;
+ /* Ideally, this should be opened before dropping privs. */
+ if (pf_socket >= 0)
+ return pf_socket;
+
+#ifdef OPENBSD
+ /* only works on OpenBSD */
+ pf = open("/dev/pf", O_RDONLY);
+#else
+ /* works on NetBSD and FreeBSD */
+ pf = open("/dev/pf", O_RDWR);
+#endif
+
+ if (pf < 0) {
+ log_warn(LD_NET, "open(\"/dev/pf\") failed: %s", strerror(errno));
+ return -1;
+ }
+
+ pf_socket = pf;
+}
+#endif
+
+/** Fetch the original destination address and port from a
+ * system-specific interface and put them into a
+ * socks_request_t as if they came from a socks request.
+ *
+ * Return -1 if an error prevents fetching the destination,
+ * else return 0.
+ */
+static int
+connection_ap_get_original_destination(edge_connection_t *conn,
+ socks_request_t *req)
+{
+#ifdef TRANS_NETFILTER
+ /* Linux 2.4+ */
+ struct sockaddr_in orig_dst;
+ socklen_t orig_dst_len = sizeof(orig_dst);
+ char tmpbuf[INET_NTOA_BUF_LEN];
+
+ if (getsockopt(conn->_base.s, SOL_IP, SO_ORIGINAL_DST,
+ (struct sockaddr*)&orig_dst, &orig_dst_len) < 0) {
+ int e = tor_socket_errno(conn->_base.s);
+ log_warn(LD_NET, "getsockopt() failed: %s", tor_socket_strerror(e));
+ return -1;
+ }
+
+ tor_inet_ntoa(&orig_dst.sin_addr, tmpbuf, sizeof(tmpbuf));
+ strlcpy(req->address, tmpbuf, sizeof(req->address));
+ req->port = ntohs(orig_dst.sin_port);
+
+ return 0;
+#elif defined(TRANS_PF)
+ struct sockaddr_in proxy_addr;
+ socklen_t proxy_addr_len = sizeof(proxy_addr);
+ char tmpbuf[INET_NTOA_BUF_LEN];
+ struct pfioc_natlook pnl;
+ int pf = -1;
+
+ if (getsockname(conn->_base.s, (struct sockaddr*)&proxy_addr,
+ &proxy_addr_len) < 0) {
+ int e = tor_socket_errno(conn->_base.s);
+ log_warn(LD_NET, "getsockname() failed: %s", tor_socket_strerror(e));
+ return -1;
+ }
+
+ memset(&pnl, 0, sizeof(pnl));
+ pnl.af = AF_INET;
+ pnl.proto = IPPROTO_TCP;
+ pnl.direction = PF_OUT;
+ pnl.saddr.v4.s_addr = htonl(conn->_base.addr);
+ pnl.sport = htons(conn->_base.port);
+ pnl.daddr.v4.s_addr = proxy_addr.sin_addr.s_addr;
+ pnl.dport = proxy_addr.sin_port;
+
+ pf = get_pf_socket();
+ if (pf<0)
+ return -1;
+
+ if (ioctl(pf, DIOCNATLOOK, &pnl) < 0) {
+ log_warn(LD_NET, "ioctl(DIOCNATLOOK) failed: %s", strerror(errno));
+ return -1;
+ }
+
+ tor_inet_ntoa(&pnl.rdaddr.v4, tmpbuf, sizeof(tmpbuf));
+ strlcpy(req->address, tmpbuf, sizeof(req->address));
+ req->port = ntohs(pnl.rdport);
+
+ return 0;
+#else
+ (void)conn;
+ (void)req;
+ log_warn(LD_BUG, "Called connection_ap_get_original_destination, but no "
+ "transparent proxy method was configured.");
+ return -1;
+#endif
+}
+
/** connection_edge_process_inbuf() found a conn in state
* socks_wait. See if conn->inbuf has the right bytes to proceed with
* the socks handshake.
@@ -1211,25 +1356,25 @@ connection_ap_handshake_rewrite_and_attach(connection_t *conn,
* for close), else return 0.
*/
static int
-connection_ap_handshake_process_socks(connection_t *conn)
+connection_ap_handshake_process_socks(edge_connection_t *conn)
{
socks_request_t *socks;
int sockshere;
or_options_t *options = get_options();
tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_AP);
- tor_assert(conn->state == AP_CONN_STATE_SOCKS_WAIT);
+ tor_assert(conn->_base.type == CONN_TYPE_AP);
+ tor_assert(conn->_base.state == AP_CONN_STATE_SOCKS_WAIT);
tor_assert(conn->socks_request);
socks = conn->socks_request;
log_debug(LD_APP,"entered.");
- sockshere = fetch_from_buf_socks(conn->inbuf, socks,
+ sockshere = fetch_from_buf_socks(conn->_base.inbuf, socks,
options->TestSocks, options->SafeSocks);
if (sockshere == 0) {
if (socks->replylen) {
- connection_write_to_buf(socks->reply, socks->replylen, conn);
+ connection_write_to_buf(socks->reply, socks->replylen, TO_CONN(conn));
/* zero it out so we can do another round of negotiation */
socks->replylen = 0;
} else {
@@ -1256,7 +1401,49 @@ connection_ap_handshake_process_socks(connection_t *conn)
control_event_stream_status(conn, STREAM_EVENT_NEW_RESOLVE);
if (options->LeaveStreamsUnattached) {
- conn->state = AP_CONN_STATE_CONTROLLER_WAIT;
+ conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
+ return 0;
+ }
+ return connection_ap_handshake_rewrite_and_attach(conn, NULL);
+}
+
+/** connection_edge_process_inbuf() found a conn in state
+ * origdst_wait. Get the original destination and
+ * send it to connection_ap_handshake_rewrite_and_attach().
+ *
+ * Return -1 if an unexpected error with conn (and it should be marked
+ * for close), else return 0.
+ */
+static int
+connection_ap_process_transparent(edge_connection_t *conn)
+{
+ socks_request_t *socks;
+ or_options_t *options = get_options();
+
+ tor_assert(conn);
+ tor_assert(conn->_base.type == CONN_TYPE_AP);
+ tor_assert(conn->_base.state == AP_CONN_STATE_ORIGDST_WAIT);
+ tor_assert(conn->socks_request);
+ socks = conn->socks_request;
+
+ /* pretend that a socks handshake completed so we don't try to
+ * send a socks reply down a transparent conn */
+ socks->command = SOCKS_COMMAND_CONNECT;
+ socks->has_finished = 1;
+
+ log_debug(LD_APP,"entered.");
+
+ if (connection_ap_get_original_destination(conn, socks) < 0) {
+ log_warn(LD_APP,"Fetching original destination failed. Closing.");
+ connection_mark_unattached_ap(conn, 0);
+ return -1;
+ }
+ /* we have the original destination */
+
+ control_event_stream_status(conn, STREAM_EVENT_NEW);
+
+ if (options->LeaveStreamsUnattached) {
+ conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
return 0;
}
return connection_ap_handshake_rewrite_and_attach(conn, NULL);
@@ -1266,9 +1453,9 @@ connection_ap_handshake_process_socks(connection_t *conn)
* already in use; return it. Return 0 if can't get a unique stream_id.
*/
static uint16_t
-get_unique_stream_id_by_circ(circuit_t *circ)
+get_unique_stream_id_by_circ(origin_circuit_t *circ)
{
- connection_t *tmpconn;
+ edge_connection_t *tmpconn;
uint16_t test_stream_id;
uint32_t attempts=0;
@@ -1293,24 +1480,25 @@ again:
* If ap_conn is broken, mark it for close and return -1. Else return 0.
*/
int
-connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
+connection_ap_handshake_send_begin(edge_connection_t *ap_conn,
+ origin_circuit_t *circ)
{
char payload[CELL_PAYLOAD_SIZE];
int payload_len;
- tor_assert(ap_conn->type == CONN_TYPE_AP);
- tor_assert(ap_conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
+ tor_assert(ap_conn->_base.type == CONN_TYPE_AP);
+ tor_assert(ap_conn->_base.state == AP_CONN_STATE_CIRCUIT_WAIT);
tor_assert(ap_conn->socks_request);
ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
if (ap_conn->stream_id==0) {
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
- circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
return -1;
}
tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d",
- (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL) ?
+ (circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL) ?
ap_conn->socks_request->address : "",
ap_conn->socks_request->port);
payload_len = strlen(payload)+1;
@@ -1318,16 +1506,17 @@ connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
log_debug(LD_APP,
"Sending relay cell to begin stream %d.", ap_conn->stream_id);
- if (connection_edge_send_command(ap_conn, circ, RELAY_COMMAND_BEGIN,
+ if (connection_edge_send_command(ap_conn, TO_CIRCUIT(circ),
+ RELAY_COMMAND_BEGIN,
payload, payload_len,
ap_conn->cpath_layer) < 0)
return -1; /* circuit is closed, don't continue */
ap_conn->package_window = STREAMWINDOW_START;
ap_conn->deliver_window = STREAMWINDOW_START;
- ap_conn->state = AP_CONN_STATE_CONNECT_WAIT;
+ ap_conn->_base.state = AP_CONN_STATE_CONNECT_WAIT;
log_info(LD_APP,"Address/port sent, ap socket %d, n_circ_id %d",
- ap_conn->s, circ->n_circ_id);
+ ap_conn->_base.s, circ->_base.n_circ_id);
control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT);
return 0;
}
@@ -1338,38 +1527,62 @@ connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
* If ap_conn is broken, mark it for close and return -1. Else return 0.
*/
int
-connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ)
+connection_ap_handshake_send_resolve(edge_connection_t *ap_conn,
+ origin_circuit_t *circ)
{
- int payload_len;
+ int payload_len, command;
const char *string_addr;
+ char inaddr_buf[32];
- tor_assert(ap_conn->type == CONN_TYPE_AP);
- tor_assert(ap_conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
+ command = ap_conn->socks_request->command;
+
+ tor_assert(ap_conn->_base.type == CONN_TYPE_AP);
+ tor_assert(ap_conn->_base.state == AP_CONN_STATE_CIRCUIT_WAIT);
tor_assert(ap_conn->socks_request);
- tor_assert(ap_conn->socks_request->command == SOCKS_COMMAND_RESOLVE);
- tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL);
+ tor_assert(command == SOCKS_COMMAND_RESOLVE ||
+ command == SOCKS_COMMAND_RESOLVE_PTR);
+ tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL);
ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
if (ap_conn->stream_id==0) {
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
- circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
return -1;
}
- string_addr = ap_conn->socks_request->address;
- payload_len = strlen(string_addr)+1;
- tor_assert(payload_len <= RELAY_PAYLOAD_SIZE);
+ if (command == SOCKS_COMMAND_RESOLVE) {
+ string_addr = ap_conn->socks_request->address;
+ payload_len = strlen(string_addr)+1;
+ tor_assert(payload_len <= RELAY_PAYLOAD_SIZE);
+ } else {
+ struct in_addr in;
+ uint32_t a;
+ if (tor_inet_aton(ap_conn->socks_request->address, &in) == 0) {
+ connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
+ return -1;
+ }
+ a = ntohl(in.s_addr);
+ tor_snprintf(inaddr_buf, sizeof(inaddr_buf), "%d.%d.%d.%d.in-addr.arpa",
+ (int)(uint8_t)((a )&0xff),
+ (int)(uint8_t)((a>>8 )&0xff),
+ (int)(uint8_t)((a>>16)&0xff),
+ (int)(uint8_t)((a>>24)&0xff));
+ string_addr = inaddr_buf;
+ payload_len = strlen(inaddr_buf)+1;
+ tor_assert(payload_len <= RELAY_PAYLOAD_SIZE);
+ }
log_debug(LD_APP,
"Sending relay cell to begin stream %d.", ap_conn->stream_id);
- if (connection_edge_send_command(ap_conn, circ, RELAY_COMMAND_RESOLVE,
+ if (connection_edge_send_command(ap_conn, TO_CIRCUIT(circ),
+ RELAY_COMMAND_RESOLVE,
string_addr, payload_len, ap_conn->cpath_layer) < 0)
return -1; /* circuit is closed, don't continue */
- ap_conn->state = AP_CONN_STATE_RESOLVE_WAIT;
+ ap_conn->_base.state = AP_CONN_STATE_RESOLVE_WAIT;
log_info(LD_APP,"Address sent for resolve, ap socket %d, n_circ_id %d",
- ap_conn->s, circ->n_circ_id);
+ ap_conn->_base.s, circ->_base.n_circ_id);
control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE);
return 0;
}
@@ -1384,7 +1597,7 @@ int
connection_ap_make_bridge(char *address, uint16_t port)
{
int fd[2];
- connection_t *conn;
+ edge_connection_t *conn;
int err;
log_info(LD_APP,"Making AP bridge to %s:%d ...",safe_str(address),port);
@@ -1396,11 +1609,14 @@ connection_ap_make_bridge(char *address, uint16_t port)
return -1;
}
+ tor_assert(fd[0] >= 0);
+ tor_assert(fd[1] >= 0);
+
set_socket_nonblocking(fd[0]);
set_socket_nonblocking(fd[1]);
- conn = connection_new(CONN_TYPE_AP);
- conn->s = fd[0];
+ conn = TO_EDGE_CONN(connection_new(CONN_TYPE_AP));
+ conn->_base.s = fd[0];
/* populate conn->socks_request */
@@ -1412,18 +1628,18 @@ connection_ap_make_bridge(char *address, uint16_t port)
conn->socks_request->port = port;
conn->socks_request->command = SOCKS_COMMAND_CONNECT;
- conn->address = tor_strdup("(local bridge)");
- conn->addr = 0;
- conn->port = 0;
+ conn->_base.address = tor_strdup("(local bridge)");
+ conn->_base.addr = 0;
+ conn->_base.port = 0;
- if (connection_add(conn) < 0) { /* no space, forget it */
- connection_free(conn); /* this closes fd[0] */
+ if (connection_add(TO_CONN(conn)) < 0) { /* no space, forget it */
+ connection_free(TO_CONN(conn)); /* this closes fd[0] */
tor_close_socket(fd[1]);
return -1;
}
- conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
- connection_start_reading(conn);
+ conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
+ connection_start_reading(TO_CONN(conn));
/* attaching to a dirty circuit is fine */
if (connection_ap_handshake_attach_circuit(conn) < 0) {
@@ -1437,18 +1653,18 @@ connection_ap_make_bridge(char *address, uint16_t port)
}
/** Send an answer to an AP connection that has requested a DNS lookup
- * via SOCKS. The type should be one of RESOLVED_TYPE_(IPV4|IPV6) or
+ * via SOCKS. The type should be one of RESOLVED_TYPE_(IPV4|IPV6|HOSTNAME) or
* -1 for unreachable; the answer should be in the format specified
* in the socks extensions document.
**/
void
-connection_ap_handshake_socks_resolved(connection_t *conn,
+connection_ap_handshake_socks_resolved(edge_connection_t *conn,
int answer_type,
size_t answer_len,
const char *answer,
int ttl)
{
- char buf[256];
+ char buf[384];
size_t replylen;
if (answer_type == RESOLVED_TYPE_IPV4) {
@@ -1487,6 +1703,14 @@ connection_ap_handshake_socks_resolved(connection_t *conn,
memcpy(buf+4, answer, 16); /* address */
set_uint16(buf+20, 0); /* port == 0. */
replylen = 22;
+ } else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) {
+ buf[1] = SOCKS5_SUCCEEDED;
+ buf[2] = 0; /* reserved */
+ buf[3] = 0x03; /* Domainname address type */
+ buf[4] = (char)answer_len;
+ memcpy(buf+5, answer, answer_len); /* address */
+ set_uint16(buf+5+answer_len, 0); /* port == 0. */
+ replylen = 5+answer_len+2;
} else {
buf[1] = SOCKS5_HOST_UNREACHABLE;
memset(buf+2, 0, 8);
@@ -1509,9 +1733,10 @@ connection_ap_handshake_socks_resolved(connection_t *conn,
* If <b>reply</b> is undefined, <b>status</b> can't be 0.
*/
void
-connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
+connection_ap_handshake_socks_reply(edge_connection_t *conn, char *reply,
size_t replylen,
- socks5_reply_status_t status) {
+ socks5_reply_status_t status)
+{
char buf[256];
tor_assert(conn->socks_request); /* make sure it's an AP stream */
@@ -1524,7 +1749,7 @@ connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
return;
}
if (replylen) { /* we already have a reply in mind */
- connection_write_to_buf(reply, replylen, conn);
+ connection_write_to_buf(reply, replylen, TO_CONN(conn));
conn->socks_request->has_finished = 1;
return;
}
@@ -1534,7 +1759,7 @@ connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
#define SOCKS4_REJECT 91
buf[1] = (status==SOCKS5_SUCCEEDED ? SOCKS4_GRANTED : SOCKS4_REJECT);
/* leave version, destport, destip zero */
- connection_write_to_buf(buf, SOCKS4_NETWORK_LEN, conn);
+ connection_write_to_buf(buf, SOCKS4_NETWORK_LEN, TO_CONN(conn));
} else if (conn->socks_request->socks_version == 5) {
buf[0] = 5; /* version 5 */
buf[1] = (char)status;
@@ -1542,7 +1767,7 @@ connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
buf[3] = 1; /* ipv4 addr */
memset(buf+4,0,6); /* Set external addr/port to 0.
The spec doesn't seem to say what to do here. -RD */
- connection_write_to_buf(buf,10,conn);
+ connection_write_to_buf(buf,10,TO_CONN(conn));
}
/* If socks_version isn't 4 or 5, don't send anything.
* This can happen in the case of AP bridges. */
@@ -1569,7 +1794,7 @@ connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
int
connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
{
- connection_t *n_stream;
+ edge_connection_t *n_stream;
relay_header_t rh;
char *address=NULL;
uint16_t port;
@@ -1590,16 +1815,19 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
relay_header_unpack(&rh, cell->payload);
if (!memchr(cell->payload+RELAY_HEADER_SIZE, 0, rh.length)) {
- log_warn(LD_PROTOCOL,"relay begin cell has no \\0. Dropping.");
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Relay begin cell has no \\0. Dropping.");
return 0;
}
- if (parse_addr_port(cell->payload+RELAY_HEADER_SIZE,&address,NULL,&port)<0) {
- log_warn(LD_PROTOCOL,"Unable to parse addr:port in relay begin cell. "
- "Dropping.");
+ if (parse_addr_port(LOG_PROTOCOL_WARN, cell->payload+RELAY_HEADER_SIZE,
+ &address,NULL,&port)<0) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Unable to parse addr:port in relay begin cell. Dropping.");
return 0;
}
if (port==0) {
- log_warn(LD_PROTOCOL,"Missing port in relay begin cell. Dropping.");
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Missing port in relay begin cell. Dropping.");
tor_free(address);
return 0;
}
@@ -1614,29 +1842,30 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
#endif
log_debug(LD_EXIT,"Creating new exit connection.");
- n_stream = connection_new(CONN_TYPE_EXIT);
- n_stream->purpose = EXIT_PURPOSE_CONNECT;
+ n_stream = TO_EDGE_CONN(connection_new(CONN_TYPE_EXIT));
+ n_stream->_base.purpose = EXIT_PURPOSE_CONNECT;
n_stream->stream_id = rh.stream_id;
- n_stream->port = port;
+ n_stream->_base.port = port;
/* leave n_stream->s at -1, because it's not yet valid */
n_stream->package_window = STREAMWINDOW_START;
n_stream->deliver_window = STREAMWINDOW_START;
if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) {
+ origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
log_debug(LD_REND,"begin is for rendezvous. configuring stream.");
- n_stream->address = tor_strdup("(rendezvous)");
- n_stream->state = EXIT_CONN_STATE_CONNECTING;
- strlcpy(n_stream->rend_query, circ->rend_query,
+ n_stream->_base.address = tor_strdup("(rendezvous)");
+ n_stream->_base.state = EXIT_CONN_STATE_CONNECTING;
+ strlcpy(n_stream->rend_query, origin_circ->rend_query,
sizeof(n_stream->rend_query));
tor_assert(connection_edge_is_rendezvous_stream(n_stream));
assert_circuit_ok(circ);
- if (rend_service_set_connection_addr_port(n_stream, circ) < 0) {
+ if (rend_service_set_connection_addr_port(n_stream, origin_circ) < 0) {
log_info(LD_REND,"Didn't find rendezvous service (port %d)",
- n_stream->port);
+ n_stream->_base.port);
connection_edge_end(n_stream, END_STREAM_REASON_EXITPOLICY,
n_stream->cpath_layer);
- connection_free(n_stream);
+ connection_free(TO_CONN(n_stream));
/* knock the whole thing down, somebody screwed up */
circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
tor_free(address);
@@ -1644,12 +1873,12 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
}
assert_circuit_ok(circ);
log_debug(LD_REND,"Finished assigning addr/port");
- n_stream->cpath_layer = circ->cpath->prev; /* link it */
+ n_stream->cpath_layer = origin_circ->cpath->prev; /* link it */
/* add it into the linked list of n_streams on this circuit */
- n_stream->next_stream = circ->n_streams;
+ n_stream->next_stream = origin_circ->p_streams;
n_stream->on_circuit = circ;
- circ->n_streams = n_stream;
+ origin_circ->p_streams = n_stream;
assert_circuit_ok(circ);
connection_exit_connect(n_stream);
@@ -1657,27 +1886,29 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
return 0;
}
tor_strlower(address);
- n_stream->address = address;
- n_stream->state = EXIT_CONN_STATE_RESOLVEFAILED;
+ n_stream->_base.address = address;
+ n_stream->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
/* default to failed, change in dns_resolve if it turns out not to fail */
if (we_are_hibernating()) {
connection_edge_end(n_stream, END_STREAM_REASON_HIBERNATING,
n_stream->cpath_layer);
- connection_free(n_stream);
+ connection_free(TO_CONN(n_stream));
return 0;
}
+ log_debug(LD_EXIT,"about to start the dns_resolve().");
/* send it off to the gethostbyname farm */
switch (dns_resolve(n_stream)) {
case 1: /* resolve worked */
/* add it into the linked list of n_streams on this circuit */
- n_stream->next_stream = circ->n_streams;
+ n_stream->next_stream = TO_OR_CIRCUIT(circ)->n_streams;
n_stream->on_circuit = circ;
- circ->n_streams = n_stream;
+ TO_OR_CIRCUIT(circ)->n_streams = n_stream;
assert_circuit_ok(circ);
+ log_debug(LD_EXIT,"about to call connection_exit_connect().");
connection_exit_connect(n_stream);
return 0;
case -1: /* resolve failed */
@@ -1685,9 +1916,9 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
break;
case 0: /* resolve added to pending list */
/* add it into the linked list of resolving_streams on this circuit */
- n_stream->next_stream = circ->resolving_streams;
+ n_stream->next_stream = TO_OR_CIRCUIT(circ)->resolving_streams;
n_stream->on_circuit = circ;
- circ->resolving_streams = n_stream;
+ TO_OR_CIRCUIT(circ)->resolving_streams = n_stream;
assert_circuit_ok(circ);
;
}
@@ -1699,12 +1930,12 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
* begin resolving the hostname, and (eventually) reply with a RESOLVED cell.
*/
int
-connection_exit_begin_resolve(cell_t *cell, circuit_t *circ)
+connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ)
{
- connection_t *dummy_conn;
+ edge_connection_t *dummy_conn;
relay_header_t rh;
- assert_circuit_ok(circ);
+ assert_circuit_ok(TO_CIRCUIT(circ));
relay_header_unpack(&rh, cell->payload);
/* This 'dummy_conn' only exists to remember the stream ID
@@ -1714,13 +1945,13 @@ connection_exit_begin_resolve(cell_t *cell, circuit_t *circ)
* resolved; but if we didn't store them in a connection like this,
* the housekeeping in dns.c would get way more complicated.)
*/
- dummy_conn = connection_new(CONN_TYPE_EXIT);
+ dummy_conn = TO_EDGE_CONN(connection_new(CONN_TYPE_EXIT));
dummy_conn->stream_id = rh.stream_id;
- dummy_conn->address = tor_strndup(cell->payload+RELAY_HEADER_SIZE,
- rh.length);
- dummy_conn->port = 0;
- dummy_conn->state = EXIT_CONN_STATE_RESOLVEFAILED;
- dummy_conn->purpose = EXIT_PURPOSE_RESOLVE;
+ dummy_conn->_base.address = tor_strndup(cell->payload+RELAY_HEADER_SIZE,
+ rh.length);
+ dummy_conn->_base.port = 0;
+ dummy_conn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
+ dummy_conn->_base.purpose = EXIT_PURPOSE_RESOLVE;
/* send it off to the gethostbyname farm */
switch (dns_resolve(dummy_conn)) {
@@ -1728,14 +1959,14 @@ connection_exit_begin_resolve(cell_t *cell, circuit_t *circ)
/* Connection freed; don't touch it. */
return 0;
case 1: /* The result was cached; a resolved cell was sent. */
- if (!dummy_conn->marked_for_close)
- connection_free(dummy_conn);
+ if (!dummy_conn->_base.marked_for_close)
+ connection_free(TO_CONN(dummy_conn));
return 0;
case 0: /* resolve added to pending list */
dummy_conn->next_stream = circ->resolving_streams;
- dummy_conn->on_circuit = circ;
+ dummy_conn->on_circuit = TO_CIRCUIT(circ);
circ->resolving_streams = dummy_conn;
- assert_circuit_ok(circ);
+ assert_circuit_ok(TO_CIRCUIT(circ));
break;
}
return 0;
@@ -1749,17 +1980,19 @@ connection_exit_begin_resolve(cell_t *cell, circuit_t *circ)
* streams must not reveal what IP they connected to.)
*/
void
-connection_exit_connect(connection_t *conn)
+connection_exit_connect(edge_connection_t *edge_conn)
{
uint32_t addr;
uint16_t port;
+ connection_t *conn = TO_CONN(edge_conn);
- if (!connection_edge_is_rendezvous_stream(conn) &&
- router_compare_to_my_exit_policy(conn)) {
+ if (!connection_edge_is_rendezvous_stream(edge_conn) &&
+ router_compare_to_my_exit_policy(edge_conn)) {
log_info(LD_EXIT,"%s:%d failed exit policy. Closing.",
escaped_safe_str(conn->address), conn->port);
- connection_edge_end(conn, END_STREAM_REASON_EXITPOLICY, conn->cpath_layer);
- circuit_detach_stream(circuit_get_by_edge_conn(conn), conn);
+ connection_edge_end(edge_conn, END_STREAM_REASON_EXITPOLICY,
+ edge_conn->cpath_layer);
+ circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
connection_free(conn);
return;
}
@@ -1790,8 +2023,8 @@ connection_exit_connect(connection_t *conn)
log_debug(LD_EXIT,"about to try connecting");
switch (connection_connect(conn, conn->address, addr, port)) {
case -1:
- connection_edge_end_errno(conn, conn->cpath_layer);
- circuit_detach_stream(circuit_get_by_edge_conn(conn), conn);
+ connection_edge_end_errno(edge_conn, edge_conn->cpath_layer);
+ circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
connection_free(conn);
return;
case 0:
@@ -1813,20 +2046,23 @@ connection_exit_connect(connection_t *conn)
connection_watch_events(conn, EV_READ);
/* also, deliver a 'connected' cell back through the circuit. */
- if (connection_edge_is_rendezvous_stream(conn)) { /* rendezvous stream */
+ if (connection_edge_is_rendezvous_stream(edge_conn)) {
+ /* rendezvous stream */
/* don't send an address back! */
- connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
+ connection_edge_send_command(edge_conn,
+ circuit_get_by_edge_conn(edge_conn),
RELAY_COMMAND_CONNECTED,
- NULL, 0, conn->cpath_layer);
+ NULL, 0, edge_conn->cpath_layer);
} else { /* normal stream */
/* This must be the original address, not the redirected address. */
char connected_payload[8];
set_uint32(connected_payload, htonl(conn->addr));
set_uint32(connected_payload+4,
- htonl(MAX_DNS_ENTRY_AGE)); /* XXXX fill with a real TTL */
- connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
+ htonl(dns_clip_ttl(edge_conn->address_ttl)));
+ connection_edge_send_command(edge_conn,
+ circuit_get_by_edge_conn(edge_conn),
RELAY_COMMAND_CONNECTED,
- connected_payload, 8, conn->cpath_layer);
+ connected_payload, 8, edge_conn->cpath_layer);
}
}
@@ -1834,7 +2070,7 @@ connection_exit_connect(connection_t *conn)
* it is a general stream.
*/
int
-connection_edge_is_rendezvous_stream(connection_t *conn)
+connection_edge_is_rendezvous_stream(edge_connection_t *conn)
{
tor_assert(conn);
if (*conn->rend_query) /* XXX */
@@ -1848,10 +2084,10 @@ connection_edge_is_rendezvous_stream(connection_t *conn)
* resolved.)
*/
int
-connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit)
+connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit)
{
tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_AP);
+ tor_assert(conn->_base.type == CONN_TYPE_AP);
tor_assert(conn->socks_request);
tor_assert(exit);
@@ -1867,13 +2103,13 @@ connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit)
if (conn->chosen_exit_name) {
if (router_get_by_nickname(conn->chosen_exit_name, 1) != exit) {
/* doesn't match */
- log_debug(LD_APP,"Requested node '%s', considering node '%s'. No.",
- conn->chosen_exit_name, exit->nickname);
+// log_debug(LD_APP,"Requested node '%s', considering node '%s'. No.",
+// conn->chosen_exit_name, exit->nickname);
return 0;
}
}
- if (conn->socks_request->command != SOCKS_COMMAND_RESOLVE) {
+ if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) {
struct in_addr in;
uint32_t addr = 0;
addr_policy_result_t r;
@@ -1883,6 +2119,16 @@ connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit)
exit->exit_policy);
if (r == ADDR_POLICY_REJECTED || r == ADDR_POLICY_PROBABLY_REJECTED)
return 0;
+ } else { /* Some kind of a resolve. */
+
+ /* Can't support reverse lookups without eventdns. */
+ if (conn->socks_request->command == SOCKS_COMMAND_RESOLVE_PTR &&
+ exit->has_old_dnsworkers)
+ return 0;
+
+ /* Don't send DNS requests to non-exit servers by default. */
+ if (policy_is_reject_star(exit->exit_policy))
+ return 0;
}
return 1;
}
@@ -1917,14 +2163,14 @@ parse_extended_hostname(char *address)
s = strrchr(address,'.');
if (!s) return 0; /* no dot, thus normal */
if (!strcmp(s+1,"exit")) {
- *s = 0; /* null-terminate it */
+ *s = 0; /* nul-terminate it */
return EXIT_HOSTNAME; /* .exit */
}
if (strcmp(s+1,"onion"))
return NORMAL_HOSTNAME; /* neither .exit nor .onion, thus normal */
/* so it is .onion */
- *s = 0; /* null-terminate it */
+ *s = 0; /* nul-terminate it */
if (strlcpy(query, address, REND_SERVICE_ID_LEN+1) >=
REND_SERVICE_ID_LEN+1)
goto failed;
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 6d1a151d3c..76c2abbf13 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -19,24 +19,23 @@ const char connection_or_c_id[] =
#define TIGHT_CERT_ALLOW_SKEW (90*60)
-static int connection_tls_finish_handshake(connection_t *conn);
-static int connection_or_process_cells_from_inbuf(connection_t *conn);
+static int connection_tls_finish_handshake(or_connection_t *conn);
+static int connection_or_process_cells_from_inbuf(or_connection_t *conn);
/**************************************************************/
/** Map from identity digest of connected OR or desired OR to a connection_t
* with that identity digest. If there is more than one such connection_t,
- * they form a linked list, with next_with_same_id as the next pointer.*/
+ * they form a linked list, with next_with_same_id as the next pointer. */
static digestmap_t *orconn_identity_map = NULL;
/** If conn is listed in orconn_identity_map, remove it, and clear
* conn->identity_digest. */
void
-connection_or_remove_from_identity_map(connection_t *conn)
+connection_or_remove_from_identity_map(or_connection_t *conn)
{
- connection_t *tmp;
+ or_connection_t *tmp;
tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_OR);
if (!orconn_identity_map)
return;
tmp = digestmap_get(orconn_identity_map, conn->identity_digest);
@@ -73,8 +72,9 @@ connection_or_clear_identity_map(void)
for (i = 0; i < n; ++i) {
connection_t* conn = carray[i];
if (conn->type == CONN_TYPE_OR) {
- memset(conn->identity_digest, 0, DIGEST_LEN);
- conn->next_with_same_id = NULL;
+ or_connection_t *or_conn = TO_OR_CONN(conn);
+ memset(or_conn->identity_digest, 0, DIGEST_LEN);
+ or_conn->next_with_same_id = NULL;
}
}
@@ -87,11 +87,10 @@ connection_or_clear_identity_map(void)
/** Change conn->identity_digest to digest, and add conn into
* orconn_digest_map. */
static void
-connection_or_set_identity_digest(connection_t *conn, const char *digest)
+connection_or_set_identity_digest(or_connection_t *conn, const char *digest)
{
- connection_t *tmp;
+ or_connection_t *tmp;
tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_OR);
tor_assert(digest);
if (!orconn_identity_map)
@@ -136,10 +135,10 @@ cell_unpack(cell_t *dest, const char *src)
}
int
-connection_or_reached_eof(connection_t *conn)
+connection_or_reached_eof(or_connection_t *conn)
{
log_info(LD_OR,"OR connection reached EOF. Closing.");
- connection_mark_for_close(conn);
+ connection_mark_for_close(TO_CONN(conn));
return 0;
}
@@ -149,13 +148,14 @@ connection_or_reached_eof(connection_t *conn)
* and hope for better luck next time.
*/
static int
-connection_or_read_proxy_response(connection_t *conn)
+connection_or_read_proxy_response(or_connection_t *or_conn)
{
char *headers;
char *reason=NULL;
int status_code;
time_t date_header;
int compression;
+ connection_t *conn = TO_CONN(or_conn);
switch (fetch_from_buf_http(conn->inbuf,
&headers, MAX_HEADERS_SIZE,
@@ -185,7 +185,7 @@ connection_or_read_proxy_response(connection_t *conn)
"HTTPS connect to '%s' successful! (200 %s) Starting TLS.",
conn->address, escaped(reason));
tor_free(reason);
- if (connection_tls_start_handshake(conn, 0) < 0) {
+ if (connection_tls_start_handshake(or_conn, 0) < 0) {
/* TLS handshaking error of some kind. */
connection_mark_for_close(conn);
@@ -209,12 +209,11 @@ connection_or_read_proxy_response(connection_t *conn)
* (else do nothing).
*/
int
-connection_or_process_inbuf(connection_t *conn)
+connection_or_process_inbuf(or_connection_t *conn)
{
tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_OR);
- switch (conn->state) {
+ switch (conn->_base.state) {
case OR_CONN_STATE_PROXY_READING:
return connection_or_read_proxy_response(conn);
case OR_CONN_STATE_OPEN:
@@ -233,24 +232,22 @@ connection_or_process_inbuf(connection_t *conn)
* return 0.
*/
int
-connection_or_finished_flushing(connection_t *conn)
+connection_or_finished_flushing(or_connection_t *conn)
{
tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_OR);
-
- assert_connection_ok(conn,0);
+ assert_connection_ok(TO_CONN(conn),0);
- switch (conn->state) {
+ switch (conn->_base.state) {
case OR_CONN_STATE_PROXY_FLUSHING:
log_debug(LD_OR,"finished sending CONNECT to proxy.");
- conn->state = OR_CONN_STATE_PROXY_READING;
- connection_stop_writing(conn);
+ conn->_base.state = OR_CONN_STATE_PROXY_READING;
+ connection_stop_writing(TO_CONN(conn));
break;
case OR_CONN_STATE_OPEN:
- connection_stop_writing(conn);
+ connection_stop_writing(TO_CONN(conn));
break;
default:
- log_err(LD_BUG,"BUG: called in unexpected state %d.", conn->state);
+ log_err(LD_BUG,"BUG: called in unexpected state %d.", conn->_base.state);
tor_fragile_assert();
return -1;
}
@@ -260,10 +257,11 @@ connection_or_finished_flushing(connection_t *conn)
/** Connected handler for OR connections: begin the TLS handshake.
*/
int
-connection_or_finished_connecting(connection_t *conn)
+connection_or_finished_connecting(or_connection_t *or_conn)
{
- tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_OR);
+ connection_t *conn;
+ tor_assert(or_conn);
+ conn = TO_CONN(or_conn);
tor_assert(conn->state == OR_CONN_STATE_CONNECTING);
log_debug(LD_OR,"OR connect() to router at %s:%u finished.",
@@ -298,7 +296,7 @@ connection_or_finished_connecting(connection_t *conn)
return 0;
}
- if (connection_tls_start_handshake(conn, 0) < 0) {
+ if (connection_tls_start_handshake(or_conn, 0) < 0) {
/* TLS handshaking error of some kind. */
connection_mark_for_close(conn);
return -1;
@@ -306,63 +304,49 @@ connection_or_finished_connecting(connection_t *conn)
return 0;
}
-/** Initialize <b>conn</b> to include all the relevant data from <b>router</b>.
- * This function is called either from connection_or_connect(), if
- * we initiated the connect, or from connection_tls_finish_handshake()
- * if the other side initiated it.
- */
-static void
-connection_or_init_conn_from_router(connection_t *conn, routerinfo_t *router,
- int started_here)
-{
- or_options_t *options = get_options();
-
- if (!started_here) {
- conn->addr = router->addr;
- conn->port = router->or_port;
- }
- conn->receiver_bucket = conn->bandwidth = (int)options->BandwidthBurst;
- conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey);
- connection_or_set_identity_digest(conn, router->cache_info.identity_digest);
- conn->nickname = tor_strdup(router->nickname);
- tor_free(conn->address);
- conn->address = tor_strdup(router->address);
-}
-
/** If we don't necessarily know the router we're connecting to, but we
* have an addr/port/id_digest, then fill in as much as we can. Start
* by checking to see if this describes a router we know. */
static void
-connection_or_init_conn_from_address(connection_t *conn,
+connection_or_init_conn_from_address(or_connection_t *conn,
uint32_t addr, uint16_t port,
const char *id_digest,
int started_here)
{
- const char *n;
or_options_t *options = get_options();
routerinfo_t *r = router_get_by_digest(id_digest);
- conn->addr = addr;
- conn->port = port;
- if (r) {
- connection_or_init_conn_from_router(conn, r, started_here);
- return;
- }
- /* This next part isn't really right, but it's good enough for now. */
- conn->receiver_bucket = conn->bandwidth = (int)options->BandwidthBurst;
+ conn->bandwidthrate = (int)options->BandwidthRate;
+ conn->receiver_bucket = conn->bandwidthburst = (int)options->BandwidthBurst;
connection_or_set_identity_digest(conn, id_digest);
- /* If we're an authoritative directory server, we may know a
- * nickname for this router. */
- n = dirserv_get_nickname_by_digest(id_digest);
- if (n) {
- conn->nickname = tor_strdup(n);
+ conn->_base.addr = addr;
+ conn->_base.port = port;
+ if (r) {
+ if (!started_here) {
+ /* Override the addr/port, so our log messages will make sense.
+ * This is dangerous, since if we ever try looking up a conn by
+ * its actual addr/port, we won't remember. Careful! */
+ conn->_base.addr = r->addr;
+ conn->_base.port = r->or_port;
+ }
+ conn->nickname = tor_strdup(r->nickname);
+ tor_free(conn->_base.address);
+ conn->_base.address = tor_strdup(r->address);
} else {
- conn->nickname = tor_malloc(HEX_DIGEST_LEN+2);
- conn->nickname[0] = '$';
- base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1,
- conn->identity_digest, DIGEST_LEN);
+ const char *n;
+ /* If we're an authoritative directory server, we may know a
+ * nickname for this router. */
+ n = dirserv_get_nickname_by_digest(id_digest);
+ if (n) {
+ conn->nickname = tor_strdup(n);
+ } else {
+ conn->nickname = tor_malloc(HEX_DIGEST_LEN+2);
+ conn->nickname[0] = '$';
+ base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1,
+ conn->identity_digest, DIGEST_LEN);
+ }
+ tor_free(conn->_base.address);
+ conn->_base.address = tor_dup_addr(addr);
}
- tor_free(conn->address);
- conn->address = tor_dup_addr(addr);
}
/** Return the best connection of type OR with the
@@ -374,11 +358,11 @@ connection_or_init_conn_from_address(connection_t *conn,
* 4) Then if there are any non-empty conns, ignore empty conns.
* 5) Of the remaining conns, prefer newer conns.
*/
-connection_t *
+or_connection_t *
connection_or_get_by_identity_digest(const char *digest)
{
int newer;
- connection_t *conn, *best=NULL;
+ or_connection_t *conn, *best=NULL;
if (!orconn_identity_map)
return NULL;
@@ -386,26 +370,26 @@ connection_or_get_by_identity_digest(const char *digest)
conn = digestmap_get(orconn_identity_map, digest);
for (; conn; conn = conn->next_with_same_id) {
- tor_assert(conn->magic == CONNECTION_MAGIC);
- tor_assert(conn->type == CONN_TYPE_OR);
+ tor_assert(conn->_base.magic == OR_CONNECTION_MAGIC);
+ tor_assert(conn->_base.type == CONN_TYPE_OR);
tor_assert(!memcmp(conn->identity_digest, digest, DIGEST_LEN));
- if (conn->marked_for_close)
+ if (conn->_base.marked_for_close)
continue;
if (!best) {
best = conn; /* whatever it is, it's better than nothing. */
continue;
}
- if (best->state == OR_CONN_STATE_OPEN &&
- conn->state != OR_CONN_STATE_OPEN)
+ if (best->_base.state == OR_CONN_STATE_OPEN &&
+ conn->_base.state != OR_CONN_STATE_OPEN)
continue; /* avoid non-open conns if we can */
- newer = best->timestamp_created < conn->timestamp_created;
+ newer = best->_base.timestamp_created < conn->_base.timestamp_created;
- if (!best->is_obsolete && conn->is_obsolete)
+ if (!best->_base.or_is_obsolete && conn->_base.or_is_obsolete)
continue; /* We never prefer obsolete over non-obsolete connections. */
if (
/* We prefer non-obsolete connections: */
- (best->is_obsolete && !conn->is_obsolete) ||
+ (best->_base.or_is_obsolete && !conn->_base.or_is_obsolete) ||
/* If both have circuits we prefer the newer: */
(best->n_circuits && conn->n_circuits && newer) ||
/* If neither has circuits we prefer the newer: */
@@ -432,26 +416,24 @@ connection_or_get_by_identity_digest(const char *digest)
*
* Return the launched conn, or NULL if it failed.
*/
-connection_t *
+or_connection_t *
connection_or_connect(uint32_t addr, uint16_t port, const char *id_digest)
{
- connection_t *conn;
- routerinfo_t *me;
+ or_connection_t *conn;
or_options_t *options = get_options();
tor_assert(id_digest);
- if (server_mode(options) && (me=router_get_my_routerinfo()) &&
- router_digest_is_me(id_digest)) {
+ if (server_mode(options) && router_digest_is_me(id_digest)) {
log_info(LD_PROTOCOL,"Client asked me to connect to myself. Refusing.");
return NULL;
}
- conn = connection_new(CONN_TYPE_OR);
+ conn = TO_OR_CONN(connection_new(CONN_TYPE_OR));
/* set up conn so it's got all the data we need to remember */
connection_or_init_conn_from_address(conn, addr, port, id_digest, 1);
- conn->state = OR_CONN_STATE_CONNECTING;
+ conn->_base.state = OR_CONN_STATE_CONNECTING;
control_event_or_conn_status(conn, OR_CONN_EVENT_LAUNCHED);
if (options->HttpsProxy) {
@@ -460,7 +442,7 @@ connection_or_connect(uint32_t addr, uint16_t port, const char *id_digest)
port = options->HttpsProxyPort;
}
- switch (connection_connect(conn, conn->address, addr, port)) {
+ switch (connection_connect(TO_CONN(conn), conn->_base.address, addr, port)) {
case -1:
/* If the connection failed immediately, and we're using
* an https proxy, our https proxy is down. Don't blame the
@@ -470,10 +452,10 @@ connection_or_connect(uint32_t addr, uint16_t port, const char *id_digest)
router_set_status(conn->identity_digest, 0);
}
control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
- connection_free(conn);
+ connection_free(TO_CONN(conn));
return NULL;
case 0:
- connection_watch_events(conn, EV_READ | EV_WRITE);
+ connection_watch_events(TO_CONN(conn), EV_READ | EV_WRITE);
/* writable indicates finish, readable indicates broken link,
error indicates broken link on windows */
return conn;
@@ -496,16 +478,16 @@ connection_or_connect(uint32_t addr, uint16_t port, const char *id_digest)
* Return -1 if <b>conn</b> is broken, else return 0.
*/
int
-connection_tls_start_handshake(connection_t *conn, int receiving)
+connection_tls_start_handshake(or_connection_t *conn, int receiving)
{
- conn->state = OR_CONN_STATE_HANDSHAKING;
- conn->tls = tor_tls_new(conn->s, receiving, 0);
+ conn->_base.state = OR_CONN_STATE_HANDSHAKING;
+ conn->tls = tor_tls_new(conn->_base.s, receiving);
if (!conn->tls) {
log_warn(LD_BUG,"tor_tls_new failed. Closing.");
return -1;
}
- connection_start_reading(conn);
- log_debug(LD_OR,"starting TLS handshake on fd %d", conn->s);
+ connection_start_reading(TO_CONN(conn));
+ log_debug(LD_OR,"starting TLS handshake on fd %d", conn->_base.s);
if (connection_tls_continue_handshake(conn) < 0) {
return -1;
}
@@ -518,7 +500,7 @@ connection_tls_start_handshake(connection_t *conn, int receiving)
* Return -1 if <b>conn</b> is broken, else return 0.
*/
int
-connection_tls_continue_handshake(connection_t *conn)
+connection_tls_continue_handshake(or_connection_t *conn)
{
check_no_tls_errors();
switch (tor_tls_handshake(conn->tls)) {
@@ -529,7 +511,7 @@ connection_tls_continue_handshake(connection_t *conn)
case TOR_TLS_DONE:
return connection_tls_finish_handshake(conn);
case TOR_TLS_WANTWRITE:
- connection_start_writing(conn);
+ connection_start_writing(TO_CONN(conn));
log_debug(LD_OR,"wanted write");
return 0;
case TOR_TLS_WANTREAD: /* handshaking conns are *always* reading */
@@ -547,14 +529,12 @@ connection_tls_continue_handshake(connection_t *conn)
* one day so we're clearer.
*/
int
-connection_or_nonopen_was_started_here(connection_t *conn)
+connection_or_nonopen_was_started_here(or_connection_t *conn)
{
- tor_assert(conn->type == CONN_TYPE_OR);
-
- if (tor_digest_is_zero(conn->identity_digest))
- return 0;
- else
- return 1;
+ tor_assert(conn->_base.type == CONN_TYPE_OR);
+ if (!conn->tls)
+ return 1; /* it's still in proxy states or something */
+ return !tor_tls_is_server(conn->tls);
}
/** Conn just completed its handshake. Return 0 if all is well, and
@@ -569,13 +549,13 @@ connection_or_nonopen_was_started_here(connection_t *conn)
* buffer is undefined.)
*
* As side effects,
- * 1) Set conn->circ_id_type according to tor-spec.txt
+ * 1) Set conn->circ_id_type according to tor-spec.txt.
* 2) If we're an authdirserver and we initiated the connection: drop all
* descriptors that claim to be on that IP/port but that aren't
* this guy; and note that this guy is reachable.
*/
static int
-connection_or_check_valid_handshake(connection_t *conn, char *digest_rcvd)
+connection_or_check_valid_handshake(or_connection_t *conn, char *digest_rcvd)
{
routerinfo_t *router;
crypto_pk_env_t *identity_rcvd=NULL;
@@ -586,7 +566,7 @@ connection_or_check_valid_handshake(connection_t *conn, char *digest_rcvd)
check_no_tls_errors();
if (! tor_tls_peer_has_cert(conn->tls)) {
log_info(LD_PROTOCOL,"Peer (%s:%d) didn't send a cert! Closing.",
- conn->address, conn->port);
+ conn->_base.address, conn->_base.port);
return -1;
}
check_no_tls_errors();
@@ -594,17 +574,17 @@ connection_or_check_valid_handshake(connection_t *conn, char *digest_rcvd)
sizeof(nickname))) {
log_fn(severity,LD_PROTOCOL,"Other side (%s:%d) has a cert without a "
"valid nickname. Closing.",
- conn->address, conn->port);
+ conn->_base.address, conn->_base.port);
return -1;
}
check_no_tls_errors();
log_debug(LD_OR, "Other side (%s:%d) claims to be router '%s'",
- conn->address, conn->port, nickname);
+ conn->_base.address, conn->_base.port, nickname);
if (tor_tls_verify(severity, conn->tls, &identity_rcvd) < 0) {
log_fn(severity,LD_OR,"Other side, which claims to be router '%s' (%s:%d),"
" has a cert but it's invalid. Closing.",
- nickname, conn->address, conn->port);
+ nickname, conn->_base.address, conn->_base.port);
return -1;
}
check_no_tls_errors();
@@ -625,7 +605,7 @@ connection_or_check_valid_handshake(connection_t *conn, char *digest_rcvd)
log_fn(severity, LD_OR,
"Identity key not as expected for router claiming to be "
"'%s' (%s:%d)",
- nickname, conn->address, conn->port);
+ nickname, conn->_base.address, conn->_base.port);
return -1;
}
@@ -641,7 +621,7 @@ connection_or_check_valid_handshake(connection_t *conn, char *digest_rcvd)
log_fn(severity, LD_OR,
"Identity key not as expected for router at %s:%d: wanted %s "
"but got %s",
- conn->address, conn->port, expected, seen);
+ conn->_base.address, conn->_base.port, expected, seen);
entry_guard_set_status(conn->identity_digest, 0);
router_set_status(conn->identity_digest, 0);
control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
@@ -651,7 +631,7 @@ connection_or_check_valid_handshake(connection_t *conn, char *digest_rcvd)
/* We initiated this connection to address:port. Drop all routers
* with the same address:port and a different key or nickname.
*/
- dirserv_orconn_tls_done(conn->address, conn->port,
+ dirserv_orconn_tls_done(conn->_base.address, conn->_base.port,
digest_rcvd, nickname, as_advertised);
}
if (!as_advertised)
@@ -667,14 +647,12 @@ connection_or_check_valid_handshake(connection_t *conn, char *digest_rcvd)
* If he initiated the connection, make sure he's not already connected,
* then initialize conn from the information in router.
*
- * If I'm not a server, set bandwidth to the default OP bandwidth.
- *
* If all is successful, call circuit_n_conn_done() to handle events
* that have been pending on the tls handshake completion. Also set the
* directory to be dirty (only matters if I'm an authdirserver).
*/
static int
-connection_tls_finish_handshake(connection_t *conn)
+connection_tls_finish_handshake(or_connection_t *conn)
{
char digest_rcvd[DIGEST_LEN];
int started_here = connection_or_nonopen_was_started_here(conn);
@@ -684,17 +662,9 @@ connection_tls_finish_handshake(connection_t *conn)
return -1;
if (!started_here) {
-#if 0
- connection_t *c;
- if ((c=connection_or_get_by_identity_digest(digest_rcvd))) {
- log_debug(LD_OR,
- "Router '%s' is already connected on fd %d. Dropping fd %d.",
- c->nickname, c->s, conn->s);
- return -1;
- }
-#endif
- connection_or_init_conn_from_address(conn,conn->addr,conn->port,
- digest_rcvd, 0);
+ connection_or_init_conn_from_address(conn,conn->_base.addr,
+ conn->_base.port, digest_rcvd, 0);
+
/* Annotate that we received a TLS connection.
* (Todo: only actually consider ourselves reachable if there
* exists a testing circuit using conn.)
@@ -705,16 +675,12 @@ connection_tls_finish_handshake(connection_t *conn)
* The reason this bandaid is here is because there's a bug in
* Tor 0.1.1.x where middle hops don't always send their create
* cell; so some servers rarely find themselves reachable. */
-// if (!is_local_IP(conn->addr))
+// if (!is_local_IP(conn->_base.addr))
// router_orport_found_reachable();
}
- if (!server_mode(get_options())) { /* If I'm an OP... */
- conn->receiver_bucket = conn->bandwidth = DEFAULT_BANDWIDTH_OP;
- }
-
directory_set_dirty();
- conn->state = OR_CONN_STATE_OPEN;
+ conn->_base.state = OR_CONN_STATE_OPEN;
control_event_or_conn_status(conn, OR_CONN_EVENT_CONNECTED);
if (started_here) {
rep_hist_note_connect_succeeded(conn->identity_digest, time(NULL));
@@ -724,7 +690,7 @@ connection_tls_finish_handshake(connection_t *conn)
}
router_set_status(conn->identity_digest, 1);
}
- connection_watch_events(conn, EV_READ);
+ connection_watch_events(TO_CONN(conn), EV_READ);
circuit_n_conn_done(conn, 1); /* send the pending creates, if any. */
return 0;
}
@@ -736,18 +702,17 @@ connection_tls_finish_handshake(connection_t *conn)
* ready, then try to flush the record now.
*/
void
-connection_or_write_cell_to_buf(const cell_t *cell, connection_t *conn)
+connection_or_write_cell_to_buf(const cell_t *cell, or_connection_t *conn)
{
char networkcell[CELL_NETWORK_SIZE];
char *n = networkcell;
tor_assert(cell);
tor_assert(conn);
- tor_assert(connection_speaks_cells(conn));
cell_pack(n, cell);
- connection_write_to_buf(n, CELL_NETWORK_SIZE, conn);
+ connection_write_to_buf(n, CELL_NETWORK_SIZE, TO_CONN(conn));
#define MIN_TLS_FLUSHLEN 15872
/* openssl tls record size is 16383, this is close. The goal here is to
@@ -755,26 +720,28 @@ connection_or_write_cell_to_buf(const cell_t *cell, connection_t *conn)
* during periods of high load we won't read the entire megabyte from
* input before pushing any data out. It also has the feature of not
* growing huge outbufs unless something is slow. */
- if (conn->outbuf_flushlen-CELL_NETWORK_SIZE < MIN_TLS_FLUSHLEN &&
- conn->outbuf_flushlen >= MIN_TLS_FLUSHLEN) {
- int extra = conn->outbuf_flushlen - MIN_TLS_FLUSHLEN;
- conn->outbuf_flushlen = MIN_TLS_FLUSHLEN;
- if (connection_handle_write(conn) < 0) {
- if (!conn->marked_for_close) {
+ if (conn->_base.outbuf_flushlen-CELL_NETWORK_SIZE < MIN_TLS_FLUSHLEN &&
+ conn->_base.outbuf_flushlen >= MIN_TLS_FLUSHLEN) {
+ int extra = conn->_base.outbuf_flushlen - MIN_TLS_FLUSHLEN;
+ conn->_base.outbuf_flushlen = MIN_TLS_FLUSHLEN;
+ if (connection_handle_write(TO_CONN(conn)) < 0) {
+ if (!conn->_base.marked_for_close) {
/* this connection is broken. remove it. */
log_warn(LD_BUG,
"Bug: unhandled error on write for OR conn (fd %d); removing",
- conn->s);
+ conn->_base.s);
tor_fragile_assert();
- conn->has_sent_end = 1; /* don't cry wolf about duplicate close */
+ // XXX This was supposed to be edge-only!
+ // conn->has_sent_end = 1; /* don't cry wolf about duplicate close */
+
/* XXX do we need a close-immediate here, so we don't try to flush? */
- connection_mark_for_close(conn);
+ connection_mark_for_close(TO_CONN(conn));
}
return;
}
if (extra) {
- conn->outbuf_flushlen += extra;
- connection_start_writing(conn);
+ conn->_base.outbuf_flushlen += extra;
+ connection_start_writing(TO_CONN(conn));
}
}
}
@@ -787,7 +754,7 @@ connection_or_write_cell_to_buf(const cell_t *cell, connection_t *conn)
* Always return 0.
*/
static int
-connection_or_process_cells_from_inbuf(connection_t *conn)
+connection_or_process_cells_from_inbuf(or_connection_t *conn)
{
char buf[CELL_NETWORK_SIZE];
cell_t cell;
@@ -795,13 +762,13 @@ connection_or_process_cells_from_inbuf(connection_t *conn)
loop:
log_debug(LD_OR,
"%d: starting, inbuf_datalen %d (%d pending in tls object).",
- conn->s,(int)buf_datalen(conn->inbuf),
+ conn->_base.s,(int)buf_datalen(conn->_base.inbuf),
tor_tls_get_pending_bytes(conn->tls));
- if (buf_datalen(conn->inbuf) < CELL_NETWORK_SIZE) /* whole response
- available? */
+ if (buf_datalen(conn->_base.inbuf) < CELL_NETWORK_SIZE) /* whole response
+ available? */
return 0; /* not yet */
- connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, conn);
+ connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, TO_CONN(conn));
/* retrieve cell info from buf (create the host-order struct from the
* network-order string) */
@@ -819,12 +786,11 @@ loop:
* Return 0.
*/
int
-connection_or_send_destroy(uint16_t circ_id, connection_t *conn, int reason)
+connection_or_send_destroy(uint16_t circ_id, or_connection_t *conn, int reason)
{
cell_t cell;
tor_assert(conn);
- tor_assert(connection_speaks_cells(conn));
memset(&cell, 0, sizeof(cell_t));
cell.circ_id = circ_id;
diff --git a/src/or/control.c b/src/or/control.c
index 55b4fc01bb..b67cd1ce7c 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -131,57 +131,64 @@ static int disable_log_messages = 0;
static int authentication_cookie_is_set = 0;
static char authentication_cookie[AUTHENTICATION_COOKIE_LEN];
-static void connection_printf_to_buf(connection_t *conn,
+static void connection_printf_to_buf(control_connection_t *conn,
const char *format, ...)
CHECK_PRINTF(2,3);
/*static*/ size_t write_escaped_data(const char *data, size_t len,
int translate_newlines, char **out);
/*static*/ size_t read_escaped_data(const char *data, size_t len,
int translate_newlines, char **out);
-static void send_control0_message(connection_t *conn, uint16_t type,
+static void send_control0_message(control_connection_t *conn, uint16_t type,
uint32_t len, const char *body);
-static void send_control_done(connection_t *conn);
-static void send_control_done2(connection_t *conn, const char *msg,
+static void send_control_done(control_connection_t *conn);
+static void send_control_done2(control_connection_t *conn, const char *msg,
size_t len);
-static void send_control0_error(connection_t *conn, uint16_t error,
+static void send_control0_error(control_connection_t *conn, uint16_t error,
const char *message);
static void send_control0_event(uint16_t event, uint32_t len,
const char *body);
static void send_control1_event(uint16_t event, const char *format, ...)
CHECK_PRINTF(2,3);
-static int handle_control_setconf(connection_t *conn, uint32_t len,
+static int handle_control_setconf(control_connection_t *conn, uint32_t len,
char *body);
-static int handle_control_resetconf(connection_t *conn, uint32_t len,
+static int handle_control_resetconf(control_connection_t *conn, uint32_t len,
char *body);
-static int handle_control_getconf(connection_t *conn, uint32_t len,
+static int handle_control_getconf(control_connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_setevents(connection_t *conn, uint32_t len,
+static int handle_control_setevents(control_connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_authenticate(connection_t *conn, uint32_t len,
+static int handle_control_authenticate(control_connection_t *conn,
+ uint32_t len,
const char *body);
-static int handle_control_saveconf(connection_t *conn, uint32_t len,
+static int handle_control_saveconf(control_connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_signal(connection_t *conn, uint32_t len,
+static int handle_control_signal(control_connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_mapaddress(connection_t *conn, uint32_t len,
+static int handle_control_mapaddress(control_connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_getinfo(connection_t *conn, uint32_t len,
+static int handle_control_getinfo(control_connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_extendcircuit(connection_t *conn, uint32_t len,
+static int handle_control_extendcircuit(control_connection_t *conn,
+ uint32_t len,
const char *body);
-static int handle_control_setpurpose(connection_t *conn, int for_circuits,
+static int handle_control_setpurpose(control_connection_t *conn,
+ int for_circuits,
uint32_t len, const char *body);
-static int handle_control_attachstream(connection_t *conn, uint32_t len,
+static int handle_control_attachstream(control_connection_t *conn,
+ uint32_t len,
const char *body);
-static int handle_control_postdescriptor(connection_t *conn, uint32_t len,
+static int handle_control_postdescriptor(control_connection_t *conn,
+ uint32_t len,
const char *body);
-static int handle_control_redirectstream(connection_t *conn, uint32_t len,
+static int handle_control_redirectstream(control_connection_t *conn,
+ uint32_t len,
const char *body);
-static int handle_control_closestream(connection_t *conn, uint32_t len,
+static int handle_control_closestream(control_connection_t *conn, uint32_t len,
const char *body);
-static int handle_control_closecircuit(connection_t *conn, uint32_t len,
+static int handle_control_closecircuit(control_connection_t *conn,
+ uint32_t len,
const char *body);
-static int write_stream_target_to_buf(connection_t *conn, char *buf,
+static int write_stream_target_to_buf(edge_connection_t *conn, char *buf,
size_t len);
/** Given a possibly invalid message type code <b>cmd</b>, return a
@@ -235,10 +242,11 @@ control_update_global_event_mask(void)
for (i = 0; i < n_conns; ++i) {
if (conns[i]->type == CONN_TYPE_CONTROL &&
STATE_IS_OPEN(conns[i]->state)) {
- if (STATE_IS_V0(conns[i]->state))
- global_event_mask0 |= conns[i]->event_mask;
+ control_connection_t *conn = TO_CONTROL_CONN(conns[i]);
+ if (STATE_IS_V0(conn->_base.state))
+ global_event_mask0 |= conn->event_mask;
else
- global_event_mask1 |= conns[i]->event_mask;
+ global_event_mask1 |= conn->event_mask;
}
}
@@ -281,10 +289,10 @@ control_adjust_event_log_severity(void)
* <b>conn</b>-\>outbuf
*/
static INLINE void
-connection_write_str_to_buf(const char *s, connection_t *conn)
+connection_write_str_to_buf(const char *s, control_connection_t *conn)
{
size_t len = strlen(s);
- connection_write_to_buf(s, len, conn);
+ connection_write_to_buf(s, len, TO_CONN(conn));
}
/** Given a <b>len</b>-character string in <b>data</b>, made of lines
@@ -446,7 +454,7 @@ get_escaped_string(const char *start, size_t in_len_max,
* Currently the length of the message is limited to 1024 (including the
* ending \n\r\0. */
static void
-connection_printf_to_buf(connection_t *conn, const char *format, ...)
+connection_printf_to_buf(control_connection_t *conn, const char *format, ...)
{
#define CONNECTION_PRINTF_TO_BUF_BUFFERSIZE 1024
va_list ap;
@@ -462,41 +470,41 @@ connection_printf_to_buf(connection_t *conn, const char *format, ...)
buf[CONNECTION_PRINTF_TO_BUF_BUFFERSIZE-2] = '\n';
buf[CONNECTION_PRINTF_TO_BUF_BUFFERSIZE-3] = '\r';
}
- connection_write_to_buf(buf, len, conn);
+ connection_write_to_buf(buf, len, TO_CONN(conn));
}
/** Send a message of type <b>type</b> containing <b>len</b> bytes
* from <b>body</b> along the control connection <b>conn</b> */
static void
-send_control0_message(connection_t *conn, uint16_t type, uint32_t len,
- const char *body)
+send_control0_message(control_connection_t *conn, uint16_t type, uint32_t len,
+ const char *body)
{
char buf[10];
tor_assert(conn);
- tor_assert(STATE_IS_V0(conn->state));
+ tor_assert(STATE_IS_V0(conn->_base.state));
tor_assert(len || !body);
tor_assert(type <= _CONTROL0_CMD_MAX_RECOGNIZED);
if (len < 65536) {
set_uint16(buf, htons(len));
set_uint16(buf+2, htons(type));
- connection_write_to_buf(buf, 4, conn);
+ connection_write_to_buf(buf, 4, TO_CONN(conn));
if (len)
- connection_write_to_buf(body, len, conn);
+ connection_write_to_buf(body, len, TO_CONN(conn));
} else {
set_uint16(buf, htons(65535));
set_uint16(buf+2, htons(CONTROL0_CMD_FRAGMENTHEADER));
set_uint16(buf+4, htons(type));
set_uint32(buf+6, htonl(len));
- connection_write_to_buf(buf, 10, conn);
- connection_write_to_buf(body, 65535-6, conn);
+ connection_write_to_buf(buf, 10, TO_CONN(conn));
+ connection_write_to_buf(body, 65535-6, TO_CONN(conn));
len -= (65535-6);
body += (65535-6);
while (len) {
size_t chunklen = (len<65535)?len:65535;
set_uint16(buf, htons((uint16_t)chunklen));
set_uint16(buf+2, htons(CONTROL0_CMD_FRAGMENT));
- connection_write_to_buf(buf, 4, conn);
- connection_write_to_buf(body, chunklen, conn);
+ connection_write_to_buf(buf, 4, TO_CONN(conn));
+ connection_write_to_buf(body, chunklen, TO_CONN(conn));
len -= chunklen;
body += chunklen;
}
@@ -505,9 +513,9 @@ send_control0_message(connection_t *conn, uint16_t type, uint32_t len,
/** Send a "DONE" message down the control connection <b>conn</b> */
static void
-send_control_done(connection_t *conn)
+send_control_done(control_connection_t *conn)
{
- if (STATE_IS_V0(conn->state)) {
+ if (STATE_IS_V0(conn->_base.state)) {
send_control0_message(conn, CONTROL0_CMD_DONE, 0, NULL);
} else {
connection_write_str_to_buf("250 OK\r\n", conn);
@@ -518,7 +526,7 @@ send_control_done(connection_t *conn)
* as provided in the <b>len</b> bytes at <b>msg</b>.
*/
static void
-send_control_done2(connection_t *conn, const char *msg, size_t len)
+send_control_done2(control_connection_t *conn, const char *msg, size_t len)
{
if (len==0)
len = strlen(msg);
@@ -528,7 +536,8 @@ send_control_done2(connection_t *conn, const char *msg, size_t len)
/** Send an error message with error code <b>error</b> and body
* <b>message</b> down the connection <b>conn</b> */
static void
-send_control0_error(connection_t *conn, uint16_t error, const char *message)
+send_control0_error(control_connection_t *conn, uint16_t error,
+ const char *message)
{
char buf[256];
size_t len;
@@ -561,11 +570,13 @@ send_control0_event(uint16_t event, uint32_t len, const char *body)
for (i = 0; i < n_conns; ++i) {
if (conns[i]->type == CONN_TYPE_CONTROL &&
!conns[i]->marked_for_close &&
- conns[i]->state == CONTROL_CONN_STATE_OPEN_V0 &&
- conns[i]->event_mask & (1<<event)) {
- send_control0_message(conns[i], CONTROL0_CMD_EVENT, buflen, buf);
- if (event == EVENT_ERR_MSG)
- _connection_controller_force_write(conns[i]);
+ conns[i]->state == CONTROL_CONN_STATE_OPEN_V0) {
+ control_connection_t *control_conn = TO_CONTROL_CONN(conns[i]);
+ if (control_conn->event_mask & (1<<event)) {
+ send_control0_message(control_conn, CONTROL0_CMD_EVENT, buflen, buf);
+ if (event == EVENT_ERR_MSG)
+ _connection_controller_force_write(control_conn);
+ }
}
}
@@ -586,11 +597,13 @@ send_control1_event_string(uint16_t event, const char *msg)
for (i = 0; i < n_conns; ++i) {
if (conns[i]->type == CONN_TYPE_CONTROL &&
!conns[i]->marked_for_close &&
- conns[i]->state == CONTROL_CONN_STATE_OPEN_V1 &&
- conns[i]->event_mask & (1<<event)) {
- connection_write_to_buf(msg, strlen(msg), conns[i]);
- if (event == EVENT_ERR_MSG)
- _connection_controller_force_write(conns[i]);
+ conns[i]->state == CONTROL_CONN_STATE_OPEN_V1) {
+ control_connection_t *control_conn = TO_CONTROL_CONN(conns[i]);
+ if (control_conn->event_mask & (1<<event)) {
+ connection_write_to_buf(msg, strlen(msg), TO_CONN(control_conn));
+ if (event == EVENT_ERR_MSG)
+ _connection_controller_force_write(control_conn);
+ }
}
}
}
@@ -626,7 +639,7 @@ send_control1_event(uint16_t event, const char *format, ...)
}
/** Given a text circuit <b>id</b>, return the corresponding circuit. */
-static circuit_t *
+static origin_circuit_t *
get_circ(const char *id)
{
unsigned long n_id;
@@ -638,17 +651,17 @@ get_circ(const char *id)
}
/** Given a text stream <b>id</b>, return the corresponding AP connection. */
-static connection_t *
+static edge_connection_t *
get_stream(const char *id)
{
unsigned long n_id;
int ok;
- connection_t *conn;
+ edge_connection_t *conn;
n_id = tor_parse_ulong(id, 10, 0, ULONG_MAX, &ok, NULL);
if (!ok)
return NULL;
conn = connection_get_by_global_id(n_id);
- if (!conn || conn->type != CONN_TYPE_AP)
+ if (!conn || conn->_base.type != CONN_TYPE_AP)
return NULL;
return conn;
}
@@ -657,14 +670,14 @@ get_stream(const char *id)
* it passes <b>use_defaults</b> on to options_trial_assign().
*/
static int
-control_setconf_helper(connection_t *conn, uint32_t len, char *body,
+control_setconf_helper(control_connection_t *conn, uint32_t len, char *body,
int use_defaults, int clear_first)
{
int r;
config_line_t *lines=NULL;
char *start = body;
char *errstring = NULL;
- int v0 = STATE_IS_V0(conn->state);
+ int v0 = STATE_IS_V0(conn->_base.state);
if (!v0) {
char *config = tor_malloc(len+1);
@@ -761,7 +774,7 @@ control_setconf_helper(connection_t *conn, uint32_t len, char *body,
/** Called when we receive a SETCONF message: parse the body and try
* to update our configuration. Reply with a DONE or ERROR message. */
static int
-handle_control_setconf(connection_t *conn, uint32_t len, char *body)
+handle_control_setconf(control_connection_t *conn, uint32_t len, char *body)
{
return control_setconf_helper(conn, len, body, 0, 1);
}
@@ -769,9 +782,9 @@ handle_control_setconf(connection_t *conn, uint32_t len, char *body)
/** Called when we receive a RESETCONF message: parse the body and try
* to update our configuration. Reply with a DONE or ERROR message. */
static int
-handle_control_resetconf(connection_t *conn, uint32_t len, char *body)
+handle_control_resetconf(control_connection_t *conn, uint32_t len, char *body)
{
- int v0 = STATE_IS_V0(conn->state);
+ int v0 = STATE_IS_V0(conn->_base.state);
tor_assert(!v0);
return control_setconf_helper(conn, len, body, 1, 1);
}
@@ -779,7 +792,8 @@ handle_control_resetconf(connection_t *conn, uint32_t len, char *body)
/** Called when we receive a GETCONF message. Parse the request, and
* reply with a CONFVALUE or an ERROR message */
static int
-handle_control_getconf(connection_t *conn, uint32_t body_len, const char *body)
+handle_control_getconf(control_connection_t *conn, uint32_t body_len,
+ const char *body)
{
smartlist_t *questions = NULL;
smartlist_t *answers = NULL;
@@ -787,9 +801,10 @@ handle_control_getconf(connection_t *conn, uint32_t body_len, const char *body)
char *msg = NULL;
size_t msg_len;
or_options_t *options = get_options();
- int v0 = STATE_IS_V0(conn->state);
+ int v0 = STATE_IS_V0(conn->_base.state);
questions = smartlist_create();
+ (void) body_len; /* body is nul-terminated; so we can ignore len. */
if (v0) {
smartlist_split_string(questions, body, "\n",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
@@ -857,7 +872,7 @@ handle_control_getconf(connection_t *conn, uint32_t body_len, const char *body)
tor_assert(strlen(tmp)>4);
tmp[3] = ' ';
msg = smartlist_join_strings(answers, "", 0, &msg_len);
- connection_write_to_buf(msg, msg_len, conn);
+ connection_write_to_buf(msg, msg_len, TO_CONN(conn));
} else {
connection_write_str_to_buf("250 OK\r\n", conn);
}
@@ -881,13 +896,14 @@ handle_control_getconf(connection_t *conn, uint32_t body_len, const char *body)
/** Called when we get a SETEVENTS message: update conn->event_mask,
* and reply with DONE or ERROR. */
static int
-handle_control_setevents(connection_t *conn, uint32_t len, const char *body)
+handle_control_setevents(control_connection_t *conn, uint32_t len,
+ const char *body)
{
uint16_t event_code;
uint32_t event_mask = 0;
unsigned int extended = 0;
- if (STATE_IS_V0(conn->state)) {
+ if (STATE_IS_V0(conn->_base.state)) {
if (len % 2) {
send_control0_error(conn, ERR_SYNTAX,
"Odd number of bytes in setevents message");
@@ -949,7 +965,7 @@ handle_control_setevents(connection_t *conn, uint32_t len, const char *body)
smartlist_free(events);
}
conn->event_mask = event_mask;
- conn->control_events_are_extended = extended;
+ conn->_base.control_events_are_extended = extended;
control_update_global_event_mask();
send_control_done(conn);
@@ -986,13 +1002,14 @@ decode_hashed_password(char *buf, const char *hashed)
* OPEN. Reply with DONE or ERROR.
*/
static int
-handle_control_authenticate(connection_t *conn, uint32_t len, const char *body)
+handle_control_authenticate(control_connection_t *conn, uint32_t len,
+ const char *body)
{
int used_quoted_string = 0;
or_options_t *options = get_options();
char *password;
size_t password_len;
- if (STATE_IS_V0(conn->state)) {
+ if (STATE_IS_V0(conn->_base.state)) {
password = (char*)body;
password_len = len;
} else {
@@ -1046,7 +1063,7 @@ handle_control_authenticate(connection_t *conn, uint32_t len, const char *body)
}
err:
- if (STATE_IS_V0(conn->state))
+ if (STATE_IS_V0(conn->_base.state))
send_control0_error(conn,ERR_REJECTED_AUTHENTICATION,
"Authentication failed");
else {
@@ -1060,12 +1077,12 @@ handle_control_authenticate(connection_t *conn, uint32_t len, const char *body)
}
return 0;
ok:
- log_info(LD_CONTROL, "Authenticated control connection (%d)", conn->s);
+ log_info(LD_CONTROL, "Authenticated control connection (%d)", conn->_base.s);
send_control_done(conn);
- if (STATE_IS_V0(conn->state))
- conn->state = CONTROL_CONN_STATE_OPEN_V0;
+ if (STATE_IS_V0(conn->_base.state))
+ conn->_base.state = CONTROL_CONN_STATE_OPEN_V0;
else {
- conn->state = CONTROL_CONN_STATE_OPEN_V1;
+ conn->_base.state = CONTROL_CONN_STATE_OPEN_V1;
tor_free(password);
}
return 0;
@@ -1074,11 +1091,13 @@ handle_control_authenticate(connection_t *conn, uint32_t len, const char *body)
/** Called when we get a SAVECONF command. Try to flush the current options to
* disk, and report success or failure. */
static int
-handle_control_saveconf(connection_t *conn, uint32_t len,
+handle_control_saveconf(control_connection_t *conn, uint32_t len,
const char *body)
{
+ (void) len;
+ (void) body;
if (options_save_current()<0) {
- if (STATE_IS_V0(conn->state))
+ if (STATE_IS_V0(conn->_base.state))
send_control0_error(conn, ERR_INTERNAL,
"Unable to write configuration to disk.");
else
@@ -1094,11 +1113,11 @@ handle_control_saveconf(connection_t *conn, uint32_t len,
* report success or failure. (If the signal results in a shutdown, success
* may not be reported.) */
static int
-handle_control_signal(connection_t *conn, uint32_t len,
+handle_control_signal(control_connection_t *conn, uint32_t len,
const char *body)
{
int sig;
- if (STATE_IS_V0(conn->state)) {
+ if (STATE_IS_V0(conn->_base.state)) {
if (len != 1) {
send_control0_error(conn, ERR_SYNTAX,
"Body of SIGNAL command too long or too short.");
@@ -1134,14 +1153,16 @@ handle_control_signal(connection_t *conn, uint32_t len,
return 0;
}
- if (control_signal_act(sig) < 0) {
- if (STATE_IS_V0(conn->state))
+ if (!control_signal_check(sig)) {
+ if (STATE_IS_V0(conn->_base.state))
send_control0_error(conn, ERR_SYNTAX, "Unrecognized signal number.");
else
- connection_write_str_to_buf("551 Internal error acting on signal\r\n",
+ connection_write_str_to_buf("551 Unable to act on signal\r\n",
conn);
} else {
+ /* Send DONE first, in case the signal makes us shut down. */
send_control_done(conn);
+ control_signal_act(sig);
}
return 0;
}
@@ -1149,14 +1170,17 @@ handle_control_signal(connection_t *conn, uint32_t len,
/** Called when we get a MAPADDRESS command; try to bind all listed addresses,
* and report success or failrue. */
static int
-handle_control_mapaddress(connection_t *conn, uint32_t len, const char *body)
+handle_control_mapaddress(control_connection_t *conn, uint32_t len,
+ const char *body)
{
smartlist_t *elts;
smartlist_t *lines;
smartlist_t *reply;
char *r;
size_t sz;
- int v0 = STATE_IS_V0(conn->state);
+ int v0 = STATE_IS_V0(conn->_base.state);
+ (void) len; /* body is nul-terminated, so it's safe to ignore the length. */
+
lines = smartlist_create();
elts = smartlist_create();
reply = smartlist_create();
@@ -1252,12 +1276,12 @@ handle_control_mapaddress(connection_t *conn, uint32_t len, const char *body)
if (smartlist_len(reply)) {
((char*)smartlist_get(reply,smartlist_len(reply)-1))[3] = ' ';
r = smartlist_join_strings(reply, "\r\n", 1, &sz);
- connection_write_to_buf(r, sz, conn);
+ connection_write_to_buf(r, sz, TO_CONN(conn));
tor_free(r);
} else {
const char *response =
"512 syntax error: not enough arguments to mapaddress.\r\n";
- connection_write_to_buf(response, strlen(response), conn);
+ connection_write_to_buf(response, strlen(response), TO_CONN(conn));
}
}
@@ -1283,13 +1307,16 @@ list_getinfo_options(void)
"addr-mappings/cache Addresses remapped by DNS cache.\n"
"addr-mappings/configl Addresses remapped from configuration options.\n"
"addr-mappings/control Addresses remapped by a controller.\n"
+ "address The best guess at our external IP address.\n"
"circuit-status Status of each current circuit.\n"
+ "config-file Current location of the \"torrc\" file.\n"
"config/names List of configuration options, types, and documentation.\n"
"desc/id/* Server descriptor by hex ID\n"
"desc/name/* Server descriptor by nickname.\n"
"desc/all-recent Latest server descriptor for every router\n"
"dir/server/* Fetch server descriptors -- see dir-spec.txt\n"
"entry-guards Which nodes will we use as entry guards?\n"
+ "exit-policy/default Default lines appended to config->ExitPolicy\n"
"info/names List of GETINFO options, types, and documentation.\n"
"network-status List of hex IDs, nicknames, server statuses.\n"
"orconn-status Status of each current OR connection.\n"
@@ -1299,7 +1326,7 @@ list_getinfo_options(void)
/** Lookup the 'getinfo' entry <b>question</b>, and return
* the answer in <b>*answer</b> (or NULL if key not recognized).
- * Return 0 if success, or -1 if internal error. */
+ * Return 0 if success, or -1 if recognized but internal error. */
static int
handle_getinfo_helper(const char *question, char **answer)
{
@@ -1323,14 +1350,14 @@ handle_getinfo_helper(const char *question, char **answer)
if (ri) {
const char *body = signed_descriptor_get_body(&ri->cache_info);
if (body)
- *answer = tor_strdup(body);
+ *answer = tor_strndup(body, ri->cache_info.signed_descriptor_len);
}
} else if (!strcmpstart(question, "desc/name/")) {
routerinfo_t *ri = router_get_by_nickname(question+strlen("desc/name/"),1);
if (ri) {
const char *body = signed_descriptor_get_body(&ri->cache_info);
if (body)
- *answer = tor_strdup(body);
+ *answer = tor_strndup(body, ri->cache_info.signed_descriptor_len);
}
} else if (!strcmp(question, "desc/all-recent")) {
routerlist_t *routerlist = router_get_routerlist();
@@ -1340,7 +1367,8 @@ handle_getinfo_helper(const char *question, char **answer)
{
const char *body = signed_descriptor_get_body(&ri->cache_info);
if (body)
- smartlist_add(sl, tor_strdup(body));
+ smartlist_add(sl,
+ tor_strndup(body, ri->cache_info.signed_descriptor_len));
});
}
*answer = smartlist_join_strings(sl, "", 0, NULL);
@@ -1364,7 +1392,7 @@ handle_getinfo_helper(const char *question, char **answer)
const char *state;
if (! CIRCUIT_IS_ORIGIN(circ) || circ->marked_for_close)
continue;
- path = circuit_list_path(circ,0);
+ path = circuit_list_path(TO_ORIGIN_CIRCUIT(circ),0);
if (circ->state == CIRCUIT_STATE_OPEN)
state = "BUILT";
else if (strlen(path))
@@ -1375,7 +1403,7 @@ handle_getinfo_helper(const char *question, char **answer)
slen = strlen(path)+strlen(state)+20;
s = tor_malloc(slen+1);
tor_snprintf(s, slen, "%lu %s %s",
- (unsigned long)circ->global_identifier,
+ (unsigned long)TO_ORIGIN_CIRCUIT(circ)->global_identifier,
state, path);
smartlist_add(status, s);
tor_free(path);
@@ -1391,19 +1419,24 @@ handle_getinfo_helper(const char *question, char **answer)
get_connection_array(&conns, &n_conns);
for (i=0; i < n_conns; ++i) {
const char *state;
+ edge_connection_t *conn;
char *s;
size_t slen;
circuit_t *circ;
+ origin_circuit_t *origin_circ = NULL;
if (conns[i]->type != CONN_TYPE_AP ||
conns[i]->marked_for_close ||
- conns[i]->state == AP_CONN_STATE_SOCKS_WAIT)
+ conns[i]->state == AP_CONN_STATE_SOCKS_WAIT ||
+ conns[i]->state == AP_CONN_STATE_ORIGDST_WAIT)
continue;
- switch (conns[i]->state)
+ conn = TO_EDGE_CONN(conns[i]);
+ switch (conn->_base.state)
{
case AP_CONN_STATE_CONTROLLER_WAIT:
case AP_CONN_STATE_CIRCUIT_WAIT:
- if (conns[i]->socks_request &&
- conns[i]->socks_request->command == SOCKS_COMMAND_RESOLVE)
+ if (conn->socks_request &&
+ (conn->socks_request->command == SOCKS_COMMAND_RESOLVE ||
+ conn->socks_request->command == SOCKS_COMMAND_RESOLVE_PTR))
state = "NEWRESOLVE";
else
state = "NEW";
@@ -1417,16 +1450,19 @@ handle_getinfo_helper(const char *question, char **answer)
state = "SUCCEEDED"; break;
default:
log_warn(LD_BUG, "Asked for stream in unknown state %d",
- conns[i]->state);
+ conn->_base.state);
continue;
}
- circ = circuit_get_by_edge_conn(conns[i]);
- write_stream_target_to_buf(conns[i], buf, sizeof(buf));
+ circ = circuit_get_by_edge_conn(conn);
+ if (circ && CIRCUIT_IS_ORIGIN(circ))
+ origin_circ = TO_ORIGIN_CIRCUIT(circ);
+ write_stream_target_to_buf(conn, buf, sizeof(buf));
slen = strlen(buf)+strlen(state)+32;
s = tor_malloc(slen+1);
tor_snprintf(s, slen, "%lu %s %lu %s",
- (unsigned long) conns[i]->global_identifier,state,
- circ?(unsigned long)circ->global_identifier : 0ul,
+ (unsigned long) conn->global_identifier,state,
+ origin_circ?
+ (unsigned long)origin_circ->global_identifier : 0ul,
buf);
smartlist_add(status, s);
}
@@ -1443,10 +1479,11 @@ handle_getinfo_helper(const char *question, char **answer)
char *s;
char name[128];
size_t slen;
- connection_t *conn = conns[i];
- if (conn->type != CONN_TYPE_OR || conn->marked_for_close)
+ or_connection_t *conn;
+ if (conns[i]->type != CONN_TYPE_OR || conns[i]->marked_for_close)
continue;
- if (conn->state == OR_CONN_STATE_OPEN)
+ conn = TO_OR_CONN(conns[i]);
+ if (conn->_base.state == OR_CONN_STATE_OPEN)
state = "CONNECTED";
else if (conn->nickname)
state = "LAUNCHED";
@@ -1456,7 +1493,7 @@ handle_getinfo_helper(const char *question, char **answer)
strlcpy(name, conn->nickname, sizeof(name));
else
tor_snprintf(name, sizeof(name), "%s:%d",
- conn->address, conn->port);
+ conn->_base.address, conn->_base.port);
slen = strlen(name)+strlen(state)+2;
s = tor_malloc(slen+1);
@@ -1482,9 +1519,14 @@ handle_getinfo_helper(const char *question, char **answer)
}
mappings = smartlist_create();
addressmap_get_mappings(mappings, min_e, max_e);
- *answer = smartlist_join_strings(mappings, "\n", 0, NULL);
+ *answer = smartlist_join_strings(mappings, "\r\n", 0, NULL);
SMARTLIST_FOREACH(mappings, char *, cp, tor_free(cp));
smartlist_free(mappings);
+ } else if (!strcmp(question, "address")) {
+ uint32_t addr;
+ if (router_pick_published_address(get_options(), &addr) < 0)
+ return -1;
+ *answer = tor_dup_addr(addr);
} else if (!strcmp(question, "dir-usage")) {
*answer = directory_dump_request_log();
} else if (!strcmpstart(question, "dir/server/")) {
@@ -1514,7 +1556,7 @@ handle_getinfo_helper(const char *question, char **answer)
char *cp;
if (!get_options()->DirPort) {
log_warn(LD_CONTROL, "getinfo dir/status/ requires an open dirport.");
- return 0;
+ return -1;
}
status_list = smartlist_create();
dirserv_get_networkstatus_v2(status_list,
@@ -1527,6 +1569,8 @@ handle_getinfo_helper(const char *question, char **answer)
cp += d->dir_len;
});
*cp = '\0';
+ } else if (!strcmpstart(question, "exit-policy/")) {
+ return policies_getinfo_helper(question, answer);
}
return 0;
}
@@ -1534,14 +1578,16 @@ handle_getinfo_helper(const char *question, char **answer)
/** Called when we receive a GETINFO command. Try to fetch all requested
* information, and reply with information or error message. */
static int
-handle_control_getinfo(connection_t *conn, uint32_t len, const char *body)
+handle_control_getinfo(control_connection_t *conn, uint32_t len,
+ const char *body)
{
smartlist_t *questions = NULL;
smartlist_t *answers = NULL;
smartlist_t *unrecognized = NULL;
char *msg = NULL, *ans = NULL;
size_t msg_len;
- int v0 = STATE_IS_V0(conn->state);
+ int v0 = STATE_IS_V0(conn->_base.state);
+ (void) len; /* body is nul-terminated, so it's safe to ignore the length. */
questions = smartlist_create();
if (v0)
@@ -1604,7 +1650,7 @@ handle_control_getinfo(connection_t *conn, uint32_t len, const char *body)
size_t len;
len = write_escaped_data(v, strlen(v), 1, &esc);
connection_printf_to_buf(conn, "250+%s=\r\n", k);
- connection_write_to_buf(esc, len, conn);
+ connection_write_to_buf(esc, len, TO_CONN(conn));
tor_free(esc);
}
}
@@ -1626,20 +1672,23 @@ handle_control_getinfo(connection_t *conn, uint32_t len, const char *body)
return 0;
}
-/** If <b>string</b> contains a recognized purpose (for
+/** If *<b>string</b> contains a recognized purpose (for
* circuits if <b>for_circuits</b> is 1, else for routers),
* possibly prefaced with the string "purpose=", then assign it
- * and return 0. Otherwise return -1. */
+ * and return 0. Otherwise return -1.
+ *
+ * If it's prefaced with "purpose=", then set *<b>string</b> to
+ * the remainder of the string. */
static int
-get_purpose(char *string, int for_circuits, uint8_t *purpose)
+get_purpose(char **string, int for_circuits, uint8_t *purpose)
{
- if (!strcmpstart(string, "purpose="))
- string += strlen("purpose=");
+ if (!strcmpstart(*string, "purpose="))
+ *string += strlen("purpose=");
- if (!strcmp(string, "general"))
+ if (!strcmp(*string, "general"))
*purpose = for_circuits ? CIRCUIT_PURPOSE_C_GENERAL :
ROUTER_PURPOSE_GENERAL;
- else if (!strcmp(string, "controller"))
+ else if (!strcmp(*string, "controller"))
*purpose = for_circuits ? CIRCUIT_PURPOSE_CONTROLLER :
ROUTER_PURPOSE_GENERAL;
else { /* not a recognized purpose */
@@ -1651,17 +1700,17 @@ get_purpose(char *string, int for_circuits, uint8_t *purpose)
/** Called when we get an EXTENDCIRCUIT message. Try to extend the listed
* circuit, and report success or failure. */
static int
-handle_control_extendcircuit(connection_t *conn, uint32_t len,
+handle_control_extendcircuit(control_connection_t *conn, uint32_t len,
const char *body)
{
smartlist_t *router_nicknames=NULL, *routers=NULL;
uint32_t circ_id;
- circuit_t *circ = NULL;
+ origin_circuit_t *circ = NULL;
int zero_circ, v0;
char reply[4];
uint8_t intended_purpose = CIRCUIT_PURPOSE_C_GENERAL;
- v0 = STATE_IS_V0(conn->state);
+ v0 = STATE_IS_V0(conn->_base.state);
router_nicknames = smartlist_create();
if (v0) {
@@ -1704,9 +1753,9 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len,
smartlist_split_string(router_nicknames, smartlist_get(args,1), ",", 0, 0);
if (zero_circ && smartlist_len(args)>2) {
- if (get_purpose(smartlist_get(args,2), 1, &intended_purpose) < 0) {
- connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n",
- (char *)smartlist_get(args,2));
+ char *purp = smartlist_get(args,2);
+ if (get_purpose(&purp, 1, &intended_purpose) < 0) {
+ connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n", purp);
SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
smartlist_free(args);
goto done;
@@ -1717,6 +1766,11 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len,
if (!zero_circ && !circ) {
goto done;
}
+ SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
+ smartlist_free(args);
+ if (!zero_circ && !circ) {
+ goto done;
+ }
}
routers = smartlist_create();
@@ -1742,7 +1796,7 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len,
if (zero_circ) {
/* start a new circuit */
- circ = circuit_init(intended_purpose, 0, 0, 0);
+ circ = origin_circuit_init(intended_purpose, 0, 0, 0);
}
/* now circ refers to something that is ready to be extended */
@@ -1756,7 +1810,7 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len,
/* now that we've populated the cpath, start extending */
if (zero_circ) {
if (circuit_handle_first_hop(circ) < 0) {
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
if (v0)
send_control0_error(conn, ERR_INTERNAL, "couldn't start circuit");
else
@@ -1764,12 +1818,12 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len,
goto done;
}
} else {
- if (circ->state == CIRCUIT_STATE_OPEN) {
- circuit_set_state(circ, CIRCUIT_STATE_BUILDING);
+ if (circ->_base.state == CIRCUIT_STATE_OPEN) {
+ circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
if (circuit_send_next_onion_skin(circ) < 0) {
log_info(LD_CONTROL,
"send_next_onion_skin failed; circuit marked for closing.");
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
if (v0)
send_control0_error(conn, ERR_INTERNAL, "couldn't send onion skin");
else
@@ -1798,13 +1852,14 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len,
* is 1) or SETROUTERPURPOSE message. If we can find
* the circuit/router and it's a valid purpose, change it. */
static int
-handle_control_setpurpose(connection_t *conn, int for_circuits,
+handle_control_setpurpose(control_connection_t *conn, int for_circuits,
uint32_t len, const char *body)
{
- circuit_t *circ = NULL;
+ origin_circuit_t *circ = NULL;
routerinfo_t *ri = NULL;
uint8_t new_purpose;
smartlist_t *args = smartlist_create();
+ (void) len; /* body is nul-terminated, so it's safe to ignore the length. */
smartlist_split_string(args, body, " ",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
if (smartlist_len(args)<2) {
@@ -1828,14 +1883,16 @@ handle_control_setpurpose(connection_t *conn, int for_circuits,
}
}
- if (get_purpose(smartlist_get(args,1), for_circuits, &new_purpose) < 0) {
- connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n",
- (char *)smartlist_get(args,1));
- goto done;
+ {
+ char *purp = smartlist_get(args,1);
+ if (get_purpose(&purp, for_circuits, &new_purpose) < 0) {
+ connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n", purp);
+ goto done;
+ }
}
if (for_circuits)
- circ->purpose = new_purpose;
+ circ->_base.purpose = new_purpose;
else
ri->purpose = new_purpose;
connection_write_str_to_buf("250 OK\r\n", conn);
@@ -1849,14 +1906,14 @@ done:
/** Called when we get an ATTACHSTREAM message. Try to attach the requested
* stream, and report success or failure. */
static int
-handle_control_attachstream(connection_t *conn, uint32_t len,
+handle_control_attachstream(control_connection_t *conn, uint32_t len,
const char *body)
{
- connection_t *ap_conn = NULL;
- circuit_t *circ = NULL;
+ edge_connection_t *ap_conn = NULL;
+ origin_circuit_t *circ = NULL;
int zero_circ;
- if (STATE_IS_V0(conn->state)) {
+ if (STATE_IS_V0(conn->_base.state)) {
uint32_t conn_id;
uint32_t circ_id;
if (len < 8) {
@@ -1905,10 +1962,10 @@ handle_control_attachstream(connection_t *conn, uint32_t len,
return 0;
}
- if (ap_conn->state != AP_CONN_STATE_CONTROLLER_WAIT &&
- ap_conn->state != AP_CONN_STATE_CONNECT_WAIT &&
- ap_conn->state != AP_CONN_STATE_RESOLVE_WAIT) {
- if (STATE_IS_V0(conn->state)) {
+ if (ap_conn->_base.state != AP_CONN_STATE_CONTROLLER_WAIT &&
+ ap_conn->_base.state != AP_CONN_STATE_CONNECT_WAIT &&
+ ap_conn->_base.state != AP_CONN_STATE_RESOLVE_WAIT) {
+ if (STATE_IS_V0(conn->_base.state)) {
send_control0_error(conn, ERR_NO_STREAM,
"Connection is not managed by controller.");
} else {
@@ -1920,28 +1977,29 @@ handle_control_attachstream(connection_t *conn, uint32_t len,
}
/* Do we need to detach it first? */
- if (ap_conn->state != AP_CONN_STATE_CONTROLLER_WAIT) {
+ if (ap_conn->_base.state != AP_CONN_STATE_CONTROLLER_WAIT) {
circuit_t *tmpcirc = circuit_get_by_edge_conn(ap_conn);
- connection_edge_end(ap_conn, END_STREAM_REASON_TIMEOUT, conn->cpath_layer);
+ connection_edge_end(ap_conn, END_STREAM_REASON_TIMEOUT,
+ ap_conn->cpath_layer);
/* Un-mark it as ending, since we're going to reuse it. */
- ap_conn->has_sent_end = 0;
+ ap_conn->_base.edge_has_sent_end = 0;
if (tmpcirc)
circuit_detach_stream(tmpcirc,ap_conn);
- ap_conn->state = AP_CONN_STATE_CONTROLLER_WAIT;
+ ap_conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
}
- if (circ && circ->state != CIRCUIT_STATE_OPEN) {
- if (STATE_IS_V0(conn->state))
+ if (circ && (circ->_base.state != CIRCUIT_STATE_OPEN)) {
+ if (STATE_IS_V0(conn->_base.state))
send_control0_error(conn, ERR_INTERNAL,
- "Refuse to attach stream to non-open circ.");
+ "Refuse to attach stream to non-open, origin circ.");
else
connection_write_str_to_buf(
- "551 Can't attach stream to non-open circuit\r\n",
- conn);
+ "551 Can't attach stream to non-open, origin circuit\r\n",
+ conn);
return 0;
}
if (connection_ap_handshake_rewrite_and_attach(ap_conn, circ) < 0) {
- if (STATE_IS_V0(conn->state))
+ if (STATE_IS_V0(conn->_base.state))
send_control0_error(conn, ERR_INTERNAL, "Unable to attach stream.");
else
connection_write_str_to_buf("551 Unable to attach stream\r\n", conn);
@@ -1954,11 +2012,11 @@ handle_control_attachstream(connection_t *conn, uint32_t len,
/** Called when we get a POSTDESCRIPTOR message. Try to learn the provided
* descriptor, and report success or failure. */
static int
-handle_control_postdescriptor(connection_t *conn, uint32_t len,
+handle_control_postdescriptor(control_connection_t *conn, uint32_t len,
const char *body)
{
char *desc;
- int v0 = STATE_IS_V0(conn->state);
+ int v0 = STATE_IS_V0(conn->_base.state);
const char *msg=NULL;
uint8_t purpose = ROUTER_PURPOSE_GENERAL;
@@ -1972,9 +2030,10 @@ handle_control_postdescriptor(connection_t *conn, uint32_t len,
smartlist_split_string(args, body, " ",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
if (smartlist_len(args)) {
- if (get_purpose(smartlist_get(args,0), 0, &purpose) < 0) {
+ char *purp = smartlist_get(args,0);
+ if (get_purpose(&purp, 0, &purpose) < 0) {
connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n",
- (char *)smartlist_get(args,0));
+ purp);
SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
smartlist_free(args);
return 0;
@@ -2013,14 +2072,14 @@ handle_control_postdescriptor(connection_t *conn, uint32_t len,
/** Called when we receive a REDIRECTSTERAM command. Try to change the target
* address of the named AP stream, and report success or failure. */
static int
-handle_control_redirectstream(connection_t *conn, uint32_t len,
+handle_control_redirectstream(control_connection_t *conn, uint32_t len,
const char *body)
{
- connection_t *ap_conn = NULL;
+ edge_connection_t *ap_conn = NULL;
uint32_t conn_id;
char *new_addr = NULL;
uint16_t new_port = 0;
- if (STATE_IS_V0(conn->state)) {
+ if (STATE_IS_V0(conn->_base.state)) {
if (len < 6) {
send_control0_error(conn, ERR_SYNTAX,
"redirectstream message too short");
@@ -2029,8 +2088,8 @@ handle_control_redirectstream(connection_t *conn, uint32_t len,
conn_id = ntohl(get_uint32(body));
if (!(ap_conn = connection_get_by_global_id(conn_id))
- || ap_conn->state != CONN_TYPE_AP
- || !ap_conn->socks_request) {
+ || ap_conn->_base.state != CONN_TYPE_AP
+ || ap_conn->socks_request) {
send_control0_error(conn, ERR_NO_STREAM,
"No AP connection found with given ID");
return 0;
@@ -2080,13 +2139,13 @@ handle_control_redirectstream(connection_t *conn, uint32_t len,
/** Called when we get a CLOSESTREAM command; try to close the named stream
* and report success or failure. */
static int
-handle_control_closestream(connection_t *conn, uint32_t len,
+handle_control_closestream(control_connection_t *conn, uint32_t len,
const char *body)
{
- connection_t *ap_conn=NULL;
+ edge_connection_t *ap_conn=NULL;
uint8_t reason=0;
- if (STATE_IS_V0(conn->state)) {
+ if (STATE_IS_V0(conn->_base.state)) {
uint32_t conn_id;
if (len < 6) {
send_control0_error(conn, ERR_SYNTAX, "closestream message too short");
@@ -2097,8 +2156,8 @@ handle_control_closestream(connection_t *conn, uint32_t len,
reason = *(uint8_t*)(body+4);
if (!(ap_conn = connection_get_by_global_id(conn_id))
- || ap_conn->state != CONN_TYPE_AP
- || !ap_conn->socks_request) {
+ || ap_conn->_base.state != CONN_TYPE_AP
+ || ap_conn->socks_request) {
send_control0_error(conn, ERR_NO_STREAM,
"No AP connection found with given ID");
return 0;
@@ -2138,13 +2197,13 @@ handle_control_closestream(connection_t *conn, uint32_t len,
/** Called when we get a CLOSECIRCUIT command; try to close the named circuit
* and report success or failure. */
static int
-handle_control_closecircuit(connection_t *conn, uint32_t len,
+handle_control_closecircuit(control_connection_t *conn, uint32_t len,
const char *body)
{
- circuit_t *circ = NULL;
+ origin_circuit_t *circ = NULL;
int safe = 0;
- if (STATE_IS_V0(conn->state)) {
+ if (STATE_IS_V0(conn->_base.state)) {
uint32_t circ_id;
if (len < 5) {
send_control0_error(conn, ERR_SYNTAX, "closecircuit message too short");
@@ -2186,7 +2245,7 @@ handle_control_closecircuit(connection_t *conn, uint32_t len,
}
if (!safe || !circ->p_streams) {
- circuit_mark_for_close(circ, END_CIRC_REASON_NONE);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_NONE);
}
send_control_done(conn);
@@ -2199,7 +2258,7 @@ handle_control_closecircuit(connection_t *conn, uint32_t len,
* fragments and report failure.
*/
static int
-handle_control_fragments(connection_t *conn, uint16_t command_type,
+handle_control_fragments(control_connection_t *conn, uint16_t command_type,
uint32_t body_len, char *body)
{
if (command_type == CONTROL0_CMD_FRAGMENTHEADER) {
@@ -2240,24 +2299,22 @@ handle_control_fragments(connection_t *conn, uint16_t command_type,
/** Called when <b>conn</b> has no more bytes left on its outbuf. */
int
-connection_control_finished_flushing(connection_t *conn)
+connection_control_finished_flushing(control_connection_t *conn)
{
tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_CONTROL);
- connection_stop_writing(conn);
+ connection_stop_writing(TO_CONN(conn));
return 0;
}
/** Called when <b>conn</b> has gotten its socket closed. */
int
-connection_control_reached_eof(connection_t *conn)
+connection_control_reached_eof(control_connection_t *conn)
{
tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_CONTROL);
log_info(LD_CONTROL,"Control connection reached EOF. Closing.");
- connection_mark_for_close(conn);
+ connection_mark_for_close(TO_CONN(conn));
return 0;
}
@@ -2265,16 +2322,15 @@ connection_control_reached_eof(connection_t *conn)
* commands from conn->inbuf, and execute them.
*/
static int
-connection_control_process_inbuf_v1(connection_t *conn)
+connection_control_process_inbuf_v1(control_connection_t *conn)
{
size_t data_len;
int cmd_len;
char *args;
tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_CONTROL);
- tor_assert(conn->state == CONTROL_CONN_STATE_OPEN_V1 ||
- conn->state == CONTROL_CONN_STATE_NEEDAUTH_V1);
+ tor_assert(conn->_base.state == CONTROL_CONN_STATE_OPEN_V1 ||
+ conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH_V1);
if (!conn->incoming_cmd) {
conn->incoming_cmd = tor_malloc(1024);
@@ -2289,7 +2345,7 @@ connection_control_process_inbuf_v1(connection_t *conn)
/* First, fetch a line. */
do {
data_len = conn->incoming_cmd_len - conn->incoming_cmd_cur_len;
- r = fetch_from_buf_line(conn->inbuf,
+ r = fetch_from_buf_line(conn->_base.inbuf,
conn->incoming_cmd+conn->incoming_cmd_cur_len,
&data_len);
if (r == 0)
@@ -2339,11 +2395,11 @@ connection_control_process_inbuf_v1(connection_t *conn)
if (!strcasecmp(conn->incoming_cmd, "QUIT")) {
connection_write_str_to_buf("250 closing connection\r\n", conn);
- connection_mark_for_close(conn);
+ connection_mark_for_close(TO_CONN(conn));
return 0;
}
- if (conn->state == CONTROL_CONN_STATE_NEEDAUTH_V1 &&
+ if (conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH_V1 &&
strcasecmp(conn->incoming_cmd, "AUTHENTICATE")) {
connection_write_str_to_buf("514 Authentication required.\r\n", conn);
conn->incoming_cmd_cur_len = 0;
@@ -2414,7 +2470,7 @@ connection_control_process_inbuf_v1(connection_t *conn)
* commands from conn->inbuf, and execute them.
*/
static int
-connection_control_process_inbuf_v0(connection_t *conn)
+connection_control_process_inbuf_v0(control_connection_t *conn)
{
uint32_t body_len;
uint16_t command_type;
@@ -2422,15 +2478,16 @@ connection_control_process_inbuf_v0(connection_t *conn)
again:
/* Try to suck a control message from the buffer. */
- switch (fetch_from_buf_control0(conn->inbuf, &body_len, &command_type, &body,
- conn->state == CONTROL_CONN_STATE_NEEDAUTH_V0))
+ switch (fetch_from_buf_control0(conn->_base.inbuf, &body_len, &command_type,
+ &body,
+ conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH_V0))
{
case -2:
tor_free(body);
log_info(LD_CONTROL,
"Detected v1 control protocol on connection (fd %d)",
- conn->s);
- conn->state = CONTROL_CONN_STATE_NEEDAUTH_V1;
+ conn->_base.s);
+ conn->_base.state = CONTROL_CONN_STATE_NEEDAUTH_V1;
return connection_control_process_inbuf_v1(conn);
case -1:
tor_free(body);
@@ -2448,7 +2505,7 @@ connection_control_process_inbuf_v0(connection_t *conn)
/* We got a command. If we need authentication, only authentication
* commands will be considered. */
- if (conn->state == CONTROL_CONN_STATE_NEEDAUTH_V0 &&
+ if (conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH_V0 &&
command_type != CONTROL0_CMD_AUTHENTICATE) {
log_info(LD_CONTROL, "Rejecting '%s' command; authentication needed.",
control_cmd_to_string(command_type));
@@ -2562,12 +2619,11 @@ connection_control_process_inbuf_v0(connection_t *conn)
/** Called when <b>conn</b> has received more bytes on its inbuf.
*/
int
-connection_control_process_inbuf(connection_t *conn)
+connection_control_process_inbuf(control_connection_t *conn)
{
tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_CONTROL);
- if (STATE_IS_V0(conn->state))
+ if (STATE_IS_V0(conn->_base.state))
return connection_control_process_inbuf_v0(conn);
else
return connection_control_process_inbuf_v1(conn);
@@ -2576,13 +2632,12 @@ connection_control_process_inbuf(connection_t *conn)
/** Something has happened to circuit <b>circ</b>: tell any interested
* control connections. */
int
-control_event_circuit_status(circuit_t *circ, circuit_status_event_t tp)
+control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp)
{
char *path, *msg;
if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS))
return 0;
tor_assert(circ);
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
path = circuit_list_path(circ,0);
if (EVENT_IS_INTERESTING0(EVENT_CIRCUIT_STATUS)) {
@@ -2623,7 +2678,7 @@ control_event_circuit_status(circuit_t *circ, circuit_status_event_t tp)
* <b>conn</b>, and write it to <b>buf</b>. Return 0 on success, -1 on
* failure. */
static int
-write_stream_target_to_buf(connection_t *conn, char *buf, size_t len)
+write_stream_target_to_buf(edge_connection_t *conn, char *buf, size_t len)
{
char buf2[256];
if (conn->chosen_exit_name)
@@ -2642,12 +2697,11 @@ write_stream_target_to_buf(connection_t *conn, char *buf, size_t len)
/** Something has happened to the stream associated with AP connection
* <b>conn</b>: tell any interested control connections. */
int
-control_event_stream_status(connection_t *conn, stream_status_event_t tp)
+control_event_stream_status(edge_connection_t *conn, stream_status_event_t tp)
{
char *msg;
size_t len;
char buf[256];
- tor_assert(conn->type == CONN_TYPE_AP);
tor_assert(conn->socks_request);
if (!EVENT_IS_INTERESTING(EVENT_STREAM_STATUS))
@@ -2667,6 +2721,7 @@ control_event_stream_status(connection_t *conn, stream_status_event_t tp)
if (EVENT_IS_INTERESTING1(EVENT_STREAM_STATUS)) {
const char *status;
circuit_t *circ;
+ origin_circuit_t *origin_circ = NULL;
switch (tp)
{
case STREAM_EVENT_SENT_CONNECT: status = "SENTCONNECT"; break;
@@ -2682,10 +2737,13 @@ control_event_stream_status(connection_t *conn, stream_status_event_t tp)
return 0;
}
circ = circuit_get_by_edge_conn(conn);
+ if (circ && CIRCUIT_IS_ORIGIN(circ))
+ origin_circ = TO_ORIGIN_CIRCUIT(circ);
send_control1_event(EVENT_STREAM_STATUS,
"650 STREAM %lu %s %lu %s\r\n",
(unsigned long)conn->global_identifier, status,
- circ?(unsigned long)circ->global_identifier : 0ul,
+ origin_circ?
+ (unsigned long)origin_circ->global_identifier : 0ul,
buf);
/* XXX need to specify its intended exit, etc? */
}
@@ -2695,13 +2753,11 @@ control_event_stream_status(connection_t *conn, stream_status_event_t tp)
/** Something has happened to the OR connection <b>conn</b>: tell any
* interested control connections. */
int
-control_event_or_conn_status(connection_t *conn,or_conn_status_event_t tp)
+control_event_or_conn_status(or_connection_t *conn,or_conn_status_event_t tp)
{
char buf[HEX_DIGEST_LEN+3]; /* status, dollar, identity, NUL */
size_t len;
- tor_assert(conn->type == CONN_TYPE_OR);
-
if (!EVENT_IS_INTERESTING(EVENT_OR_CONN_STATUS))
return 0;
@@ -2718,13 +2774,14 @@ control_event_or_conn_status(connection_t *conn,or_conn_status_event_t tp)
strlcpy(name, conn->nickname, sizeof(name));
else
tor_snprintf(name, sizeof(name), "%s:%d",
- conn->address, conn->port);
+ conn->_base.address, conn->_base.port);
switch (tp)
{
case OR_CONN_EVENT_LAUNCHED: status = "LAUNCHED"; break;
case OR_CONN_EVENT_CONNECTED: status = "CONNECTED"; break;
case OR_CONN_EVENT_FAILED: status = "FAILED"; break;
case OR_CONN_EVENT_CLOSED: status = "CLOSED"; break;
+ case OR_CONN_EVENT_NEW: status = "NEW"; break;
default:
log_warn(LD_BUG, "Unrecognized status code %d", (int)tp);
return 0;
@@ -2781,6 +2838,7 @@ void
control_event_logmsg(int severity, unsigned int domain, const char *msg)
{
int oldlog, event;
+ (void) domain;
if (disable_log_messages)
return;
@@ -2858,8 +2916,12 @@ control_event_descriptors_changed(smartlist_t *routers)
tor_free(msg);
}
if (EVENT_IS_INTERESTING1(EVENT_NEW_DESC)) {
- msg = smartlist_join_strings(identities, " ", 0, &len);
- send_control1_event(EVENT_NEW_DESC, "650 NEWDESC %s\r\n", msg);
+ char *ids = smartlist_join_strings(identities, " ", 0, &len);
+ size_t len = strlen(ids)+32;
+ msg = tor_malloc(len);
+ tor_snprintf(msg, len, "650 NEWDESC %s\r\n", ids);
+ send_control1_event_string(EVENT_NEW_DESC, msg);
+ tor_free(ids);
tor_free(msg);
}
SMARTLIST_FOREACH(identities, char *, cp, tor_free(cp));
diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c
index bece3456bc..17c176ae11 100644
--- a/src/or/cpuworker.c
+++ b/src/or/cpuworker.c
@@ -36,7 +36,7 @@ static int num_cpuworkers_busy=0;
* the last time we got a key rotation event. */
static time_t last_rotation_time=0;
-static int cpuworker_main(void *data);
+static void cpuworker_main(void *data);
static int spawn_cpuworker(void);
static void spawn_enough_cpuworkers(void);
static void process_pending_task(connection_t *cpuworker);
@@ -137,7 +137,7 @@ connection_cpu_process_inbuf(connection_t *conn)
uint32_t addr;
uint16_t port;
uint16_t circ_id;
- connection_t *p_conn;
+ or_connection_t *p_conn;
circuit_t *circ;
tor_assert(conn);
@@ -181,8 +181,8 @@ connection_cpu_process_inbuf(connection_t *conn)
log_debug(LD_OR,"processed onion for a circ that's gone. Dropping.");
goto done_processing;
}
- tor_assert(circ->p_conn);
- if (onionskin_answer(circ, CELL_CREATED, buf+TAG_LEN,
+ tor_assert(! CIRCUIT_IS_ORIGIN(circ));
+ if (onionskin_answer(TO_OR_CIRCUIT(circ), CELL_CREATED, buf+TAG_LEN,
buf+TAG_LEN+ONIONSKIN_REPLY_LEN) < 0) {
log_warn(LD_OR,"onionskin_answer failed. Closing.");
circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
@@ -222,7 +222,7 @@ done_processing:
* (Note: this _should_ be by addr/port, since we're concerned with specific
* connections, not with routers (where we'd use identity).)
*/
-static int
+static void
cpuworker_main(void *data)
{
char question[ONIONSKIN_CHALLENGE_LEN];
@@ -308,7 +308,6 @@ cpuworker_main(void *data)
tor_close_socket(fd);
crypto_thread_cleanup();
spawn_exit();
- return 0; /* windows wants this function to return an int */
}
/** Launch a new cpuworker. Return 0 if we're happy, -1 if we failed.
@@ -329,6 +328,9 @@ spawn_cpuworker(void)
return -1;
}
+ tor_assert(fdarray[0] >= 0);
+ tor_assert(fdarray[1] >= 0);
+
fd = fdarray[0];
spawn_func(cpuworker_main, (void*)fdarray);
log_debug(LD_OR,"just spawned a cpu worker.");
@@ -383,7 +385,7 @@ spawn_enough_cpuworkers(void)
static void
process_pending_task(connection_t *cpuworker)
{
- circuit_t *circ;
+ or_circuit_t *circ;
tor_assert(cpuworker);
@@ -441,7 +443,7 @@ int
assign_to_cpuworker(connection_t *cpuworker, uint8_t question_type,
void *task)
{
- circuit_t *circ;
+ or_circuit_t *circ;
char tag[TAG_LEN];
tor_assert(question_type == CPUWORKER_TASK_ONION);
@@ -451,7 +453,7 @@ assign_to_cpuworker(connection_t *cpuworker, uint8_t question_type,
if (question_type == CPUWORKER_TASK_ONION) {
circ = task;
- tor_assert(circ->onionskin);
+ tor_assert(circ->_base.onionskin);
if (num_cpuworkers_busy == num_cpuworkers) {
log_debug(LD_OR,"No idle cpuworkers. Queuing.");
@@ -470,7 +472,8 @@ assign_to_cpuworker(connection_t *cpuworker, uint8_t question_type,
log_info(LD_OR,"circ->p_conn gone. Failing circ.");
return -1;
}
- tag_pack(tag, circ->p_conn->addr, circ->p_conn->port, circ->p_circ_id);
+ tag_pack(tag, circ->p_conn->_base.addr, circ->p_conn->_base.port,
+ circ->p_circ_id);
cpuworker->state = CPUWORKER_STATE_BUSY_ONION;
/* touch the lastwritten timestamp, since that's how we check to
@@ -481,9 +484,9 @@ assign_to_cpuworker(connection_t *cpuworker, uint8_t question_type,
connection_write_to_buf((char*)&question_type, 1, cpuworker);
connection_write_to_buf(tag, sizeof(tag), cpuworker);
- connection_write_to_buf(circ->onionskin, ONIONSKIN_CHALLENGE_LEN,
+ connection_write_to_buf(circ->_base.onionskin, ONIONSKIN_CHALLENGE_LEN,
cpuworker);
- tor_free(circ->onionskin);
+ tor_free(circ->_base.onionskin);
}
return 0;
}
diff --git a/src/or/directory.c b/src/or/directory.c
index 3a3f3a0012..91b5322bcf 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -38,16 +38,17 @@ directory_initiate_command(const char *address, uint32_t addr, uint16_t port,
const char *payload, size_t payload_len);
static void
-directory_send_command(connection_t *conn, const char *platform,
+directory_send_command(dir_connection_t *conn, const char *platform,
int purpose, const char *resource,
const char *payload, size_t payload_len);
-static int directory_handle_command(connection_t *conn);
+static int directory_handle_command(dir_connection_t *conn);
static int body_is_plausible(const char *body, size_t body_len, int purpose);
static int purpose_is_private(uint8_t purpose);
static char *http_get_header(const char *headers, const char *which);
-static char *http_get_origin(const char *headers, connection_t *conn);
-static void connection_dir_download_networkstatus_failed(connection_t *conn);
-static void connection_dir_download_routerdesc_failed(connection_t *conn);
+static void http_set_address_origin(const char *headers, connection_t *conn);
+static void connection_dir_download_networkstatus_failed(
+ dir_connection_t *conn);
+static void connection_dir_download_routerdesc_failed(dir_connection_t *conn);
static void dir_networkstatus_download_failed(smartlist_t *failed);
static void dir_routerdesc_download_failed(smartlist_t *failed);
static void note_request(const char *key, size_t bytes);
@@ -58,6 +59,8 @@ static void note_request(const char *key, size_t bytes);
* before deciding that one of us has the wrong time? */
#define ALLOW_DIRECTORY_TIME_SKEW (30*60)
+#define X_ADDRESS_HEADER "X-Your-Address-Is: "
+
/********* END VARIABLES ************/
/** Return true iff the directory purpose 'purpose' must use an
@@ -238,7 +241,7 @@ directory_initiate_command_routerstatus(routerstatus_t *status,
{
const char *platform = NULL;
routerinfo_t *router;
- char address_buf[INET_NTOA_BUF_LEN];
+ char address_buf[INET_NTOA_BUF_LEN+1];
struct in_addr in;
const char *address;
if ((router = router_get_by_digest(status->identity_digest))) {
@@ -259,24 +262,24 @@ directory_initiate_command_routerstatus(routerstatus_t *status,
* directory server: Mark the router as down and try again if possible.
*/
void
-connection_dir_request_failed(connection_t *conn)
+connection_dir_request_failed(dir_connection_t *conn)
{
if (router_digest_is_me(conn->identity_digest))
return; /* this was a test fetch. don't retry. */
router_set_status(conn->identity_digest, 0); /* don't try him again */
- if (conn->purpose == DIR_PURPOSE_FETCH_DIR ||
- conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
+ if (conn->_base.purpose == DIR_PURPOSE_FETCH_DIR ||
+ conn->_base.purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
log_info(LD_DIR, "Giving up on directory server at '%s:%d'; retrying",
- conn->address, conn->port);
- directory_get_from_dirserver(conn->purpose, NULL,
+ conn->_base.address, conn->_base.port);
+ directory_get_from_dirserver(conn->_base.purpose, NULL,
0 /* don't retry_if_no_servers */);
- } else if (conn->purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) {
+ } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) {
log_info(LD_DIR, "Giving up on directory server at '%s'; retrying",
- conn->address);
+ conn->_base.address);
connection_dir_download_networkstatus_failed(conn);
- } else if (conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC) {
+ } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC) {
log_info(LD_DIR, "Giving up on directory server at '%s'; retrying",
- conn->address);
+ conn->_base.address);
connection_dir_download_routerdesc_failed(conn);
}
}
@@ -286,7 +289,7 @@ connection_dir_request_failed(connection_t *conn)
* retry the fetch now, later, or never.
*/
static void
-connection_dir_download_networkstatus_failed(connection_t *conn)
+connection_dir_download_networkstatus_failed(dir_connection_t *conn)
{
if (!conn->requested_resource) {
/* We never reached directory_send_command, which means that we never
@@ -299,14 +302,14 @@ connection_dir_download_networkstatus_failed(connection_t *conn)
smartlist_t *trusted_dirs = router_get_trusted_dir_servers();
SMARTLIST_FOREACH(trusted_dirs, trusted_dir_server_t *, ds,
++ds->n_networkstatus_failures);
- directory_get_from_dirserver(conn->purpose, "all.z",
+ directory_get_from_dirserver(conn->_base.purpose, "all.z",
0 /* don't retry_if_no_servers */);
} else if (!strcmpstart(conn->requested_resource, "fp/")) {
/* We were trying to download by fingerprint; mark them all as having
* failed, and possibly retry them later.*/
smartlist_t *failed = smartlist_create();
dir_split_resource_into_fingerprints(conn->requested_resource+3,
- failed, NULL, 0);
+ failed, NULL, 0, 0);
if (smartlist_len(failed)) {
dir_networkstatus_download_failed(failed);
SMARTLIST_FOREACH(failed, char *, cp, tor_free(cp));
@@ -319,11 +322,13 @@ connection_dir_download_networkstatus_failed(connection_t *conn)
* on connection <b>conn</b> failed.
*/
static void
-connection_dir_download_routerdesc_failed(connection_t *conn)
+connection_dir_download_routerdesc_failed(dir_connection_t *conn)
{
/* Try again. No need to increment the failure count for routerdescs, since
* it's not their fault.*/
/* update_router_descriptor_downloads(time(NULL)); */
+ (void) conn;
+ /* XXXX Why did the above get commented out? -NM */
}
/** Helper for directory_initiate_command_(router|trusted_dir): send the
@@ -338,7 +343,7 @@ directory_initiate_command(const char *address, uint32_t addr,
int private_connection, const char *resource,
const char *payload, size_t payload_len)
{
- connection_t *conn;
+ dir_connection_t *conn;
tor_assert(address);
tor_assert(addr);
@@ -372,18 +377,19 @@ directory_initiate_command(const char *address, uint32_t addr,
tor_assert(0);
}
- conn = connection_new(CONN_TYPE_DIR);
+ conn = TO_DIR_CONN(connection_new(CONN_TYPE_DIR));
/* set up conn so it's got all the data we need to remember */
- conn->addr = addr;
- conn->port = dir_port;
- conn->address = tor_strdup(address);
+ conn->_base.addr = addr;
+ conn->_base.port = dir_port;
+ conn->_base.address = tor_strdup(address);
memcpy(conn->identity_digest, digest, DIGEST_LEN);
- conn->purpose = purpose;
+ conn->_base.purpose = purpose;
/* give it an initial state */
- conn->state = DIR_CONN_STATE_CONNECTING;
+ conn->_base.state = DIR_CONN_STATE_CONNECTING;
+ conn->dirconn_direct = (private_connection == 0);
if (!private_connection) {
/* then we want to connect directly */
@@ -393,19 +399,21 @@ directory_initiate_command(const char *address, uint32_t addr,
dir_port = get_options()->HttpProxyPort;
}
- switch (connection_connect(conn, conn->address, addr, dir_port)) {
+ switch (connection_connect(TO_CONN(conn), conn->_base.address, addr,
+ dir_port)) {
case -1:
connection_dir_request_failed(conn); /* retry if we want */
- connection_free(conn);
+ connection_free(TO_CONN(conn));
return;
case 1:
- conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
+ /* start flushing conn */
+ conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING;
/* fall through */
case 0:
/* queue the command on the outbuf */
directory_send_command(conn, platform, purpose, resource,
payload, payload_len);
- connection_watch_events(conn, EV_READ | EV_WRITE);
+ connection_watch_events(TO_CONN(conn), EV_READ | EV_WRITE);
/* writable indicates finish, readable indicates broken link,
error indicates broken link in windowsland. */
}
@@ -414,23 +422,24 @@ directory_initiate_command(const char *address, uint32_t addr,
* populate it and add it at the right state
* socketpair and hook up both sides
*/
- conn->s = connection_ap_make_bridge(conn->address, conn->port);
- if (conn->s < 0) {
+ conn->_base.s = connection_ap_make_bridge(conn->_base.address,
+ conn->_base.port);
+ if (conn->_base.s < 0) {
log_warn(LD_NET,"Making AP bridge to dirserver failed.");
- connection_mark_for_close(conn);
+ connection_mark_for_close(TO_CONN(conn));
return;
}
- if (connection_add(conn) < 0) {
+ if (connection_add(TO_CONN(conn)) < 0) {
log_warn(LD_NET,"Unable to add AP bridge to dirserver.");
- connection_mark_for_close(conn);
+ connection_mark_for_close(TO_CONN(conn));
return;
}
- conn->state = DIR_CONN_STATE_CLIENT_SENDING;
+ conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING;
/* queue the command on the outbuf */
directory_send_command(conn, platform, purpose, resource,
payload, payload_len);
- connection_watch_events(conn, EV_READ | EV_WRITE);
+ connection_watch_events(TO_CONN(conn), EV_READ | EV_WRITE);
}
}
@@ -438,7 +447,7 @@ directory_initiate_command(const char *address, uint32_t addr,
* are as in directory_initiate_command.
*/
static void
-directory_send_command(connection_t *conn, const char *platform,
+directory_send_command(dir_connection_t *conn, const char *platform,
int purpose, const char *resource,
const char *payload, size_t payload_len)
{
@@ -451,18 +460,18 @@ directory_send_command(connection_t *conn, const char *platform,
size_t len;
tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_DIR);
+ tor_assert(conn->_base.type == CONN_TYPE_DIR);
tor_free(conn->requested_resource);
if (resource)
conn->requested_resource = tor_strdup(resource);
/* come up with a string for which Host: we want */
- if (conn->port == 80) {
- strlcpy(hoststring, conn->address, sizeof(hoststring));
+ if (conn->_base.port == 80) {
+ strlcpy(hoststring, conn->_base.address, sizeof(hoststring));
} else {
tor_snprintf(hoststring, sizeof(hoststring),"%s:%d",
- conn->address, conn->port);
+ conn->_base.address, conn->_base.port);
}
/* come up with some proxy lines, if we're using one. */
@@ -559,8 +568,8 @@ directory_send_command(connection_t *conn, const char *platform,
}
tor_snprintf(request, sizeof(request), "%s %s", httpcommand, proxystring);
- connection_write_to_buf(request, strlen(request), conn);
- connection_write_to_buf(url, strlen(url), conn);
+ connection_write_to_buf(request, strlen(request), TO_CONN(conn));
+ connection_write_to_buf(url, strlen(url), TO_CONN(conn));
tor_free(url);
if (!strcmp(httpcommand, "GET") && !payload) {
@@ -575,11 +584,11 @@ directory_send_command(connection_t *conn, const char *platform,
hoststring,
proxyauthstring);
}
- connection_write_to_buf(request, strlen(request), conn);
+ connection_write_to_buf(request, strlen(request), TO_CONN(conn));
if (payload) {
/* then send the payload afterwards too */
- connection_write_to_buf(payload, payload_len, conn);
+ connection_write_to_buf(payload, payload_len, TO_CONN(conn));
}
}
@@ -588,7 +597,7 @@ directory_send_command(connection_t *conn, const char *platform,
* "\%s [http[s]://]\%s HTTP/1..."
* \endverbatim
* If it's well-formed, strdup the second \%s into *<b>url</b>, and
- * null-terminate it. If the url doesn't start with "/tor/", rewrite it
+ * nul-terminate it. If the url doesn't start with "/tor/", rewrite it
* so it does. Return 0.
* Otherwise, return -1.
*/
@@ -655,12 +664,11 @@ http_get_header(const char *headers, const char *which)
return NULL;
}
-/** Allocate and return a string describing the source of an HTTP request with
- * headers <b>headers</b> received on <b>conn</b>. The format is either
- * "'1.2.3.4'", or "'1.2.3.4' (forwarded for '5.6.7.8')".
- */
-static char *
-http_get_origin(const char *headers, connection_t *conn)
+/** If <b>headers</b> indicates that a proxy was involved, then rewrite
+ * <b>conn</b>-\>address to describe our best guess of the address that
+ * originated this HTTP request. */
+static void
+http_set_address_origin(const char *headers, connection_t *conn)
{
char *fwd;
@@ -668,17 +676,9 @@ http_get_origin(const char *headers, connection_t *conn)
if (!fwd)
fwd = http_get_header(headers, "X-Forwarded-For: ");
if (fwd) {
- size_t len = strlen(fwd)+strlen(conn->address)+32;
- char *result = tor_malloc(len);
- tor_snprintf(result, len, "'%s' (forwarded for %s)", conn->address,
- escaped(fwd));
+ tor_free(conn->address);
+ conn->address = tor_strdup(escaped(fwd));
tor_free(fwd);
- return result;
- } else {
- size_t len = strlen(conn->address)+3;
- char *result = tor_malloc(len);
- tor_snprintf(result, len, "'%s'", conn->address);
- return result;
}
}
@@ -808,7 +808,7 @@ body_is_plausible(const char *body, size_t len, int purpose)
* The caller will take care of marking the connection for close.
*/
static int
-connection_dir_client_reached_eof(connection_t *conn)
+connection_dir_client_reached_eof(dir_connection_t *conn)
{
char *body;
char *headers;
@@ -820,17 +820,18 @@ connection_dir_client_reached_eof(connection_t *conn)
int compression;
int plausible;
int skewed=0;
- int allow_partial = conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC;
+ int allow_partial = conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC;
int was_compressed=0;
+ char *guess;
- switch (fetch_from_buf_http(conn->inbuf,
+ switch (fetch_from_buf_http(conn->_base.inbuf,
&headers, MAX_HEADERS_SIZE,
&body, &body_len, MAX_DIR_SIZE,
allow_partial)) {
case -1: /* overflow */
log_warn(LD_PROTOCOL,
"'fetch' response too large (server '%s:%d'). Closing.",
- conn->address, conn->port);
+ conn->_base.address, conn->_base.port);
return -1;
case 0:
log_info(LD_HTTP,
@@ -843,7 +844,7 @@ connection_dir_client_reached_eof(connection_t *conn)
if (parse_http_response(headers, &status_code, &date_header,
&compression, &reason) < 0) {
log_warn(LD_HTTP,"Unparseable headers (server '%s:%d'). Closing.",
- conn->address, conn->port);
+ conn->_base.address, conn->_base.port);
tor_free(body); tor_free(headers);
return -1;
}
@@ -851,7 +852,15 @@ connection_dir_client_reached_eof(connection_t *conn)
log_debug(LD_DIR,
"Received response from directory server '%s:%d': %d %s",
- conn->address, conn->port, status_code, escaped(reason));
+ conn->_base.address, conn->_base.port, status_code,
+ escaped(reason));
+
+ /* now check if it's got any hints for us about our IP address. */
+ guess = http_get_header(headers, X_ADDRESS_HEADER);
+ if (guess) {
+ router_new_address_suggestion(guess);
+ tor_free(guess);
+ }
if (date_header > 0) {
now = time(NULL);
@@ -862,7 +871,7 @@ connection_dir_client_reached_eof(connection_t *conn)
LD_HTTP,
"Received directory with skewed time (server '%s:%d'): "
"we are %d minutes %s, or the directory is %d minutes %s.",
- conn->address, conn->port,
+ conn->_base.address, conn->_base.port,
abs(delta)/60, delta>0 ? "ahead" : "behind",
abs(delta)/60, delta>0 ? "behind" : "ahead");
skewed = 1; /* don't check the recommended-versions line */
@@ -875,12 +884,13 @@ connection_dir_client_reached_eof(connection_t *conn)
if (status_code == 503) {
log_info(LD_DIR,"Received http status code %d (%s) from server "
"'%s:%d'. I'll try again soon.",
- status_code, escaped(reason), conn->address, conn->port);
+ status_code, escaped(reason), conn->_base.address,
+ conn->_base.port);
tor_free(body); tor_free(headers); tor_free(reason);
return -1;
}
- plausible = body_is_plausible(body, body_len, conn->purpose);
+ plausible = body_is_plausible(body, body_len, conn->_base.purpose);
if (compression || !plausible) {
char *new_body = NULL;
size_t new_len = 0;
@@ -907,7 +917,8 @@ connection_dir_client_reached_eof(connection_t *conn)
log_info(LD_HTTP, "HTTP body from server '%s:%d' was labeled %s, "
"but it seems to be %s.%s",
- conn->address, conn->port, description1, description2,
+ conn->_base.address, conn->_base.port, description1,
+ description2,
(compression>0 && guessed>0)?" Trying both.":"");
}
/* Try declared compression first if we can. */
@@ -924,7 +935,7 @@ connection_dir_client_reached_eof(connection_t *conn)
if (!plausible && !new_body) {
log_fn(LOG_PROTOCOL_WARN, LD_HTTP,
"Unable to decompress HTTP body (server '%s:%d').",
- conn->address, conn->port);
+ conn->_base.address, conn->_base.port);
tor_free(body); tor_free(headers); tor_free(reason);
return -1;
}
@@ -936,38 +947,40 @@ connection_dir_client_reached_eof(connection_t *conn)
}
}
- if (conn->purpose == DIR_PURPOSE_FETCH_DIR) {
+ if (conn->_base.purpose == DIR_PURPOSE_FETCH_DIR) {
/* fetch/process the directory to cache it. */
log_info(LD_DIR,"Received directory (size %d) from server '%s:%d'",
- (int)body_len, conn->address, conn->port);
+ (int)body_len, conn->_base.address, conn->_base.port);
if (status_code != 200) {
log_warn(LD_DIR,"Received http status code %d (%s) from server "
"'%s:%d'. I'll try again soon.",
- status_code, escaped(reason), conn->address, conn->port);
+ status_code, escaped(reason), conn->_base.address,
+ conn->_base.port);
tor_free(body); tor_free(headers); tor_free(reason);
return -1;
}
if (router_parse_directory(body) < 0) {
log_notice(LD_DIR,"I failed to parse the directory I fetched from "
- "'%s:%d'. Ignoring.", conn->address, conn->port);
+ "'%s:%d'. Ignoring.", conn->_base.address, conn->_base.port);
}
note_request(was_compressed?"dl/dir.z":"dl/dir", orig_len);
}
- if (conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
+ if (conn->_base.purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
/* just update our list of running routers, if this list is new info */
log_info(LD_DIR,"Received running-routers list (size %d)", (int)body_len);
if (status_code != 200) {
log_warn(LD_DIR,"Received http status code %d (%s) from server "
"'%s:%d'. I'll try again soon.",
- status_code, escaped(reason), conn->address, conn->port);
+ status_code, escaped(reason), conn->_base.address,
+ conn->_base.port);
tor_free(body); tor_free(headers); tor_free(reason);
return -1;
}
if (router_parse_runningrouters(body)<0) {
log_warn(LD_DIR,
"Bad running-routers from server '%s:%d'. I'll try again soon.",
- conn->address, conn->port);
+ conn->_base.address, conn->_base.port);
tor_free(body); tor_free(headers); tor_free(reason);
return -1;
}
@@ -975,17 +988,18 @@ connection_dir_client_reached_eof(connection_t *conn)
"dl/running-routers", orig_len);
}
- if (conn->purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) {
+ if (conn->_base.purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) {
smartlist_t *which = NULL;
+ int source;
char *cp;
log_info(LD_DIR,"Received networkstatus objects (size %d) from server "
- "'%s:%d'",(int) body_len, conn->address, conn->port);
+ "'%s:%d'",(int) body_len, conn->_base.address, conn->_base.port);
if (status_code != 200) {
log_warn(LD_DIR,
"Received http status code %d (%s) from server "
"'%s:%d' while fetching \"/tor/status/%s\". I'll try again soon.",
- status_code, escaped(reason), conn->address, conn->port,
- conn->requested_resource);
+ status_code, escaped(reason), conn->_base.address,
+ conn->_base.port, conn->requested_resource);
tor_free(body); tor_free(headers); tor_free(reason);
connection_dir_download_networkstatus_failed(conn);
return -1;
@@ -993,11 +1007,13 @@ connection_dir_client_reached_eof(connection_t *conn)
note_request(was_compressed?"dl/status.z":"dl/status", orig_len);
if (conn->requested_resource &&
!strcmpstart(conn->requested_resource,"fp/")) {
+ source = NS_FROM_DIR_BY_FP;
which = smartlist_create();
dir_split_resource_into_fingerprints(conn->requested_resource+3,
- which, NULL, 0);
+ which, NULL, 0, 0);
} else if (conn->requested_resource &&
!strcmpstart(conn->requested_resource, "all")) {
+ source = NS_FROM_DIR_ALL;
which = smartlist_create();
SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
trusted_dir_server_t *, ds,
@@ -1006,6 +1022,11 @@ connection_dir_client_reached_eof(connection_t *conn)
base16_encode(cp, HEX_DIGEST_LEN+1, ds->digest, DIGEST_LEN);
smartlist_add(which, cp);
});
+ } else {
+ /* Can we even end up here? -- weasel*/
+ source = NS_FROM_DIR_BY_FP;
+ log_warn(LD_BUG, "we received a networkstatus but we did neither ask"
+ "for it by fp/ nor did we ask for all.");
}
cp = body;
while (*cp) {
@@ -1013,7 +1034,7 @@ connection_dir_client_reached_eof(connection_t *conn)
if (next)
next[1] = '\0';
/* learn from it, and then remove it from 'which' */
- if (router_set_networkstatus(cp, time(NULL), NS_FROM_DIR, which)<0)
+ if (router_set_networkstatus(cp, time(NULL), source, which)<0)
break;
if (next) {
next[1] = 'n';
@@ -1033,17 +1054,17 @@ connection_dir_client_reached_eof(connection_t *conn)
}
}
- if (conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC) {
+ if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC) {
smartlist_t *which = NULL;
int n_asked_for = 0;
log_info(LD_DIR,"Received server info (size %d) from server '%s:%d'",
- (int)body_len, conn->address, conn->port);
+ (int)body_len, conn->_base.address, conn->_base.port);
note_request(was_compressed?"dl/server.z":"dl/server", orig_len);
if (conn->requested_resource &&
!strcmpstart(conn->requested_resource,"d/")) {
which = smartlist_create();
dir_split_resource_into_fingerprints(conn->requested_resource+2,
- which, NULL, 0);
+ which, NULL, 0, 0);
n_asked_for = smartlist_len(which);
}
if (status_code != 200) {
@@ -1054,8 +1075,8 @@ connection_dir_client_reached_eof(connection_t *conn)
log_fn(dir_okay ? LOG_INFO : LOG_WARN, LD_DIR,
"Received http status code %d (%s) from server '%s:%d' "
"while fetching \"/tor/server/%s\". I'll try again soon.",
- status_code, escaped(reason), conn->address, conn->port,
- conn->requested_resource);
+ status_code, escaped(reason), conn->_base.address,
+ conn->_base.port, conn->requested_resource);
if (!which) {
connection_dir_download_routerdesc_failed(conn);
} else {
@@ -1074,13 +1095,13 @@ connection_dir_client_reached_eof(connection_t *conn)
if (which || (conn->requested_resource &&
!strcmpstart(conn->requested_resource, "all"))) {
/* as we learn from them, we remove them from 'which' */
- router_load_routers_from_string(body, 0, which);
+ router_load_routers_from_string(body, SAVED_NOWHERE, which);
directory_info_has_arrived(time(NULL), 0);
}
if (which) { /* mark remaining ones as failed */
log_info(LD_DIR, "Received %d/%d routers requested from %s:%d",
n_asked_for-smartlist_len(which), n_asked_for,
- conn->address, (int)conn->port);
+ conn->_base.address, (int)conn->_base.port);
if (smartlist_len(which)) {
dir_routerdesc_download_failed(which);
}
@@ -1093,13 +1114,13 @@ connection_dir_client_reached_eof(connection_t *conn)
routerinfo_t *me = router_get_my_routerinfo();
if (me &&
router_digest_is_me(conn->identity_digest) &&
- me->addr == conn->addr &&
- me->dir_port == conn->port)
+ me->addr == conn->_base.addr &&
+ me->dir_port == conn->_base.port)
router_dirport_found_reachable();
}
}
- if (conn->purpose == DIR_PURPOSE_UPLOAD_DIR) {
+ if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_DIR) {
switch (status_code) {
case 200:
log_info(LD_GENERAL,"eof (status 200) after uploading server "
@@ -1108,7 +1129,7 @@ connection_dir_client_reached_eof(connection_t *conn)
case 400:
log_warn(LD_GENERAL,"http status 400 (%s) response from "
"dirserver '%s:%d'. Please correct.",
- escaped(reason), conn->address, conn->port);
+ escaped(reason), conn->_base.address, conn->_base.port);
break;
case 403:
log_warn(LD_GENERAL,
@@ -1116,19 +1137,21 @@ connection_dir_client_reached_eof(connection_t *conn)
"'%s:%d'. Is your clock skewed? Have you mailed us your key "
"fingerprint? Are you using the right key? Are you using a "
"private IP address? See http://tor.eff.org/doc/"
- "tor-doc-server.html",escaped(reason), conn->address, conn->port);
+ "tor-doc-server.html",escaped(reason), conn->_base.address,
+ conn->_base.port);
break;
default:
log_warn(LD_GENERAL,
"http status %d (%s) reason unexpected (server '%s:%d').",
- status_code, escaped(reason), conn->address, conn->port);
+ status_code, escaped(reason), conn->_base.address,
+ conn->_base.port);
break;
}
/* return 0 in all cases, since we don't want to mark any
* dirservers down just because they don't like us. */
}
- if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC) {
+ if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC) {
log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d "
"(%s))",
(int)body_len, status_code, escaped(reason));
@@ -1140,7 +1163,7 @@ connection_dir_client_reached_eof(connection_t *conn)
* cleans it up */
} else {
/* success. notify pending connections about this. */
- conn->purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
+ conn->_base.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
rend_client_desc_here(conn->rend_query);
}
break;
@@ -1156,12 +1179,13 @@ connection_dir_client_reached_eof(connection_t *conn)
default:
log_warn(LD_REND,"http status %d (%s) response unexpected (server "
"'%s:%d').",
- status_code, escaped(reason), conn->address, conn->port);
+ status_code, escaped(reason), conn->_base.address,
+ conn->_base.port);
break;
}
}
- if (conn->purpose == DIR_PURPOSE_UPLOAD_RENDDESC) {
+ if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_RENDDESC) {
switch (status_code) {
case 200:
log_info(LD_REND,
@@ -1171,12 +1195,13 @@ connection_dir_client_reached_eof(connection_t *conn)
case 400:
log_warn(LD_REND,"http status 400 (%s) response from dirserver "
"'%s:%d'. Malformed rendezvous descriptor?",
- escaped(reason), conn->address, conn->port);
+ escaped(reason), conn->_base.address, conn->_base.port);
break;
default:
log_warn(LD_REND,"http status %d (%s) response unexpected (server "
"'%s:%d').",
- status_code, escaped(reason), conn->address, conn->port);
+ status_code, escaped(reason), conn->_base.address,
+ conn->_base.port);
break;
}
}
@@ -1186,20 +1211,20 @@ connection_dir_client_reached_eof(connection_t *conn)
/** Called when a directory connection reaches EOF */
int
-connection_dir_reached_eof(connection_t *conn)
+connection_dir_reached_eof(dir_connection_t *conn)
{
int retval;
- if (conn->state != DIR_CONN_STATE_CLIENT_READING) {
+ if (conn->_base.state != DIR_CONN_STATE_CLIENT_READING) {
log_info(LD_HTTP,"conn reached eof, not reading. Closing.");
- connection_close_immediate(conn); /* error: give up on flushing */
- connection_mark_for_close(conn);
+ connection_close_immediate(TO_CONN(conn)); /* error: give up on flushing */
+ connection_mark_for_close(TO_CONN(conn));
return -1;
}
retval = connection_dir_client_reached_eof(conn);
if (retval == 0) /* success */
- conn->state = DIR_CONN_STATE_CLIENT_FINISHED;
- connection_mark_for_close(conn);
+ conn->_base.state = DIR_CONN_STATE_CLIENT_FINISHED;
+ connection_mark_for_close(TO_CONN(conn));
return retval;
}
@@ -1207,10 +1232,10 @@ connection_dir_reached_eof(connection_t *conn)
* directory servers and connections <em>at</em> directory servers.)
*/
int
-connection_dir_process_inbuf(connection_t *conn)
+connection_dir_process_inbuf(dir_connection_t *conn)
{
tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_DIR);
+ tor_assert(conn->_base.type == CONN_TYPE_DIR);
/* Directory clients write, then read data until they receive EOF;
* directory servers read data until they get an HTTP command, then
@@ -1219,9 +1244,9 @@ connection_dir_process_inbuf(connection_t *conn)
*/
/* If we're on the dirserver side, look for a command. */
- if (conn->state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
+ if (conn->_base.state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
if (directory_handle_command(conn) < 0) {
- connection_mark_for_close(conn);
+ connection_mark_for_close(TO_CONN(conn));
return -1;
}
return 0;
@@ -1229,7 +1254,7 @@ connection_dir_process_inbuf(connection_t *conn)
/* XXX for READ states, might want to make sure inbuf isn't too big */
- if (!conn->inbuf_reached_eof)
+ if (!conn->_base.inbuf_reached_eof)
log_debug(LD_HTTP,"Got data, not eof. Leaving on inbuf.");
return 0;
}
@@ -1238,7 +1263,7 @@ connection_dir_process_inbuf(connection_t *conn)
* <b>status</b> and <b>reason_phrase</b>. Write it to <b>conn</b>.
*/
static void
-write_http_status_line(connection_t *conn, int status,
+write_http_status_line(dir_connection_t *conn, int status,
const char *reason_phrase)
{
char buf[256];
@@ -1247,7 +1272,43 @@ write_http_status_line(connection_t *conn, int status,
log_warn(LD_BUG,"Bug: status line too long.");
return;
}
- connection_write_to_buf(buf, strlen(buf), conn);
+ connection_write_to_buf(buf, strlen(buf), TO_CONN(conn));
+}
+
+/** DOCDOC */
+static void
+write_http_response_header(dir_connection_t *conn, ssize_t length,
+ const char *type, const char *encoding)
+{
+ char date[RFC1123_TIME_LEN+1];
+ char tmp[1024];
+ char *cp;
+
+ tor_assert(conn);
+ tor_assert(type);
+
+ format_rfc1123_time(date, time(NULL));
+ cp = tmp;
+ tor_snprintf(cp, sizeof(tmp),
+ "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Type: %s\r\n"
+ X_ADDRESS_HEADER "%s\r\n",
+ date, type, conn->_base.address);
+ cp += strlen(tmp);
+ if (encoding) {
+ tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
+ "Content-Encoding: %s\r\n", encoding);
+ cp += strlen(cp);
+ }
+ if (length >= 0) {
+ tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
+ "Content-Length: %ld\r\n", (long)length);
+ cp += strlen(cp);
+ }
+ if (sizeof(tmp)-(cp-tmp) > 3)
+ memcpy(cp, "\r\n", 3);
+ else
+ tor_assert(0);
+ connection_write_to_buf(tmp, strlen(tmp), TO_CONN(conn));
}
/** Helper function: return 1 if there are any dir conns of purpose
@@ -1267,7 +1328,7 @@ already_fetching_directory(int purpose)
if (conn->type == CONN_TYPE_DIR &&
conn->purpose == purpose &&
!conn->marked_for_close &&
- !router_digest_is_me(conn->identity_digest))
+ !router_digest_is_me(TO_DIR_CONN(conn)->identity_digest))
return 1;
}
return 0;
@@ -1331,7 +1392,8 @@ directory_dump_request_log(void)
static void
note_request(const char *key, size_t bytes)
{
- return;
+ (void)key;
+ (void)bytes;
}
char *
@@ -1347,18 +1409,19 @@ directory_dump_request_log(void)
* conn-\>outbuf. If the request is unrecognized, send a 400.
* Always return 0. */
static int
-directory_handle_command_get(connection_t *conn, char *headers,
+directory_handle_command_get(dir_connection_t *conn, char *headers,
char *body, size_t body_len)
{
size_t dlen;
const char *cp;
char *url = NULL;
- char tmp[8192];
- char date[RFC1123_TIME_LEN+1];
+ /* We ignore the body of a GET request. */
+ (void)body;
+ (void)body_len;
log_debug(LD_DIRSERV,"Received GET command.");
- conn->state = DIR_CONN_STATE_SERVER_WRITING;
+ conn->_base.state = DIR_CONN_STATE_SERVER_WRITING;
if (parse_http_url(headers, &url) < 0) {
write_http_status_line(conn, 400, "Bad request");
@@ -1368,9 +1431,9 @@ directory_handle_command_get(connection_t *conn, char *headers,
if (!strcmp(url,"/tor/") || !strcmp(url,"/tor/dir.z")) { /* dir fetch */
int deflated = !strcmp(url,"/tor/dir.z");
- dlen = dirserv_get_directory(&cp, deflated);
+ cached_dir_t *d = dirserv_get_directory();
- if (dlen == 0) {
+ if (!d) {
log_notice(LD_DIRSERV,"Client asked for the mirrored directory, but we "
"don't have a good one yet. Sending 503 Dir not available.");
write_http_status_line(conn, 503, "Directory unavailable");
@@ -1380,6 +1443,7 @@ directory_handle_command_get(connection_t *conn, char *headers,
tor_free(url);
return 0;
}
+ dlen = deflated ? d->dir_z_len : d->dir_len;
if (global_write_bucket_empty()) {
log_info(LD_DIRSERV,
@@ -1395,16 +1459,18 @@ directory_handle_command_get(connection_t *conn, char *headers,
log_debug(LD_DIRSERV,"Dumping %sdirectory to client.",
deflated?"deflated ":"");
- format_rfc1123_time(date, time(NULL));
- tor_snprintf(tmp, sizeof(tmp),
- "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n"
- "Content-Type: %s\r\nContent-Encoding: %s\r\n\r\n",
- date,
- (int)dlen,
- deflated?"application/octet-stream":"text/plain",
- deflated?"deflate":"identity");
- connection_write_to_buf(tmp, strlen(tmp), conn);
- connection_write_to_buf(cp, dlen, conn);
+ write_http_response_header(conn, dlen,
+ deflated?"application/octet-stream":"text/plain",
+ deflated?"deflate":"identity");
+ conn->cached_dir = d;
+ conn->cached_dir_offset = 0;
+ if (! deflated)
+ conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD);
+ ++d->refcnt;
+
+ /* Prime the connection with some data. */
+ conn->dir_spool_src = DIR_SPOOL_CACHED_DIR;
+ connection_dirserv_flushed_some(conn);
return 0;
}
@@ -1422,16 +1488,10 @@ directory_handle_command_get(connection_t *conn, char *headers,
return 0;
}
- format_rfc1123_time(date, time(NULL));
- tor_snprintf(tmp, sizeof(tmp),
- "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n"
- "Content-Type: %s\r\nContent-Encoding: %s\r\n\r\n",
- date,
- (int)dlen,
+ write_http_response_header(conn, dlen,
deflated?"application/octet-stream":"text/plain",
deflated?"deflate":"identity");
- connection_write_to_buf(tmp, strlen(tmp), conn);
- connection_write_to_buf(cp, strlen(cp), conn);
+ connection_write_to_buf(cp, strlen(cp), TO_CONN(conn));
return 0;
}
@@ -1439,12 +1499,12 @@ directory_handle_command_get(connection_t *conn, char *headers,
/* v2 network status fetch. */
size_t url_len = strlen(url);
int deflated = !strcmp(url+url_len-2, ".z");
- smartlist_t *dir_objs = smartlist_create();
+ smartlist_t *dir_fps = smartlist_create();
const char *request_type = NULL;
const char *key = url + strlen("/tor/status/");
if (deflated)
url[url_len-2] = '\0';
- dirserv_get_networkstatus_v2(dir_objs, key);
+ dirserv_get_networkstatus_v2_fingerprints(dir_fps, key);
if (!strcmpstart(key, "fp/"))
request_type = deflated?"/tor/status/fp.z":"/tor/status/fp";
else if (!strcmpstart(key, "authority"))
@@ -1455,32 +1515,24 @@ directory_handle_command_get(connection_t *conn, char *headers,
else
request_type = "/tor/status/?";
tor_free(url);
- if (!smartlist_len(dir_objs)) { /* we failed to create/cache cp */
+ if (!smartlist_len(dir_fps)) { /* we failed to create/cache cp */
write_http_status_line(conn, 503, "Network status object unavailable");
- smartlist_free(dir_objs);
+ smartlist_free(dir_fps);
return 0;
}
- dlen = 0;
- SMARTLIST_FOREACH(dir_objs, cached_dir_t *, d,
- dlen += deflated?d->dir_z_len:d->dir_len);
- note_request(request_type,dlen);
- format_rfc1123_time(date, time(NULL));
- tor_snprintf(tmp, sizeof(tmp),
- "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n"
- "Content-Type: %s\r\nContent-Encoding: %s\r\n\r\n",
- date,
- (int)dlen,
- deflated?"application/octet-stream":"text/plain",
- deflated?"deflate":"identity");
- connection_write_to_buf(tmp, strlen(tmp), conn);
- SMARTLIST_FOREACH(dir_objs, cached_dir_t *, d,
- {
- if (deflated)
- connection_write_to_buf(d->dir_z, d->dir_z_len, conn);
- else
- connection_write_to_buf(d->dir, d->dir_len, conn);
- });
- smartlist_free(dir_objs);
+ // note_request(request_type,dlen);
+ write_http_response_header(conn, -1,
+ deflated?"application/octet_stream":"text/plain",
+ deflated?"deflate":NULL);
+
+ conn->fingerprint_stack = dir_fps;
+ if (! deflated)
+ conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD);
+
+ /* Prime the connection with some data. */
+ conn->dir_spool_src = DIR_SPOOL_NETWORKSTATUS;
+ connection_dirserv_flushed_some(conn);
+
return 0;
}
@@ -1489,11 +1541,12 @@ directory_handle_command_get(connection_t *conn, char *headers,
int deflated = !strcmp(url+url_len-2, ".z");
int res;
const char *msg;
- smartlist_t *descs = smartlist_create();
const char *request_type = NULL;
if (deflated)
url[url_len-2] = '\0';
- res = dirserv_get_routerdescs(descs, url, &msg);
+ conn->fingerprint_stack = smartlist_create();
+ res = dirserv_get_routerdesc_fingerprints(conn->fingerprint_stack, url,
+ &msg);
if (!strcmpstart(url, "/tor/server/fp/"))
request_type = deflated?"/tor/server/fp.z":"/tor/server/fp";
@@ -1506,62 +1559,22 @@ directory_handle_command_get(connection_t *conn, char *headers,
request_type = deflated?"/tor/server/d.z":"/tor/server/d";
else
request_type = "/tor/server/?";
+ if (!strcmpstart(url, "/tor/server/d/"))
+ conn->dir_spool_src = DIR_SPOOL_SERVER_BY_DIGEST;
+ else
+ conn->dir_spool_src = DIR_SPOOL_SERVER_BY_FP;
tor_free(url);
if (res < 0)
write_http_status_line(conn, 404, msg);
else {
- size_t len = 0;
- format_rfc1123_time(date, time(NULL));
- SMARTLIST_FOREACH(descs, signed_descriptor_t *, ri,
- len += ri->signed_descriptor_len);
- if (deflated) {
- size_t compressed_len;
- char *compressed;
- char *inp = tor_malloc(len+smartlist_len(descs)+1);
- char *cp = inp;
- SMARTLIST_FOREACH(descs, signed_descriptor_t *, ri,
- {
- const char *body = signed_descriptor_get_body(ri);
- memcpy(cp, body, ri->signed_descriptor_len);
- cp += ri->signed_descriptor_len;
- *cp++ = '\n';
- });
- *cp = '\0';
- /* XXXX This could be way more efficiently handled; let's see if it
- * shows up under oprofile. */
- if (tor_gzip_compress(&compressed, &compressed_len,
- inp, cp-inp, ZLIB_METHOD)<0) {
- tor_free(inp);
- smartlist_free(descs);
- return -1;
- }
- tor_free(inp);
- tor_snprintf(tmp, sizeof(tmp),
- "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n"
- "Content-Type: application/octet-stream\r\n"
- "Content-Encoding: deflate\r\n\r\n",
- date,
- (int)compressed_len);
- note_request(request_type, compressed_len);
- connection_write_to_buf(tmp, strlen(tmp), conn);
- connection_write_to_buf(compressed, compressed_len, conn);
- tor_free(compressed);
- } else {
- tor_snprintf(tmp, sizeof(tmp),
- "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n"
- "Content-Type: text/plain\r\n\r\n",
- date,
- (int)len);
- note_request(request_type, len);
- connection_write_to_buf(tmp, strlen(tmp), conn);
- SMARTLIST_FOREACH(descs, signed_descriptor_t *, ri,
- {
- const char *body = signed_descriptor_get_body(ri);
- connection_write_to_buf(body, ri->signed_descriptor_len, conn);
- });
- }
+ write_http_response_header(conn, -1,
+ deflated?"application/octet_stream":"text/plain",
+ deflated?"deflate":NULL);
+ if (deflated)
+ conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD);
+ /* Prime the connection with some data. */
+ connection_dirserv_flushed_some(conn);
}
- smartlist_free(descs);
return 0;
}
@@ -1586,16 +1599,11 @@ directory_handle_command_get(connection_t *conn, char *headers,
}
switch (rend_cache_lookup_desc(query, versioned?-1:0, &descp, &desc_len)) {
case 1: /* valid */
- format_rfc1123_time(date, time(NULL));
- tor_snprintf(tmp, sizeof(tmp),
- "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n"
- "Content-Type: application/octet-stream\r\n\r\n",
- date,
- (int)desc_len);
+ write_http_response_header(conn, desc_len, "application/octet-stream",
+ NULL);
note_request("/tor/rendezvous?/", desc_len);
- connection_write_to_buf(tmp, strlen(tmp), conn);
/* need to send descp separately, because it may include nuls */
- connection_write_to_buf(descp, desc_len, conn);
+ connection_write_to_buf(descp, desc_len, TO_CONN(conn));
break;
case 0: /* well-formed but not present */
write_http_status_line(conn, 404, "Not found");
@@ -1611,14 +1619,8 @@ directory_handle_command_get(connection_t *conn, char *headers,
if (!strcmpstart(url,"/tor/bytes.txt")) {
char *bytes = directory_dump_request_log();
size_t len = strlen(bytes);
- format_rfc1123_time(date, time(NULL));
- tor_snprintf(tmp, sizeof(tmp),
- "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n"
- "Content-Type: text/plain\r\n\r\n",
- date,
- (int)len);
- connection_write_to_buf(tmp, strlen(tmp), conn);
- connection_write_to_buf(bytes, len, conn);
+ write_http_response_header(conn, len, "text/plain", NULL);
+ connection_write_to_buf(bytes, len, TO_CONN(conn));
tor_free(bytes);
tor_free(url);
return 0;
@@ -1628,14 +1630,32 @@ directory_handle_command_get(connection_t *conn, char *headers,
rewritten to /tor/robots.txt */
char robots[] = "User-agent: *\r\nDisallow: /\r\n";
size_t len = strlen(robots);
- format_rfc1123_time(date, time(NULL));
- tor_snprintf(tmp, sizeof(tmp),
- "HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Length: %d\r\n"
- "Content-Type: text/plain\r\n\r\n",
- date,
- (int)len);
- connection_write_to_buf(tmp, strlen(tmp), conn);
- connection_write_to_buf(robots, len, conn);
+ write_http_response_header(conn, len, "text/plain", NULL);
+ connection_write_to_buf(robots, len, TO_CONN(conn));
+ tor_free(url);
+ return 0;
+ }
+
+ if (!strcmp(url,"/tor/dir-all-weaselhack") &&
+ (conn->_base.addr == 0x7f000001ul) &&
+ authdir_mode(get_options())) {
+ /* XXX until weasel rewrites his scripts XXXX012 */
+ char *new_directory=NULL;
+
+ if (dirserv_dump_directory_to_string(&new_directory,
+ get_identity_key(), 1)) {
+ log_warn(LD_BUG, "Error creating full v1 directory.");
+ tor_free(new_directory);
+ write_http_status_line(conn, 503, "Directory unavailable");
+ return 0;
+ }
+
+ dlen = strlen(new_directory);
+
+ write_http_response_header(conn, dlen, "text/plain", "identity");
+
+ connection_write_to_buf(new_directory, dlen, TO_CONN(conn));
+ tor_free(new_directory);
tor_free(url);
return 0;
}
@@ -1652,16 +1672,14 @@ directory_handle_command_get(connection_t *conn, char *headers,
* response into conn-\>outbuf. If the request is unrecognized, send a
* 400. Always return 0. */
static int
-directory_handle_command_post(connection_t *conn, char *headers,
+directory_handle_command_post(dir_connection_t *conn, char *headers,
char *body, size_t body_len)
{
- const char *cp;
- char *origin = NULL;
char *url = NULL;
log_debug(LD_DIRSERV,"Received POST command.");
- conn->state = DIR_CONN_STATE_SERVER_WRITING;
+ conn->_base.state = DIR_CONN_STATE_SERVER_WRITING;
if (!authdir_mode(get_options())) {
/* we just provide cached directories; we don't want to
@@ -1676,19 +1694,19 @@ directory_handle_command_post(connection_t *conn, char *headers,
return 0;
}
log_debug(LD_DIRSERV,"rewritten url as '%s'.", url);
- origin = http_get_origin(headers, conn);
if (!strcmp(url,"/tor/")) { /* server descriptor post */
const char *msg;
int r = dirserv_add_descriptor(body, &msg);
tor_assert(msg);
if (r > 0)
- dirserv_get_directory(&cp, 0); /* rebuild and write to disk */
+ dirserv_get_directory(); /* rebuild and write to disk */
switch (r) {
case -2:
case -1:
case 1:
- log_notice(LD_DIRSERV,"Rejected router descriptor from %s.", origin);
+ log_notice(LD_DIRSERV,"Rejected router descriptor from %s.",
+ conn->_base.address);
/* malformed descriptor, or something wrong */
write_http_status_line(conn, 400, msg);
break;
@@ -1706,7 +1724,7 @@ directory_handle_command_post(connection_t *conn, char *headers,
// char tmp[1024*2+1];
log_fn(LOG_PROTOCOL_WARN, LD_DIRSERV,
"Rejected rend descriptor (length %d) from %s.",
- (int)body_len, origin);
+ (int)body_len, conn->_base.address);
#if 0
if (body_len <= 1024) {
base16_encode(tmp, sizeof(tmp), body, body_len);
@@ -1725,7 +1743,6 @@ directory_handle_command_post(connection_t *conn, char *headers,
done:
tor_free(url);
- tor_free(origin);
return 0;
}
@@ -1735,21 +1752,22 @@ directory_handle_command_post(connection_t *conn, char *headers,
* buffer. Return a 0 on success, or -1 on error.
*/
static int
-directory_handle_command(connection_t *conn)
+directory_handle_command(dir_connection_t *conn)
{
char *headers=NULL, *body=NULL;
size_t body_len=0;
int r;
tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_DIR);
+ tor_assert(conn->_base.type == CONN_TYPE_DIR);
- switch (fetch_from_buf_http(conn->inbuf,
+ switch (fetch_from_buf_http(conn->_base.inbuf,
&headers, MAX_HEADERS_SIZE,
&body, &body_len, MAX_BODY_SIZE, 0)) {
case -1: /* overflow */
log_warn(LD_DIRSERV,
- "Invalid input from address '%s'. Closing.", conn->address);
+ "Invalid input from address '%s'. Closing.",
+ conn->_base.address);
return -1;
case 0:
log_debug(LD_DIRSERV,"command not all here yet.");
@@ -1757,6 +1775,7 @@ directory_handle_command(connection_t *conn)
/* case 1, fall through */
}
+ http_set_address_origin(headers, TO_CONN(conn));
//log_debug(LD_DIRSERV,"headers %s, body %s.", headers, body);
if (!strncasecmp(headers,"GET",3))
@@ -1779,23 +1798,24 @@ directory_handle_command(connection_t *conn)
* appropriate.
*/
int
-connection_dir_finished_flushing(connection_t *conn)
+connection_dir_finished_flushing(dir_connection_t *conn)
{
tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_DIR);
+ tor_assert(conn->_base.type == CONN_TYPE_DIR);
- switch (conn->state) {
+ switch (conn->_base.state) {
case DIR_CONN_STATE_CLIENT_SENDING:
log_debug(LD_DIR,"client finished sending command.");
- conn->state = DIR_CONN_STATE_CLIENT_READING;
- connection_stop_writing(conn);
+ conn->_base.state = DIR_CONN_STATE_CLIENT_READING;
+ connection_stop_writing(TO_CONN(conn));
return 0;
case DIR_CONN_STATE_SERVER_WRITING:
log_debug(LD_DIRSERV,"Finished writing server response. Closing.");
- connection_mark_for_close(conn);
+ connection_mark_for_close(TO_CONN(conn));
return 0;
default:
- log_warn(LD_BUG,"Bug: called in unexpected state %d.", conn->state);
+ log_warn(LD_BUG,"Bug: called in unexpected state %d.",
+ conn->_base.state);
tor_fragile_assert();
return -1;
}
@@ -1805,16 +1825,16 @@ connection_dir_finished_flushing(connection_t *conn)
/** Connected handler for directory connections: begin sending data to the
* server */
int
-connection_dir_finished_connecting(connection_t *conn)
+connection_dir_finished_connecting(dir_connection_t *conn)
{
tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_DIR);
- tor_assert(conn->state == DIR_CONN_STATE_CONNECTING);
+ tor_assert(conn->_base.type == CONN_TYPE_DIR);
+ tor_assert(conn->_base.state == DIR_CONN_STATE_CONNECTING);
log_debug(LD_HTTP,"Dir connection to router %s:%u established.",
- conn->address,conn->port);
+ conn->_base.address,conn->_base.port);
- conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
+ conn->_base.state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
return 0;
}
@@ -1892,21 +1912,21 @@ dir_routerdesc_download_failed(smartlist_t *failed)
* the strings, in order, into <b>fp_out</b>. If <b>compressed_out</b> is
* non-NULL, set it to 1 if the resource ends in ".z", else set it to 0. If
* decode_hex is true, then delete all elements that aren't hex digests, and
- * decode the rest.
+ * decode the rest. If sort_uniq is true, then sort the list and remove
+ * all duplicates.
*/
int
dir_split_resource_into_fingerprints(const char *resource,
smartlist_t *fp_out, int *compressed_out,
- int decode_hex)
+ int decode_hex, int sort_uniq)
{
- int old_len;
+ smartlist_t *fp_tmp = smartlist_create();
tor_assert(fp_out);
- old_len = smartlist_len(fp_out);
- smartlist_split_string(fp_out, resource, "+", 0, 0);
+ smartlist_split_string(fp_tmp, resource, "+", 0, 0);
if (compressed_out)
*compressed_out = 0;
- if (smartlist_len(fp_out) > old_len) {
- char *last = smartlist_get(fp_out,smartlist_len(fp_out)-1);
+ if (smartlist_len(fp_tmp)) {
+ char *last = smartlist_get(fp_tmp,smartlist_len(fp_tmp)-1);
size_t last_len = strlen(last);
if (last_len > 2 && !strcmp(last+last_len-2, ".z")) {
last[last_len-2] = '\0';
@@ -1917,27 +1937,51 @@ dir_split_resource_into_fingerprints(const char *resource,
if (decode_hex) {
int i;
char *cp, *d = NULL;
- for (i = old_len; i < smartlist_len(fp_out); ++i) {
- cp = smartlist_get(fp_out, i);
+ for (i = 0; i < smartlist_len(fp_tmp); ++i) {
+ cp = smartlist_get(fp_tmp, i);
if (strlen(cp) != HEX_DIGEST_LEN) {
log_info(LD_DIR,
"Skipping digest %s with non-standard length.", escaped(cp));
- smartlist_del(fp_out, i--);
+ smartlist_del_keeporder(fp_tmp, i--);
goto again;
}
d = tor_malloc_zero(DIGEST_LEN);
if (base16_decode(d, DIGEST_LEN, cp, HEX_DIGEST_LEN)<0) {
log_info(LD_DIR, "Skipping non-decodable digest %s", escaped(cp));
- smartlist_del(fp_out, i--);
+ smartlist_del_keeporder(fp_tmp, i--);
goto again;
}
- smartlist_set(fp_out, i, d);
+ smartlist_set(fp_tmp, i, d);
d = NULL;
again:
tor_free(cp);
tor_free(d);
}
}
+ if (sort_uniq) {
+ smartlist_t *fp_tmp2 = smartlist_create();
+ int i;
+ if (decode_hex)
+ smartlist_sort_digests(fp_tmp);
+ else
+ smartlist_sort_strings(fp_tmp);
+ if (smartlist_len(fp_tmp))
+ smartlist_add(fp_tmp2, smartlist_get(fp_tmp, 0));
+ for (i = 1; i < smartlist_len(fp_tmp); ++i) {
+ char *cp = smartlist_get(fp_tmp, i);
+ char *last = smartlist_get(fp_tmp2, smartlist_len(fp_tmp2)-1);
+
+ if ((decode_hex && memcmp(cp, last, DIGEST_LEN))
+ || (!decode_hex && strcasecmp(cp, last)))
+ smartlist_add(fp_tmp2, cp);
+ else
+ tor_free(cp);
+ }
+ smartlist_free(fp_tmp);
+ fp_tmp = fp_tmp2;
+ }
+ smartlist_add_all(fp_out, fp_tmp);
+ smartlist_free(fp_tmp);
return 0;
}
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index e85575e6f9..b159afed97 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -36,7 +36,7 @@ static int runningrouters_is_dirty = 1;
static int the_v2_networkstatus_is_dirty = 1;
static void directory_remove_invalid(void);
-static int dirserv_regenerate_directory(void);
+static cached_dir_t *dirserv_regenerate_directory(void);
static char *format_versions_list(config_line_t *ln);
/* Should be static; exposed for testing */
int add_fingerprint_to_dir(const char *nickname, const char *fp,
@@ -51,6 +51,7 @@ dirserv_get_status_impl(const char *fp, const char *nickname,
const char **msg, int should_log);
static int dirserv_thinks_router_is_reachable(routerinfo_t *router,
time_t now);
+static void clear_cached_dir(cached_dir_t *d);
/************** Fingerprint handling code ************/
@@ -121,24 +122,31 @@ dirserv_add_own_fingerprint(const char *nickname, crypto_pk_env_t *pk)
return 0;
}
-/** Parse the nickname-\>fingerprint mappings stored in the file named
- * <b>fname</b>. The file format is line-based, with each non-blank
- * holding one nickname, some space, and a fingerprint for that
- * nickname. On success, replace the current fingerprint list with
- * the contents of <b>fname</b> and return 0. On failure, leave the
- * current fingerprint list untouched, and return -1. */
+/** Load the nickname-\>fingerprint mappings stored in the approved-routers
+ * file. The file format is line-based, with each non-blank holding one
+ * nickname, some space, and a fingerprint for that nickname. On success,
+ * replace the current fingerprint list with the new list and return 0. On
+ * failure, leave the current fingerprint list untouched, and
+ * return -1. */
int
-dirserv_parse_fingerprint_file(const char *fname)
+dirserv_load_fingerprint_file(void)
{
+ char fname[512];
char *cf;
char *nickname, *fingerprint;
smartlist_t *fingerprint_list_new;
int result;
config_line_t *front=NULL, *list;
+ or_options_t *options = get_options();
+
+ tor_snprintf(fname, sizeof(fname),
+ "%s/approved-routers", options->DataDirectory);
+ log_info(LD_GENERAL,
+ "Reloading approved fingerprints from \"%s\"...", fname);
cf = read_file_to_str(fname, 0);
if (!cf) {
- if (get_options()->NamingAuthoritativeDir) {
+ if (options->NamingAuthoritativeDir) {
log_warn(LD_FS, "Cannot open fingerprint file '%s'. Failing.", fname);
return -1;
} else {
@@ -454,6 +462,7 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
case FP_INVALID:
ri->is_named = ri->is_valid = 0;
break;
+ case FP_REJECT:
default:
tor_assert(0);
}
@@ -480,7 +489,7 @@ dirserv_add_descriptor(const char *desc, const char **msg)
*msg = NULL;
/* Check: is the descriptor syntactically valid? */
- ri = router_parse_entry_from_string(desc, NULL);
+ ri = router_parse_entry_from_string(desc, NULL, 1);
if (!ri) {
log_warn(LD_DIRSERV, "Couldn't parse uploaded server descriptor");
*msg = "Rejected: Couldn't parse server descriptor.";
@@ -656,7 +665,7 @@ list_single_server_status(routerinfo_t *desc, int is_live)
/** Each server needs to have passed a reachability test no more
* than this number of seconds ago, or he is listed as down in
* the directory. */
-#define REACHABLE_TIMEOUT (30*60)
+#define REACHABLE_TIMEOUT (45*60)
/** Treat a router as alive if
* - It's me, and I'm not hibernating.
@@ -760,11 +769,12 @@ live_enough_for_v1_dir(routerinfo_t *ri, time_t now)
/** Generate a new v1 directory and write it into a newly allocated string.
* Point *<b>dir_out</b> to the allocated string. Sign the
* directory with <b>private_key</b>. Return 0 on success, -1 on
- * failure.
+ * failure. If <b>complete</b> is set, give us all the descriptors;
+ * otherwise leave out non-running and non-valid ones.
*/
int
dirserv_dump_directory_to_string(char **dir_out,
- crypto_pk_env_t *private_key)
+ crypto_pk_env_t *private_key, int complete)
{
char *cp;
char *router_status;
@@ -798,7 +808,7 @@ dirserv_dump_directory_to_string(char **dir_out,
buf_len = 2048+strlen(recommended_versions)+
strlen(router_status);
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri,
- if (live_enough_for_v1_dir(ri, now))
+ if (complete || live_enough_for_v1_dir(ri, now))
buf_len += ri->cache_info.signed_descriptor_len+1);
buf = tor_malloc(buf_len);
/* We'll be comparing against buf_len throughout the rest of the
@@ -824,7 +834,7 @@ dirserv_dump_directory_to_string(char **dir_out,
{
size_t len = ri->cache_info.signed_descriptor_len;
const char *body;
- if (!live_enough_for_v1_dir(ri, now))
+ if (!complete && !live_enough_for_v1_dir(ri, now))
continue;
if (cp+len+1 >= buf+buf_len)
goto truncated;
@@ -864,12 +874,12 @@ dirserv_dump_directory_to_string(char **dir_out,
}
/** Most recently generated encoded signed directory. (auth dirservers only.)*/
-static cached_dir_t the_directory = { NULL, NULL, 0, 0, 0 };
+static cached_dir_t *the_directory = NULL;
/* Used only by non-auth dirservers: The directory and runningrouters we'll
* serve when requested. */
-static cached_dir_t cached_directory = { NULL, NULL, 0, 0, 0 };
-static cached_dir_t cached_runningrouters = { NULL, NULL, 0, 0, 0 };
+static cached_dir_t *cached_directory = NULL;
+static cached_dir_t cached_runningrouters = { NULL, NULL, 0, 0, 0, -1 };
/* Used for other dirservers' v2 network statuses. Map from hexdigest to
* cached_dir_t. */
@@ -879,7 +889,7 @@ static digestmap_t *cached_v2_networkstatus = NULL;
* <b>directory</b> published on <b>when</b>, unless <b>when</b> is older than
* the last value, or too far in the future.
*
- * Does not copy <b>directory</b>; free it if it isn't used.
+ * Does not copy <b>directory</b>; frees it if it isn't used.
*/
static void
set_cached_dir(cached_dir_t *d, char *directory, time_t when)
@@ -906,6 +916,32 @@ set_cached_dir(cached_dir_t *d, char *directory, time_t when)
}
}
+/** DOCDOC */
+void
+cached_dir_decref(cached_dir_t *d)
+{
+ if (!d || --d->refcnt > 0)
+ return;
+ clear_cached_dir(d);
+ tor_free(d);
+}
+
+/** DOCDOC */
+static cached_dir_t *
+new_cached_dir(char *s, time_t published)
+{
+ cached_dir_t *d = tor_malloc_zero(sizeof(cached_dir_t));
+ d->refcnt = 1;
+ d->dir = s;
+ d->dir_len = strlen(s);
+ d->published = published;
+ if (tor_gzip_compress(&(d->dir_z), &(d->dir_z_len), d->dir, d->dir_len,
+ ZLIB_METHOD)) {
+ log_warn(LD_BUG, "Error compressing directory");
+ }
+ return d;
+}
+
/** Remove all storage held in <b>d</b>, but do not free <b>d</b> itself. */
static void
clear_cached_dir(cached_dir_t *d)
@@ -917,11 +953,10 @@ clear_cached_dir(cached_dir_t *d)
/** Free all storage held by the cached_dir_t in <b>d</b>. */
static void
-free_cached_dir(void *_d)
+_free_cached_dir(void *_d)
{
cached_dir_t *d = (cached_dir_t *)_d;
- clear_cached_dir(d);
- tor_free(d);
+ cached_dir_decref(d);
}
/** If we have no cached directory, or it is older than <b>when</b>, then
@@ -931,9 +966,12 @@ void
dirserv_set_cached_directory(const char *directory, time_t published,
int is_running_routers)
{
- cached_dir_t *d;
- d = is_running_routers ? &cached_runningrouters : &cached_directory;
- set_cached_dir(d, tor_strdup(directory), published);
+ if (is_running_routers) {
+ set_cached_dir(&cached_runningrouters, tor_strdup(directory), published);
+ } else {
+ cached_dir_decref(cached_directory);
+ cached_directory = new_cached_dir(tor_strdup(directory), published);
+ }
}
/** We've just received a v2 network-status for an authoritative directory
@@ -947,28 +985,30 @@ dirserv_set_cached_networkstatus_v2(const char *networkstatus,
const char *identity,
time_t published)
{
- cached_dir_t *d;
+ cached_dir_t *d, *old_d;
smartlist_t *trusted_dirs;
if (!cached_v2_networkstatus)
cached_v2_networkstatus = digestmap_new();
- if (!(d = digestmap_get(cached_v2_networkstatus, identity))) {
- if (!networkstatus)
- return;
- d = tor_malloc_zero(sizeof(cached_dir_t));
- digestmap_set(cached_v2_networkstatus, identity, d);
- }
+ old_d = digestmap_get(cached_v2_networkstatus, identity);
+ if (!old_d && !networkstatus)
+ return;
- tor_assert(d);
if (networkstatus) {
- if (published > d->published) {
- set_cached_dir(d, tor_strdup(networkstatus), published);
+ if (!old_d || published > old_d->published) {
+ d = new_cached_dir(tor_strdup(networkstatus), published);
+ digestmap_set(cached_v2_networkstatus, identity, d);
+ if (old_d)
+ cached_dir_decref(old_d);
}
} else {
- free_cached_dir(d);
- digestmap_remove(cached_v2_networkstatus, identity);
+ if (old_d) {
+ digestmap_remove(cached_v2_networkstatus, identity);
+ cached_dir_decref(old_d);
+ }
}
+ /* Now purge old entries. */
trusted_dirs = router_get_trusted_dir_servers();
if (digestmap_size(cached_v2_networkstatus) >
smartlist_len(trusted_dirs) + MAX_UNTRUSTED_NETWORKSTATUSES) {
@@ -993,7 +1033,7 @@ dirserv_set_cached_networkstatus_v2(const char *networkstatus,
tor_assert(oldest);
d = digestmap_remove(cached_v2_networkstatus, oldest);
if (d)
- free_cached_dir(d);
+ cached_dir_decref(d);
}
}
@@ -1005,7 +1045,7 @@ dirserv_set_cached_networkstatus_v2(const char *networkstatus,
static cached_dir_t *
dirserv_pick_cached_dir_obj(cached_dir_t *cache_src,
cached_dir_t *auth_src,
- time_t dirty, int (*regenerate)(void),
+ time_t dirty, cached_dir_t *(*regenerate)(void),
const char *name,
int is_v1_object)
{
@@ -1018,7 +1058,7 @@ dirserv_pick_cached_dir_obj(cached_dir_t *cache_src,
/* We're authoritative. */
if (regenerate != NULL) {
if (dirty && dirty + DIR_REGEN_SLACK_TIME < time(NULL)) {
- if (regenerate()) {
+ if (!(auth_src = regenerate())) {
log_err(LD_BUG, "Couldn't generate %s?", name);
exit(1);
}
@@ -1042,10 +1082,11 @@ dirserv_pick_cached_dir_obj(cached_dir_t *cache_src,
* this kind of object.
**/
static size_t
-dirserv_get_obj(const char **out, int compress,
+dirserv_get_obj(const char **out,
+ int compress,
cached_dir_t *cache_src,
cached_dir_t *auth_src,
- time_t dirty, int (*regenerate)(void),
+ time_t dirty, cached_dir_t *(*regenerate)(void),
const char *name,
int is_v1_object)
{
@@ -1064,53 +1105,54 @@ dirserv_get_obj(const char **out, int compress,
}
}
-/** Set *<b>directory</b> to the most recently generated encoded signed
- * directory, generating a new one as necessary. If not an authoritative
- * directory may return 0 if no directory is yet cached.*/
-size_t
-dirserv_get_directory(const char **directory, int compress)
+/** Return the most recently generated encoded signed directory, generating a
+ * new one as necessary. If not an authoritative directory may return NULL if
+ * no directory is yet cached.*/
+cached_dir_t *
+dirserv_get_directory(void)
{
- return dirserv_get_obj(directory, compress,
- &cached_directory, &the_directory,
- the_directory_is_dirty,
- dirserv_regenerate_directory,
- "server directory", 1);
+ return dirserv_pick_cached_dir_obj(cached_directory, the_directory,
+ the_directory_is_dirty,
+ dirserv_regenerate_directory,
+ "server directory", 1);
}
/**
- * Generate a fresh v1 directory (authdirservers only.)
+ * Generate a fresh v1 directory (authdirservers only); set the_directory
+ * and return a pointer to the new value.
*/
-static int
+static cached_dir_t *
dirserv_regenerate_directory(void)
{
char *new_directory=NULL;
if (dirserv_dump_directory_to_string(&new_directory,
- get_identity_key())) {
+ get_identity_key(), 0)) {
log_warn(LD_BUG, "Error creating directory.");
tor_free(new_directory);
- return -1;
+ return NULL;
}
- set_cached_dir(&the_directory, new_directory, time(NULL));
+ cached_dir_decref(the_directory);
+ the_directory = new_cached_dir(new_directory, time(NULL));
log_info(LD_DIRSERV,"New directory (size %d) has been built.",
- (int)the_directory.dir_len);
+ (int)the_directory->dir_len);
log_debug(LD_DIRSERV,"New directory (size %d):\n%s",
- (int)the_directory.dir_len, the_directory.dir);
+ (int)the_directory->dir_len, the_directory->dir);
the_directory_is_dirty = 0;
/* Save the directory to disk so we re-load it quickly on startup.
*/
- dirserv_set_cached_directory(the_directory.dir, time(NULL), 0);
+ dirserv_set_cached_directory(the_directory->dir, time(NULL), 0);
- return 0;
+ return the_directory;
}
/** For authoritative directories: the current (v1) network status */
-static cached_dir_t the_runningrouters = { NULL, NULL, 0, 0, 0 };
+static cached_dir_t the_runningrouters = { NULL, NULL, 0, 0, 0, -1 };
/** Replace the current running-routers list with a newly generated one. */
-static int
+static cached_dir_t *
generate_runningrouters(void)
{
char *s=NULL;
@@ -1155,11 +1197,11 @@ generate_runningrouters(void)
set_cached_dir(&the_runningrouters, s, time(NULL));
runningrouters_is_dirty = 0;
- return 0;
+ return &the_runningrouters;
err:
tor_free(s);
tor_free(router_status);
- return -1;
+ return NULL;
}
/** Set *<b>rr</b> to the most recently generated encoded signed
@@ -1176,7 +1218,7 @@ dirserv_get_runningrouters(const char **rr, int compress)
}
/** For authoritative directories: the current (v2) network status */
-static cached_dir_t the_v2_networkstatus = { NULL, NULL, 0, 0, 0 };
+static cached_dir_t *the_v2_networkstatus = NULL;
static int
should_generate_v2_networkstatus(void)
@@ -1260,6 +1302,9 @@ dirserv_compute_performance_thresholds(routerlist_t *rl)
if (smartlist_len(bandwidths)) {
fast_bandwidth = *(uint32_t*)smartlist_get(bandwidths,
smartlist_len(bandwidths)/8);
+ if (fast_bandwidth < ROUTER_REQUIRED_MIN_BANDWIDTH)
+ fast_bandwidth = *(uint32_t*)smartlist_get(bandwidths,
+ smartlist_len(bandwidths)/4);
guard_bandwidth = *(uint32_t*)smartlist_get(bandwidths,
smartlist_len(bandwidths)/2);
}
@@ -1278,7 +1323,7 @@ dirserv_compute_performance_thresholds(routerlist_t *rl)
/** For authoritative directories only: replace the contents of
* <b>the_v2_networkstatus</b> with a newly generated network status
* object. */
-static int
+static cached_dir_t *
generate_v2_networkstatus(void)
{
#define LONGEST_STATUS_FLAG_NAME_LEN 7
@@ -1290,7 +1335,7 @@ generate_v2_networkstatus(void)
/* second line */ \
(LONGEST_STATUS_FLAG_NAME_LEN+1)*N_STATUS_FLAGS + 2)
- int r = -1;
+ cached_dir_t *r = NULL;
size_t len, identity_pkey_len;
char *status = NULL, *client_versions = NULL, *server_versions = NULL,
*identity_pkey = NULL, *hostname = NULL;
@@ -1310,7 +1355,7 @@ generate_v2_networkstatus(void)
int versioning = options->VersioningAuthoritativeDir;
const char *contact;
- if (resolve_my_address(options, &addr, &hostname)<0) {
+ if (resolve_my_address(LOG_WARN, options, &addr, &hostname)<0) {
log_warn(LD_NET, "Couldn't resolve my hostname");
goto done;
}
@@ -1359,9 +1404,9 @@ generate_v2_networkstatus(void)
naming ? " Names" : "",
versioning ? " Versions" : "",
versioning ? "client-versions " : "",
- client_versions,
+ versioning ? client_versions : "",
versioning ? "\nserver-versions " : "",
- server_versions,
+ versioning ? server_versions : "",
versioning ? "\n" : "",
identity_pkey);
outp = status + strlen(status);
@@ -1452,13 +1497,14 @@ generate_v2_networkstatus(void)
goto done;
}
- set_cached_dir(&the_v2_networkstatus, status, time(NULL));
+ if (the_v2_networkstatus)
+ cached_dir_decref(the_v2_networkstatus);
+ the_v2_networkstatus = new_cached_dir(status, time(NULL));
status = NULL; /* So it doesn't get double-freed. */
the_v2_networkstatus_is_dirty = 0;
- router_set_networkstatus(the_v2_networkstatus.dir, time(NULL), NS_GENERATED,
- NULL);
-
- r = 0;
+ router_set_networkstatus(the_v2_networkstatus->dir,
+ time(NULL), NS_GENERATED, NULL);
+ r = the_v2_networkstatus;
done:
tor_free(client_versions);
tor_free(server_versions);
@@ -1468,6 +1514,45 @@ generate_v2_networkstatus(void)
return r;
}
+/* DOCDOC */
+void
+dirserv_get_networkstatus_v2_fingerprints(smartlist_t *result,
+ const char *key)
+{
+ tor_assert(result);
+
+ if (!cached_v2_networkstatus)
+ cached_v2_networkstatus = digestmap_new();
+
+ if (should_generate_v2_networkstatus())
+ generate_v2_networkstatus();
+
+ if (!strcmp(key,"authority")) {
+ if (get_options()->AuthoritativeDir) {
+ routerinfo_t *me = router_get_my_routerinfo();
+ if (me)
+ smartlist_add(result,
+ tor_memdup(me->cache_info.identity_digest, DIGEST_LEN));
+ }
+ } else if (!strcmp(key, "all")) {
+ digestmap_iter_t *iter;
+ iter = digestmap_iter_init(cached_v2_networkstatus);
+ while (!digestmap_iter_done(iter)) {
+ const char *ident;
+ void *val;
+ digestmap_iter_get(iter, &ident, &val);
+ smartlist_add(result, tor_memdup(ident, DIGEST_LEN));
+ iter = digestmap_iter_next(cached_v2_networkstatus, iter);
+ }
+ smartlist_sort_digests(result);
+ if (smartlist_len(result) == 0)
+ log_warn(LD_DIRSERV,
+ "Client requested 'all' network status objects; we have none.");
+ } else if (!strcmpstart(key, "fp/")) {
+ dir_split_resource_into_fingerprints(key+3, result, NULL, 1, 1);
+ }
+}
+
/** Look for a network status object as specified by <b>key</b>, which should
* be either "authority" (to find a network status generated by us), a hex
* identity digest (to find a network status generated by given directory), or
@@ -1486,7 +1571,7 @@ dirserv_get_networkstatus_v2(smartlist_t *result,
if (get_options()->AuthoritativeDir) {
cached_dir_t *d =
dirserv_pick_cached_dir_obj(NULL,
- &the_v2_networkstatus,
+ the_v2_networkstatus,
the_v2_networkstatus_is_dirty,
generate_v2_networkstatus,
"network status list", 0);
@@ -1513,7 +1598,7 @@ dirserv_get_networkstatus_v2(smartlist_t *result,
"Client requested 'all' network status objects; we have none.");
} else if (!strcmpstart(key, "fp/")) {
smartlist_t *digests = smartlist_create();
- dir_split_resource_into_fingerprints(key+3, digests, NULL, 1);
+ dir_split_resource_into_fingerprints(key+3, digests, NULL, 1, 1);
SMARTLIST_FOREACH(digests, char *, cp,
{
cached_dir_t *cached;
@@ -1534,6 +1619,44 @@ dirserv_get_networkstatus_v2(smartlist_t *result,
}
}
+/** As dirserv_get_routerdescs(), but instead of getting signed_descriptor_t
+ * pointers, adds copies of digests to fps_out. For a /tor/server/d/ request,
+ * adds descriptor digests; for other requests, adds identity digests.
+ */
+int
+dirserv_get_routerdesc_fingerprints(smartlist_t *fps_out, const char *key,
+ const char **msg)
+{
+ *msg = NULL;
+
+ if (!strcmp(key, "/tor/server/all")) {
+ routerlist_t *rl = router_get_routerlist();
+ SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r,
+ smartlist_add(fps_out,
+ tor_memdup(r->cache_info.identity_digest, DIGEST_LEN)));
+ } else if (!strcmp(key, "/tor/server/authority")) {
+ routerinfo_t *ri = router_get_my_routerinfo();
+ if (ri)
+ smartlist_add(fps_out,
+ tor_memdup(ri->cache_info.identity_digest, DIGEST_LEN));
+ } else if (!strcmpstart(key, "/tor/server/d/")) {
+ key += strlen("/tor/server/d/");
+ dir_split_resource_into_fingerprints(key, fps_out, NULL, 1, 1);
+ } else if (!strcmpstart(key, "/tor/server/fp/")) {
+ key += strlen("/tor/server/fp/");
+ dir_split_resource_into_fingerprints(key, fps_out, NULL, 1, 1);
+ } else {
+ *msg = "Key not recognized";
+ return -1;
+ }
+
+ if (!smartlist_len(fps_out)) {
+ *msg = "Servers unavailable";
+ return -1;
+ }
+ return 0;
+}
+
/** Add a signed_descriptor_t to <b>descs_out</b> for each router matching
* <b>key</b>. The key should be either
* - "/tor/server/authority" for our own routerinfo;
@@ -1569,7 +1692,7 @@ dirserv_get_routerdescs(smartlist_t *descs_out, const char *key,
} else if (!strcmpstart(key, "/tor/server/d/")) {
smartlist_t *digests = smartlist_create();
key += strlen("/tor/server/d/");
- dir_split_resource_into_fingerprints(key, digests, NULL, 1);
+ dir_split_resource_into_fingerprints(key, digests, NULL, 1, 1);
SMARTLIST_FOREACH(digests, const char *, d,
{
signed_descriptor_t *sd = router_get_by_descriptor_digest(d);
@@ -1582,7 +1705,7 @@ dirserv_get_routerdescs(smartlist_t *descs_out, const char *key,
smartlist_t *digests = smartlist_create();
time_t cutoff = time(NULL) - ROUTER_MAX_AGE_TO_PUBLISH;
key += strlen("/tor/server/fp/");
- dir_split_resource_into_fingerprints(key, digests, NULL, 1);
+ dir_split_resource_into_fingerprints(key, digests, NULL, 1, 1);
SMARTLIST_FOREACH(digests, const char *, d,
{
if (router_digest_is_me(d)) {
@@ -1633,6 +1756,7 @@ dirserv_orconn_tls_done(const char *address,
tor_assert(address);
tor_assert(digest_rcvd);
tor_assert(nickname_rcvd);
+ (void) as_advertised; // XXXX This should really be implemented. -NM
// XXXXNM We should really have a better solution here than dropping
// XXXXNM whole routers; otherwise, they come back way too easily.
@@ -1671,6 +1795,211 @@ dirserv_orconn_tls_done(const char *address,
}
}
+/** Auth dir server only: if <b>try_all</b> is 1, launch connections to
+ * all known routers; else we want to load balance such that we only
+ * try a few connections per call.
+ *
+ * The load balancing is such that if we get called once every ten
+ * seconds, we will cycle through all the tests in 1280 seconds (a
+ * bit over 20 minutes).
+ */
+void
+dirserv_test_reachability(int try_all)
+{
+ time_t now = time(NULL);
+ routerlist_t *rl = router_get_routerlist();
+ static char ctr = 0;
+
+ SMARTLIST_FOREACH(rl->routers, routerinfo_t *, router, {
+ const char *id_digest = router->cache_info.identity_digest;
+ if (router_is_me(router))
+ continue;
+ if (try_all || (((uint8_t)id_digest[0]) % 128) == ctr) {
+ log_debug(LD_OR,"Testing reachability of %s at %s:%u.",
+ router->nickname, router->address, router->or_port);
+ /* Remember when we started trying to determine reachability */
+ if (!router->testing_since)
+ router->testing_since = now;
+ connection_or_connect(router->addr, router->or_port,
+ id_digest);
+ }
+ });
+ if (!try_all) /* increment ctr */
+ ctr = (ctr + 1) % 128;
+}
+
+/** When we're spooling data onto our outbuf, add more whenever we dip
+ * below this threshold. */
+#define DIRSERV_BUFFER_MIN 16384
+
+static int
+connection_dirserv_finish_spooling(dir_connection_t *conn)
+{
+ if (conn->zlib_state) {
+ connection_write_to_buf_zlib(conn, "", 0, 1);
+ tor_zlib_free(conn->zlib_state);
+ conn->zlib_state = NULL;
+ }
+ conn->dir_spool_src = DIR_SPOOL_NONE;
+ return 0;
+}
+
+/** DOCDOC */
+static int
+connection_dirserv_add_servers_to_outbuf(dir_connection_t *conn)
+{
+ int by_fp = conn->dir_spool_src == DIR_SPOOL_SERVER_BY_FP;
+
+ while (smartlist_len(conn->fingerprint_stack) &&
+ buf_datalen(conn->_base.outbuf) < DIRSERV_BUFFER_MIN) {
+ const char *body;
+ char *fp = smartlist_pop_last(conn->fingerprint_stack);
+ signed_descriptor_t *sd = NULL;
+ if (by_fp) {
+ if (router_digest_is_me(fp)) {
+ sd = &(router_get_my_routerinfo()->cache_info);
+ } else {
+ routerinfo_t *ri = router_get_by_digest(fp);
+ if (ri &&
+ ri->cache_info.published_on > time(NULL)-ROUTER_MAX_AGE_TO_PUBLISH)
+ sd = &ri->cache_info;
+ }
+ } else
+ sd = router_get_by_descriptor_digest(fp);
+ tor_free(fp);
+ if (!sd)
+ continue;
+ body = signed_descriptor_get_body(sd);
+ if (conn->zlib_state) {
+ int last = ! smartlist_len(conn->fingerprint_stack);
+ connection_write_to_buf_zlib(conn, body,
+ sd->signed_descriptor_len, last);
+ if (last) {
+ tor_zlib_free(conn->zlib_state);
+ conn->zlib_state = NULL;
+ }
+ } else {
+ connection_write_to_buf(body,
+ sd->signed_descriptor_len,
+ TO_CONN(conn));
+ }
+ }
+
+ if (!smartlist_len(conn->fingerprint_stack)) {
+ /* We just wrote the last one; finish up. */
+ conn->dir_spool_src = DIR_SPOOL_NONE;
+ smartlist_free(conn->fingerprint_stack);
+ conn->fingerprint_stack = NULL;
+ }
+ return 0;
+}
+
+/** DOCDOC */
+static int
+connection_dirserv_add_dir_bytes_to_outbuf(dir_connection_t *conn)
+{
+ int bytes, remaining;
+
+ bytes = DIRSERV_BUFFER_MIN - buf_datalen(conn->_base.outbuf);
+ tor_assert(bytes > 0);
+ tor_assert(conn->cached_dir);
+ if (bytes < 8192)
+ bytes = 8192;
+ remaining = conn->cached_dir->dir_z_len - conn->cached_dir_offset;
+ if (bytes > remaining)
+ bytes = remaining;
+
+ if (conn->zlib_state) {
+ connection_write_to_buf_zlib(conn,
+ conn->cached_dir->dir_z + conn->cached_dir_offset,
+ bytes, bytes == remaining);
+ } else {
+ connection_write_to_buf(conn->cached_dir->dir_z + conn->cached_dir_offset,
+ bytes, TO_CONN(conn));
+ }
+ conn->cached_dir_offset += bytes;
+ if (conn->cached_dir_offset == (int)conn->cached_dir->dir_z_len) {
+ /* We just wrote the last one; finish up. */
+ connection_dirserv_finish_spooling(conn);
+ cached_dir_decref(conn->cached_dir);
+ conn->cached_dir = NULL;
+ }
+ return 0;
+}
+
+/* DOCDOC */
+static int
+connection_dirserv_add_networkstatus_bytes_to_outbuf(dir_connection_t *conn)
+{
+
+ while (buf_datalen(conn->_base.outbuf) < DIRSERV_BUFFER_MIN) {
+ if (conn->cached_dir) {
+ int uncompressing = (conn->zlib_state != NULL);
+ int r = connection_dirserv_add_dir_bytes_to_outbuf(conn);
+ if (conn->dir_spool_src == DIR_SPOOL_NONE) {
+ /* add_dir_bytes thinks we're done with the cached_dir. But we
+ * may have more cached_dirs! */
+ conn->dir_spool_src = DIR_SPOOL_NETWORKSTATUS;
+ /* This bit is tricky. If we were uncompressing the last
+ * networkstatus, we may need to make a new zlib object to
+ * uncompress the next one. */
+ if (uncompressing && ! conn->zlib_state &&
+ conn->fingerprint_stack &&
+ smartlist_len(conn->fingerprint_stack)) {
+ conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD);
+ }
+ }
+ if (r) return r;
+ } else if (conn->fingerprint_stack &&
+ smartlist_len(conn->fingerprint_stack)) {
+ /* Add another networkstatus; start serving it. */
+ char *fp = smartlist_pop_last(conn->fingerprint_stack);
+ cached_dir_t *d;
+ if (router_digest_is_me(fp))
+ d = the_v2_networkstatus;
+ else
+ d = digestmap_get(cached_v2_networkstatus, fp);
+ tor_free(fp);
+ if (d) {
+ ++d->refcnt;
+ conn->cached_dir = d;
+ conn->cached_dir_offset = 0;
+ }
+ } else {
+ connection_dirserv_finish_spooling(conn);
+ if (conn->fingerprint_stack)
+ smartlist_free(conn->fingerprint_stack);
+ conn->fingerprint_stack = NULL;
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/** Called whenever we have flushed some directory data in state
+ * SERVER_WRITING. */
+int
+connection_dirserv_flushed_some(dir_connection_t *conn)
+{
+ tor_assert(conn->_base.state == DIR_CONN_STATE_SERVER_WRITING);
+
+ if (buf_datalen(conn->_base.outbuf) >= DIRSERV_BUFFER_MIN)
+ return 0;
+
+ switch (conn->dir_spool_src) {
+ case DIR_SPOOL_SERVER_BY_DIGEST:
+ case DIR_SPOOL_SERVER_BY_FP:
+ return connection_dirserv_add_servers_to_outbuf(conn);
+ case DIR_SPOOL_CACHED_DIR:
+ return connection_dirserv_add_dir_bytes_to_outbuf(conn);
+ case DIR_SPOOL_NETWORKSTATUS:
+ return connection_dirserv_add_networkstatus_bytes_to_outbuf(conn);
+ case DIR_SPOOL_NONE:
+ default:
+ return 0;
+ }
+}
+
/** Release all storage used by the directory server. */
void
dirserv_free_all(void)
@@ -1683,13 +2012,13 @@ dirserv_free_all(void)
smartlist_free(fingerprint_list);
fingerprint_list = NULL;
}
- clear_cached_dir(&the_directory);
+ cached_dir_decref(the_directory);
clear_cached_dir(&the_runningrouters);
- clear_cached_dir(&the_v2_networkstatus);
- clear_cached_dir(&cached_directory);
+ cached_dir_decref(the_v2_networkstatus);
+ cached_dir_decref(cached_directory);
clear_cached_dir(&cached_runningrouters);
if (cached_v2_networkstatus) {
- digestmap_free(cached_v2_networkstatus, free_cached_dir);
+ digestmap_free(cached_v2_networkstatus, _free_cached_dir);
cached_v2_networkstatus = NULL;
}
}
diff --git a/src/or/dns.c b/src/or/dns.c
index 5303ced78a..adfadb6f13 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -7,20 +7,21 @@ const char dns_c_id[] =
/**
* \file dns.c
- * \brief Implements a farm of 'DNS worker' threads or processes to
- * perform DNS lookups for onion routers and cache the results.
- * [This needs to be done in the background because of the lack of a
- * good, ubiquitous asynchronous DNS implementation.]
+ * \brief Implements a local cache for DNS results for Tor servers.
+ * We provide two asynchronous backend implementations:
+ * 1) A farm of 'DNS worker' threads or processes to perform DNS lookups for
+ * onion routers and cache the results.
+ * 2) A wrapper around Adam Langley's eventdns.c code, to send requests
+ * to the nameservers asynchronously.
+ * (We can't just use gethostbyname() and friends because we really need to
+ * be nonblocking.)
**/
-/* See
- * http://elvin.dstc.com/ListArchive/elvin-dev/archive/2001/09/msg00027.html
- * for some approaches to asynchronous dns. We will want to switch once one of
- * them becomes more commonly available.
- */
-
#include "or.h"
#include "../common/ht.h"
+#ifdef USE_EVENTDNS
+#include "eventdns.h"
+#endif
/** Longest hostname we're willing to resolve. */
#define MAX_ADDRESSLEN 256
@@ -33,51 +34,103 @@ const char dns_c_id[] =
/** If more than this many processes are idle, shut down the extras. */
#define MAX_IDLE_DNSWORKERS 10
+/** How long will we wait for an answer from the resolver before we decide
+ * that the resolver is wedged? */
+#define RESOLVE_MAX_TIMEOUT 300
+
/** Possible outcomes from hostname lookup: permanent failure,
* transient (retryable) failure, and success. */
#define DNS_RESOLVE_FAILED_TRANSIENT 1
#define DNS_RESOLVE_FAILED_PERMANENT 2
#define DNS_RESOLVE_SUCCEEDED 3
+#ifndef USE_EVENTDNS
/** How many dnsworkers we have running right now. */
static int num_dnsworkers=0;
/** How many of the running dnsworkers have an assigned task right now. */
static int num_dnsworkers_busy=0;
/** When did we last rotate the dnsworkers? */
static time_t last_rotation_time=0;
+#else
+/** Have we currently configured nameservers with eventdns? */
+static int nameservers_configured = 0;
+/** What was the resolv_conf fname we last used when configuring the
+ * nameservers? Used to check whether we need to reconfigure. */
+static char *resolv_conf_fname = NULL;
+/** What was the mtime on the resolv.conf file we last used when configuring
+ * the nameservers? Used to check whether we need to reconfigure. */
+static time_t resolv_conf_mtime = 0;
+#endif
/** Linked list of connections waiting for a DNS answer. */
typedef struct pending_connection_t {
- connection_t *conn;
+ edge_connection_t *conn;
struct pending_connection_t *next;
} pending_connection_t;
+#define CACHED_RESOLVE_MAGIC 0x1234F00D
+
+/* Possible states for a cached resolve_t */
+/** We are waiting for the resolver system to tell us an answer here.
+ * When we get one, or when we time out, the state of this cached_resolve_t
+ * will become "DONE" and we'll possibly add a CACHED_VALID or a CACHED_FAILED
+ * entry. This cached_resolve_t will be in the hash table so that we will
+ * know not to launch more requests for this addr, but rather to add more
+ * connections to the pending list for the addr. */
+#define CACHE_STATE_PENDING 0
+/** This used to be a pending cached_resolve_t, and we got an answer for it.
+ * Now we're waiting for this cached_resolve_t to expire. This should
+ * have no pending connections, and should not appear in the hash table. */
+#define CACHE_STATE_DONE 1
+/** We are caching an answer for this address. This should have no pending
+ * connections, and should appear in the hash table. */
+#define CACHE_STATE_CACHED_VALID 2
+/** We are caching a failure for this address. This should have no pending
+ * connections, and should appear in the hash table */
+#define CACHE_STATE_CACHED_FAILED 3
+
/** A DNS request: possibly completed, possibly pending; cached_resolve
* structs are stored at the OR side in a hash table, and as a linked
* list from oldest to newest.
*/
typedef struct cached_resolve_t {
HT_ENTRY(cached_resolve_t) node;
+ uint32_t magic;
char address[MAX_ADDRESSLEN]; /**< The hostname to be resolved. */
- uint32_t addr; /**< IPv4 addr for <b>address</b>. */
- char state; /**< 0 is pending; 1 means answer is valid; 2 means resolve
- * failed. */
-#define CACHE_STATE_PENDING 0
-#define CACHE_STATE_VALID 1
-#define CACHE_STATE_FAILED 2
- uint32_t expire; /**< Remove items from cache after this time. */
+ union {
+ uint32_t addr; /**< IPv4 addr for <b>address</b>. */
+ char *hostname; /**< Hostname for <b>address</b> (if a reverse lookup) */
+ } result;
+ uint8_t state; /**< Is this cached entry pending/done/valid/failed? */
+ uint8_t is_reverse; /**< Is this a reverse (addr-to-hostname) lookup? */
+ time_t expire; /**< Remove items from cache after this time. */
+ uint32_t ttl; /**< What TTL did the nameserver tell us? */
+ /** Connections that want to know when we get an answer for this resolve. */
pending_connection_t *pending_connections;
- struct cached_resolve_t *next;
} cached_resolve_t;
-static void purge_expired_resolves(uint32_t now);
-static int assign_to_dnsworker(connection_t *exitconn);
-static void dns_purge_resolve(cached_resolve_t *resolve);
-static void dns_found_answer(char *address, uint32_t addr, char outcome);
-static int dnsworker_main(void *data);
+static void purge_expired_resolves(time_t now);
+static void dns_found_answer(const char *address, int is_reverse,
+ uint32_t addr, const char *hostname, char outcome,
+ uint32_t ttl);
+static void send_resolved_cell(edge_connection_t *conn, uint8_t answer_type);
+static int launch_resolve(edge_connection_t *exitconn);
+#ifndef USE_EVENTDNS
+static void dnsworkers_rotate(void);
+static void dnsworker_main(void *data);
static int spawn_dnsworker(void);
static int spawn_enough_dnsworkers(void);
-static void send_resolved_cell(connection_t *conn, uint8_t answer_type);
+#else
+static int configure_nameservers(int force);
+static int answer_is_wildcarded(const char *ip);
+#endif
+#ifdef DEBUG_DNS_CACHE
+static void _assert_cache_ok(void);
+#define assert_cache_ok() _assert_cache_ok()
+#else
+#define assert_cache_ok() do {} while (0)
+#endif
+static void assert_resolve_ok(cached_resolve_t *resolve);
/** Hash table of cached_resolve objects. */
static HT_HEAD(cache_map, cached_resolve_t) cache_root;
@@ -88,9 +141,11 @@ static INLINE int
cached_resolves_eq(cached_resolve_t *a, cached_resolve_t *b)
{
/* make this smarter one day? */
+ assert_resolve_ok(a); // Not b; b may be just a search.
return !strncmp(a->address, b->address, MAX_ADDRESSLEN);
}
+/** Hash function for cached_resolve objects */
static INLINE unsigned int
cached_resolve_hash(cached_resolve_t *a)
{
@@ -109,12 +164,82 @@ init_cache_map(void)
HT_INIT(&cache_root);
}
+#ifdef USE_EVENTDNS
+/** Helper: called by eventdns when eventdns wants to log something. */
+static void
+eventdns_log_cb(int warn, const char *msg)
+{
+ if (!strcmpstart(msg, "Resolve requested for") &&
+ get_options()->SafeLogging) {
+ log(LOG_INFO, LD_EXIT, "eventdns: Resolve requested.");
+ return;
+ } else if (!strcmpstart(msg, "Search: ")) {
+ return;
+ }
+ log(warn?LOG_WARN:LOG_INFO, LD_EXIT, "eventdns: %s", msg);
+}
+#endif
+
/** Initialize the DNS subsystem; called by the OR process. */
-void
+int
dns_init(void)
{
init_cache_map();
+#ifdef USE_EVENTDNS
+ if (server_mode(get_options()))
+ return configure_nameservers(1);
+#else
+ dnsworkers_rotate();
+#endif
+ return 0;
+}
+
+/** Called when DNS-related options change (or may have changed) */
+void
+dns_reset(void)
+{
+#ifdef USE_EVENTDNS
+ or_options_t *options = get_options();
+ if (! server_mode(options)) {
+ eventdns_clear_nameservers_and_suspend();
+ eventdns_search_clear();
+ nameservers_configured = 0;
+ tor_free(resolv_conf_fname);
+ resolv_conf_mtime = 0;
+ } else {
+ if (configure_nameservers(0) < 0)
+ /* XXXX */
+ return;
+ }
+#else
dnsworkers_rotate();
+#endif
+}
+
+/** Helper: Given a TTL from a DNS response, determine what TTL to give the
+ * OP that asked us to resolve it. */
+uint32_t
+dns_clip_ttl(uint32_t ttl)
+{
+ if (ttl < MIN_DNS_TTL)
+ return MIN_DNS_TTL;
+ else if (ttl > MAX_DNS_TTL)
+ return MAX_DNS_TTL;
+ else
+ return ttl;
+}
+
+/** Helper: Given a TTL from a DNS response, determine how long to hold it in
+ * our cache. */
+static uint32_t
+dns_get_expiry_ttl(uint32_t ttl)
+{
+ if (ttl < MIN_DNS_TTL)
+ return MIN_DNS_TTL;
+ else if (ttl > MAX_DNS_ENTRY_AGE)
+ return MAX_DNS_ENTRY_AGE;
+ else
+ return ttl;
}
/** Helper: free storage held by an entry in the DNS cache. */
@@ -126,10 +251,41 @@ _free_cached_resolve(cached_resolve_t *r)
r->pending_connections = victim->next;
tor_free(victim);
}
+ if (r->is_reverse)
+ tor_free(r->result.hostname);
+ r->magic = 0xFF00FF00;
tor_free(r);
}
-/** Free all storage held in the DNS cache */
+/** Compare two cached_resolve_t pointers by expiry time, and return
+ * less-than-zero, zero, or greater-than-zero as appropriate. Used for
+ * the priority queue implementation. */
+static int
+_compare_cached_resolves_by_expiry(const void *_a, const void *_b)
+{
+ const cached_resolve_t *a = _a, *b = _b;
+ return a->expire - b->expire;
+}
+
+/** Priority queue of cached_resolve_t objects to let us know when they
+ * will expire. */
+static smartlist_t *cached_resolve_pqueue = NULL;
+
+/** Set an expiry time for a cached_resolve_t, and add it to the expiry
+ * priority queue */
+static void
+set_expiry(cached_resolve_t *resolve, time_t expires)
+{
+ tor_assert(resolve && resolve->expire == 0);
+ if (!cached_resolve_pqueue)
+ cached_resolve_pqueue = smartlist_create();
+ resolve->expire = expires;
+ smartlist_pqueue_add(cached_resolve_pqueue,
+ _compare_cached_resolves_by_expiry,
+ resolve);
+}
+
+/** Free all storage held in the DNS cache and related structures. */
void
dns_free_all(void)
{
@@ -140,78 +296,112 @@ dns_free_all(void)
_free_cached_resolve(item);
}
HT_CLEAR(cache_map, &cache_root);
+ if (cached_resolve_pqueue)
+ smartlist_free(cached_resolve_pqueue);
+ cached_resolve_pqueue = NULL;
+#ifdef USE_EVENTDNS
+ tor_free(resolv_conf_fname);
+#endif
}
-/** Linked list of resolved addresses, oldest to newest. */
-static cached_resolve_t *oldest_cached_resolve = NULL;
-static cached_resolve_t *newest_cached_resolve = NULL;
-
/** Remove every cached_resolve whose <b>expire</b> time is before <b>now</b>
* from the cache. */
static void
-purge_expired_resolves(uint32_t now)
+purge_expired_resolves(time_t now)
{
- cached_resolve_t *resolve;
+ cached_resolve_t *resolve, *removed;
pending_connection_t *pend;
- connection_t *pendconn;
+ edge_connection_t *pendconn;
+
+ assert_cache_ok();
+ if (!cached_resolve_pqueue)
+ return;
+
+ while (smartlist_len(cached_resolve_pqueue)) {
+ resolve = smartlist_get(cached_resolve_pqueue, 0);
+ if (resolve->expire > now)
+ break;
+ smartlist_pqueue_pop(cached_resolve_pqueue,
+ _compare_cached_resolves_by_expiry);
- /* this is fast because the linked list
- * oldest_cached_resolve is ordered by when they came in.
- */
- while (oldest_cached_resolve && (oldest_cached_resolve->expire < now)) {
- resolve = oldest_cached_resolve;
- log_debug(LD_EXIT,
- "Forgetting old cached resolve (address %s, expires %lu)",
- escaped_safe_str(resolve->address),
- (unsigned long)resolve->expire);
if (resolve->state == CACHE_STATE_PENDING) {
log_debug(LD_EXIT,
- "Bug: Expiring a dns resolve %s that's still pending."
- " Forgot to cull it?", escaped_safe_str(resolve->address));
- tor_fragile_assert();
+ "Expiring a dns resolve %s that's still pending. Forgot to "
+ "cull it? DNS resolve didn't tell us about the timeout?",
+ escaped_safe_str(resolve->address));
+ } else if (resolve->state == CACHE_STATE_CACHED_VALID ||
+ resolve->state == CACHE_STATE_CACHED_FAILED) {
+ log_debug(LD_EXIT,
+ "Forgetting old cached resolve (address %s, expires %lu)",
+ escaped_safe_str(resolve->address),
+ (unsigned long)resolve->expire);
+ tor_assert(!resolve->pending_connections);
+ } else {
+ tor_assert(resolve->state == CACHE_STATE_DONE);
+ tor_assert(!resolve->pending_connections);
}
+
if (resolve->pending_connections) {
log_debug(LD_EXIT,
- "Closing pending connections on expiring DNS resolve!");
+ "Closing pending connections on timed-out DNS resolve!");
tor_fragile_assert();
while (resolve->pending_connections) {
pend = resolve->pending_connections;
resolve->pending_connections = pend->next;
/* Connections should only be pending if they have no socket. */
- tor_assert(pend->conn->s == -1);
+ tor_assert(pend->conn->_base.s == -1);
pendconn = pend->conn;
connection_edge_end(pendconn, END_STREAM_REASON_TIMEOUT,
pendconn->cpath_layer);
circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
- connection_free(pendconn);
+ connection_free(TO_CONN(pendconn));
tor_free(pend);
}
}
- oldest_cached_resolve = resolve->next;
- if (!oldest_cached_resolve) /* if there are no more, */
- newest_cached_resolve = NULL; /* then make sure the list's tail knows
- * that too */
- HT_REMOVE(cache_map, &cache_root, resolve);
- tor_free(resolve);
+
+ if (resolve->state == CACHE_STATE_CACHED_VALID ||
+ resolve->state == CACHE_STATE_CACHED_FAILED ||
+ resolve->state == CACHE_STATE_PENDING) {
+ removed = HT_REMOVE(cache_map, &cache_root, resolve);
+ if (removed != resolve) {
+ log_err(LD_BUG, "The expired resolve we purged didn't match any in"
+ " the cache. Tried to purge %s (%p); instead got %s (%p).",
+ resolve->address, (void*)resolve,
+ removed ? removed->address : "NULL", (void*)remove);
+ }
+ tor_assert(removed == resolve);
+ if (resolve->is_reverse)
+ tor_free(resolve->result.hostname);
+ resolve->magic = 0xF0BBF0BB;
+ tor_free(resolve);
+ } else {
+ /* This should be in state DONE. Make sure it's not in the cache. */
+ cached_resolve_t *tmp = HT_FIND(cache_map, &cache_root, resolve);
+ tor_assert(tmp != resolve);
+ }
}
+
+ assert_cache_ok();
}
-/** Send a response to the RESOVLE request of a connection. answer_type must
+/** Send a response to the RESOLVE request of a connection. answer_type must
* be one of RESOLVED_TYPE_(IPV4|ERROR|ERROR_TRANSIENT) */
static void
-send_resolved_cell(connection_t *conn, uint8_t answer_type)
+send_resolved_cell(edge_connection_t *conn, uint8_t answer_type)
{
char buf[RELAY_PAYLOAD_SIZE];
size_t buflen;
+ uint32_t ttl;
buf[0] = answer_type;
+ ttl = dns_clip_ttl(conn->address_ttl);
switch (answer_type)
{
case RESOLVED_TYPE_IPV4:
buf[1] = 4;
- set_uint32(buf+2, htonl(conn->addr));
- set_uint32(buf+6, htonl(MAX_DNS_ENTRY_AGE)); /*XXXX send a real TTL*/
+ set_uint32(buf+2, htonl(conn->_base.addr));
+ set_uint32(buf+6, htonl(ttl));
buflen = 10;
break;
case RESOLVED_TYPE_ERROR_TRANSIENT:
@@ -219,35 +409,91 @@ send_resolved_cell(connection_t *conn, uint8_t answer_type)
{
const char *errmsg = "Error resolving hostname";
int msglen = strlen(errmsg);
- int ttl = (answer_type == RESOLVED_TYPE_ERROR ? MAX_DNS_ENTRY_AGE : 0);
+
buf[1] = msglen;
strlcpy(buf+2, errmsg, sizeof(buf)-2);
- set_uint32(buf+2+msglen, htonl((uint32_t)ttl));
+ set_uint32(buf+2+msglen, htonl(ttl));
buflen = 6+msglen;
break;
}
default:
tor_assert(0);
+ return;
}
+ // log_notice(LD_EXIT, "Sending a regular RESOLVED reply: ");
connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
RELAY_COMMAND_RESOLVED, buf, buflen,
conn->cpath_layer);
}
-/** Link <b>r</b> into the hash table of address-to-result mappings, and add it
- * to the linked list of resolves-by-age. */
+/** Send a response to the RESOLVE request of a connection for an in-addr.arpa
+ * address on connection <b>conn</b> which yielded the result <b>hostname</b>.
+ * The answer type will be RESOLVED_HOSTNAME.
+ */
static void
-insert_resolve(cached_resolve_t *r)
+send_resolved_hostname_cell(edge_connection_t *conn, const char *hostname)
{
- /* add us to the linked list of resolves */
- if (!oldest_cached_resolve) {
- oldest_cached_resolve = r;
- } else {
- newest_cached_resolve->next = r;
+ char buf[RELAY_PAYLOAD_SIZE];
+ size_t buflen;
+ uint32_t ttl;
+ size_t namelen = strlen(hostname);
+
+ tor_assert(namelen < 256);
+ ttl = dns_clip_ttl(conn->address_ttl);
+
+ buf[0] = RESOLVED_TYPE_HOSTNAME;
+ buf[1] = (uint8_t)namelen;
+ memcpy(buf+2, hostname, namelen);
+ set_uint32(buf+2+namelen, htonl(ttl));
+ buflen = 2+namelen+4;
+
+ // log_notice(LD_EXIT, "Sending a reply RESOLVED reply: %s", hostname);
+ connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
+ RELAY_COMMAND_RESOLVED, buf, buflen,
+ conn->cpath_layer);
+ // log_notice(LD_EXIT, "Sent");
+}
+
+/** Given a lower-case <b>address</b>, check to see whether it's a
+ * 1.2.3.4.in-addr.arpa address used for reverse lookups. If so,
+ * parse it and place the address in <b>in</b> if present. Return 1 on success;
+ * 0 if the address is not in in-addr.arpa format, and -1 if the address is
+ * malformed. */
+static int
+parse_inaddr_arpa_address(const char *address, struct in_addr *in)
+{
+ char buf[INET_NTOA_BUF_LEN];
+ char *cp;
+ size_t len;
+ struct in_addr inaddr;
+
+ cp = strstr(address, ".in-addr.arpa");
+ if (!cp || *(cp+strlen(".in-addr.arpa")))
+ return 0; /* not an .in-addr.arpa address */
+
+ len = cp - address;
+
+ if (len >= INET_NTOA_BUF_LEN)
+ return -1; /* Too long. */
+
+ memcpy(buf, address, len);
+ buf[len] = '\0';
+ if (tor_inet_aton(buf, &inaddr) == 0)
+ return -1; /* malformed. */
+
+ if (in) {
+ uint32_t a;
+ /* reverse the bytes */
+ a = ( ((inaddr.s_addr & 0x000000fful) << 24)
+ |((inaddr.s_addr & 0x0000ff00ul) << 8)
+ |((inaddr.s_addr & 0x00ff0000ul) >> 8)
+ |((inaddr.s_addr & 0xff000000ul) >> 24));
+ inaddr.s_addr = a;
+
+ memcpy(in, &inaddr, sizeof(inaddr));
}
- newest_cached_resolve = r;
- HT_INSERT(cache_map, &cache_root, r);
+ return 1;
}
/** See if we have a cache entry for <b>exitconn</b>-\>address. if so,
@@ -261,22 +507,28 @@ insert_resolve(cached_resolve_t *r)
* dns farm, and return 0.
*/
int
-dns_resolve(connection_t *exitconn)
+dns_resolve(edge_connection_t *exitconn)
{
cached_resolve_t *resolve;
cached_resolve_t search;
pending_connection_t *pending_connection;
- struct in_addr in;
circuit_t *circ;
- uint32_t now = time(NULL);
- assert_connection_ok(exitconn, 0);
- tor_assert(exitconn->s == -1);
+ struct in_addr in;
+ time_t now = time(NULL);
+ int is_reverse = 0, is_resolve, r;
+ assert_connection_ok(TO_CONN(exitconn), 0);
+ tor_assert(exitconn->_base.s == -1);
- /* first check if exitconn->address is an IP. If so, we already
+ assert_cache_ok();
+
+ is_resolve = exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE;
+
+ /* first check if exitconn->_base.address is an IP. If so, we already
* know the answer. */
- if (tor_inet_aton(exitconn->address, &in) != 0) {
- exitconn->addr = ntohl(in.s_addr);
- if (exitconn->purpose == EXIT_PURPOSE_RESOLVE)
+ if (tor_inet_aton(exitconn->_base.address, &in) != 0) {
+ exitconn->_base.addr = ntohl(in.s_addr);
+ exitconn->address_ttl = DEFAULT_DNS_TTL;
+ if (is_resolve)
send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4);
return 1;
}
@@ -285,13 +537,51 @@ dns_resolve(connection_t *exitconn)
* resolves in the hash table. */
purge_expired_resolves(now);
- /* lower-case exitconn->address, so it's in canonical form */
- tor_strlower(exitconn->address);
+ /* lower-case exitconn->_base.address, so it's in canonical form */
+ tor_strlower(exitconn->_base.address);
+
+ /* Check whether this is a reverse lookup. If it's malformed, or it's a
+ * .in-addr.arpa address but this isn't a resolve request, kill the
+ * connecction.
+ */
+ if ((r = parse_inaddr_arpa_address(exitconn->_base.address, NULL)) != 0) {
+ if (r == 1)
+ is_reverse = 1;
+
+#ifdef USE_EVENTDNS
+ if (!is_reverse || !is_resolve) {
+ if (!is_reverse)
+ log_info(LD_EXIT, "Bad .in-addr.arpa address \"%s\"; sending error.",
+ escaped_safe_str(exitconn->_base.address));
+ else if (!is_resolve)
+ log_info(LD_EXIT,
+ "Attempt to connect to a .in-addr.arpa address \"%s\"; "
+ "sending error.",
+ escaped_safe_str(exitconn->_base.address));
+#else
+ if (1) {
+ log_info(LD_PROTOCOL, "Dnsworker code does not support in-addr.arpa "
+ "domain, but received a request for \"%s\"; sending error.",
+ escaped_safe_str(exitconn->_base.address));
+#endif
+
+ if (exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE)
+ send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR);
+ circ = circuit_get_by_edge_conn(exitconn);
+ if (circ)
+ circuit_detach_stream(circ, exitconn);
+ if (!exitconn->_base.marked_for_close)
+ connection_free(TO_CONN(exitconn));
+ return -1;
+ }
+ //log_notice(LD_EXIT, "Looks like an address %s",
+ // exitconn->_base.address);
+ }
/* now check the hash table to see if 'address' is already there. */
- strlcpy(search.address, exitconn->address, sizeof(search.address));
+ strlcpy(search.address, exitconn->_base.address, sizeof(search.address));
resolve = HT_FIND(cache_map, &cache_root, &search);
- if (resolve) { /* already there */
+ if (resolve && resolve->expire > now) { /* already there */
switch (resolve->state) {
case CACHE_STATE_PENDING:
/* add us to the pending list */
@@ -301,121 +591,124 @@ dns_resolve(connection_t *exitconn)
pending_connection->next = resolve->pending_connections;
resolve->pending_connections = pending_connection;
log_debug(LD_EXIT,"Connection (fd %d) waiting for pending DNS "
- "resolve of %s",
- exitconn->s, escaped_safe_str(exitconn->address));
- exitconn->state = EXIT_CONN_STATE_RESOLVING;
+ "resolve of %s", exitconn->_base.s,
+ escaped_safe_str(exitconn->_base.address));
+ exitconn->_base.state = EXIT_CONN_STATE_RESOLVING;
return 0;
- case CACHE_STATE_VALID:
- exitconn->addr = resolve->addr;
+ case CACHE_STATE_CACHED_VALID:
log_debug(LD_EXIT,"Connection (fd %d) found cached answer for %s",
- exitconn->s, escaped_safe_str(exitconn->address));
- if (exitconn->purpose == EXIT_PURPOSE_RESOLVE)
- send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4);
+ exitconn->_base.s,
+ escaped_safe_str(resolve->address));
+ exitconn->address_ttl = resolve->ttl;
+ if (resolve->is_reverse) {
+ tor_assert(is_resolve);
+ send_resolved_hostname_cell(exitconn, resolve->result.hostname);
+ } else {
+ exitconn->_base.addr = resolve->result.addr;
+ if (is_resolve)
+ send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4);
+ }
return 1;
- case CACHE_STATE_FAILED:
+ case CACHE_STATE_CACHED_FAILED:
log_debug(LD_EXIT,"Connection (fd %d) found cached error for %s",
- exitconn->s, escaped_safe_str(exitconn->address));
- if (exitconn->purpose == EXIT_PURPOSE_RESOLVE)
+ exitconn->_base.s,
+ escaped_safe_str(exitconn->_base.address));
+ if (is_resolve)
send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR);
circ = circuit_get_by_edge_conn(exitconn);
if (circ)
circuit_detach_stream(circ, exitconn);
- if (!exitconn->marked_for_close)
- connection_free(exitconn);
+ if (!exitconn->_base.marked_for_close)
+ connection_free(TO_CONN(exitconn));
return -1;
+ case CACHE_STATE_DONE:
+ log_err(LD_BUG, "Found a 'DONE' dns resolve still in the cache.");
+ tor_fragile_assert();
}
tor_assert(0);
}
/* not there, need to add it */
resolve = tor_malloc_zero(sizeof(cached_resolve_t));
+ resolve->magic = CACHED_RESOLVE_MAGIC;
resolve->state = CACHE_STATE_PENDING;
- resolve->expire = now + MAX_DNS_ENTRY_AGE;
- strlcpy(resolve->address, exitconn->address, sizeof(resolve->address));
+ resolve->is_reverse = is_reverse;
+ strlcpy(resolve->address, exitconn->_base.address, sizeof(resolve->address));
- /* add us to the pending list */
+ /* add this connection to the pending list */
pending_connection = tor_malloc_zero(sizeof(pending_connection_t));
pending_connection->conn = exitconn;
resolve->pending_connections = pending_connection;
- exitconn->state = EXIT_CONN_STATE_RESOLVING;
+ exitconn->_base.state = EXIT_CONN_STATE_RESOLVING;
- insert_resolve(resolve);
- return assign_to_dnsworker(exitconn);
+ /* Add this resolve to the cache and priority queue. */
+ HT_INSERT(cache_map, &cache_root, resolve);
+ set_expiry(resolve, now + RESOLVE_MAX_TIMEOUT);
+
+ log_debug(LD_EXIT,"Launching %s.",
+ escaped_safe_str(exitconn->_base.address));
+ assert_cache_ok();
+ return launch_resolve(exitconn);
}
-/** Find or spawn a dns worker process to handle resolving
- * <b>exitconn</b>-\>address; tell that dns worker to begin resolving.
+/** Log an error and abort if conn is waiting for a DNS resolve.
*/
-static int
-assign_to_dnsworker(connection_t *exitconn)
+void
+assert_connection_edge_not_dns_pending(edge_connection_t *conn)
{
- connection_t *dnsconn;
- unsigned char len;
-
- tor_assert(exitconn->state == EXIT_CONN_STATE_RESOLVING);
- tor_assert(exitconn->s == -1);
+ pending_connection_t *pend;
+ cached_resolve_t **resolve;
- /* respawn here, to be sure there are enough */
- if (spawn_enough_dnsworkers() < 0) {
- goto err;
+ HT_FOREACH(resolve, cache_map, &cache_root) {
+ for (pend = (*resolve)->pending_connections;
+ pend;
+ pend = pend->next) {
+ tor_assert(pend->conn != conn);
+ }
}
+}
- dnsconn = connection_get_by_type_state(CONN_TYPE_DNSWORKER,
- DNSWORKER_STATE_IDLE);
+/** Log an error and abort if any connection waiting for a DNS resolve is
+ * corrupted. */
+void
+assert_all_pending_dns_resolves_ok(void)
+{
+ pending_connection_t *pend;
+ cached_resolve_t **resolve;
- if (!dnsconn) {
- log_warn(LD_EXIT,"no idle dns workers. Failing.");
- if (exitconn->purpose == EXIT_PURPOSE_RESOLVE)
- send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR_TRANSIENT);
- goto err;
+ HT_FOREACH(resolve, cache_map, &cache_root) {
+ for (pend = (*resolve)->pending_connections;
+ pend;
+ pend = pend->next) {
+ assert_connection_ok(TO_CONN(pend->conn), 0);
+ tor_assert(pend->conn->_base.s == -1);
+ tor_assert(!connection_in_array(TO_CONN(pend->conn)));
+ }
}
-
- log_debug(LD_EXIT,
- "Connection (fd %d) needs to resolve %s; assigning "
- "to DNSWorker (fd %d)", exitconn->s,
- escaped_safe_str(exitconn->address), dnsconn->s);
-
- tor_free(dnsconn->address);
- dnsconn->address = tor_strdup(exitconn->address);
- dnsconn->state = DNSWORKER_STATE_BUSY;
- /* touch the lastwritten timestamp, since that's how we check to
- * see how long it's been since we asked the question, and sometimes
- * we check before the first call to connection_handle_write(). */
- dnsconn->timestamp_lastwritten = time(NULL);
- num_dnsworkers_busy++;
-
- len = strlen(dnsconn->address);
- connection_write_to_buf((char*)&len, 1, dnsconn);
- connection_write_to_buf(dnsconn->address, len, dnsconn);
-
- return 0;
-err:
- dns_cancel_pending_resolve(exitconn->address); /* also sends end and frees */
- return -1;
}
/** Remove <b>conn</b> from the list of connections waiting for conn-\>address.
*/
void
-connection_dns_remove(connection_t *conn)
+connection_dns_remove(edge_connection_t *conn)
{
pending_connection_t *pend, *victim;
cached_resolve_t search;
cached_resolve_t *resolve;
- tor_assert(conn->type == CONN_TYPE_EXIT);
- tor_assert(conn->state == EXIT_CONN_STATE_RESOLVING);
+ tor_assert(conn->_base.type == CONN_TYPE_EXIT);
+ tor_assert(conn->_base.state == EXIT_CONN_STATE_RESOLVING);
- strlcpy(search.address, conn->address, sizeof(search.address));
+ strlcpy(search.address, conn->_base.address, sizeof(search.address));
resolve = HT_FIND(cache_map, &cache_root, &search);
if (!resolve) {
log_notice(LD_BUG, "Address %s is not pending. Dropping.",
- escaped_safe_str(conn->address));
+ escaped_safe_str(conn->_base.address));
return;
}
tor_assert(resolve->pending_connections);
- assert_connection_ok(conn,0);
+ assert_connection_ok(TO_CONN(conn),0);
pend = resolve->pending_connections;
@@ -424,7 +717,7 @@ connection_dns_remove(connection_t *conn)
tor_free(pend);
log_debug(LD_EXIT, "First connection (fd %d) no longer waiting "
"for resolve of %s",
- conn->s, escaped_safe_str(conn->address));
+ conn->_base.s, escaped_safe_str(conn->_base.address));
return;
} else {
for ( ; pend->next; pend = pend->next) {
@@ -434,7 +727,7 @@ connection_dns_remove(connection_t *conn)
tor_free(victim);
log_debug(LD_EXIT,
"Connection (fd %d) no longer waiting for resolve of %s",
- conn->s, escaped_safe_str(conn->address));
+ conn->_base.s, escaped_safe_str(conn->_base.address));
return; /* more are pending */
}
}
@@ -442,59 +735,23 @@ connection_dns_remove(connection_t *conn)
}
}
-/** Log an error and abort if conn is waiting for a DNS resolve.
- */
-void
-assert_connection_edge_not_dns_pending(connection_t *conn)
-{
- pending_connection_t *pend;
- cached_resolve_t **resolve;
-
- HT_FOREACH(resolve, cache_map, &cache_root) {
- for (pend = (*resolve)->pending_connections;
- pend;
- pend = pend->next) {
- tor_assert(pend->conn != conn);
- }
- }
-}
-
-/** Log an error and abort if any connection waiting for a DNS resolve is
- * corrupted. */
-void
-assert_all_pending_dns_resolves_ok(void)
-{
- pending_connection_t *pend;
- cached_resolve_t **resolve;
-
- HT_FOREACH(resolve, cache_map, &cache_root) {
- for (pend = (*resolve)->pending_connections;
- pend;
- pend = pend->next) {
- assert_connection_ok(pend->conn, 0);
- tor_assert(pend->conn->s == -1);
- tor_assert(!connection_in_array(pend->conn));
- }
- }
-}
-
/** Mark all connections waiting for <b>address</b> for close. Then cancel
* the resolve for <b>address</b> itself, and remove any cached results for
* <b>address</b> from the cache.
*/
void
-dns_cancel_pending_resolve(char *address)
+dns_cancel_pending_resolve(const char *address)
{
pending_connection_t *pend;
cached_resolve_t search;
- cached_resolve_t *resolve;
- connection_t *pendconn;
+ cached_resolve_t *resolve, *tmp;
+ edge_connection_t *pendconn;
circuit_t *circ;
strlcpy(search.address, address, sizeof(search.address));
resolve = HT_FIND(cache_map, &cache_root, &search);
- if (!resolve) {
+ if (!resolve || resolve->state != CACHE_STATE_PENDING) {
log_notice(LD_BUG,"Address %s is not pending. Dropping.",
escaped_safe_str(address));
return;
@@ -516,84 +773,104 @@ dns_cancel_pending_resolve(char *address)
escaped_safe_str(address));
while (resolve->pending_connections) {
pend = resolve->pending_connections;
- pend->conn->state = EXIT_CONN_STATE_RESOLVEFAILED;
+ pend->conn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
pendconn = pend->conn;
- tor_assert(pendconn->s == -1);
- if (!pendconn->marked_for_close) {
+ assert_connection_ok(TO_CONN(pendconn), 0);
+ tor_assert(pendconn->_base.s == -1);
+ if (!pendconn->_base.marked_for_close) {
connection_edge_end(pendconn, END_STREAM_REASON_RESOURCELIMIT,
pendconn->cpath_layer);
}
circ = circuit_get_by_edge_conn(pendconn);
if (circ)
circuit_detach_stream(circ, pendconn);
- connection_free(pendconn);
+ connection_free(TO_CONN(pendconn));
resolve->pending_connections = pend->next;
tor_free(pend);
}
- dns_purge_resolve(resolve);
+ tmp = HT_REMOVE(cache_map, &cache_root, resolve);
+ if (tmp != resolve) {
+ log_err(LD_BUG, "The cancelled resolve we purged didn't match any in"
+ " the cache. Tried to purge %s (%p); instead got %s (%p).",
+ resolve->address, (void*)resolve,
+ tmp ? tmp->address : "NULL", (void*)tmp);
+ }
+ tor_assert(tmp == resolve);
+
+ resolve->state = CACHE_STATE_DONE;
}
-/** Remove <b>resolve</b> from the cache.
- */
+/** Helper: adds an entry to the DNS cache mapping <b>address</b> to the ipv4
+ * address <b>addr</b> (if is_reverse is 0) or the hostname <b>hostname</b> if
+ * (is_reverse is 1). <b>ttl</b> is a cache ttl; <b>outcome</b> is one of
+ * DNS_RESOLVE_{FAILED_TRANSIENT|FAILED_PERMANENT|SUCCEEDED}.
+ **/
static void
-dns_purge_resolve(cached_resolve_t *resolve)
+add_answer_to_cache(const char *address, int is_reverse, uint32_t addr,
+ const char *hostname, char outcome, uint32_t ttl)
{
- cached_resolve_t *tmp;
-
- /* remove resolve from the linked list */
- if (resolve == oldest_cached_resolve) {
- oldest_cached_resolve = resolve->next;
- if (oldest_cached_resolve == NULL)
- newest_cached_resolve = NULL;
- } else {
- /* FFFF make it a doubly linked list if this becomes too slow */
- for (tmp=oldest_cached_resolve; tmp && tmp->next != resolve; tmp=tmp->next)
- ;
- tor_assert(tmp); /* it's got to be in the list, or we screwed up somewhere
- * else */
- tmp->next = resolve->next; /* unlink it */
+ cached_resolve_t *resolve;
+ if (outcome == DNS_RESOLVE_FAILED_TRANSIENT)
+ return;
- if (newest_cached_resolve == resolve)
- newest_cached_resolve = tmp;
- }
+ /* XXX This is dumb, but it seems to workaround a bug I can't find. We
+ * should nail this so we can cache reverse DNS answers. -NM */
+ if (is_reverse)
+ return;
- /* remove resolve from the map */
- HT_REMOVE(cache_map, &cache_root, resolve);
+ //log_notice(LD_EXIT, "Adding to cache: %s -> %s (%lx, %s), %d",
+ // address, is_reverse?"(reverse)":"", (unsigned long)addr,
+ // hostname?hostname:"NULL",(int)outcome);
- tor_free(resolve);
+ resolve = tor_malloc_zero(sizeof(cached_resolve_t));
+ resolve->magic = CACHED_RESOLVE_MAGIC;
+ resolve->state = (outcome == DNS_RESOLVE_SUCCEEDED) ?
+ CACHE_STATE_CACHED_VALID : CACHE_STATE_CACHED_FAILED;
+ strlcpy(resolve->address, address, sizeof(resolve->address));
+ resolve->is_reverse = is_reverse;
+ if (is_reverse) {
+ tor_assert(hostname);
+ resolve->result.hostname = tor_strdup(hostname);
+ } else {
+ tor_assert(!hostname);
+ resolve->result.addr = addr;
+ }
+ resolve->ttl = ttl;
+ assert_resolve_ok(resolve);
+ HT_INSERT(cache_map, &cache_root, resolve);
+ set_expiry(resolve, time(NULL) + dns_get_expiry_ttl(ttl));
}
-/** Called on the OR side when a DNS worker tells us the outcome of a DNS
- * resolve: tell all pending connections about the result of the lookup, and
- * cache the value. (<b>address</b> is a NUL-terminated string containing the
- * address to look up; <b>addr</b> is an IPv4 address in host order;
- * <b>outcome</b> is one of
+/** Called on the OR side when a DNS worker or the eventdns library tells us
+ * the outcome of a DNS resolve: tell all pending connections about the result
+ * of the lookup, and cache the value. (<b>address</b> is a NUL-terminated
+ * string containing the address to look up; <b>addr</b> is an IPv4 address in
+ * host order; <b>outcome</b> is one of
* DNS_RESOLVE_{FAILED_TRANSIENT|FAILED_PERMANENT|SUCCEEDED}.
*/
static void
-dns_found_answer(char *address, uint32_t addr, char outcome)
+dns_found_answer(const char *address, int is_reverse, uint32_t addr,
+ const char *hostname, char outcome, uint32_t ttl)
{
pending_connection_t *pend;
cached_resolve_t search;
- cached_resolve_t *resolve;
- connection_t *pendconn;
+ cached_resolve_t *resolve, *removed;
+ edge_connection_t *pendconn;
circuit_t *circ;
+ assert_cache_ok();
+
strlcpy(search.address, address, sizeof(search.address));
resolve = HT_FIND(cache_map, &cache_root, &search);
if (!resolve) {
log_info(LD_EXIT,"Resolved unasked address %s; caching anyway.",
escaped_safe_str(address));
- resolve = tor_malloc_zero(sizeof(cached_resolve_t));
- resolve->state = (outcome == DNS_RESOLVE_SUCCEEDED) ?
- CACHE_STATE_VALID : CACHE_STATE_FAILED;
- resolve->addr = addr;
- resolve->expire = time(NULL) + MAX_DNS_ENTRY_AGE;
- insert_resolve(resolve);
+ add_answer_to_cache(address, is_reverse, addr, hostname, outcome, ttl);
return;
}
+ assert_resolve_ok(resolve);
if (resolve->state != CACHE_STATE_PENDING) {
/* XXXX Maybe update addr? or check addr for consistency? Or let
@@ -609,23 +886,18 @@ dns_found_answer(char *address, uint32_t addr, char outcome)
* resolve X.Y.Z. */
/* tor_assert(resolve->state == CACHE_STATE_PENDING); */
- resolve->addr = addr;
- if (outcome == DNS_RESOLVE_SUCCEEDED)
- resolve->state = CACHE_STATE_VALID;
- else
- resolve->state = CACHE_STATE_FAILED;
-
while (resolve->pending_connections) {
pend = resolve->pending_connections;
- assert_connection_ok(pend->conn,time(NULL));
- pend->conn->addr = resolve->addr;
pendconn = pend->conn; /* don't pass complex things to the
connection_mark_for_close macro */
+ assert_connection_ok(TO_CONN(pendconn),time(NULL));
+ pendconn->_base.addr = addr;
+ pendconn->address_ttl = ttl;
- if (resolve->state == CACHE_STATE_FAILED) {
+ if (outcome != DNS_RESOLVE_SUCCEEDED) {
/* prevent double-remove. */
- pendconn->state = EXIT_CONN_STATE_RESOLVEFAILED;
- if (pendconn->purpose == EXIT_PURPOSE_CONNECT) {
+ pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
+ if (pendconn->_base.purpose == EXIT_PURPOSE_CONNECT) {
connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED,
pendconn->cpath_layer);
/* This detach must happen after we send the end cell. */
@@ -635,40 +907,109 @@ dns_found_answer(char *address, uint32_t addr, char outcome)
/* This detach must happen after we send the resolved cell. */
circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
}
- connection_free(pendconn);
+ connection_free(TO_CONN(pendconn));
} else {
- if (pendconn->purpose == EXIT_PURPOSE_CONNECT) {
+ if (pendconn->_base.purpose == EXIT_PURPOSE_CONNECT) {
+ tor_assert(!is_reverse);
/* prevent double-remove. */
- pend->conn->state = EXIT_CONN_STATE_CONNECTING;
+ pend->conn->_base.state = EXIT_CONN_STATE_CONNECTING;
circ = circuit_get_by_edge_conn(pend->conn);
tor_assert(circ);
+ tor_assert(!CIRCUIT_IS_ORIGIN(circ));
/* unlink pend->conn from resolving_streams, */
circuit_detach_stream(circ, pend->conn);
/* and link it to n_streams */
- pend->conn->next_stream = circ->n_streams;
+ pend->conn->next_stream = TO_OR_CIRCUIT(circ)->n_streams;
pend->conn->on_circuit = circ;
- circ->n_streams = pend->conn;
+ TO_OR_CIRCUIT(circ)->n_streams = pend->conn;
connection_exit_connect(pend->conn);
} else {
/* prevent double-remove. This isn't really an accurate state,
* but it does the right thing. */
- pendconn->state = EXIT_CONN_STATE_RESOLVEFAILED;
- send_resolved_cell(pendconn, RESOLVED_TYPE_IPV4);
+ pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
+ if (is_reverse)
+ send_resolved_hostname_cell(pendconn, hostname);
+ else
+ send_resolved_cell(pendconn, RESOLVED_TYPE_IPV4);
circ = circuit_get_by_edge_conn(pendconn);
tor_assert(circ);
circuit_detach_stream(circ, pendconn);
- connection_free(pendconn);
+ connection_free(TO_CONN(pendconn));
}
}
resolve->pending_connections = pend->next;
tor_free(pend);
}
- if (outcome == DNS_RESOLVE_FAILED_TRANSIENT) { /* remove from cache */
- dns_purge_resolve(resolve);
+ resolve->state = CACHE_STATE_DONE;
+ removed = HT_REMOVE(cache_map, &cache_root, &search);
+ if (removed != resolve) {
+ log_err(LD_BUG, "The pending resolve we found wasn't removable from"
+ " the cache. Tried to purge %s (%p); instead got %s (%p).",
+ resolve->address, (void*)resolve,
+ removed ? removed->address : "NULL", (void*)removed);
}
+ assert_resolve_ok(resolve);
+ assert_cache_ok();
+
+ add_answer_to_cache(address, is_reverse, addr, hostname, outcome, ttl);
+ assert_cache_ok();
+}
+
+#ifndef USE_EVENTDNS
+/** Find or spawn a dns worker process to handle resolving
+ * <b>exitconn</b>-\>address; tell that dns worker to begin resolving.
+ */
+static int
+launch_resolve(edge_connection_t *exitconn)
+{
+ connection_t *dnsconn;
+ unsigned char len;
+
+ tor_assert(exitconn->_base.state == EXIT_CONN_STATE_RESOLVING);
+ assert_connection_ok(TO_CONN(exitconn), 0);
+ tor_assert(exitconn->_base.s == -1);
+
+ /* respawn here, to be sure there are enough */
+ if (spawn_enough_dnsworkers() < 0) {
+ goto err;
+ }
+
+ dnsconn = connection_get_by_type_state(CONN_TYPE_DNSWORKER,
+ DNSWORKER_STATE_IDLE);
+
+ if (!dnsconn) {
+ log_warn(LD_EXIT,"no idle dns workers. Failing.");
+ if (exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE)
+ send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR_TRANSIENT);
+ goto err;
+ }
+
+ log_debug(LD_EXIT,
+ "Connection (fd %d) needs to resolve %s; assigning "
+ "to DNSWorker (fd %d)", exitconn->_base.s,
+ escaped_safe_str(exitconn->_base.address), dnsconn->s);
+
+ tor_free(dnsconn->address);
+ dnsconn->address = tor_strdup(exitconn->_base.address);
+ dnsconn->state = DNSWORKER_STATE_BUSY;
+ /* touch the lastwritten timestamp, since that's how we check to
+ * see how long it's been since we asked the question, and sometimes
+ * we check before the first call to connection_handle_write(). */
+ dnsconn->timestamp_lastwritten = time(NULL);
+ num_dnsworkers_busy++;
+
+ len = strlen(dnsconn->address);
+ connection_write_to_buf((char*)&len, 1, dnsconn);
+ connection_write_to_buf(dnsconn->address, len, dnsconn);
+
+ return 0;
+err:
+ /* also sends end and frees */
+ dns_cancel_pending_resolve(exitconn->_base.address);
+ return -1;
}
/******************************************************************/
@@ -687,6 +1028,8 @@ connection_dns_finished_flushing(connection_t *conn)
return 0;
}
+/** Called when a connection to a dnsworker hits an EOF; this only happens
+ * when a dnsworker dies unexpectedly. */
int
connection_dns_reached_eof(connection_t *conn)
{
@@ -711,6 +1054,7 @@ connection_dns_process_inbuf(connection_t *conn)
{
char success;
uint32_t addr;
+ int ttl;
tor_assert(conn);
tor_assert(conn->type == CONN_TYPE_DNSWORKER);
@@ -746,7 +1090,9 @@ connection_dns_process_inbuf(connection_t *conn)
tor_assert(success >= DNS_RESOLVE_FAILED_TRANSIENT);
tor_assert(success <= DNS_RESOLVE_SUCCEEDED);
- dns_found_answer(conn->address, ntohl(addr), success);
+
+ ttl = (success == DNS_RESOLVE_FAILED_TRANSIENT) ? 0 : MAX_DNS_ENTRY_AGE;
+ dns_found_answer(conn->address, 0, ntohl(addr), NULL, success, ttl);
tor_free(conn->address);
conn->address = tor_strdup("<idle>");
@@ -763,7 +1109,7 @@ connection_dns_process_inbuf(connection_t *conn)
/** Close and re-open all idle dnsworkers; schedule busy ones to be closed
* and re-opened once they're no longer busy.
**/
-void
+static void
dnsworkers_rotate(void)
{
connection_t *dnsconn;
@@ -794,10 +1140,10 @@ dnsworkers_rotate(void)
* The dnsworker runs indefinitely, until its connection is closed or an error
* occurs.
*/
-static int
+static void
dnsworker_main(void *data)
{
- char address[MAX_ADDRESSLEN];
+ char address[MAX_ADDRESSLEN+1]; /* Plus a byte for a final '.' */
unsigned char address_len;
char *log_address;
char answer[5];
@@ -805,6 +1151,7 @@ dnsworker_main(void *data)
int *fdarray = data;
int fd;
int result;
+ int search = get_options()->ServerDNSSearchDomains;
/* log_fn(LOG_NOTICE,"After spawn: fdarray @%d has %d:%d", (int)fdarray,
* fdarray[0],fdarray[1]); */
@@ -842,7 +1189,13 @@ dnsworker_main(void *data)
crypto_thread_cleanup();
spawn_exit();
}
- address[address_len] = 0; /* null terminate it */
+ /* Add a period to prevent local domain search, and NUL-terminate. */
+ if (address[address_len-1] != '.' && !search) {
+ address[address_len] = '.';
+ address[address_len+1] = '\0';
+ } else {
+ address[address_len] = '\0';
+ }
log_address = esc_for_log(safe_str(address));
result = tor_lookup_hostname(address, &ip);
@@ -852,17 +1205,17 @@ dnsworker_main(void *data)
switch (result) {
case 1:
/* XXX result can never be 1, because we set it to -1 above on error */
- log_info(LD_NET,"Could not resolve dest addr %s (transient).",
+ log_info(LD_NET,"Could not resolve dest addr %s (transient)",
log_address);
answer[0] = DNS_RESOLVE_FAILED_TRANSIENT;
break;
case -1:
- log_info(LD_NET,"Could not resolve dest addr %s (permanent).",
+ log_info(LD_NET,"Could not resolve dest addr %s (permanent)",
log_address);
answer[0] = DNS_RESOLVE_FAILED_PERMANENT;
break;
case 0:
- log_info(LD_NET,"Resolved address %s.", log_address);
+ log_info(LD_NET,"Resolved address %s", log_address);
answer[0] = DNS_RESOLVE_SUCCEEDED;
break;
}
@@ -875,7 +1228,6 @@ dnsworker_main(void *data)
spawn_exit();
}
}
- return 0; /* windows wants this function to return an int */
}
/** Launch a new DNS worker; return 0 on success, -1 on failure.
@@ -896,12 +1248,15 @@ spawn_dnsworker(void)
return -1;
}
+ tor_assert(fdarray[0] >= 0);
+ tor_assert(fdarray[1] >= 0);
+
/* log_fn(LOG_NOTICE,"Before spawn: fdarray @%d has %d:%d",
(int)fdarray, fdarray[0],fdarray[1]); */
fd = fdarray[0]; /* We copy this out here, since dnsworker_main may free
* fdarray */
- spawn_func(dnsworker_main, (void*)fdarray);
+ spawn_func((void*) dnsworker_main, (void*)fdarray);
log_debug(LD_EXIT,"just spawned a dns worker.");
#ifndef TOR_IS_MULTITHREADED
tor_close_socket(fdarray[1]); /* don't need the worker's side of the pipe */
@@ -992,3 +1347,424 @@ spawn_enough_dnsworkers(void)
return 0;
}
+void
+dns_launch_wildcard_checks(void)
+{
+}
+#else /* !USE_EVENTDNS */
+
+/** Eventdns helper: return true iff the eventdns result <b>err</b> is
+ * a transient failure. */
+static int
+eventdns_err_is_transient(int err)
+{
+ switch (err)
+ {
+ case DNS_ERR_SERVERFAILED:
+ case DNS_ERR_TRUNCATED:
+ case DNS_ERR_TIMEOUT:
+ return 1;
+ default:
+ return 0;
+ }
+}
+/* Dummy function; never called with eventdns enabled. */
+int
+connection_dns_finished_flushing(connection_t *conn)
+{
+ (void)conn;
+ tor_assert(0);
+ return 0;
+}
+/* Dummy function; never called with eventdns enabled. */
+int
+connection_dns_process_inbuf(connection_t *conn)
+{
+ (void)conn;
+ tor_assert(0);
+ return 0;
+}
+/* Dummy function; never called with eventdns enabled. */
+int
+connection_dns_reached_eof(connection_t *conn)
+{
+ (void)conn;
+ tor_assert(0);
+ return 0;
+}
+
+/** Configure eventdns nameservers if force is true, or if the configuration
+ * has changed since the last time we called this function. On Unix, this
+ * reads from options->ServerDNSResolvConfFile or /etc/resolv.conf; on
+ * Windows, this reads from options->ServerDNSResolvConfFile or the registry.
+ * Return 0 on success or -1 on failure. */
+static int
+configure_nameservers(int force)
+{
+ or_options_t *options;
+ const char *conf_fname;
+ struct stat st;
+ options = get_options();
+ conf_fname = options->ServerDNSResolvConfFile;
+#ifndef MS_WINDOWS
+ if (!conf_fname)
+ conf_fname = "/etc/resolv.conf";
+#endif
+
+ eventdns_set_log_fn(eventdns_log_cb);
+ if (conf_fname) {
+ if (stat(conf_fname, &st)) {
+ log_warn(LD_EXIT, "Unable to stat resolver configuration in '%s'",
+ conf_fname);
+ return -1;
+ }
+ if (!force && resolv_conf_fname && !strcmp(conf_fname,resolv_conf_fname)
+ && st.st_mtime == resolv_conf_mtime) {
+ log_info(LD_EXIT, "No change to '%s'", conf_fname);
+ return 0;
+ }
+ if (nameservers_configured) {
+ eventdns_search_clear();
+ eventdns_clear_nameservers_and_suspend();
+ }
+ log_info(LD_EXIT, "Parsing resolver configuration in '%s'", conf_fname);
+ if (eventdns_resolv_conf_parse(DNS_OPTIONS_ALL, conf_fname))
+ return -1;
+ if (eventdns_count_nameservers() == 0) {
+ log_warn(LD_EXIT, "Unable to find any nameservers in '%s'.", conf_fname);
+ return -1;
+ }
+ tor_free(resolv_conf_fname);
+ resolv_conf_fname = tor_strdup(conf_fname);
+ resolv_conf_mtime = st.st_mtime;
+ if (nameservers_configured)
+ eventdns_resume();
+ }
+#ifdef MS_WINDOWS
+ else {
+ if (nameservers_configured) {
+ eventdns_search_clear();
+ eventdns_clear_nameservers_and_suspend();
+ }
+ if (eventdns_config_windows_nameservers()) {
+ log_warn(LD_EXIT,"Could not config nameservers.");
+ return -1;
+ }
+ if (eventdns_count_nameservers() == 0) {
+ log_warn(LD_EXIT, "Unable to find any platform nameservers in "
+ "your Windows configuration. Perhaps you should list a "
+ "ServerDNSResolvConfFile file in your torrc?");
+ return -1;
+ }
+ if (nameservers_configured)
+ eventdns_resume();
+ tor_free(resolv_conf_fname);
+ resolv_conf_mtime = 0;
+ }
+#endif
+
+ nameservers_configured = 1;
+ return 0;
+}
+
+/** For eventdns: Called when we get an answer for a request we launched.
+ * See eventdns.h for arguments; 'arg' holds the address we tried to resolve.
+ */
+static void
+eventdns_callback(int result, char type, int count, int ttl, void *addresses,
+ void *arg)
+{
+ char *string_address = arg;
+ int is_reverse = 0;
+ int status = DNS_RESOLVE_FAILED_PERMANENT;
+ uint32_t addr = 0;
+ const char *hostname = NULL;
+
+ if (result == DNS_ERR_NONE) {
+ if (type == DNS_IPv4_A && count) {
+ char answer_buf[INET_NTOA_BUF_LEN+1];
+ struct in_addr in;
+ char *escaped_address;
+ uint32_t *addrs = addresses;
+ in.s_addr = addrs[0];
+ addr = ntohl(addrs[0]);
+ status = DNS_RESOLVE_SUCCEEDED;
+ tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf));
+ escaped_address = esc_for_log(string_address);
+
+ if (answer_is_wildcarded(answer_buf)) {
+ log_debug(LD_EXIT, "eventdns said that %s resolves to ISP-hijacked "
+ "address %s; treating as a failure.",
+ safe_str(escaped_address),
+ escaped_safe_str(answer_buf));
+ addr = 0;
+ status = DNS_RESOLVE_FAILED_PERMANENT;
+ } else {
+ log_debug(LD_EXIT, "eventdns said that %s resolves to %s",
+ safe_str(escaped_address),
+ escaped_safe_str(answer_buf));
+ }
+ tor_free(escaped_address);
+ } else if (type == DNS_PTR && count) {
+ char *escaped_address;
+ is_reverse = 1;
+ hostname = ((char**)addresses)[0];
+ status = DNS_RESOLVE_SUCCEEDED;
+ escaped_address = esc_for_log(string_address);
+ log_debug(LD_EXIT, "eventdns said that %s resolves to %s",
+ safe_str(escaped_address),
+ escaped_safe_str(hostname));
+ tor_free(escaped_address);
+ } else if (count) {
+ log_warn(LD_EXIT, "eventdns returned only non-IPv4 answers for %s.",
+ escaped_safe_str(string_address));
+ } else {
+ log_warn(LD_BUG, "eventdns returned no addresses or error for %s!",
+ escaped_safe_str(string_address));
+ }
+ } else {
+ if (eventdns_err_is_transient(result))
+ status = DNS_RESOLVE_FAILED_TRANSIENT;
+ }
+ dns_found_answer(string_address, is_reverse, addr, hostname, status, ttl);
+ tor_free(string_address);
+}
+
+/** For eventdns: start resolving as necessary to find the target for
+ * <b>exitconn</b> */
+static int
+launch_resolve(edge_connection_t *exitconn)
+{
+ char *addr = tor_strdup(exitconn->_base.address);
+ struct in_addr in;
+ int r;
+ int options = get_options()->ServerDNSSearchDomains ? 0
+ : DNS_QUERY_NO_SEARCH;
+ /* What? Nameservers not configured? Sounds like a bug. */
+ if (!nameservers_configured) {
+ log_warn(LD_EXIT, "Harmless bug: nameservers not configured, but resolve "
+ "launched. Configuring.");
+ if (configure_nameservers(1) < 0)
+ return -1;
+ }
+
+ r = parse_inaddr_arpa_address(exitconn->_base.address, &in);
+ if (r == 0) {
+ log_info(LD_EXIT, "Launching eventdns request for %s",
+ escaped_safe_str(exitconn->_base.address));
+ r = eventdns_resolve_ipv4(exitconn->_base.address, options,
+ eventdns_callback, addr);
+ } else if (r == 1) {
+ log_info(LD_EXIT, "Launching eventdns reverse request for %s",
+ escaped_safe_str(exitconn->_base.address));
+ r = eventdns_resolve_reverse(&in, DNS_QUERY_NO_SEARCH,
+ eventdns_callback, addr);
+ } else if (r == -1) {
+ log_warn(LD_BUG, "Somehow a malformed in-addr.arpa address reached here.");
+ }
+
+ if (r) {
+ log_warn(LD_EXIT, "eventdns rejected address %s: error %d.",
+ escaped_safe_str(addr), r);
+ if (exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE) {
+ if (eventdns_err_is_transient(r))
+ send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR_TRANSIENT);
+ else {
+ exitconn->address_ttl = DEFAULT_DNS_TTL;
+ send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR);
+ }
+ }
+ dns_cancel_pending_resolve(addr); /* also sends end and frees */
+ tor_free(addr);
+ }
+ return r ? -1 : 0;
+}
+
+/** How many requests for bogus addresses have we launched so far? */
+static int n_wildcard_requests = 0;
+
+/** Map from dotted-quad IP address in response to an int holding how many
+ * times we've seen it for a randomly generated (hopefully bogus) address. It
+ * would be easier to use definitely-invalid addresses (as specified by
+ * RFC2606), but see comment in dns_launch_wildcard_checks(). */
+static strmap_t *dns_wildcard_response_count = NULL;
+
+/** If present, a list of dotted-quad IP addresses that we are pretty sure our
+ * nameserver wants to return in response to requests for nonexistent domains.
+ */
+static smartlist_t *dns_wildcard_list = NULL;
+
+/** Called when we see <b>id</b> (a dotted quad) in response to a request for
+ * a hopefully bogus address. */
+static void
+wildcard_increment_answer(const char *id)
+{
+ int *ip;
+ static int notice_given = 0;
+ if (!dns_wildcard_response_count)
+ dns_wildcard_response_count = strmap_new();
+
+ ip = strmap_get(dns_wildcard_response_count, id); // may be null (0)
+ if (!ip) {
+ ip = tor_malloc_zero(sizeof(int));
+ strmap_set(dns_wildcard_response_count, id, ip);
+ }
+ ++*ip;
+
+ if (*ip > 5 && n_wildcard_requests > 10) {
+ if (!dns_wildcard_list) dns_wildcard_list = smartlist_create();
+ if (!smartlist_string_isin(dns_wildcard_list, id)) {
+ log(notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT,
+ "Your DNS provider has given \"%s\" as an answer for %d different "
+ "invalid addresses. Apparently they are hijacking DNS failures. "
+ "I'll trying to correct for this by treating future occurrences of "
+ "\"%s\" as 'not found'.", id, *ip, id);
+ smartlist_add(dns_wildcard_list, tor_strdup(id));
+ }
+ }
+}
+
+/** Callback function when we get an answer (possibly failing) for a request
+ * for a (hopefully) nonexistent domain. */
+static void
+eventdns_wildcard_check_callback(int result, char type, int count, int ttl,
+ void *addresses, void *arg)
+{
+ static int notice_given = 0;
+ (void)ttl;
+ ++n_wildcard_requests;
+ if (result == DNS_ERR_NONE && type == DNS_IPv4_A && count) {
+ uint32_t *addrs = addresses;
+ int i;
+ char *string_address = arg;
+ for (i = 0; i < count; ++i) {
+ char answer_buf[INET_NTOA_BUF_LEN+1];
+ struct in_addr in;
+ in.s_addr = addrs[i];
+ tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf));
+ wildcard_increment_answer(answer_buf);
+ }
+ log(notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT,
+ "Your DNS provider gave an answer for \"%s\", which "
+ "is not supposed to exist. Apparently they are hijacking "
+ "DNS failures. Trying to correct for this. We've noticed %d possibly "
+ "bad addresses so far.",
+ string_address, strmap_size(dns_wildcard_response_count));
+ notice_given = 1;
+ }
+ tor_free(arg);
+}
+
+/** Launch a single request for a nonexistent hostname consisting of between
+ * <b>min_len</b> and <b>max_len</b> random (plausible) characters followed by
+ * <b>suffix</b> */
+static void
+launch_wildcard_check(int min_len, int max_len, const char *suffix)
+{
+ char random_bytes[20], name[64], *addr;
+ size_t len;
+ int r;
+
+ len = min_len + crypto_rand_int(max_len-min_len+1);
+ if (crypto_rand(random_bytes, sizeof(random_bytes)) < 0)
+ return;
+ base32_encode(name, sizeof(name), random_bytes, sizeof(random_bytes));
+ name[len] = '\0';
+ strlcat(name, suffix, sizeof(name));
+
+ addr = tor_strdup(name);
+ r = eventdns_resolve_ipv4(name, DNS_QUERY_NO_SEARCH,
+ eventdns_wildcard_check_callback, addr);
+ if (r)
+ tor_free(addr);
+}
+
+#define N_WILDCARD_CHECKS 2
+
+/** Launch DNS requests for a few nonexistent hostnames, and see if we can
+ * catch our nameserver trying to hijack them and map them to a stupid "I
+ * couldn't find ggoogle.com but maybe you'd like to buy these lovely
+ * encyclopedias" page. */
+void
+dns_launch_wildcard_checks(void)
+{
+ int i;
+ if (!get_options()->ServerDNSDetectHijacking)
+ return;
+ log_info(LD_EXIT, "Launching checks to see whether our nameservers like "
+ "to hijack DNS failures.");
+ for (i = 0; i < N_WILDCARD_CHECKS; ++i) {
+ /* RFC2606 reserves these. Sadly, some DNS hijackers, in a silly attempt
+ * to 'comply' with rfc2606, refrain from giving A records for these.
+ * This is the standards-complaince equivalent of making sure that your
+ * crackhouse's elevator inspection certificate is up to date.
+ */
+ launch_wildcard_check(2, 16, "%s.invalid");
+ launch_wildcard_check(2, 16, "%s.test");
+
+ /* Thy somese will break specs if there are ever any number of
+ * 8+-character top-level domains. */
+ launch_wildcard_check(8, 16,"");
+
+ /* Try some random .com/org/net domains. This will work fine so long as
+ * not too many resolve to the same place. */
+ launch_wildcard_check(8, 16, "%s.com");
+ launch_wildcard_check(8, 16, "%s.org");
+ launch_wildcard_check(8, 16, "%s.net");
+ }
+}
+
+/** Return true iff we have noticed that the dotted-quad <b>ip</b> has been
+ * returned in response to requests for nonexistent hostnames. */
+static int
+answer_is_wildcarded(const char *ip)
+{
+ return dns_wildcard_list && smartlist_string_isin(dns_wildcard_list, ip);
+}
+#endif /* USE_EVENTDNS */
+
+/** Exit with an assertion if <b>resolve</b> is corrupt. */
+static void
+assert_resolve_ok(cached_resolve_t *resolve)
+{
+ tor_assert(resolve);
+ tor_assert(resolve->magic == CACHED_RESOLVE_MAGIC);
+ tor_assert(strlen(resolve->address) < MAX_ADDRESSLEN);
+ tor_assert(tor_strisnonupper(resolve->address));
+ if (resolve->state != CACHE_STATE_PENDING) {
+ tor_assert(!resolve->pending_connections);
+ }
+ if (resolve->state == CACHE_STATE_PENDING ||
+ resolve->state == CACHE_STATE_DONE) {
+ tor_assert(!resolve->ttl);
+ if (resolve->is_reverse)
+ tor_assert(!resolve->result.hostname);
+ else
+ tor_assert(!resolve->result.addr);
+ }
+}
+
+#ifdef DEBUG_DNS_CACHE
+/** Exit with an assertion if the DNS cache is corrupt. */
+static void
+_assert_cache_ok(void)
+{
+ cached_resolve_t **resolve;
+ int bad_rep = _cache_map_HT_REP_IS_BAD(&cache_root);
+ if (bad_rep) {
+ log_err(LD_BUG, "Bad rep type %d on dns cache hash table", bad_rep);
+ tor_assert(!bad_rep);
+ }
+
+ HT_FOREACH(resolve, cache_map, &cache_root) {
+ assert_resolve_ok(*resolve);
+ tor_assert((*resolve)->state != CACHE_STATE_DONE);
+ }
+ if (!cached_resolve_pqueue)
+ return;
+
+ smartlist_pqueue_assert_ok(cached_resolve_pqueue,
+ _compare_cached_resolves_by_expiry);
+}
+#endif
+
diff --git a/src/or/eventdns.c b/src/or/eventdns.c
new file mode 100644
index 0000000000..b9c60f0dbe
--- /dev/null
+++ b/src/or/eventdns.c
@@ -0,0 +1,2292 @@
+/* $Id$ */
+
+/* The original version of this module was written by Adam Langley; for
+ * a history of modifications, check out the subversion logs.
+ *
+ * When editing this module, try to keep it re-mergeable by Adam. Don't
+ * reformat the whitespace, add Tor dependencies, or so on.
+ *
+ * TODO:
+ * - Support AAAA records
+ * - Have a way to query for AAAA and A records simultaneously.
+ * - Improve request API.
+ * - (Can we suppress cnames? Should we?)
+ * - Replace all externally visible magic numbers with #defined constants.
+ * - Write documentation for APIs of all external functions.
+ */
+
+/* Async DNS Library
+ * Adam Langley <agl@imperialviolet.org>
+ * Public Domain code
+ *
+ * This software is Public Domain. To view a copy of the public domain dedication,
+ * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
+ * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+ *
+ * I ask and expect, but do not require, that all derivative works contain an
+ * attribution similar to:
+ * Parts developed by Adam Langley <agl@imperialviolet.org>
+ *
+ * You may wish to replace the word "Parts" with something else depending on
+ * the amount of original code.
+ *
+ * (Derivative works does not include programs which link against, run or include
+ * the source verbatim in their source distributions)
+ *
+ * Version: 0.1b
+ *
+ *
+ * Welcome, gentle reader
+ *
+ * Async DNS lookups are really a whole lot harder than they should be,
+ * mostly stemming from the fact that the libc resolver has never been
+ * very good at them. Before you use this library you should see if libc
+ * can do the job for you with the modern async call getaddrinfo_a
+ * (see http://www.imperialviolet.org/page25.html#e498). Otherwise,
+ * please continue.
+ *
+ * This code is based on libevent and you must call event_init before
+ * any of the APIs in this file. You must also seed the OpenSSL random
+ * source if you are using OpenSSL for ids (see below).
+ *
+ * This library is designed to be included and shipped with your source
+ * code. You statically link with it. You should also test for the
+ * existence of strtok_r and define HAVE_STRTOK_R if you have it.
+ *
+ * The DNS protocol requires a good source of id numbers and these
+ * numbers should be unpredictable for spoofing reasons. There are
+ * three methods for generating them here and you must define exactly
+ * one of them. In increasing order of preference:
+ *
+ * DNS_USE_GETTIMEOFDAY_FOR_ID:
+ * Using the bottom 16 bits of the usec result from gettimeofday. This
+ * is a pretty poor solution but should work anywhere.
+ * DNS_USE_CPU_CLOCK_FOR_ID:
+ * Using the bottom 16 bits of the nsec result from the CPU's time
+ * counter. This is better, but may not work everywhere. Requires
+ * POSIX realtime support and you'll need to link against -lrt on
+ * glibc systems at least.
+ * DNS_USE_OPENSSL_FOR_ID:
+ * Uses the OpenSSL RAND_bytes call to generate the data. You must
+ * have seeded the pool before making any calls to this library.
+ *
+ * The library keeps track of the state of nameservers and will avoid
+ * them when they go down. Otherwise it will round robin between them.
+ *
+ * Quick start guide:
+ * #include "eventdns.h"
+ * void callback(int result, char type, int count, int ttl,
+ * void *addresses, void *arg);
+ * eventdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
+ * eventdns_resolve("www.hostname.com", 0, callback, NULL);
+ *
+ * When the lookup is complete the callback function is called. The
+ * first argument will be one of the DNS_ERR_* defines in eventdns.h.
+ * Hopefully it will be DNS_ERR_NONE, in which case type will be
+ * DNS_IPv4_A, count will be the number of IP addresses, ttl is the time
+ * which the data can be cached for (in seconds), addresses will point
+ * to an array of uint32_t's and arg will be whatever you passed to
+ * eventdns_resolve.
+ *
+ * Searching:
+ *
+ * In order for this library to be a good replacement for glibc's resolver it
+ * supports searching. This involves setting a list of default domains, in
+ * which names will be queried for. The number of dots in the query name
+ * determines the order in which this list is used.
+ *
+ * Searching appears to be a single lookup from the point of view of the API,
+ * although many DNS queries may be generated from a single call to
+ * eventdns_resolve. Searching can also drastically slow down the resolution
+ * of names.
+ *
+ * To disable searching:
+ * 1. Never set it up. If you never call eventdns_resolv_conf_parse or
+ * eventdns_search_add then no searching will occur.
+ *
+ * 2. If you do call eventdns_resolv_conf_parse then don't pass
+ * DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it).
+ *
+ * 3. When calling eventdns_resolve, pass the DNS_QUERY_NO_SEARCH flag.
+ *
+ * The order of searches depends on the number of dots in the name. If the
+ * number is greater than the ndots setting then the names is first tried
+ * globally. Otherwise each search domain is appended in turn.
+ *
+ * The ndots setting can either be set from a resolv.conf, or by calling
+ * eventdns_search_ndots_set.
+ *
+ * For example, with ndots set to 1 (the default) and a search domain list of
+ * ["myhome.net"]:
+ * Query: www
+ * Order: www.myhome.net, www.
+ *
+ * Query: www.abc
+ * Order: www.abc., www.abc.myhome.net
+ *
+ * API reference:
+ *
+ * int eventdns_nameserver_add(unsigned long int address)
+ * Add a nameserver. The address should be an IP address in
+ * network byte order. The type of address is chosen so that
+ * it matches in_addr.s_addr.
+ * Returns non-zero on error.
+ *
+ * int eventdns_nameserver_ip_add(const char *ip_as_string)
+ * This wraps the above function by parsing a string as an IP
+ * address and adds it as a nameserver.
+ * Returns non-zero on error
+ *
+ * int eventdns_resolve(const char *name, int flags,
+ * eventdns_callback_type callback,
+ * void *ptr)
+ * Resolve a name. The name parameter should be a DNS name.
+ * The flags parameter should be 0, or DNS_QUERY_NO_SEARCH
+ * which disables searching for this query. (see defn of
+ * searching above).
+ *
+ * The callback argument is a function which is called when
+ * this query completes and ptr is an argument which is passed
+ * to that callback function.
+ *
+ * Returns non-zero on error
+ *
+ * void eventdns_search_clear()
+ * Clears the list of search domains
+ *
+ * void eventdns_search_add(const char *domain)
+ * Add a domain to the list of search domains
+ *
+ * void eventdns_search_ndots_set(int ndots)
+ * Set the number of dots which, when found in a name, causes
+ * the first query to be without any search domain.
+ *
+ * int eventdns_count_nameservers(void)
+ * Return the number of configured nameservers (not necessarily the
+ * number of running nameservers). This is useful for double-checking
+ * whether our calls to the various nameserver configuration functions
+ * have been successful.
+ *
+ * int eventdns_clear_nameservers_and_suspend(void)
+ * Remove all currently configured nameservers, and suspend all pending
+ * resolves. Resolves will not necessarily be re-attempted until
+ * eventdns_resume() is called.
+ *
+ * int eventdns_resume(void)
+ * Re-attempt resolves left in limbo after an earlier call to
+ * eventdns_clear_nameservers_and_suspend().
+ *
+ * int eventdns_config_windows_nameservers(void)
+ * Attempt to configure a set of nameservers based on platform settings on
+ * a win32 host. Preferentially tries to use GetNetworkParams; if that fails,
+ * looks in the registry. Returns 0 on success, nonzero on failure.
+ *
+ * int eventdns_resolv_conf_parse(int flags, const char *filename)
+ * Parse a resolv.conf like file from the given filename.
+ *
+ * See the man page for resolv.conf for the format of this file.
+ * The flags argument determines what information is parsed from
+ * this file:
+ * DNS_OPTION_SEARCH - domain, search and ndots options
+ * DNS_OPTION_NAMESERVERS - nameserver lines
+ * DNS_OPTION_MISC - timeout and attempts options
+ * DNS_OPTIONS_ALL - all of the above
+ * The following directives are not parsed from the file:
+ * sortlist, rotate, no-check-names, inet6, debug
+ *
+ * Returns non-zero on error:
+ * 0 no errors
+ * 1 failed to open file
+ * 2 failed to stat file
+ * 3 file too large
+ * 4 out of memory
+ * 5 short read from file
+ *
+ * Internals:
+ *
+ * Requests are kept in two queues. The first is the inflight queue. In
+ * this queue requests have an allocated transaction id and nameserver.
+ * They will soon be transmitted if they haven't already been.
+ *
+ * The second is the waiting queue. The size of the inflight ring is
+ * limited and all other requests wait in waiting queue for space. This
+ * bounds the number of concurrent requests so that we don't flood the
+ * nameserver. Several algorithms require a full walk of the inflight
+ * queue and so bounding its size keeps thing going nicely under huge
+ * (many thousands of requests) loads.
+ *
+ * If a nameserver loses too many requests it is considered down and we
+ * try not to use it. After a while we send a probe to that nameserver
+ * (a lookup for google.com) and, if it replies, we consider it working
+ * again. If the nameserver fails a probe we wait longer to try again
+ * with the next probe.
+ */
+
+#include "eventdns.h"
+#include "eventdns_tor.h"
+//#define NDEBUG
+
+#ifndef DNS_USE_CPU_CLOCK_FOR_ID
+#ifndef DNS_USE_GETTIMEOFDAY_FOR_ID
+#ifndef DNS_USE_OPENSSL_FOR_ID
+#error Must configure at least one id generation method.
+#error Please see the documentation.
+#endif
+#endif
+#endif
+
+// #define _POSIX_C_SOURCE 200507
+#define _GNU_SOURCE
+
+#ifdef DNS_USE_CPU_CLOCK_FOR_ID
+#ifdef DNS_USE_OPENSSL_FOR_ID
+#error Multiple id options selected
+#endif
+#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
+#error Multiple id options selected
+#endif
+#include <time.h>
+#endif
+
+#ifdef DNS_USE_OPENSSL_FOR_ID
+#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
+#error Multiple id options selected
+#endif
+#include <openssl/rand.h>
+#endif
+
+#define _FORTIFY_SOURCE 3
+
+#include <string.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#ifdef WIN32
+#include <windows.h>
+#include <winsock2.h>
+#include <iphlpapi.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#define EVENTDNS_LOG_DEBUG 0
+#define EVENTDNS_LOG_WARN 1
+
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 255
+#endif
+
+#ifndef NDEBUG
+#include <stdio.h>
+#endif
+
+#undef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+#if 0
+#ifdef __USE_ISOC99B
+// libevent doesn't work without this
+typedef uint8_t u_char;
+typedef unsigned int uint;
+#endif
+#endif
+#include <event.h>
+
+#define u64 uint64_t
+#define u32 uint32_t
+#define u16 uint16_t
+#define u8 uint8_t
+
+#include "eventdns.h"
+
+#define MAX_ADDRS 4 // maximum number of addresses from a single packet
+// which we bother recording
+
+#define TYPE_A 1
+#define TYPE_CNAME 5
+#define TYPE_PTR 12
+#define TYPE_AAAA 28
+
+#define CLASS_INET 1
+
+struct request {
+ u8 *request; // the dns packet data
+ unsigned int request_len;
+ u8 reissue_count;
+ u8 tx_count; // the number of times that this packet has been sent
+ u8 request_type; // TYPE_PTR or TYPE_A
+ void *user_pointer; // the pointer given to us for this request
+ eventdns_callback_type user_callback;
+ struct nameserver *ns; // the server which we last sent it
+
+ // elements used by the searching code
+ int search_index;
+ struct search_state *search_state;
+ char *search_origname; // needs to be free()ed
+ int search_flags;
+
+ // these objects are kept in a circular list
+ struct request *next, *prev;
+
+ struct event timeout_event;
+
+ u16 trans_id; // the transaction id
+ char request_appended; // true if the request pointer is data which follows this struct
+ char transmit_me; // needs to be transmitted
+};
+
+struct reply {
+ u8 type;
+ u8 have_answer;
+ union {
+ struct {
+ u32 addrcount;
+ u32 addresses[MAX_ADDRS];
+ } a;
+ struct {
+ char name[HOST_NAME_MAX];
+ } ptr;
+ } data;
+};
+
+struct nameserver {
+ int socket; // a connected UDP socket
+ u32 address;
+ int failed_times; // number of times which we have given this server a chance
+ int timedout; // number of times in a row a request has timed out
+ struct event event;
+ // these objects are kept in a circular list
+ struct nameserver *next, *prev;
+ struct event timeout_event; // used to keep the timeout for
+ // when we next probe this server.
+ // Valid if state == 0
+ char state; // zero if we think that this server is down
+ char choaked; // true if we have an EAGAIN from this server's socket
+ char write_waiting; // true if we are waiting for EV_WRITE events
+};
+
+static struct request *req_head = NULL, *req_waiting_head = NULL;
+static struct nameserver *server_head = NULL;
+
+// The number of good nameservers that we have
+static int global_good_nameservers = 0;
+
+// inflight requests are contained in the req_head list
+// and are actually going out across the network
+static int global_requests_inflight = 0;
+// requests which aren't inflight are in the waiting list
+// and are counted here
+static int global_requests_waiting = 0;
+
+static int global_max_requests_inflight = 64;
+
+static struct timeval global_timeout = {3, 0}; // 3 seconds
+static u8 global_max_reissues = 1; // a reissue occurs when we get some errors from the server
+static u8 global_max_retransmits = 3; // number of times we'll retransmit a request which timed out
+// number of timeouts in a row before we consider this server to be down
+static int global_max_nameserver_timeout = 3;
+
+// These are the timeout values for nameservers. If we find a nameserver is down
+// we try to probe it at intervals as given below. Values are in seconds.
+static const struct timeval global_nameserver_timeouts[] = {{10, 0}, {60, 0}, {300, 0}, {900, 0}, {3600, 0}};
+static const int global_nameserver_timeouts_length = sizeof(global_nameserver_timeouts)/sizeof(struct timeval);
+
+const char *const eventdns_error_strings[] = {"no error", "The name server was unable to interpret the query", "The name server suffered an internal error", "The requested domain name does not exist", "The name server refused to reply to the request"};
+
+static struct nameserver *nameserver_pick(void);
+static void eventdns_request_insert(struct request *req, struct request **head);
+static void nameserver_ready_callback(int fd, short events, void *arg);
+static int eventdns_transmit(void);
+static int eventdns_request_transmit(struct request *req);
+static void nameserver_send_probe(struct nameserver *const ns);
+static void search_request_finished(struct request *const);
+static int search_try_next(struct request *const req);
+static int search_request_new(int type, const char *const name, int flags, eventdns_callback_type user_callback, void *user_arg);
+static void eventdns_requests_pump_waiting_queue(void);
+static u16 transaction_id_pick(void);
+static struct request *request_new(int type, const char *name, int flags, eventdns_callback_type, void *ptr);
+static void request_submit(struct request *req);
+
+#ifdef MS_WINDOWS
+static int
+last_error(int sock) {
+ int optval, optvallen=sizeof(optval);
+ int err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK && sock >= 0) {
+ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval,
+ &optvallen))
+ return err;
+ if (optval)
+ return optval;
+ }
+ return err;
+
+}
+static int
+error_is_eagain(int err) {
+ return err == EAGAIN || err == WSAEWOULDBLOCK;
+}
+static int
+inet_aton(const char *c, struct in_addr *addr) {
+ uint32_t r;
+ if (strcmp(c, "255.255.255.255") == 0) {
+ addr->s_addr = 0xffffffffu;
+ } else {
+ r = inet_addr(c);
+ if (r == INADDR_NONE)
+ return 0;
+ addr->s_addr = r;
+ }
+ return 1;
+}
+#define CLOSE_SOCKET(x) closesocket(x)
+#else
+#define last_error(sock) (errno)
+#define error_is_eagain(err) ((err) == EAGAIN)
+#define CLOSE_SOCKET(x) close(x)
+#endif
+
+#define ISSPACE(c) isspace((int)(unsigned char)(c))
+#define ISDIGIT(c) isdigit((int)(unsigned char)(c))
+
+#ifndef NDEBUG
+static const char *
+debug_ntoa(u32 address) {
+ static char buf[32];
+ u32 a = ntohl(address);
+ sprintf(buf, "%d.%d.%d.%d",
+ (int)(u8)((a>>24)&0xff),
+ (int)(u8)((a>>16)&0xff),
+ (int)(u8)((a>>8 )&0xff),
+ (int)(u8)((a )&0xff));
+ return buf;
+}
+#endif
+
+static eventdns_debug_log_fn_type eventdns_log_fn = NULL;
+
+void
+eventdns_set_log_fn(eventdns_debug_log_fn_type fn) {
+ eventdns_log_fn = fn;
+}
+
+#ifdef __GNUC__
+#define EVENTDNS_LOG_CHECK __attribute__ ((format(printf, 2, 3)))
+#else
+#define EVENTDNS_LOG_CHECK
+#endif
+
+static void _eventdns_log(int warn, const char *fmt, ...) EVENTDNS_LOG_CHECK;
+static void
+_eventdns_log(int warn, const char *fmt, ...) {
+ va_list args;
+ static char buf[512];
+ if (!eventdns_log_fn)
+ return;
+ va_start(args,fmt);
+#ifdef MS_WINDOWS
+ _vsnprintf(buf, sizeof(buf), fmt, args);
+#else
+ vsnprintf(buf, sizeof(buf), fmt, args);
+#endif
+ buf[sizeof(buf)-1] = '\0';
+ eventdns_log_fn(warn, buf);
+ va_end(args);
+}
+
+#define log _eventdns_log
+
+// This walks the list of inflight requests to find the
+// one with a matching transaction id. Returns NULL on
+// failure
+static struct request *
+request_find_from_trans_id(u16 trans_id) {
+ struct request *req = req_head, *const started_at = req_head;
+
+ if (req) {
+ do {
+ if (req->trans_id == trans_id) return req;
+ req = req->next;
+ } while (req != started_at);
+ }
+
+ return NULL;
+}
+
+// a libevent callback function which is called when a nameserver
+// has gone down and we want to test if it has came back to life yet
+static void
+nameserver_prod_callback(int fd, short events, void *arg) {
+ struct nameserver *const ns = (struct nameserver *) arg;
+ (void)fd;
+ (void)events;
+
+ nameserver_send_probe(ns);
+}
+
+// a libevent callback which is called when a nameserver probe (to see if
+// it has come back to life) times out. We increment the count of failed_times
+// and wait longer to send the next probe packet.
+static void
+nameserver_probe_failed(struct nameserver *const ns) {
+ const struct timeval * timeout;
+ (void) evtimer_del(&ns->timeout_event);
+ if (ns->state == 1) {
+ // This can happen if the nameserver acts in a way which makes us mark
+ // it as bad and then starts sending good replies.
+ return;
+ }
+
+ timeout =
+ &global_nameserver_timeouts[MIN(ns->failed_times,
+ global_nameserver_timeouts_length - 1)];
+ ns->failed_times++;
+
+ evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns);
+ if (evtimer_add(&ns->timeout_event, (struct timeval *) timeout) < 0) {
+ log(EVENTDNS_LOG_WARN,
+ "Error from libevent when adding timer event for %s",
+ debug_ntoa(ns->address));
+ // ???? Do more?
+ }
+}
+
+// called when a nameserver has been deemed to have failed. For example, too
+// many packets have timed out etc
+static void
+nameserver_failed(struct nameserver *const ns, const char *msg) {
+ struct request *req, *started_at;
+ // if this nameserver has already been marked as failed
+ // then don't do anything
+ if (!ns->state) return;
+
+ log(EVENTDNS_LOG_WARN, "Nameserver %s has failed: %s",
+ debug_ntoa(ns->address), msg);
+ global_good_nameservers--;
+ assert(global_good_nameservers >= 0);
+ if (global_good_nameservers == 0) {
+ log(EVENTDNS_LOG_WARN, "All nameservers have failed");
+ }
+
+ ns->state = 0;
+ ns->failed_times = 1;
+
+ evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns);
+ if (evtimer_add(&ns->timeout_event, (struct timeval *) &global_nameserver_timeouts[0]) < 0) {
+ log(EVENTDNS_LOG_WARN,
+ "Error from libevent when adding timer event for %s",
+ debug_ntoa(ns->address));
+ // ???? Do more?
+ }
+
+ // walk the list of inflight requests to see if any can be reassigned to
+ // a different server. Requests in the waiting queue don't have a
+ // nameserver assigned yet
+
+ // if we don't have *any* good nameservers then there's no point
+ // trying to reassign requests to one
+ if (!global_good_nameservers) return;
+
+ req = req_head;
+ started_at = req_head;
+ if (req) {
+ do {
+ if (req->tx_count == 0 && req->ns == ns) {
+ // still waiting to go out, can be moved
+ // to another server
+ req->ns = nameserver_pick();
+ }
+ req = req->next;
+ } while (req != started_at);
+ }
+}
+
+static void
+nameserver_up(struct nameserver *const ns) {
+ if (ns->state) return;
+ log(EVENTDNS_LOG_WARN, "Nameserver %s is back up",
+ debug_ntoa(ns->address));
+ evtimer_del(&ns->timeout_event);
+ ns->state = 1;
+ ns->failed_times = 0;
+ global_good_nameservers++;
+}
+
+static void
+request_trans_id_set(struct request *const req, const u16 trans_id) {
+ req->trans_id = trans_id;
+ *((u16 *) req->request) = htons(trans_id);
+}
+
+// Called to remove a request from a list and dealloc it.
+// head is a pointer to the head of the list it should be
+// removed from or NULL if the request isn't in a list.
+static void
+request_finished(struct request *const req, struct request **head) {
+ if (head) {
+ if (req->next == req) {
+ // only item in the list
+ *head = NULL;
+ } else {
+ req->next->prev = req->prev;
+ req->prev->next = req->next;
+ if (*head == req) *head = req->next;
+ }
+ }
+
+ log(EVENTDNS_LOG_DEBUG, "Removing timeout for request %lx",
+ (unsigned long) req);
+ evtimer_del(&req->timeout_event);
+
+ search_request_finished(req);
+ global_requests_inflight--;
+
+ if (!req->request_appended) {
+ // need to free the request data on it's own
+ free(req->request);
+ } else {
+ // the request data is appended onto the header
+ // so everything gets free()ed when we:
+ }
+
+ free(req);
+
+ eventdns_requests_pump_waiting_queue();
+}
+
+// This is called when a server returns a funny error code.
+// We try the request again with another server.
+//
+// return:
+// 0 ok
+// 1 failed/reissue is pointless
+static int
+request_reissue(struct request *req) {
+ const struct nameserver *const last_ns = req->ns;
+ // the last nameserver should have been marked as failing
+ // by the caller of this function, therefore pick will try
+ // not to return it
+ req->ns = nameserver_pick();
+ if (req->ns == last_ns) {
+ // ... but pick did return it
+ // not a lot of point in trying again with the
+ // same server
+ return 1;
+ }
+
+ req->reissue_count++;
+ req->tx_count = 0;
+ req->transmit_me = 1;
+
+ return 0;
+}
+
+// this function looks for space on the inflight queue and promotes
+// requests from the waiting queue if it can.
+static void
+eventdns_requests_pump_waiting_queue(void) {
+ while (global_requests_inflight < global_max_requests_inflight &&
+ global_requests_waiting) {
+ struct request *req;
+ // move a request from the waiting queue to the inflight queue
+ assert(req_waiting_head);
+ if (req_waiting_head->next == req_waiting_head) {
+ // only one item in the queue
+ req = req_waiting_head;
+ req_waiting_head = NULL;
+ } else {
+ req = req_waiting_head;
+ req->next->prev = req->prev;
+ req->prev->next = req->next;
+ req_waiting_head = req->next;
+ }
+
+ global_requests_waiting--;
+ global_requests_inflight++;
+
+ req->ns = nameserver_pick();
+ request_trans_id_set(req, transaction_id_pick());
+
+ eventdns_request_insert(req, &req_head);
+ eventdns_request_transmit(req);
+ eventdns_transmit();
+ }
+}
+
+static void
+reply_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply) {
+ switch (req->request_type) {
+ case TYPE_A:
+ if (reply)
+ req->user_callback(DNS_ERR_NONE, DNS_IPv4_A,
+ reply->data.a.addrcount, ttl,
+ reply->data.a.addresses,
+ req->user_pointer);
+ else
+ req->user_callback(err, 0, 0, 0, NULL, req->user_pointer);
+ return;
+ case TYPE_PTR:
+ if (reply) {
+ char *name = reply->data.ptr.name;
+ req->user_callback(DNS_ERR_NONE, DNS_PTR, 1, ttl,
+ &name, req->user_pointer);
+ } else {
+ req->user_callback(err, 0, 0, 0, NULL,
+ req->user_pointer);
+ }
+ return;
+ }
+ assert(0);
+}
+
+// this processes a parsed reply packet
+static void
+reply_handle(struct request *const req,
+ u16 flags, u32 ttl, struct reply *reply) {
+ int error;
+ static const int error_codes[] = {DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST, DNS_ERR_NOTIMPL, DNS_ERR_REFUSED};
+
+ if (flags & 0x020f || !reply || !reply->have_answer) {
+ // there was an error
+ if (flags & 0x0200) {
+ error = DNS_ERR_TRUNCATED;
+ } else {
+ u16 error_code = (flags & 0x000f) - 1;
+ if (error_code > 4) {
+ error = DNS_ERR_UNKNOWN;
+ } else {
+ error = error_codes[error_code];
+ }
+ }
+
+ switch(error) {
+ case DNS_ERR_SERVERFAILED:
+ case DNS_ERR_NOTIMPL:
+ case DNS_ERR_REFUSED:
+ // we regard these errors as marking a bad nameserver
+ if (req->reissue_count < global_max_reissues) {
+ char msg[64];
+ snprintf(msg, sizeof(msg), "Bad response %d",
+ error);
+ nameserver_failed(req->ns, msg);
+ if (!request_reissue(req)) return;
+ }
+ break;
+ default:
+ // we got a good reply from the nameserver
+ nameserver_up(req->ns);
+ }
+
+ if (req->search_state && req->request_type != TYPE_PTR) {
+ // if we have a list of domains to search in, try the next one
+ if (!search_try_next(req)) {
+ // a new request was issued so this request is finished and
+ // the user callback will be made when that request (or a
+ // child of it) finishes.
+ request_finished(req, &req_head);
+ return;
+ }
+ }
+
+ // all else failed. Pass the failure up
+ reply_callback(req, 0, error, NULL);
+ request_finished(req, &req_head);
+ } else {
+ // all ok, tell the user
+ reply_callback(req, ttl, 0, reply);
+ nameserver_up(req->ns);
+ request_finished(req, &req_head);
+ }
+}
+
+static inline int
+name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) {
+ int name_end = -1;
+ int j = *idx;
+#define GET32(x) do { if (j + 4 > length) return -1; memcpy(&_t32, packet + j, 4); j += 4; x = ntohl(_t32); } while(0);
+#define GET16(x) do { if (j + 2 > length) return -1; memcpy(&_t, packet + j, 2); j += 2; x = ntohs(_t); } while(0);
+#define GET8(x) do { if (j >= length) return -1; x = packet[j++]; } while(0);
+
+ char *cp = name_out;
+ const char *const end = name_out + name_out_len;
+
+ // Normally, names are a series of length prefixed strings terminated
+ // with a length of 0 (the lengths are u8's < 63).
+ // However, the length can start with a pair of 1 bits and that
+ // means that the next 14 bits are a pointer within the current
+ // packet.
+
+ for(;;) {
+ u8 label_len;
+ if (j >= length) return -1;
+ GET8(label_len);
+ if (!label_len) break;
+ if (label_len & 0xc0) {
+ u8 ptr_low;
+ GET8(ptr_low);
+ if (name_end < 0) name_end = j;
+ j = (((int)label_len & 0x3f) << 8) + ptr_low;
+ if (j < 0 || j >= length) return -1;
+ continue;
+ }
+ if (label_len > 63) return -1;
+ if (cp != name_out) {
+ if (cp + 1 >= end) return -1;
+ *cp++ = '.';
+ }
+ if (cp + label_len >= end) return -1;
+ memcpy(cp, packet + j, label_len);
+ cp += label_len;
+ j += label_len;
+ }
+ if (cp >= end) return -1;
+ *cp = '\0';
+ if (name_end < 0)
+ *idx = j;
+ else
+ *idx = name_end;
+ return 0;
+}
+
+// parses a raw packet from the wire
+static int
+reply_parse(u8 *packet, int length) {
+ int j = 0; // index into packet
+ u16 _t; // used by the macros
+ u32 _t32; // used by the macros
+ char tmp_name[256]; // used by the macros
+
+ u16 trans_id, flags, questions, answers, authority, additional, datalength;
+ u32 ttl, ttl_r = 0xffffffff;
+ struct reply reply;
+ struct request *req;
+ unsigned int i;
+
+ GET16(trans_id);
+ GET16(flags);
+ GET16(questions);
+ GET16(answers);
+ GET16(authority);
+ GET16(additional);
+
+ req = request_find_from_trans_id(trans_id);
+ if (!req) return -1;
+ // XXXX should the other return points also call reply_handle? -NM
+ // log("reqparse: trans was %d\n", (int)trans_id);
+
+ memset(&reply, 0, sizeof(reply));
+
+ if (!(flags & 0x8000)) return -1; // must be an answer
+ if (flags & 0x020f) {
+ // there was an error
+ reply_handle(req, flags, 0, NULL);
+ return -1;
+ }
+ // if (!answers) return; // must have an answer of some form
+
+ // This macro skips a name in the DNS reply.
+#define SKIP_NAME \
+ do { tmp_name[0] = '\0'; \
+ if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0) \
+ return -1; \
+ } while(0);
+
+ reply.type = req->request_type;
+
+ // skip over each question in the reply
+ for (i = 0; i < questions; ++i) {
+ // the question looks like
+ // <label:name><u16:type><u16:class>
+ SKIP_NAME;
+ j += 4;
+ if (j >= length) return -1;
+ }
+
+ // now we have the answer section which looks like
+ // <label:name><u16:type><u16:class><u32:ttl><u16:len><data...>
+ for (i = 0; i < answers; ++i) {
+ u16 type, class;
+ //int pre = j;
+
+ // XXX I'd be more comfortable if we actually checked the name
+ // here. -NM
+ SKIP_NAME;
+ GET16(type);
+ GET16(class);
+ GET32(ttl);
+ GET16(datalength);
+
+ // log("@%d, Name %s, type %d, class %d, j=%d", pre, tmp_name, (int)type, (int)class, j);
+
+ if (type == TYPE_A && class == CLASS_INET) {
+ int addrcount, addrtocopy;
+ if (req->request_type != TYPE_A) {
+ j += datalength; continue;
+ }
+ // XXXX do something sane with malformed A answers.
+ addrcount = datalength >> 2; // each IP address is 4 bytes
+ addrtocopy = MIN(MAX_ADDRS - reply.data.a.addrcount, (unsigned)addrcount);
+ ttl_r = MIN(ttl_r, ttl);
+ // we only bother with the first four addresses.
+ if (j + 4*addrtocopy > length) return -1;
+ memcpy(&reply.data.a.addresses[reply.data.a.addrcount],
+ packet + j, 4*addrtocopy);
+ j += 4*addrtocopy;
+ reply.data.a.addrcount += addrtocopy;
+ reply.have_answer = 1;
+ if (reply.data.a.addrcount == MAX_ADDRS) break;
+ } else if (type == TYPE_PTR && class == CLASS_INET) {
+ if (req->request_type != TYPE_PTR) {
+ j += datalength; continue;
+ }
+ if (name_parse(packet, length, &j, reply.data.ptr.name,
+ sizeof(reply.data.ptr.name))<0)
+ return -1;
+ reply.have_answer = 1;
+ break;
+ } else if (type == TYPE_AAAA && class == CLASS_INET) {
+ if (req->request_type != TYPE_AAAA) {
+ j += datalength; continue;
+ }
+ // XXXX Implement me. -NM
+ j += datalength;
+ } else {
+ // skip over any other type of resource
+ j += datalength;
+ }
+ }
+
+ reply_handle(req, flags, ttl_r, &reply);
+ return 0;
+#undef SKIP_NAME
+#undef GET32
+#undef GET16
+#undef GET8
+}
+
+// Try to choose a strong transaction id which isn't already in flight
+static u16
+transaction_id_pick(void) {
+ for (;;) {
+ const struct request *req = req_head, *started_at;
+#ifdef DNS_USE_CPU_CLOCK_FOR_ID
+ struct timespec ts;
+ const u16 trans_id = ts.tv_nsec & 0xffff;
+ if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts)) abort();
+#endif
+
+#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
+ struct timeval tv;
+ const u16 trans_id = tv.tv_usec & 0xffff;
+ gettimeofday(&tv, NULL);
+#endif
+
+#ifdef DNS_USE_OPENSSL_FOR_ID
+ u16 trans_id;
+ if (RAND_pseudo_bytes((u8 *) &trans_id, 2) == -1) {
+ /* // in the case that the RAND call fails we back
+ // down to using gettimeofday.
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ trans_id = tv.tv_usec & 0xffff; */
+ abort();
+ }
+#endif
+
+ if (trans_id == 0xffff) continue;
+ // now check to see if that id is already inflight
+ req = started_at = req_head;
+ if (req) {
+ do {
+ if (req->trans_id == trans_id) break;
+ req = req->next;
+ } while (req != started_at);
+ }
+ // we didn't find it, so this is a good id
+ if (req == started_at) return trans_id;
+ }
+}
+
+// choose a namesever to use. This function will try to ignore
+// nameservers which we think are down and load balance across the rest
+// by updating the server_head global each time.
+static struct nameserver *
+nameserver_pick(void) {
+ struct nameserver *started_at = server_head, *picked;
+ if (!server_head) return NULL;
+
+ // if we don't have any good nameservers then there's no
+ // point in trying to find one.
+ if (!global_good_nameservers) {
+ server_head = server_head->next;
+ return server_head;
+ }
+
+ // remember that nameservers are in a circular list
+ for (;;) {
+ if (server_head->state) {
+ // we think this server is currently good
+ picked = server_head;
+ server_head = server_head->next;
+ return picked;
+ }
+
+ server_head = server_head->next;
+ if (server_head == started_at) {
+ // all the nameservers seem to be down
+ // so we just return this one and hope for the
+ // best
+ assert(global_good_nameservers == 0);
+ picked = server_head;
+ server_head = server_head->next;
+ return picked;
+ }
+ }
+}
+
+// this is called when a namesever socket is ready for reading
+static void
+nameserver_read(struct nameserver *ns) {
+ u8 packet[1500];
+
+ for (;;) {
+ const int r = recv(ns->socket, packet, sizeof(packet), 0);
+ if (r < 0) {
+ int err = last_error(ns->socket);
+ if (error_is_eagain(err)) return;
+ nameserver_failed(ns, strerror(err));
+ return;
+ }
+ reply_parse(packet, r);
+ }
+}
+
+// set if we are waiting for the ability to write to this server.
+// if waiting is true then we ask libevent for EV_WRITE events, otherwise
+// we stop these events.
+static void
+nameserver_write_waiting(struct nameserver *ns, char waiting) {
+ if (ns->write_waiting == waiting) return;
+
+ ns->write_waiting = waiting;
+ (void) event_del(&ns->event);
+ event_set(&ns->event, ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST,
+ nameserver_ready_callback, ns);
+ if (event_add(&ns->event, NULL) < 0) {
+ log(EVENTDNS_LOG_WARN, "Error from libevent when adding event for %s",
+ debug_ntoa(ns->address));
+ // ???? Do more?
+ }
+}
+
+// a callback function. Called by libevent when the kernel says that
+// a nameserver socket is ready for writing or reading
+static void
+nameserver_ready_callback(int fd, short events, void *arg) {
+ struct nameserver *ns = (struct nameserver *) arg;
+ (void)fd;
+
+ if (events & EV_WRITE) {
+ ns->choaked = 0;
+ if (!eventdns_transmit()) {
+ nameserver_write_waiting(ns, 0);
+ }
+ }
+ if (events & EV_READ) {
+ nameserver_read(ns);
+ }
+}
+
+// Converts a string to a length-prefixed set of DNS labels.
+// @buf must be strlen(name)+2 or longer. name and buf must
+// not overlap. name_len should be the length of name
+//
+// Input: abc.def
+// Output: <3>abc<3>def<0>
+//
+// Returns the length of the data. negative on error
+// -1 label was > 63 bytes
+// -2 name was > 255 bytes
+static int
+dnsname_to_labels(u8 *const buf, const char *name, const int name_len) {
+ const char *end = name + name_len;
+ int j = 0; // current offset into buf
+
+ if (name_len > 255) return -2;
+
+ for (;;) {
+ const char *const start = name;
+ name = strchr(name, '.');
+ if (!name) {
+ const unsigned int label_len = end - start;
+ if (label_len > 63) return -1;
+ buf[j++] = label_len;
+
+ memcpy(buf + j, start, end - start);
+ j += end - start;
+ break;
+ } else {
+ // append length of the label.
+ const unsigned int label_len = name - start;
+ if (label_len > 63) return -1;
+ buf[j++] = label_len;
+
+ memcpy(buf + j, start, name - start);
+ j += name - start;
+ // hop over the '.'
+ name++;
+ }
+ }
+
+ // the labels must be terminated by a 0.
+ // It's possible that the name ended in a .
+ // in which case the zero is already there
+ if (!j || buf[j-1]) buf[j++] = 0;
+ return j;
+}
+
+// Finds the length of a dns request for a DNS name of the given
+// length. The actual request may be smaller than the value returned
+// here
+static int
+eventdns_request_len(const int name_len) {
+ return 96 + // length of the DNS standard header
+ name_len + 2 +
+ 4; // space for the resource type
+}
+
+// build a dns request packet into buf. buf should be at least as long
+// as eventdns_request_len told you it should be.
+//
+// Returns the amount of space used. Negative on error.
+static int
+eventdns_request_data_build(const char *const name, const int name_len, const u16 trans_id,
+ const u16 type, const u16 class,
+ u8 *const buf) {
+ int j = 0; // current offset into buf
+ u16 _t; // used by the macros
+ u8 *labels;
+ int labels_len;
+
+#define APPEND16(x) do { _t = htons(x); memcpy(buf + j, &_t, 2); j += 2; } while(0);
+ APPEND16(trans_id);
+ APPEND16(0x0100); // standard query, recusion needed
+ APPEND16(1); // one question
+ APPEND16(0); // no answers
+ APPEND16(0); // no authority
+ APPEND16(0); // no additional
+
+ labels = (u8 *) malloc(name_len + 2);
+ if (!labels) return -1;
+ labels_len = dnsname_to_labels(labels, name, name_len);
+ if (labels_len < 0) {
+ free(labels);
+ return labels_len;
+ }
+ memcpy(buf + j, labels, labels_len);
+ j += labels_len;
+ free(labels);
+
+ APPEND16(type);
+ APPEND16(class);
+#undef APPEND16
+
+ return j;
+}
+
+// this is a libevent callback function which is called when a request
+// has timed out.
+static void
+eventdns_request_timeout_callback(int fd, short events, void *arg) {
+ struct request *const req = (struct request *) arg;
+ (void) fd;
+ (void) events;
+
+ log(EVENTDNS_LOG_DEBUG, "Request %lx timed out", (unsigned long) arg);
+
+ req->ns->timedout++;
+ if (req->ns->timedout > global_max_nameserver_timeout) {
+ nameserver_failed(req->ns, "request timed out.");
+ }
+
+ (void) evtimer_del(&req->timeout_event);
+ if (req->tx_count >= global_max_retransmits) {
+ // this request has failed
+ reply_callback(req, 0, DNS_ERR_TIMEOUT, NULL);
+ request_finished(req, &req_head);
+ } else {
+ // retransmit it
+ eventdns_request_transmit(req);
+ }
+}
+
+// try to send a request to a given server.
+//
+// return:
+// 0 ok
+// 1 temporary failure
+// 2 other failure
+static int
+eventdns_request_transmit_to(struct request *req, struct nameserver *server) {
+ const int r = send(server->socket, req->request, req->request_len, 0);
+ if (r < 0) {
+ int err = last_error(server->socket);
+ if (error_is_eagain(err)) return 1;
+ nameserver_failed(req->ns, strerror(err));
+ return 2;
+ } else if (r != (int)req->request_len) {
+ return 1; // short write
+ } else {
+ return 0;
+ }
+}
+
+// try to send a request, updating the fields of the request
+// as needed
+//
+// return:
+// 0 ok
+// 1 failed
+static int
+eventdns_request_transmit(struct request *req) {
+ int retcode = 0, r;
+
+ // if we fail to send this packet then this flag marks it
+ // for eventdns_transmit
+ req->transmit_me = 1;
+ if (req->trans_id == 0xffff) abort();
+
+ if (req->ns->choaked) {
+ // don't bother trying to write to a socket
+ // which we have had EAGAIN from
+ return 1;
+ }
+
+ r = eventdns_request_transmit_to(req, req->ns);
+ switch (r) {
+ case 1:
+ // temp failure
+ req->ns->choaked = 1;
+ nameserver_write_waiting(req->ns, 1);
+ return 1;
+ case 2:
+ // failed in some other way
+ retcode = 1;
+ // fall through
+ default:
+ // all ok
+ log(EVENTDNS_LOG_DEBUG,
+ "Setting timeout for request %lx", (unsigned long) req);
+ evtimer_set(&req->timeout_event, eventdns_request_timeout_callback, req);
+ if (evtimer_add(&req->timeout_event, &global_timeout) < 0) {
+ log(EVENTDNS_LOG_WARN,
+ "Error from libevent when adding timer for "
+ "request %lx", (unsigned long) req);
+ // ???? Do more?
+ }
+ req->tx_count++;
+ req->transmit_me = 0;
+ return retcode;
+ }
+}
+
+static void
+nameserver_probe_callback(int result, char type, int count, int ttl, void *addresses, void *arg) {
+ struct nameserver *const ns = (struct nameserver *) arg;
+ (void) type;
+ (void) count;
+ (void) ttl;
+ (void) addresses;
+
+ if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) {
+ // this is a good reply
+ nameserver_up(ns);
+ } else nameserver_probe_failed(ns);
+}
+
+static void
+nameserver_send_probe(struct nameserver *const ns) {
+ struct request *req;
+ // here we need to send a probe to a given nameserver
+ // in the hope that it is up now.
+
+ log(EVENTDNS_LOG_DEBUG, "Sending probe to %s", debug_ntoa(ns->address));
+ req = request_new(TYPE_A, "www.google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns);
+ if (!req) return;
+ // we force this into the inflight queue no matter what
+ request_trans_id_set(req, transaction_id_pick());
+ req->ns = ns;
+ request_submit(req);
+}
+
+// returns:
+// 0 didn't try to transmit anything
+// 1 tried to transmit something
+static int
+eventdns_transmit(void) {
+ char did_try_to_transmit = 0;
+
+ if (req_head) {
+ struct request *const started_at = req_head, *req = req_head;
+ // first transmit all the requests which are currently waiting
+ do {
+ if (req->transmit_me) {
+ did_try_to_transmit = 1;
+ eventdns_request_transmit(req);
+ }
+
+ req = req->next;
+ } while (req != started_at);
+ }
+
+ return did_try_to_transmit;
+}
+
+// exported function
+int
+eventdns_count_nameservers(void) {
+ const struct nameserver *server = server_head;
+ int n = 0;
+ if (!server)
+ return 0;
+ do {
+ ++n;
+ server = server->next;
+ } while (server != server_head);
+ return n;
+}
+
+// exported function
+int
+eventdns_clear_nameservers_and_suspend(void) {
+ struct nameserver *server = server_head, *started_at = server_head;
+ struct request *req = req_head, *req_started_at = req_head;
+
+ if (!server)
+ return 0;
+ while (1) {
+ struct nameserver *next = server->next;
+ (void) event_del(&server->event);
+ (void) evtimer_del(&server->timeout_event);
+ if (server->socket >= 0)
+ CLOSE_SOCKET(server->socket);
+ free(server);
+ if (next == started_at)
+ break;
+ server = next;
+ }
+ server_head = NULL;
+ global_good_nameservers = 0;
+
+ while (req) {
+ struct request *next = req->next;
+ req->tx_count = req->reissue_count = 0;
+ req->ns = NULL;
+ // ???? What to do about searches?
+ (void) evtimer_del(&req->timeout_event);
+ req->trans_id = 0;
+ req->transmit_me = 0;
+
+ global_requests_waiting++;
+ eventdns_request_insert(req, &req_waiting_head);
+ /* We want to insert these suspended elements at the front of
+ * the waiting queue, since they were pending before any of
+ * the waiting entries were added. This is a circular list,
+ * so we can just shift the start back by one.*/
+ req_waiting_head = req_waiting_head->prev;
+
+ if (next == req_started_at)
+ break;
+ req = next;
+ }
+ req_head = NULL;
+ global_requests_inflight = 0;
+
+ return 0;
+}
+
+// exported function
+int
+eventdns_resume(void) {
+ eventdns_requests_pump_waiting_queue();
+ return 0;
+}
+
+// exported function
+int
+eventdns_nameserver_add(unsigned long int address) {
+ // first check to see if we already have this nameserver
+
+ const struct nameserver *server = server_head, *const started_at = server_head;
+ struct nameserver *ns;
+ struct sockaddr_in sin;
+ int err = 0;
+ if (server) {
+ do {
+ if (server->address == address) return 3;
+ server = server->next;
+ } while (server != started_at);
+ }
+
+ ns = (struct nameserver *) malloc(sizeof(struct nameserver));
+ if (!ns) return -1;
+
+ memset(ns, 0, sizeof(struct nameserver));
+
+ ns->socket = socket(PF_INET, SOCK_DGRAM, 0);
+ if (ns->socket < 0) { err = 1; goto out1; }
+#ifdef MS_WINDOWS
+ {
+ u_long nonblocking = 1;
+ ioctlsocket(ns->socket, FIONBIO, &nonblocking);
+ }
+#else
+ fcntl(ns->socket, F_SETFL, O_NONBLOCK);
+#endif
+ sin.sin_addr.s_addr = address;
+ sin.sin_port = htons(53);
+ sin.sin_family = AF_INET;
+ if (connect(ns->socket, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
+ err = 2;
+ goto out2;
+ }
+
+ ns->address = address;
+ ns->state = 1;
+ event_set(&ns->event, ns->socket, EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
+ if (event_add(&ns->event, NULL) < 0) {
+ err = 2;
+ goto out2;
+ }
+
+ log(EVENTDNS_LOG_DEBUG, "Added nameserver %s", debug_ntoa(address));
+
+ // insert this nameserver into the list of them
+ if (!server_head) {
+ ns->next = ns->prev = ns;
+ server_head = ns;
+ } else {
+ ns->next = server_head->next;
+ ns->prev = server_head;
+ server_head->next = ns;
+ if (server_head->prev == server_head) {
+ server_head->prev = ns;
+ }
+ }
+
+ global_good_nameservers++;
+
+ return 0;
+
+ out2:
+ CLOSE_SOCKET(ns->socket);
+ out1:
+ free(ns);
+ log(EVENTDNS_LOG_WARN, "Unable to add nameserver %s: error %d",
+ debug_ntoa(address), err);
+ return err;
+}
+
+// exported function
+int
+eventdns_nameserver_ip_add(const char *ip_as_string) {
+ struct in_addr ina;
+ if (!inet_aton(ip_as_string, &ina)) return 4;
+ return eventdns_nameserver_add(ina.s_addr);
+}
+
+// insert into the tail of the queue
+static void
+eventdns_request_insert(struct request *req, struct request **head) {
+ if (!*head) {
+ *head = req;
+ req->next = req->prev = req;
+ return;
+ }
+
+ req->prev = (*head)->prev;
+ req->prev->next = req;
+ req->next = *head;
+ (*head)->prev = req;
+}
+
+static int
+string_num_dots(const char *s) {
+ int count = 0;
+ while ((s = strchr(s, '.'))) {
+ s++;
+ count++;
+ }
+ return count;
+}
+
+static struct request *
+request_new(int type, const char *name, int flags, eventdns_callback_type callback, void *user_ptr) {
+ const char issuing_now = (global_requests_inflight < global_max_requests_inflight) ? 1 : 0;
+
+ const int name_len = strlen(name);
+ const int request_max_len = eventdns_request_len(name_len);
+ const u16 trans_id = issuing_now ? transaction_id_pick() : 0xffff;
+ // the request data is alloced in a single block with the header
+ struct request *const req = (struct request *) malloc(sizeof(struct request) + request_max_len);
+ int rlen;
+ (void) flags;
+
+ if (!req) return NULL;
+ memset(req, 0, sizeof(struct request));
+
+ // request data lives just after the header
+ req->request = ((u8 *) req) + sizeof(struct request);
+ req->request_appended = 1; // denotes that the request data shouldn't be free()ed
+ rlen = eventdns_request_data_build(name, name_len, trans_id, type, CLASS_INET, req->request);
+ if (rlen < 0) goto err1;
+ req->request_len = rlen;
+ req->trans_id = trans_id;
+ req->tx_count = 0;
+ req->request_type = type;
+ req->user_pointer = user_ptr;
+ req->user_callback = callback;
+ req->ns = issuing_now ? nameserver_pick() : NULL;
+ req->next = req->prev = NULL;
+
+ return req;
+ err1:
+ free(req);
+ return NULL;
+}
+
+static void
+request_submit(struct request *const req) {
+ if (req->ns) {
+ // if it has a nameserver assigned then this is going
+ // straight into the inflight queue
+ eventdns_request_insert(req, &req_head);
+ global_requests_inflight++;
+ eventdns_request_transmit(req);
+ } else {
+ eventdns_request_insert(req, &req_waiting_head);
+ global_requests_waiting++;
+ }
+}
+
+// exported function
+int eventdns_resolve_ipv4(const char *name, int flags, eventdns_callback_type callback, void *ptr) {
+ log(EVENTDNS_LOG_DEBUG, "Resolve requested for %s", name);
+ if (flags & DNS_QUERY_NO_SEARCH) {
+ struct request *const req = request_new(TYPE_A, name, flags, callback, ptr);
+ if (!req) return 1;
+ request_submit(req);
+ return 0;
+ } else {
+ return search_request_new(TYPE_A, name, flags, callback, ptr);
+ }
+}
+
+int eventdns_resolve_reverse(struct in_addr *in, int flags, eventdns_callback_type callback, void *ptr) {
+ char buf[32];
+ struct request *req;
+ u32 a;
+ assert(in);
+ a = ntohl(in->s_addr);
+ sprintf(buf, "%d.%d.%d.%d.in-addr.arpa",
+ (int)(u8)((a )&0xff),
+ (int)(u8)((a>>8 )&0xff),
+ (int)(u8)((a>>16)&0xff),
+ (int)(u8)((a>>24)&0xff));
+ log(EVENTDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
+ req = request_new(TYPE_PTR, buf, flags, callback, ptr);
+ if (!req) return 1;
+ request_submit(req);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////
+// Search support
+//
+// the libc resolver has support for searching a number of domains
+// to find a name. If nothing else then it takes the single domain
+// from the gethostname() call.
+//
+// It can also be configured via the domain and search options in a
+// resolv.conf.
+//
+// The ndots option controls how many dots it takes for the resolver
+// to decide that a name is non-local and so try a raw lookup first.
+
+struct search_domain {
+ int len;
+ struct search_domain *next;
+ // the text string is appended to this structure
+};
+
+struct search_state {
+ int refcount;
+ int ndots;
+ int num_domains;
+ struct search_domain *head;
+};
+
+static struct search_state *global_search_state = NULL;
+
+static void
+search_state_decref(struct search_state *const state) {
+ if (!state) return;
+ state->refcount--;
+ if (!state->refcount) {
+ struct search_domain *next, *dom;
+ for (dom = state->head; dom; dom = next) {
+ next = dom->next;
+ free(dom);
+ }
+ free(state);
+ }
+}
+
+static struct search_state *
+search_state_new(void) {
+ struct search_state *state = (struct search_state *) malloc(sizeof(struct search_state));
+ if (!state) return NULL;
+ memset(state, 0, sizeof(struct search_state));
+ state->refcount = 1;
+ state->ndots = 1;
+
+ return state;
+}
+
+static void
+search_postfix_clear(void) {
+ search_state_decref(global_search_state);
+
+ global_search_state = search_state_new();
+}
+
+// exported function
+void
+eventdns_search_clear(void) {
+ search_postfix_clear();
+}
+
+static void
+search_postfix_add(const char *domain) {
+ int domain_len;
+ struct search_domain *sdomain;
+ while (domain[0] == '.') domain++;
+ domain_len = strlen(domain);
+
+ if (!global_search_state) global_search_state = search_state_new();
+ if (!global_search_state) return;
+ global_search_state->num_domains++;
+
+ sdomain = (struct search_domain *) malloc(sizeof(struct search_domain) + domain_len);
+ if (!sdomain) return;
+ memcpy( ((u8 *) sdomain) + sizeof(struct search_domain), domain, domain_len);
+ sdomain->next = global_search_state->head;
+ sdomain->len = domain_len;
+
+ global_search_state->head = sdomain;
+}
+
+// reverse the order of members in the postfix list. This is needed because,
+// when parsing resolv.conf we push elements in the wrong order
+static void
+search_reverse(void) {
+ struct search_domain *cur, *prev = NULL, *next;
+ cur = global_search_state->head;
+ while (cur) {
+ next = cur->next;
+ cur->next = prev;
+ prev = cur;
+ cur = next;
+ }
+
+ global_search_state->head = prev;
+}
+
+// exported function
+void
+eventdns_search_add(const char *domain) {
+ search_postfix_add(domain);
+}
+
+// exported function
+void
+eventdns_search_ndots_set(const int ndots) {
+ if (!global_search_state) global_search_state = search_state_new();
+ if (!global_search_state) return;
+ global_search_state->ndots = ndots;
+}
+
+static void
+search_set_from_hostname(void) {
+ char hostname[HOST_NAME_MAX + 1], *domainname;
+
+ search_postfix_clear();
+ if (gethostname(hostname, sizeof(hostname))) return;
+ domainname = strchr(hostname, '.');
+ if (!domainname) return;
+ search_postfix_add(domainname);
+}
+
+// warning: returns malloced string
+static char *
+search_make_new(const struct search_state *const state, int n, const char *const base_name) {
+ const int base_len = strlen(base_name);
+ const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
+ struct search_domain *dom;
+
+ for (dom = state->head; dom; dom = dom->next) {
+ if (!n--) {
+ // this is the postfix we want
+ // the actual postfix string is kept at the end of the structure
+ const u8 *const postfix = ((u8 *) dom) + sizeof(struct search_domain);
+ const int postfix_len = dom->len;
+ char *const newname = (char *) malloc(base_len + need_to_append_dot + postfix_len + 1);
+ if (!newname) return NULL;
+ memcpy(newname, base_name, base_len);
+ if (need_to_append_dot) newname[base_len] = '.';
+ memcpy(newname + base_len + need_to_append_dot, postfix, postfix_len);
+ newname[base_len + need_to_append_dot + postfix_len] = 0;
+ return newname;
+ }
+ }
+
+ // we ran off the end of the list and still didn't find the requested string
+ abort();
+}
+
+static int
+search_request_new(int type, const char *const name, int flags, eventdns_callback_type user_callback, void *user_arg) {
+ assert(type == TYPE_A);
+ if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) &&
+ global_search_state &&
+ global_search_state->num_domains) {
+ // we have some domains to search
+ struct request *req;
+ if (string_num_dots(name) >= global_search_state->ndots) {
+ req = request_new(type, name, flags, user_callback, user_arg);
+ if (!req) return 1;
+ req->search_index = -1;
+ } else {
+ char *const new_name = search_make_new(global_search_state, 0, name);
+ if (!new_name) return 1;
+ req = request_new(type, new_name, flags, user_callback, user_arg);
+ free(new_name);
+ if (!req) return 1;
+ req->search_index = 0;
+ }
+ req->search_origname = strdup(name);
+ req->search_state = global_search_state;
+ req->search_flags = flags;
+ global_search_state->refcount++;
+ request_submit(req);
+ return 0;
+ } else {
+ struct request *const req = request_new(type, name, flags, user_callback, user_arg);
+ if (!req) return 1;
+ request_submit(req);
+ return 0;
+ }
+}
+
+// this is called when a request has failed to find a name. We need to check
+// if it is part of a search and, if so, try the next name in the list
+// returns:
+// 0 another request has been submitted
+// 1 no more requests needed
+static int
+search_try_next(struct request *const req) {
+ if (req->search_state) {
+ // it is part of a search
+ char *new_name;
+ struct request *newreq;
+ req->search_index++;
+ if (req->search_index >= req->search_state->num_domains) {
+ // no more postfixes to try, however we may need to try
+ // this name without a postfix
+ if (string_num_dots(req->search_origname) < req->search_state->ndots) {
+ // yep, we need to try it raw
+ struct request *const newreq = request_new(req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer);
+ log(EVENTDNS_LOG_DEBUG, "Search: trying raw query %s", req->search_origname);
+ if (newreq) {
+ request_submit(newreq);
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+ new_name = search_make_new(req->search_state, req->search_index, req->search_origname);
+ if (!new_name) return 1;
+ log(EVENTDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, req->search_index);
+ newreq = request_new(req->request_type, new_name, req->search_flags, req->user_callback, req->user_pointer);
+ free(new_name);
+ if (!newreq) return 1;
+ newreq->search_origname = req->search_origname;
+ req->search_origname = NULL;
+ newreq->search_state = req->search_state;
+ newreq->search_flags = req->search_flags;
+ newreq->search_index = req->search_index;
+ newreq->search_state->refcount++;
+ request_submit(newreq);
+ return 0;
+ }
+ return 1;
+}
+
+static void
+search_request_finished(struct request *const req) {
+ if (req->search_state) {
+ search_state_decref(req->search_state);
+ req->search_state = NULL;
+ }
+ if (req->search_origname) {
+ free(req->search_origname);
+ req->search_origname = NULL;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////
+// Parsing resolv.conf files
+
+static void
+eventdns_resolv_set_defaults(int flags) {
+ // if the file isn't found then we assume a local resolver
+ if (flags & DNS_OPTION_SEARCH) search_set_from_hostname();
+ if (flags & DNS_OPTION_NAMESERVERS) eventdns_nameserver_ip_add("127.0.0.1");
+}
+
+#ifndef HAVE_STRTOK_R
+static char *
+strtok_r(char *s, const char *delim, char **state) {
+ return strtok(s, delim);
+}
+#endif
+
+// helper version of atoi which returns -1 on error
+static int
+strtoint(const char *const str) {
+ char *endptr;
+ const int r = strtol(str, &endptr, 10);
+ if (*endptr) return -1;
+ return r;
+}
+
+static void
+resolv_conf_parse_line(char *const start, int flags) {
+ char *strtok_state;
+ static const char *const delims = " \t";
+#define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
+
+ char *const first_token = strtok_r(start, delims, &strtok_state);
+ if (!first_token) return;
+
+ if (!strcmp(first_token, "nameserver")) {
+ const char *const nameserver = NEXT_TOKEN;
+ struct in_addr ina;
+
+ if (inet_aton(nameserver, &ina)) {
+ // address is valid
+ eventdns_nameserver_add(ina.s_addr);
+ }
+ } else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) {
+ const char *const domain = NEXT_TOKEN;
+ if (domain) {
+ search_postfix_clear();
+ search_postfix_add(domain);
+ }
+ } else if (!strcmp(first_token, "search") && (flags & DNS_OPTION_SEARCH)) {
+ const char *domain;
+ search_postfix_clear();
+
+ while ((domain = NEXT_TOKEN)) {
+ search_postfix_add(domain);
+ }
+ search_reverse();
+ } else if (!strcmp(first_token, "options")) {
+ const char *option;
+
+ while ((option = NEXT_TOKEN)) {
+ if (!strncmp(option, "ndots:", 6)) {
+ const int ndots = strtoint(&option[6]);
+ if (ndots == -1) continue;
+ if (!(flags & DNS_OPTION_SEARCH)) continue;
+ log(EVENTDNS_LOG_DEBUG,"Setting ndots to %d", ndots);
+ if (!global_search_state) global_search_state = search_state_new();
+ if (!global_search_state) return;
+ global_search_state->ndots = ndots;
+ } else if (!strncmp(option, "timeout:", 8)) {
+ const int timeout = strtoint(&option[8]);
+ if (timeout == -1) continue;
+ if (!(flags & DNS_OPTION_MISC)) continue;
+ log(EVENTDNS_LOG_DEBUG,"Setting timeout to %d", timeout);
+ global_timeout.tv_sec = timeout;
+ } else if (!strncmp(option, "attempts:", 9)) {
+ int retries = strtoint(&option[9]);
+ if (retries == -1) continue;
+ if (retries > 255) retries = 255;
+ if (!(flags & DNS_OPTION_MISC)) continue;
+ log(EVENTDNS_LOG_DEBUG,"Setting retries to %d", retries);
+ global_max_retransmits = retries;
+ }
+ }
+ }
+#undef NEXT_TOKEN
+}
+
+// exported function
+// returns:
+// 0 no errors
+// 1 failed to open file
+// 2 failed to stat file
+// 3 file too large
+// 4 out of memory
+// 5 short read from file
+int
+eventdns_resolv_conf_parse(int flags, const char *const filename) {
+ struct stat st;
+ int fd;
+ u8 *resolv;
+ char *start;
+ int err = 0;
+
+ log(EVENTDNS_LOG_DEBUG,"Parsing resolve.conf file %s", filename);
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ eventdns_resolv_set_defaults(flags);
+ return 0;
+ }
+
+ if (fstat(fd, &st)) { err = 2; goto out1; }
+ if (!st.st_size) {
+ eventdns_resolv_set_defaults(flags);
+ err = 0;
+ goto out1;
+ }
+ if (st.st_size > 65535) { err = 3; goto out1; } // no resolv.conf should be any bigger
+
+ resolv = (u8 *) malloc(st.st_size + 1);
+ if (!resolv) { err = 4; goto out1; }
+
+ if (read(fd, resolv, st.st_size) != st.st_size) { err = 5; goto out2; }
+ resolv[st.st_size] = 0; // we malloced an extra byte
+
+ start = (char *) resolv;
+ for (;;) {
+ char *const newline = strchr(start, '\n');
+ if (!newline) {
+ resolv_conf_parse_line(start, flags);
+ break;
+ } else {
+ *newline = 0;
+ resolv_conf_parse_line(start, flags);
+ start = newline + 1;
+ }
+ }
+
+ if (!server_head && (flags & DNS_OPTION_NAMESERVERS)) {
+ // no nameservers were configured.
+ eventdns_nameserver_ip_add("127.0.0.1");
+ }
+ if (flags & DNS_OPTION_SEARCH && (!global_search_state || global_search_state->num_domains == 0)) {
+ search_set_from_hostname();
+ }
+
+out2:
+ free(resolv);
+out1:
+ close(fd);
+ return err;
+}
+
+#ifdef MS_WINDOWS
+// Add multiple nameservers from a space-or-comma-separated list.
+static int
+eventdns_nameserver_ip_add_line(const char *ips) {
+ const char *addr;
+ char *buf;
+ int r;
+ while (*ips) {
+ while (ISSPACE(*ips) || *ips == ',' || *ips == '\t')
+ ++ips;
+ addr = ips;
+ while (ISDIGIT(*ips) || *ips == '.')
+ ++ips;
+ buf = malloc(ips-addr+1);
+ if (!buf) return 4;
+ memcpy(buf, addr, ips-addr);
+ buf[ips-addr] = '\0';
+ r = eventdns_nameserver_ip_add(buf);
+ free(buf);
+ if (r) return r;
+ }
+ return 0;
+}
+
+typedef DWORD(WINAPI *GetNetworkParams_fn_t)(FIXED_INFO *, DWORD*);
+
+// Use the windows GetNetworkParams interface in iphlpapi.dll to
+// figure out what our nameservers are.
+static int
+load_nameservers_with_getnetworkparams(void) {
+ // Based on MSDN examples and inspection of c-ares code.
+ FIXED_INFO *fixed;
+ HMODULE handle = 0;
+ ULONG size = sizeof(FIXED_INFO);
+ void *buf = NULL;
+ int status = 0, r, added_any;
+ IP_ADDR_STRING *ns;
+ GetNetworkParams_fn_t fn;
+
+ if (!(handle = LoadLibrary("iphlpapi.dll"))) {
+ log(EVENTDNS_LOG_WARN,"Could not open iphlpapi.dll");
+ //right now status = 0, doesn't that mean "good" - mikec
+ status = -1;
+ goto done;
+ }
+
+ if (!(fn =
+ (GetNetworkParams_fn_t)
+ GetProcAddress(handle, "GetNetworkParams"))) {
+ log(EVENTDNS_LOG_WARN,"Could not get address of function.");
+ //same as above
+ status = -1;
+ goto done;
+ }
+
+ buf = malloc(size);
+ if (!buf) {
+ status = 4;
+ goto done;
+ }
+ fixed = buf;
+ r = fn(fixed, &size);
+ if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) {
+ status = -1;
+ goto done;
+ }
+ if (r != ERROR_SUCCESS) {
+ free(buf);
+ buf = malloc(size);
+ if (!buf) { status = 4; goto done; }
+ fixed = buf;
+ r = fn(fixed, &size);
+ if (r != ERROR_SUCCESS) {
+ log(EVENTDNS_LOG_DEBUG,"fn() failed.");
+ status = -1;
+ goto done;
+ }
+ }
+
+ assert(fixed);
+ added_any = 0;
+ ns = &(fixed->DnsServerList);
+ while (ns) {
+ r = eventdns_nameserver_ip_add_line(ns->IpAddress.String);
+ if (r) {
+ log(EVENTDNS_LOG_DEBUG,"Could not add nameserver %s to list,error: %d",
+ (ns->IpAddress.String),(int)GetLastError());
+ status = r;
+ goto done;
+ } else {
+ log(EVENTDNS_LOG_DEBUG,"Succesfully added %s as nameserver",ns->IpAddress.String);
+ }
+
+ added_any++;
+ ns = ns->Next;
+ }
+
+ if (!added_any) {
+ //should we ever get here? - mikec
+ log(EVENTDNS_LOG_DEBUG,"No name servers added.");
+ status = -1;
+ }
+
+ done:
+ if (buf)
+ free(buf);
+ if (handle)
+ FreeLibrary(handle);
+ return status;
+}
+
+static int
+config_nameserver_from_reg_key(HKEY key, const char *subkey) {
+ char *buf;
+ DWORD bufsz = 0, type = 0;
+ int status = 0;
+
+ if (RegQueryValueEx(key, subkey, 0, &type, NULL, &bufsz)
+ != ERROR_MORE_DATA)
+ return -1;
+ if (!(buf = malloc(bufsz)))
+ return -1;
+
+ if (RegQueryValueEx(key, subkey, 0, &type, (LPBYTE)buf, &bufsz)
+ == ERROR_SUCCESS && bufsz > 1) {
+ status = eventdns_nameserver_ip_add_line(buf);
+ }
+
+ free(buf);
+ return status;
+}
+
+#define SERVICES_KEY "System\\CurrentControlSet\\Services\\"
+
+#define WIN_NS_9X_KEY SERVICES_KEY "VxD\\MSTCP"
+#define WIN_NS_NT_KEY SERVICES_KEY "Tcpip\\Parameters"
+
+static int
+load_nameservers_from_registry(void) {
+ int found = 0;
+ int r;
+#define TRY(k, name) \
+ if (!found && config_nameserver_from_reg_key(k,name) == 0) { \
+ log(EVENTDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \
+ found = 1; \
+ } else { \
+ if (!found) \
+ log(EVENTDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s", \
+ #k,#name); \
+ }
+
+ if (((int)GetVersion()) > 0) { /* NT */
+ HKEY nt_key = 0, interfaces_key = 0;
+
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
+ KEY_READ, &nt_key) != ERROR_SUCCESS) {
+ log(EVENTDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError());
+ return -1;
+ }
+
+ r = RegOpenKeyEx(nt_key, "Interfaces", 0,
+ KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS,
+ &interfaces_key);
+
+ if (r != ERROR_SUCCESS ) {
+ log(EVENTDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError());
+ return -1;
+ }
+
+ TRY(nt_key, "NameServer");
+ TRY(nt_key, "DhcpNameServer");
+ TRY(interfaces_key, "NameServer");
+ TRY(interfaces_key, "DhcpNameServer");
+ RegCloseKey(interfaces_key);
+ RegCloseKey(nt_key);
+ } else {
+ HKEY win_key = 0;
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0,
+ KEY_READ, &win_key) != ERROR_SUCCESS) {
+ log(EVENTDNS_LOG_DEBUG,"Couldn't open registry key, %d",(int)GetLastError());
+ return -1;
+
+ }
+ TRY(win_key, "NameServer");
+ RegCloseKey(win_key);
+ }
+
+ if (found == 0) {
+ log(EVENTDNS_LOG_WARN,"Didn't find any nameservers.");
+ }
+
+ return found ? 0 : -1;
+#undef TRY
+}
+
+int
+eventdns_config_windows_nameservers(void) {
+ if (load_nameservers_with_getnetworkparams() == 0) {
+ return 0;
+ }
+
+ return load_nameservers_from_registry();
+}
+#endif
+
+#ifdef EVENTDNS_MAIN
+void
+main_callback(int result, char type, int count, int ttl,
+ void *addrs, void *orig) {
+ char *n = (char*)orig;
+ int i;
+ for (i = 0; i < count; ++i) {
+ if (type == DNS_IPv4_A) {
+ printf("%s: %s\n", n, debug_ntoa(((u32*)addrs)[i]));
+ } else if (type == DNS_PTR) {
+ printf("%s: %s\n", n, ((char**)addrs)[i]);
+ }
+ }
+ if (!count) {
+ printf("%s: No answer (%d)\n", n, result);
+ }
+ fflush(stdout);
+}
+
+void
+logfn(const char *msg) {
+ fprintf(stderr, "%s\n", msg);
+}
+int
+main(int c, char **v) {
+ int idx;
+ int reverse = 0, verbose = 1;
+ if (c<2) {
+ fprintf(stderr, "syntax: %s [-x] [-v] hostname\n", v[0]);
+ return 1;
+ }
+ idx = 1;
+ while (idx < c && v[idx][0] == '-') {
+ if (!strcmp(v[idx], "-x"))
+ reverse = 1;
+ else if (!strcmp(v[idx], "-v"))
+ verbose = 1;
+ else
+ fprintf(stderr, "Unknown option %s\n", v[idx]);
+ ++idx;
+ }
+ event_init();
+ if (verbose)
+ eventdns_set_log_fn(logfn);
+ eventdns_resolv_conf_parse(DNS_OPTION_NAMESERVERS, "/etc/resolv.conf");
+ for (; idx < c; ++idx) {
+ if (reverse) {
+ struct in_addr addr;
+ if (!inet_aton(v[idx], &addr)) {
+ fprintf(stderr, "Skipping non-IP %s\n", v[idx]);
+ continue;
+ }
+ fprintf(stderr, "resolving %s...\n",v[idx]);
+ eventdns_resolve_reverse(&addr, 0, main_callback, v[idx]);
+ } else {
+ fprintf(stderr, "resolving (fwd) %s...\n",v[idx]);
+ eventdns_resolve_ipv4(v[idx], 0, main_callback, v[idx]);
+ }
+ }
+ fflush(stdout);
+ event_dispatch();
+ return 0;
+}
+
+#endif
+
+// Local Variables:
+// tab-width: 4
+// c-basic-offset: 4
+// indent-tabs-mode: t
+// End:
+
diff --git a/src/or/eventdns.h b/src/or/eventdns.h
new file mode 100644
index 0000000000..0897b50ca6
--- /dev/null
+++ b/src/or/eventdns.h
@@ -0,0 +1,73 @@
+/* This software is Public Domain. To view a copy of the public domain dedication,
+ * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
+ * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+ *
+ * I ask and expect, but do not require, that all derivative works contain an
+ * attribution similar to:
+ * Parts developed by Adam Langley <agl@imperialviolet.org>
+ *
+ * You may wish to replace the word "Parts" with something else depending on
+ * the amount of original code.
+ *
+ * (Derivative works does not include programs which link against, run or include
+ * the source verbatim in their source distributions)
+ */
+
+#ifndef EVENTDNS_H
+#define EVENTDNS_H
+
+/* Error codes 0-5 are as described in RFC 1035. */
+#define DNS_ERR_NONE 0
+/* The name server was unable to interpret the query */
+#define DNS_ERR_FORMAT 1
+/* The name server was unable to process this query due to a problem with the
+ * name server */
+#define DNS_ERR_SERVERFAILED 2
+/* The domain name does not exist */
+#define DNS_ERR_NOTEXIST 3
+/* The name server does not support the requested kind of query */
+#define DNS_ERR_NOTIMPL 4
+/* The name server refuses to reform the specified operation for policy
+ * reasons */
+#define DNS_ERR_REFUSED 5
+/* The reply was truncated or ill-formated */
+#define DNS_ERR_TRUNCATED 65
+/* An unknown error occurred */
+#define DNS_ERR_UNKNOWN 66
+/* Communication with the server timed out */
+#define DNS_ERR_TIMEOUT 67
+
+#define DNS_IPv4_A 1
+#define DNS_PTR 2 /* XXXX ???? */
+
+#define DNS_QUERY_NO_SEARCH 1
+
+#define DNS_OPTION_SEARCH 1
+#define DNS_OPTION_NAMESERVERS 2
+#define DNS_OPTION_MISC 4
+#define DNS_OPTIONS_ALL 7
+
+typedef void (*eventdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg);
+
+int eventdns_nameserver_add(unsigned long int address);
+int eventdns_count_nameservers(void);
+int eventdns_clear_nameservers_and_suspend(void);
+int eventdns_resume(void);
+int eventdns_nameserver_ip_add(const char *ip_as_string);
+int eventdns_resolve_ipv4(const char *name, int flags, eventdns_callback_type callback, void *ptr);
+struct in_addr;
+int eventdns_resolve_reverse(struct in_addr *addr, int flags, eventdns_callback_type callback, void *ptr);
+int eventdns_resolv_conf_parse(int flags, const char *);
+#ifdef MS_WINDOWS
+int eventdns_config_windows_nameservers(void);
+#endif
+void eventdns_search_clear(void);
+void eventdns_search_add(const char *domain);
+void eventdns_search_ndots_set(const int ndots);
+
+typedef void (*eventdns_debug_log_fn_type)(int warn, const char *msg);
+void eventdns_set_log_fn(eventdns_debug_log_fn_type fn);
+
+#define DNS_NO_SEARCH 1
+
+#endif // !EVENTDNS_H
diff --git a/src/or/eventdns_tor.h b/src/or/eventdns_tor.h
new file mode 100644
index 0000000000..a10b3726bb
--- /dev/null
+++ b/src/or/eventdns_tor.h
@@ -0,0 +1,13 @@
+
+#include "orconfig.h"
+#define DNS_USE_OPENSSL_FOR_ID
+#ifndef HAVE_UINT
+typedef unsigned int uint;
+#endif
+#ifndef HAVE_U_CHAR
+typedef unsigned char u_char;
+#endif
+#ifdef MS_WINDOWS
+#define inline __inline
+#endif
+
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index da74e98dd2..93c4cbe553 100644
--- a/src/or/hibernate.c
+++ b/src/or/hibernate.c
@@ -536,7 +536,7 @@ accounting_set_wakeup_time(void)
#define BW_ACCOUNTING_VERSION 1
/** Save all our bandwidth tracking information to disk. Return 0 on
- * success, -1 on failure*/
+ * success, -1 on failure. */
int
accounting_record_bandwidth_usage(time_t now)
{
@@ -545,11 +545,18 @@ accounting_record_bandwidth_usage(time_t now)
char time1[ISO_TIME_LEN+1];
char time2[ISO_TIME_LEN+1];
char *cp = buf;
+ time_t tmp;
/* Format is:
Version\nTime\nTime\nRead\nWrite\nSeconds\nExpected-Rate\n */
format_iso_time(time1, interval_start_time);
format_iso_time(time2, now);
+ /* now check to see if they're valid times -- if they're not,
+ * and we write them, then tor will refuse to start next time. */
+ if (parse_iso_time(time1, &tmp) || parse_iso_time(time2, &tmp)) {
+ log_warn(LD_ACCT, "Created a time that we refused to parse.");
+ return -1;
+ }
tor_snprintf(cp, sizeof(buf),
"%d\n%s\n%s\n"U64_FORMAT"\n"U64_FORMAT"\n%lu\n%lu\n",
BW_ACCOUNTING_VERSION,
@@ -676,7 +683,8 @@ hibernate_hard_limit_reached(void)
static int
hibernate_soft_limit_reached(void)
{
- uint64_t soft_limit = (uint64_t) ((get_options()->AccountingMax) * .95);
+ uint64_t soft_limit = DBL_TO_U64(U64_TO_DBL(get_options()->AccountingMax)
+ * .95);
if (!soft_limit)
return 0;
return n_bytes_read_in_interval >= soft_limit
@@ -704,6 +712,7 @@ hibernate_begin(int new_state, time_t now)
/* close listeners. leave control listener(s). */
while ((conn = connection_get_by_type(CONN_TYPE_OR_LISTENER)) ||
(conn = connection_get_by_type(CONN_TYPE_AP_LISTENER)) ||
+ (conn = connection_get_by_type(CONN_TYPE_AP_TRANS_LISTENER)) ||
(conn = connection_get_by_type(CONN_TYPE_DIR_LISTENER))) {
log_info(LD_NET,"Closing listener type %d", conn->type);
connection_mark_for_close(conn);
@@ -778,11 +787,12 @@ hibernate_go_dormant(time_t now)
(conn = connection_get_by_type(CONN_TYPE_AP)) ||
(conn = connection_get_by_type(CONN_TYPE_EXIT))) {
if (CONN_IS_EDGE(conn))
- connection_edge_end(conn, END_STREAM_REASON_HIBERNATING,
- conn->cpath_layer);
+ connection_edge_end(TO_EDGE_CONN(conn), END_STREAM_REASON_HIBERNATING,
+ TO_EDGE_CONN(conn)->cpath_layer);
log_info(LD_NET,"Closing conn type %d", conn->type);
if (conn->type == CONN_TYPE_AP) /* send socks failure if needed */
- connection_mark_unattached_ap(conn, END_STREAM_REASON_HIBERNATING);
+ connection_mark_unattached_ap(TO_EDGE_CONN(conn),
+ END_STREAM_REASON_HIBERNATING);
else
connection_mark_for_close(conn);
}
diff --git a/src/or/main.c b/src/or/main.c
index 336de8b5a7..b2fd0359d7 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -50,13 +50,12 @@ static time_t time_to_fetch_directory = 0;
/** When do we next download a running-routers summary? */
static time_t time_to_fetch_running_routers = 0;
-/** Array of all open connections; each element corresponds to the element of
- * poll_array in the same position. The first nfds elements are valid. */
+/** Array of all open connections. The first n_conns elements are valid. */
static connection_t *connection_array[MAXCONNECTIONS+1] =
{ NULL };
static smartlist_t *closeable_connection_lst = NULL;
-static int nfds=0; /**< Number of connections currently active. */
+static int n_conns=0; /**< Number of connections currently active. */
/** We set this to 1 when we've opened a circuit, so we can print a log
* entry to inform the user that Tor is working. */
@@ -112,8 +111,8 @@ static char* nt_strerror(uint32_t errnum);
/** How old do we let a connection to an OR get before deciding it's
* obsolete? */
#define TIME_BEFORE_OR_CONN_IS_OBSOLETE (60*60*24*7)
-/** How long do we OR connections to handshake before we decide that they
- * could be obsolete? */
+/** How long do we let OR connections handshake before we decide that
+ * they are obsolete? */
#define TLS_HANDSHAKE_TIMEOUT (60)
/********* END VARIABLES ************/
@@ -121,8 +120,7 @@ static char* nt_strerror(uint32_t errnum);
/****************************************************************************
*
* This section contains accessors and other methods on the connection_array
-* and poll_array variables (which are global within this file and unavailable
-* outside it).
+* variables (which are global within this file and unavailable outside it).
*
****************************************************************************/
@@ -136,15 +134,15 @@ connection_add(connection_t *conn)
tor_assert(conn);
tor_assert(conn->s >= 0);
- if (nfds >= get_options()->_ConnLimit-1) {
+ if (n_conns >= get_options()->_ConnLimit-1) {
log_warn(LD_NET,"Failing because we have %d connections already. Please "
- "raise your ulimit -n.", nfds);
+ "raise your ulimit -n.", n_conns);
return -1;
}
- tor_assert(conn->poll_index == -1); /* can only connection_add once */
- conn->poll_index = nfds;
- connection_array[nfds] = conn;
+ tor_assert(conn->conn_array_index == -1); /* can only connection_add once */
+ conn->conn_array_index = n_conns;
+ connection_array[n_conns] = conn;
conn->read_event = tor_malloc_zero(sizeof(struct event));
conn->write_event = tor_malloc_zero(sizeof(struct event));
@@ -153,10 +151,10 @@ connection_add(connection_t *conn)
event_set(conn->write_event, conn->s, EV_WRITE|EV_PERSIST,
conn_write_callback, conn);
- nfds++;
+ n_conns++;
- log_debug(LD_NET,"new conn type %s, socket %d, nfds %d.",
- conn_type_to_string(conn->type), conn->s, nfds);
+ log_debug(LD_NET,"new conn type %s, socket %d, n_conns %d.",
+ conn_type_to_string(conn->type), conn->s, n_conns);
return 0;
}
@@ -171,24 +169,24 @@ connection_remove(connection_t *conn)
int current_index;
tor_assert(conn);
- tor_assert(nfds>0);
+ tor_assert(n_conns>0);
- log_debug(LD_NET,"removing socket %d (type %s), nfds now %d",
- conn->s, conn_type_to_string(conn->type), nfds-1);
+ log_debug(LD_NET,"removing socket %d (type %s), n_conns now %d",
+ conn->s, conn_type_to_string(conn->type), n_conns-1);
- tor_assert(conn->poll_index >= 0);
- current_index = conn->poll_index;
- if (current_index == nfds-1) { /* this is the end */
- nfds--;
+ tor_assert(conn->conn_array_index >= 0);
+ current_index = conn->conn_array_index;
+ if (current_index == n_conns-1) { /* this is the end */
+ n_conns--;
return 0;
}
connection_unregister(conn);
/* replace this one with the one at the end */
- nfds--;
- connection_array[current_index] = connection_array[nfds];
- connection_array[current_index]->poll_index = current_index;
+ n_conns--;
+ connection_array[current_index] = connection_array[n_conns];
+ connection_array[current_index]->conn_array_index = current_index;
return 0;
}
@@ -212,11 +210,11 @@ connection_unlink(connection_t *conn, int remove)
}
smartlist_remove(closeable_connection_lst, conn);
if (conn->type == CONN_TYPE_EXIT) {
- assert_connection_edge_not_dns_pending(conn);
+ assert_connection_edge_not_dns_pending(TO_EDGE_CONN(conn));
}
- if (conn->type == CONN_TYPE_OR &&
- !tor_digest_is_zero(conn->identity_digest)) {
- connection_or_remove_from_identity_map(conn);
+ if (conn->type == CONN_TYPE_OR) {
+ if (!tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest))
+ connection_or_remove_from_identity_map(TO_OR_CONN(conn));
}
connection_free(conn);
}
@@ -243,7 +241,7 @@ int
connection_in_array(connection_t *conn)
{
int i;
- for (i=0; i<nfds; ++i) {
+ for (i=0; i<n_conns; ++i) {
if (conn==connection_array[i])
return 1;
}
@@ -258,7 +256,7 @@ void
get_connection_array(connection_t ***array, int *n)
{
*array = connection_array;
- *n = nfds;
+ *n = n_conns;
}
/** Set the event mask on <b>conn</b> to <b>events</b>. (The event
@@ -382,10 +380,10 @@ close_closeable_connections(void)
int i;
for (i = 0; i < smartlist_len(closeable_connection_lst); ) {
connection_t *conn = smartlist_get(closeable_connection_lst, i);
- if (conn->poll_index < 0) {
+ if (conn->conn_array_index < 0) {
connection_unlink(conn, 0); /* blow it away right now */
} else {
- if (!conn_close_if_marked(conn->poll_index))
+ if (!conn_close_if_marked(conn->conn_array_index))
++i;
}
}
@@ -397,6 +395,8 @@ static void
conn_read_callback(int fd, short event, void *_conn)
{
connection_t *conn = _conn;
+ (void)fd;
+ (void)event;
log_debug(LD_NET,"socket %d wants to read.",conn->s);
@@ -411,7 +411,8 @@ conn_read_callback(int fd, short event, void *_conn)
tor_fragile_assert();
#endif
if (CONN_IS_EDGE(conn))
- connection_edge_end_errno(conn, conn->cpath_layer);
+ connection_edge_end_errno(TO_EDGE_CONN(conn),
+ TO_EDGE_CONN(conn)->cpath_layer);
connection_mark_for_close(conn);
}
}
@@ -427,6 +428,8 @@ static void
conn_write_callback(int fd, short events, void *_conn)
{
connection_t *conn = _conn;
+ (void)fd;
+ (void)events;
LOG_FN_CONN(conn, (LOG_DEBUG, LD_NET, "socket %d wants to write.",conn->s));
@@ -439,7 +442,10 @@ conn_write_callback(int fd, short events, void *_conn)
"Bug: unhandled error on write for %s connection (fd %d); removing",
conn_type_to_string(conn->type), conn->s);
tor_fragile_assert();
- conn->has_sent_end = 1; /* otherwise we cry wolf about duplicate close */
+ if (CONN_IS_EDGE(conn)) {
+ /* otherwise we cry wolf about duplicate close */
+ conn->edge_has_sent_end = 1;
+ }
/* XXX do we need a close-immediate here, so we don't try to flush? */
connection_mark_for_close(conn);
}
@@ -485,7 +491,7 @@ conn_close_if_marked(int i)
conn->marked_for_close_file, conn->marked_for_close);
if (connection_speaks_cells(conn)) {
if (conn->state == OR_CONN_STATE_OPEN) {
- retval = flush_buf_tls(conn->tls, conn->outbuf, sz,
+ retval = flush_buf_tls(TO_OR_CONN(conn)->tls, conn->outbuf, sz,
&conn->outbuf_flushlen);
} else
retval = -1; /* never flush non-open broken tls connections */
@@ -534,54 +540,23 @@ void
directory_all_unreachable(time_t now)
{
connection_t *conn;
+ (void)now;
stats_n_seconds_working=0; /* reset it */
while ((conn = connection_get_by_type_state(CONN_TYPE_AP,
AP_CONN_STATE_CIRCUIT_WAIT))) {
+ edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
log_notice(LD_NET,
"Is your network connection down? "
"Failing connection to '%s:%d'.",
- safe_str(conn->socks_request->address),
- conn->socks_request->port);
- connection_mark_unattached_ap(conn, END_STREAM_REASON_NET_UNREACHABLE);
+ safe_str(edge_conn->socks_request->address),
+ edge_conn->socks_request->port);
+ connection_mark_unattached_ap(edge_conn,
+ END_STREAM_REASON_NET_UNREACHABLE);
}
}
-/**
- * Return the interval to wait between directory downloads, in seconds.
- */
-static INLINE int
-get_dir_fetch_period(or_options_t *options)
-{
- if (options->DirFetchPeriod)
- /* Value from config file. */
- return options->DirFetchPeriod;
- else if (options->DirPort)
- /* Default for directory server */
- return 60*60;
- else
- /* Default for average user. */
- return 120*60;
-}
-
-/**
- * Return the interval to wait betweeen router status downloads, in seconds.
- */
-static INLINE int
-get_status_fetch_period(or_options_t *options)
-{
- if (options->StatusFetchPeriod)
- /* Value from config file. */
- return options->StatusFetchPeriod;
- else if (options->DirPort)
- /* Default for directory server */
- return 15*60;
- else
- /* Default for average user. */
- return 30*60;
-}
-
/** This function is called whenever we successfully pull down some new
* network statuses or server descriptors. */
void
@@ -597,14 +572,9 @@ directory_info_has_arrived(time_t now, int from_cache)
return;
}
- if (server_mode(options) &&
- !we_are_hibernating()) { /* connect to the appropriate routers */
- if (!authdir_mode(options))
- router_retry_connections(0, 1);
- if (!from_cache &&
- (has_completed_circuit || !any_predicted_circuits(now)))
- consider_testing_reachability();
- }
+ if (server_mode(options) && !we_are_hibernating() && !from_cache &&
+ (has_completed_circuit || !any_predicted_circuits(now)))
+ consider_testing_reachability(1, 1);
}
/** Perform regular maintenance tasks for a single connection. This
@@ -616,9 +586,10 @@ run_connection_housekeeping(int i, time_t now)
cell_t cell;
connection_t *conn = connection_array[i];
or_options_t *options = get_options();
+ or_connection_t *or_conn;
- if (conn->outbuf && !buf_datalen(conn->outbuf))
- conn->timestamp_lastempty = now;
+ if (conn->outbuf && !buf_datalen(conn->outbuf) && conn->type == CONN_TYPE_OR)
+ TO_OR_CONN(conn)->timestamp_lastempty = now;
if (conn->marked_for_close) {
/* nothing to do here */
@@ -640,7 +611,7 @@ run_connection_housekeeping(int i, time_t now)
buf_datalen(conn->inbuf)>=1024) {
log_info(LD_DIR,"Trying to extract information from wedged server desc "
"download.");
- connection_dir_reached_eof(conn);
+ connection_dir_reached_eof(TO_DIR_CONN(conn));
} else {
connection_mark_for_close(conn);
}
@@ -650,17 +621,19 @@ run_connection_housekeeping(int i, time_t now)
if (!connection_speaks_cells(conn))
return; /* we're all done here, the rest is just for OR conns */
- if (!conn->is_obsolete) {
+ or_conn = TO_OR_CONN(conn);
+
+ if (!conn->or_is_obsolete) {
if (conn->timestamp_created + TIME_BEFORE_OR_CONN_IS_OBSOLETE < now) {
log_info(LD_OR,
"Marking OR conn to %s:%d obsolete (fd %d, %d secs old).",
conn->address, conn->port, conn->s,
(int)(now - conn->timestamp_created));
- conn->is_obsolete = 1;
+ conn->or_is_obsolete = 1;
} else {
- connection_t *best =
- connection_or_get_by_identity_digest(conn->identity_digest);
- if (best && best != conn &&
+ or_connection_t *best =
+ connection_or_get_by_identity_digest(or_conn->identity_digest);
+ if (best && best != or_conn &&
(conn->state == OR_CONN_STATE_OPEN ||
now > conn->timestamp_created + TLS_HANDSHAKE_TIMEOUT)) {
/* We only mark as obsolete connections that already are in
@@ -675,16 +648,16 @@ run_connection_housekeeping(int i, time_t now)
"(fd %d, %d secs old).",
conn->address, conn->port, conn->s,
(int)(now - conn->timestamp_created));
- conn->is_obsolete = 1;
+ conn->or_is_obsolete = 1;
}
}
}
- if (conn->is_obsolete && !conn->n_circuits) {
+ if (conn->or_is_obsolete && !or_conn->n_circuits) {
/* no unmarked circs -- mark it now */
log_info(LD_OR,
"Expiring non-used OR connection to fd %d (%s:%d) [Obsolete].",
- conn->s,conn->address, conn->port);
+ conn->s, conn->address, conn->port);
connection_mark_for_close(conn);
conn->hold_open_until_flushed = 1;
return;
@@ -693,20 +666,20 @@ run_connection_housekeeping(int i, time_t now)
/* If we haven't written to an OR connection for a while, then either nuke
the connection or send a keepalive, depending. */
if (now >= conn->timestamp_lastwritten + options->KeepalivePeriod) {
- routerinfo_t *router = router_get_by_digest(conn->identity_digest);
+ routerinfo_t *router = router_get_by_digest(or_conn->identity_digest);
if (!connection_state_is_open(conn)) {
log_info(LD_OR,"Expiring non-open OR connection to fd %d (%s:%d).",
conn->s,conn->address, conn->port);
connection_mark_for_close(conn);
conn->hold_open_until_flushed = 1;
- } else if (we_are_hibernating() && !conn->n_circuits &&
+ } else if (we_are_hibernating() && !or_conn->n_circuits &&
!buf_datalen(conn->outbuf)) {
log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) "
"[Hibernating or exiting].",
conn->s,conn->address, conn->port);
connection_mark_for_close(conn);
conn->hold_open_until_flushed = 1;
- } else if (!clique_mode(options) && !conn->n_circuits &&
+ } else if (!clique_mode(options) && !or_conn->n_circuits &&
(!router || !server_mode(options) ||
!router_is_clique_mode(router))) {
log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) "
@@ -715,7 +688,7 @@ run_connection_housekeeping(int i, time_t now)
connection_mark_for_close(conn);
conn->hold_open_until_flushed = 1;
} else if (
- now >= conn->timestamp_lastempty + options->KeepalivePeriod*10 &&
+ now >= or_conn->timestamp_lastempty + options->KeepalivePeriod*10 &&
now >= conn->timestamp_lastwritten + options->KeepalivePeriod*10) {
log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,
"Expiring stuck OR connection to fd %d (%s:%d). (%d bytes to "
@@ -730,7 +703,7 @@ run_connection_housekeeping(int i, time_t now)
conn->address, conn->port);
memset(&cell,0,sizeof(cell_t));
cell.command = CELL_PADDING;
- connection_or_write_cell_to_buf(&cell, conn);
+ connection_or_write_cell_to_buf(&cell, or_conn);
}
}
}
@@ -749,6 +722,7 @@ run_scheduled_events(time_t now)
static time_t time_to_try_getting_descriptors = 0;
static time_t time_to_reset_descriptor_failures = 0;
static time_t time_to_add_entropy = 0;
+ static time_t time_to_check_for_wildcarded_dns = 0;
or_options_t *options = get_options();
int i;
int have_dir_info;
@@ -769,13 +743,15 @@ run_scheduled_events(time_t now)
rotate_onion_key();
cpuworkers_rotate();
if (router_rebuild_descriptor(1)<0) {
- log_warn(LD_BUG, "Couldn't rebuild router descriptor");
+ log_info(LD_CONFIG, "Couldn't rebuild router descriptor");
}
if (advertised_server_mode())
router_upload_dir_desc_to_dirservers(0);
}
if (time_to_try_getting_descriptors < now) {
+ /* XXXX Maybe we should do this every 10sec when not enough info,
+ * and every 60sec when we have enough info -NM */
update_router_descriptor_downloads(now);
time_to_try_getting_descriptors = now + DESCRIPTOR_RETRY_INTERVAL;
}
@@ -791,7 +767,7 @@ run_scheduled_events(time_t now)
last_rotated_certificate = now;
if (last_rotated_certificate+MAX_SSL_KEY_LIFETIME < now) {
log_info(LD_GENERAL,"Rotating tls context.");
- if (tor_tls_context_new(get_identity_key(), 1, options->Nickname,
+ if (tor_tls_context_new(get_identity_key(), options->Nickname,
MAX_SSL_KEY_LIFETIME) < 0) {
log_warn(LD_BUG, "Error reinitializing TLS context");
/* XXX is it a bug here, that we just keep going? */
@@ -816,7 +792,7 @@ run_scheduled_events(time_t now)
if (now % 10 == 0 && authdir_mode(options) && !we_are_hibernating()) {
/* try to determine reachability */
- router_retry_connections(1, 0);
+ dirserv_test_reachability(0);
}
/** 2. Periodically, we consider getting a new directory, getting a
@@ -835,7 +811,8 @@ run_scheduled_events(time_t now)
directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 1);
}
- time_to_fetch_directory = now + get_dir_fetch_period(options);
+#define V1_DIR_FETCH_PERIOD (60*60)
+ time_to_fetch_directory = now + V1_DIR_FETCH_PERIOD;
/* Also, take this chance to remove old information from rephist
* and the rend cache. */
@@ -851,7 +828,8 @@ run_scheduled_events(time_t now)
if (!authdir_mode(options) || !options->V1AuthoritativeDir) {
directory_get_from_dirserver(DIR_PURPOSE_FETCH_RUNNING_LIST, NULL, 1);
}
- time_to_fetch_running_routers = now + get_status_fetch_period(options);
+#define V1_RUNNINGROUTERS_FETCH_PERIOD (20*60)
+ time_to_fetch_running_routers = now + V1_RUNNINGROUTERS_FETCH_PERIOD;
}
/* 2b. Once per minute, regenerate and upload the descriptor if the old
@@ -865,14 +843,14 @@ run_scheduled_events(time_t now)
}
mark_my_descriptor_dirty_if_older_than(
now - FORCE_REGENERATE_DESCRIPTOR_INTERVAL);
- consider_publishable_server(now, 0);
+ consider_publishable_server(0);
/* also, check religiously for reachability, if it's within the first
* 20 minutes of our uptime. */
if (server_mode(options) &&
(has_completed_circuit || !any_predicted_circuits(now)) &&
stats_n_seconds_working < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT &&
!we_are_hibernating())
- consider_testing_reachability();
+ consider_testing_reachability(1, 1);
/* If any networkstatus documents are no longer recent, we need to
* update all the descriptors' running status. */
@@ -920,11 +898,11 @@ run_scheduled_events(time_t now)
circuit_build_needed_circs(now);
/** 5. We do housekeeping for each connection... */
- for (i=0;i<nfds;i++) {
+ for (i=0;i<n_conns;i++) {
run_connection_housekeeping(i, now);
}
if (time_to_shrink_buffers < now) {
- for (i=0;i<nfds;i++) {
+ for (i=0;i<n_conns;i++) {
connection_t *conn = connection_array[i];
if (conn->outbuf)
buf_shrink(conn->outbuf);
@@ -946,6 +924,18 @@ run_scheduled_events(time_t now)
* we'll pass it to poll/select and bad things will happen.
*/
close_closeable_connections();
+
+ /** 9. and if we're a server, check whether our DNS is telling stories to
+ * us. */
+ if (server_mode(options) && time_to_check_for_wildcarded_dns < now) {
+ if (!time_to_check_for_wildcarded_dns) {
+ time_to_check_for_wildcarded_dns = now + 60 + crypto_rand_int(120);
+ } else {
+ dns_launch_wildcard_checks();
+ time_to_check_for_wildcarded_dns = now + 12*3600 +
+ crypto_rand_int(12*3600);
+ }
+ }
}
static struct event *timeout_event = NULL;
@@ -962,6 +952,9 @@ second_elapsed_callback(int fd, short event, void *args)
size_t bytes_read;
int seconds_elapsed;
or_options_t *options = get_options();
+ (void)fd;
+ (void)event;
+ (void)args;
if (!timeout_event) {
timeout_event = tor_malloc_zero(sizeof(struct event));
evtimer_set(timeout_event, second_elapsed_callback, NULL);
@@ -1014,9 +1007,11 @@ second_elapsed_callback(int fd, short event, void *args)
me->address, me->dir_port);
}
- /* if more than 100s have elapsed, probably the clock jumped: doesn't
- * count. */
- if (seconds_elapsed < 100)
+/** If more than this many seconds have elapsed, probably the clock
+ * jumped: doesn't count. */
+#define NUM_JUMPED_SECONDS_BEFORE_WARN 10
+/* This used to be 100, but I cranked it down for Mike Chiussi -RD */
+ if (seconds_elapsed < NUM_JUMPED_SECONDS_BEFORE_WARN)
stats_n_seconds_working += seconds_elapsed;
else
circuit_note_clock_jumped(seconds_elapsed);
@@ -1056,7 +1051,6 @@ got_libevent_error(void)
static int
do_hup(void)
{
- char keydir[512];
or_options_t *options = get_options();
log_notice(LD_GENERAL,"Received reload signal (hup). Reloading config.");
@@ -1076,11 +1070,8 @@ do_hup(void)
options = get_options(); /* they have changed now */
if (authdir_mode(options)) {
/* reload the approved-routers file */
- tor_snprintf(keydir, sizeof(keydir),
- "%s/approved-routers", options->DataDirectory);
- log_info(LD_GENERAL,
- "Reloading approved fingerprints from \"%s\"...", keydir);
- if (dirserv_parse_fingerprint_file(keydir) < 0) {
+ if (dirserv_load_fingerprint_file() < 0) {
+ /* warnings are logged from dirserv_load_fingerprint_file() directly */
log_info(LD_GENERAL, "Error reloading fingerprints. "
"Continuing with old list.");
}
@@ -1101,11 +1092,14 @@ do_hup(void)
if (server_mode(options)) {
// const char *descriptor;
+ mark_my_descriptor_dirty();
/* Restart cpuworker and dnsworker processes, so they get up-to-date
* configuration options. */
cpuworkers_rotate();
- dnsworkers_rotate();
+ dns_reset();
#if 0
+ const char *descriptor;
+ char keydir[512];
/* Write out a fresh descriptor, but leave old one on failure. */
router_rebuild_descriptor(1);
descriptor = router_get_my_descriptor();
@@ -1128,7 +1122,11 @@ do_main_loop(void)
{
int loop_result;
- dns_init(); /* initialize dns resolve map, spawn workers if needed */
+ /* initialize dns resolve map, spawn workers if needed */
+ if (dns_init() < 0) {
+ log_err(LD_GENERAL,"Error initializing dns subsystem; exiting");
+ return -1;
+ }
handle_signals(1);
@@ -1160,7 +1158,7 @@ do_main_loop(void)
if (authdir_mode(get_options())) {
/* the directory is already here, run startup things */
- router_retry_connections(1, 1);
+ dirserv_test_reachability(1);
}
if (server_mode(get_options())) {
@@ -1219,16 +1217,33 @@ do_main_loop(void)
}
}
+/* DOCDOC */
+int
+control_signal_check(int the_signal)
+{
+ switch (the_signal)
+ {
+ case 1:
+ case 2:
+ case 10:
+ case 12:
+ case 15:
+ case SIGNEWNYM:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
/** Used to implement the SIGNAL control command: if we accept
- * <b>the_signal</b> as a remote pseudo-signal, then act on it and
- * return 0. Else return -1. */
+ * <b>the_signal</b> as a remote pseudo-signal, act on it. */
/* We don't re-use catch() here because:
* 1. We handle a different set of signals than those allowed in catch.
* 2. Platforms without signal() are unlikely to define SIGfoo.
* 3. The control spec is defined to use fixed numeric signal values
* which just happen to match the unix values.
*/
-int
+void
control_signal_act(int the_signal)
{
switch (the_signal)
@@ -1252,9 +1267,9 @@ control_signal_act(int the_signal)
signal_callback(0,0,(void*)(uintptr_t)SIGNEWNYM);
break;
default:
- return -1;
+ log_warn(LD_BUG, "Unrecognized signal number %d.", the_signal);
+ break;
}
- return 0;
}
/** Libevent callback: invoked when we get a signal.
@@ -1263,6 +1278,8 @@ static void
signal_callback(int fd, short events, void *arg)
{
uintptr_t sig = (uintptr_t)arg;
+ (void)fd;
+ (void)events;
switch (sig)
{
case SIGTERM:
@@ -1311,21 +1328,21 @@ signal_callback(int fd, short events, void *arg)
}
}
+extern uint64_t buf_total_used;
+extern uint64_t buf_total_alloc;
+extern uint64_t rephist_total_alloc;
+extern uint32_t rephist_total_num;
+
/**
* Write current memory usage information to the log.
*/
static void
dumpmemusage(int severity)
{
- extern uint64_t buf_total_used;
- extern uint64_t buf_total_alloc;
- extern uint64_t rephist_total_alloc;
- extern uint32_t rephist_total_num;
-
log(severity, LD_GENERAL,
"In buffers: "U64_FORMAT" used/"U64_FORMAT" allocated (%d conns).",
U64_PRINTF_ARG(buf_total_used), U64_PRINTF_ARG(buf_total_alloc),
- nfds);
+ n_conns);
log(severity, LD_GENERAL, "In rephist: "U64_FORMAT" used by %d Tors.",
U64_PRINTF_ARG(rephist_total_alloc), rephist_total_num);
dump_routerlist_mem_usage(severity);
@@ -1343,7 +1360,7 @@ dumpstats(int severity)
log(severity, LD_GENERAL, "Dumping stats:");
- for (i=0;i<nfds;i++) {
+ for (i=0;i<n_conns;i++) {
conn = connection_array[i];
log(severity, LD_GENERAL,
"Conn %d (socket %d) type %d (%s), state %d (%s), created %d secs ago",
@@ -1352,7 +1369,7 @@ dumpstats(int severity)
(int)(now - conn->timestamp_created));
if (!connection_is_listener(conn)) {
log(severity,LD_GENERAL,
- "Conn %d is to '%s:%d'.", i,
+ "Conn %d is to %s:%d.", i,
safe_str(conn->address), conn->port);
log(severity,LD_GENERAL,
"Conn %d: %d bytes waiting on inbuf (len %d, last read %d secs ago)",
@@ -1387,12 +1404,12 @@ dumpstats(int severity)
U64_PRINTF_ARG(stats_n_destroy_cells_processed));
if (stats_n_data_cells_packaged)
log(severity,LD_NET,"Average packaged cell fullness: %2.3f%%",
- 100*(((double)stats_n_data_bytes_packaged) /
- (stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)) );
+ 100*(U64_TO_DBL(stats_n_data_bytes_packaged) /
+ U64_TO_DBL(stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)) );
if (stats_n_data_cells_received)
log(severity,LD_NET,"Average delivered cell fullness: %2.3f%%",
- 100*(((double)stats_n_data_bytes_received) /
- (stats_n_data_cells_received*RELAY_PAYLOAD_SIZE)) );
+ 100*(U64_TO_DBL(stats_n_data_bytes_received) /
+ U64_TO_DBL(stats_n_data_cells_received*RELAY_PAYLOAD_SIZE)) );
if (now - time_of_process_start >= 0)
elapsed = now - time_of_process_start;
@@ -1504,8 +1521,7 @@ tor_init(int argc, char *argv[])
atexit(exit_function);
if (options_init_from_torrc(argc,argv) < 0) {
- log_err(LD_CONFIG,"Reading config failed--see warnings above. "
- "For usage, try -h.");
+ log_err(LD_CONFIG,"Reading config failed--see warnings above.");
return -1;
}
@@ -1582,30 +1598,32 @@ tor_cleanup(void)
}
/** Read/create keys as needed, and echo our fingerprint to stdout. */
-static void
+static int
do_list_fingerprint(void)
{
char buf[FINGERPRINT_LEN+1];
crypto_pk_env_t *k;
const char *nickname = get_options()->Nickname;
if (!server_mode(get_options())) {
- printf("Clients don't have long-term identity keys. Exiting.\n");
- return;
+ log_err(LD_GENERAL,
+ "Clients don't have long-term identity keys. Exiting.\n");
+ return -1;
}
tor_assert(nickname);
if (init_keys() < 0) {
log_err(LD_BUG,"Error initializing keys; exiting");
- return;
+ return -1;
}
if (!(k = get_identity_key())) {
log_err(LD_GENERAL,"Error: missing identity key.");
- return;
+ return -1;
}
if (crypto_pk_get_fingerprint(k, buf, 1)<0) {
- log_warn(LD_BUG, "Error computing fingerprint");
- return;
+ log_err(LD_BUG, "Error computing fingerprint");
+ return -1;
}
printf("%s %s\n", nickname, buf);
+ return 0;
}
/** Entry point for password hashing: take the desired password from
@@ -1773,7 +1791,7 @@ nt_service_main(void)
if (!StartServiceCtrlDispatcher(table)) {
result = GetLastError();
errmsg = nt_strerror(result);
- printf("Service error %d : %s\n", result, errmsg);
+ printf("Service error %d : %s\n", (int) result, errmsg);
LocalFree(errmsg);
if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
if (tor_init(backup_argc, backup_argv) < 0)
@@ -1897,7 +1915,7 @@ nt_service_stop(SC_HANDLE hService)
}
else {
errmsg = nt_strerror(GetLastError());
- printf("Service failed to stop : %s\n");
+ printf("Service failed to stop : %s\n",errmsg);
LocalFree(errmsg);
}
}
@@ -2010,7 +2028,6 @@ nt_service_remove(void)
{
SC_HANDLE hSCManager = NULL;
SC_HANDLE hService = NULL;
- BOOL result = FALSE;
char *errmsg;
if ((hSCManager = nt_service_open_scm()) == NULL) {
@@ -2114,10 +2131,11 @@ _tor_dmalloc_free(void *p)
int
tor_main(int argc, char *argv[])
{
+ int result = 0;
#ifdef USE_DMALLOC
- int r = CRYPTO_set_mem_ex_functions(_tor_malloc, _tor_realloc,
- _tor_dmalloc_free);
- log_notice(LD_CONFIG, "Set up damalloc; returned %d", r);
+ int r = CRYPTO_set_mem_ex_functions(_tor_malloc, _tor_realloc,
+ _tor_dmalloc_free);
+ log_notice(LD_CONFIG, "Set up dmalloc; returned %d", r);
#endif
#ifdef MS_WINDOWS_SERVICE
backup_argv = argv;
@@ -2154,22 +2172,26 @@ tor_main(int argc, char *argv[])
#ifdef MS_WINDOWS_SERVICE
service_status.dwCurrentState = SERVICE_RUNNING;
#endif
- do_main_loop();
+ result = do_main_loop();
break;
case CMD_LIST_FINGERPRINT:
- do_list_fingerprint();
+ result = do_list_fingerprint();
break;
case CMD_HASH_PASSWORD:
do_hash_password();
+ result = 0;
break;
case CMD_VERIFY_CONFIG:
printf("Configuration was valid\n");
+ result = 0;
break;
+ case CMD_RUN_UNITTESTS: /* only set by test.c */
default:
log_warn(LD_BUG,"Illegal command number %d: internal error.",
get_options()->command);
+ result = -1;
}
tor_cleanup();
- return -1;
+ return result;
}
diff --git a/src/or/onion.c b/src/or/onion.c
index 315c5f12dd..ba41f21a22 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -17,7 +17,7 @@ const char onion_c_id[] =
/** Type for a linked list of circuits that are waiting for a free CPU worker
* to process a waiting onion handshake. */
typedef struct onion_queue_t {
- circuit_t *circ;
+ or_circuit_t *circ;
time_t when_added;
struct onion_queue_t *next;
} onion_queue_t;
@@ -35,7 +35,7 @@ static int ol_length=0;
* if ol_list is too long, in which case do nothing and return -1.
*/
int
-onion_pending_add(circuit_t *circ)
+onion_pending_add(or_circuit_t *circ)
{
onion_queue_t *tmp;
time_t now = time(NULL);
@@ -75,7 +75,7 @@ onion_pending_add(circuit_t *circ)
onion_pending_remove(ol_list->circ);
log_info(LD_CIRC,
"Circuit create request is too old; cancelling due to overload.");
- circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
}
return 0;
}
@@ -83,10 +83,10 @@ onion_pending_add(circuit_t *circ)
/** Remove the first item from ol_list and return it, or return
* NULL if the list is empty.
*/
-circuit_t *
+or_circuit_t *
onion_next_task(void)
{
- circuit_t *circ;
+ or_circuit_t *circ;
if (!ol_list)
return NULL; /* no onions pending, we're done */
@@ -103,7 +103,7 @@ onion_next_task(void)
* circ, remove and free that element. Leave circ itself alone.
*/
void
-onion_pending_remove(circuit_t *circ)
+onion_pending_remove(or_circuit_t *circ)
{
onion_queue_t *tmpo, *victim;
diff --git a/src/or/or.h b/src/or/or.h
index b529fcb617..a74a892dd2 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -22,7 +22,6 @@
#include <stdio.h>
#include <stdlib.h>
-#include <limits.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -38,30 +37,10 @@
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
-#include "../common/torint.h"
-#ifdef HAVE_INTTYPES_H
-#include <inttypes.h>
-#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h> /* FreeBSD needs this to know what version it is */
#endif
-#ifdef HAVE_SYS_LIMITS_H
-#include <sys/limits.h>
-#endif
-#ifdef HAVE_MACHINE_LIMITS_H
-#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
- /* FreeBSD has a bug where it complains that this file is obsolete,
- and I should migrate to using sys/limits. It complains even when
- I include both.
- __FreeBSD_kernel__ is defined by Debian GNU/kFreeBSD which
- does the same thing (but doesn't defined __FreeBSD__).
- */
-#include <machine/limits.h>
-#endif
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h> /* Must be included before sys/stat.h for Ultrix */
-#endif
+#include "../common/torint.h"
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
@@ -101,7 +80,13 @@
/** Upper bound on maximum simultaneous connections; can be lowered by
* config file. */
+#ifdef CYGWIN
+/* http://archives.seul.org/or/talk/Aug-2006/msg00210.html */
+#define MAXCONNECTIONS 3200
+#else
+/* very high by default. "nobody should need more than this..." */
#define MAXCONNECTIONS 15000
+#endif
#ifdef MS_WINDOWS
/* No, we don't need to redefine FD_SETSIZE before including winsock:
@@ -170,7 +155,6 @@
#define cell_t tor_cell_t
#endif
-#define DEFAULT_BANDWIDTH_OP (1024 * 1000)
#define MAX_NICKNAME_LEN 19
/* Hex digest plus dollar sign. */
#define MAX_HEX_NICKNAME_LEN (HEX_DIGEST_LEN+1)
@@ -182,12 +166,14 @@
#define MAX_HEADERS_SIZE 50000
#define MAX_BODY_SIZE 500000
-#ifdef TOR_PERF
-/** How long do we keep DNS cache entries before purging them? */
-#define MAX_DNS_ENTRY_AGE (150*60)
-#else
+/** How long do we keep DNS cache entries before purging them (regardless of
+ * their TTL)? */
#define MAX_DNS_ENTRY_AGE (30*60)
-#endif
+#define DEFAULT_DNS_TTL (30*60)
+/** How long can a TTL be before we stop believing it? */
+#define MAX_DNS_TTL (3*60*60)
+/** How small can a TTL be before we stop believing it? */
+#define MIN_DNS_TTL (60)
/** How often do we rotate onion keys? */
#define MIN_ONION_KEY_LIFETIME (7*24*60*60)
@@ -235,7 +221,9 @@ typedef enum {
#define CONN_TYPE_CONTROL_LISTENER 12
/** Type for connections from user interface process. */
#define CONN_TYPE_CONTROL 13
-#define _CONN_TYPE_MAX 13
+/** Type for sockets listening for transparent proxy connections. */
+#define CONN_TYPE_AP_TRANS_LISTENER 14
+#define _CONN_TYPE_MAX 14
#define CONN_IS_EDGE(x) \
((x)->type == CONN_TYPE_EXIT || (x)->type == CONN_TYPE_AP)
@@ -303,7 +291,10 @@ typedef enum {
#define AP_CONN_STATE_RESOLVE_WAIT 10
/** State for a SOCKS connection: ready to send and receive. */
#define AP_CONN_STATE_OPEN 11
-#define _AP_CONN_STATE_MAX 11
+/** State for a transparent proxy connection: waiting for original
+ * destination. */
+#define AP_CONN_STATE_ORIGDST_WAIT 12
+#define _AP_CONN_STATE_MAX 12
#define _DIR_CONN_STATE_MIN 1
/** State for connection to directory server: waiting for connect(). */
@@ -496,6 +487,7 @@ typedef enum {
#define RESOLVED_TYPE_ERROR_TRANSIENT 0xF0
#define RESOLVED_TYPE_ERROR 0xF1
+/* XXX We should document the meaning of these. */
#define END_CIRC_AT_ORIGIN -1
#define _END_CIRC_REASON_MIN 0
#define END_CIRC_REASON_NONE 0
@@ -597,7 +589,11 @@ typedef struct {
typedef struct buf_t buf_t;
typedef struct socks_request_t socks_request_t;
-#define CONNECTION_MAGIC 0x7C3C304Eu
+#define BASE_CONNECTION_MAGIC 0x7C3C304Eu
+#define OR_CONNECTION_MAGIC 0x7D31FF03u
+#define EDGE_CONNECTION_MAGIC 0xF0374013u
+#define DIR_CONNECTION_MAGIC 0x9988ffeeu
+#define CONTROL_CONNECTION_MAGIC 0x8abc765du
/** Description of a connection to another host or process, and associated
* data.
@@ -617,48 +613,51 @@ typedef struct socks_request_t socks_request_t;
* conn->outbuf. Connections differ primarily in the functions called
* to fill and drain these buffers.
*/
-struct connection_t {
- uint32_t magic; /**< For memory debugging: must equal CONNECTION_MAGIC. */
+typedef struct connection_t {
+ uint32_t magic; /**< For memory debugging: must equal one of
+ * *_CONNECTION_MAGIC. */
uint8_t type; /**< What kind of connection is this? */
uint8_t state; /**< Current state of this connection. */
- uint8_t purpose; /**< Only used for DIR types currently. */
+ uint8_t purpose; /**< Only used for DIR and EXIT types currently. */
+
+ /* The next fields are all one-bit booleans. Some are only applicable
+ * to connection subtypes, but we hold them here anyway, to save space.
+ * (Currently, they all fit into a single byte.) */
unsigned wants_to_read:1; /**< Boolean: should we start reading again once
- * the bandwidth throttler allows it?
- */
+ * the bandwidth throttler allows it? */
unsigned wants_to_write:1; /**< Boolean: should we start writing again once
- * the bandwidth throttler allows reads?
- */
+ * the bandwidth throttler allows reads? */
unsigned hold_open_until_flushed:1; /**< Despite this connection's being
* marked for close, do we flush it
- * before closing it?
- */
- unsigned has_sent_end:1; /**< For debugging; only used on edge connections.
- * Set once we've set the stream end,
+ * before closing it? */
+ unsigned int inbuf_reached_eof:1; /**< Boolean: did read() return 0 on this
+ * conn? */
+ unsigned edge_has_sent_end:1; /**< For debugging; only used on edge
+ * connections. Set once we've set the stream end,
* and check in circuit_about_to_close_connection(). */
/** For control connections only. If set, we send extended info with control
* events as appropriate. */
unsigned int control_events_are_extended:1;
/** Used for OR conns that shouldn't get any new circs attached to them. */
- unsigned int is_obsolete:1;
+ unsigned int or_is_obsolete:1;
+ /** For AP connections only. If 1, and we fail to reach the chosen exit,
+ * stop requiring it. */
+ unsigned int chosen_exit_optional:1;
int s; /**< Our socket; -1 if this connection is closed. */
- int poll_index; /* XXXX rename. */
- struct event *read_event; /**< libevent event structure. */
- struct event *write_event; /**< libevent event structure. */
+ int conn_array_index; /**< Index into the global connection array. */
+ struct event *read_event; /**< Libevent event structure. */
+ struct event *write_event; /**< Libevent event structure. */
buf_t *inbuf; /**< Buffer holding data read over this connection. */
- int inbuf_reached_eof; /**< Boolean: did read() return 0 on this conn? */
- time_t timestamp_lastread; /**< When was the last time poll() said we could
- * read? */
-
buf_t *outbuf; /**< Buffer holding data to write over this connection. */
size_t outbuf_flushlen; /**< How much data should we try to flush from the
* outbuf? */
- time_t timestamp_lastwritten; /**< When was the last time poll() said we
+ time_t timestamp_lastread; /**< When was the last time libevent said we could
+ * read? */
+ time_t timestamp_lastwritten; /**< When was the last time libevent said we
* could write? */
-
time_t timestamp_created; /**< When was this connection_t created? */
- time_t timestamp_lastempty; /**< When was the outbuf last completely empty?*/
uint32_t addr; /**< IP of the other side of the connection; used to identify
* routers, along with port. */
@@ -667,81 +666,166 @@ struct connection_t {
uint16_t marked_for_close; /**< Should we close this conn on the next
* iteration of the main loop? (If true, holds
* the line number where this connection was
- * marked.)
- */
+ * marked.) */
const char *marked_for_close_file; /**< For debugging: in which file were
* we marked for close? */
char *address; /**< FQDN (or IP) of the guy on the other end.
- * strdup into this, because free_connection frees it.
- */
- crypto_pk_env_t *identity_pkey; /**< Public RSA key for the other side's
- * signing key. */
- char identity_digest[DIGEST_LEN]; /**< Hash of identity_pkey */
+ * strdup into this, because free_connection frees it. */
+
+} connection_t;
+
+/** Subtype of connection_t for an "OR connection" -- that is, one that speaks
+ * cells over TLS. */
+typedef struct or_connection_t {
+ connection_t _base;
+
+ char identity_digest[DIGEST_LEN]; /**< Hash of the public RSA key for
+ * the other side's signing key. */
char *nickname; /**< Nickname of OR on other side (if any). */
- /** Nickname of planned exit node -- used with .exit support. */
- char *chosen_exit_name;
+ tor_tls_t *tls; /**< TLS connection state */
-/* Used only by OR connections: */
- tor_tls_t *tls; /**< TLS connection state (OR only.) */
+ time_t timestamp_lastempty; /**< When was the outbuf last completely empty?*/
- /* bandwidth and receiver_bucket only used by ORs in OPEN state: */
- int bandwidth; /**< Connection bandwidth. (OPEN ORs only.) */
+ /* bandwidth* and receiver_bucket only used by ORs in OPEN state: */
+ int bandwidthrate; /**< Bytes/s added to the bucket. (OPEN ORs only.) */
+ int bandwidthburst; /**< Max bucket size for this conn. (OPEN ORs only.) */
int receiver_bucket; /**< When this hits 0, stop receiving. Every second we
- * add 'bandwidth' to this, capping it at 10*bandwidth.
- * (OPEN ORs only)
- */
+ * add 'bandwidthrate' to this, capping it at
+ * bandwidthburst. (OPEN ORs only) */
circ_id_type_t circ_id_type; /**< When we send CREATE cells along this
* connection, which half of the space should
* we use? */
int n_circuits; /**< How many circuits use this connection as p_conn or
* n_conn ? */
- struct connection_t *next_with_same_id; /**< Next connection with same
+ struct or_connection_t *next_with_same_id; /**< Next connection with same
* identity digest as this one. */
uint16_t next_circ_id; /**< Which circ_id do we try to use next on
* this connection? This is always in the
- * range 0..1<<15-1. (OR only.)*/
+ * range 0..1<<15-1. */
+} or_connection_t;
+
+/** Subtype of connection_t for an "edge connection" -- that is, a socks (ap)
+ * connection, or an exit. */
+typedef struct edge_connection_t {
+ connection_t _base;
-/* Used only by edge connections: */
- uint16_t stream_id;
- struct connection_t *next_stream; /**< Points to the next stream at this
- * edge, if any (Edge only). */
+ struct edge_connection_t *next_stream; /**< Points to the next stream at this
+ * edge, if any */
struct crypt_path_t *cpath_layer; /**< A pointer to which node in the circ
- * this conn exits at. (Edge only.) */
- int package_window; /**< How many more relay cells can i send into the
- * circuit? (Edge only.) */
- int deliver_window; /**< How many more relay cells can end at me? (Edge
- * only.) */
+ * this conn exits at. */
+ int package_window; /**< How many more relay cells can I send into the
+ * circuit? */
+ int deliver_window; /**< How many more relay cells can end at me? */
-/* Used only by Dir connections */
- char *requested_resource; /**< Which 'resource' did we ask the directory
- * for?*/
+ /** Nickname of planned exit node -- used with .exit support. */
+ char *chosen_exit_name;
-/* Used only by AP connections */
socks_request_t *socks_request; /**< SOCKS structure describing request (AP
* only.) */
+ struct circuit_t *on_circuit; /**< The circuit (if any) that this edge
+ * connection is using. */
+
+ uint32_t address_ttl; /**< TTL for address-to-addr mapping on exit
+ * connection. Exit connections only. */
+
+ uint16_t stream_id; /**< The stream ID used for this edge connection on its
+ * circuit */
/** Quasi-global identifier for this connection; used for control.c */
- /* XXXX NM This can get re-used after 2**32 circuits. */
+ /* XXXX NM This can get re-used after 2**32 streams */
uint32_t global_identifier;
- /* Used only by control connections */
- uint32_t event_mask;
- uint32_t incoming_cmd_len;
- uint32_t incoming_cmd_cur_len;
- char *incoming_cmd;
+ char rend_query[REND_SERVICE_ID_LEN+1]; /**< What rendezvous service are we
+ * querying for? (AP only) */
+
+ /** Number of times we've reassigned this application connection to
+ * a new circuit. We keep track because the timeout is longer if we've
+ * already retried several times. */
+ uint8_t num_socks_retries;
+
+} edge_connection_t;
+
+/** Subtype of connection_t for an "directory connection" -- that is, an HTTP
+ * connection to retrieve or serve directory material. */
+typedef struct dir_connection_t {
+ connection_t _base;
+
+ char *requested_resource; /**< Which 'resource' did we ask the directory
+ * for? */
+ unsigned int dirconn_direct:1; /**< Is this dirconn direct, or via Tor? */
+
+ /* Used only for server sides of some dir connections, to implement
+ * "spooling" of directory material to the outbuf. Otherwise, we'd have
+ * to append everything to the outbuf in one enormous chunk. */
+ enum {
+ DIR_SPOOL_NONE=0, DIR_SPOOL_SERVER_BY_DIGEST, DIR_SPOOL_SERVER_BY_FP,
+ DIR_SPOOL_CACHED_DIR, DIR_SPOOL_NETWORKSTATUS
+ } dir_spool_src;
+ smartlist_t *fingerprint_stack;
+ struct cached_dir_t *cached_dir;
+ off_t cached_dir_offset;
+ tor_zlib_state_t *zlib_state;
-/* Used only by DIR and AP connections: */
- struct circuit_t *on_circuit; /**< The circuit (if any) that this edge
- * connection is using. */
char rend_query[REND_SERVICE_ID_LEN+1]; /**< What rendezvous service are we
- * querying for? (DIR/AP only) */
+ * querying for? */
+
+ char identity_digest[DIGEST_LEN]; /**< Hash of the public RSA key for
+ * the directory server's signing key. */
+} dir_connection_t;
+/** Subtype of connection_t for an connection to a controller. */
+typedef struct control_connection_t {
+ connection_t _base;
+
+ uint32_t event_mask; /**< Bitfield: which events does this controller
+ * care about? */
+ uint32_t incoming_cmd_len;
+ uint32_t incoming_cmd_cur_len;
+ char *incoming_cmd;
/* Used only by control v0 connections */
uint16_t incoming_cmd_type;
-};
-
-typedef struct connection_t connection_t;
+} control_connection_t;
+
+/** Cast a connection_t subtype pointer to a connection_t **/
+#define TO_CONN(c) &(((c)->_base))
+/** Helper macro: Given a pointer to to._base, of type from*, return &to. */
+#define DOWNCAST(to, ptr) \
+ (to*) (((char*)(ptr)) - STRUCT_OFFSET(to, _base))
+
+/** Convert a connection_t* to an or_connection_t*; assert if the cast is
+ * invalid. */
+static or_connection_t *TO_OR_CONN(connection_t *);
+/** Convert a connection_t* to a dir_connection_t*; assert if the cast is
+ * invalid. */
+static dir_connection_t *TO_DIR_CONN(connection_t *);
+/** Convert a connection_t* to an edge_connection_t*; assert if the cast is
+ * invalid. */
+static edge_connection_t *TO_EDGE_CONN(connection_t *);
+/** Convert a connection_t* to an control_connection_t*; assert if the cast is
+ * invalid. */
+static control_connection_t *TO_CONTROL_CONN(connection_t *);
+
+static INLINE or_connection_t *TO_OR_CONN(connection_t *c)
+{
+ tor_assert(c->magic == OR_CONNECTION_MAGIC);
+ return DOWNCAST(or_connection_t, c);
+}
+static INLINE dir_connection_t *TO_DIR_CONN(connection_t *c)
+{
+ tor_assert(c->magic == DIR_CONNECTION_MAGIC);
+ return DOWNCAST(dir_connection_t, c);
+}
+static INLINE edge_connection_t *TO_EDGE_CONN(connection_t *c)
+{
+ tor_assert(c->magic == EDGE_CONNECTION_MAGIC);
+ return DOWNCAST(edge_connection_t, c);
+}
+static INLINE control_connection_t *TO_CONTROL_CONN(connection_t *c)
+{
+ tor_assert(c->magic == CONTROL_CONNECTION_MAGIC);
+ return DOWNCAST(control_connection_t, c);
+}
typedef enum {
ADDR_POLICY_ACCEPT=1,
@@ -769,8 +853,13 @@ typedef struct cached_dir_t {
size_t dir_len; /**< Length of <b>dir</b> */
size_t dir_z_len; /**< Length of <b>dir_z</b> */
time_t published; /**< When was this object published */
+ int refcnt; /**< Reference count for this cached_dir_t. */
} cached_dir_t;
+typedef enum {
+ SAVED_NOWHERE=0, SAVED_IN_CACHE, SAVED_IN_JOURNAL
+} saved_location_t;
+
/** Information need to cache an onion router's descriptor. */
typedef struct signed_descriptor_t {
char *signed_descriptor_body;
@@ -778,6 +867,8 @@ typedef struct signed_descriptor_t {
char signed_descriptor_digest[DIGEST_LEN];
char identity_digest[DIGEST_LEN];
time_t published_on;
+ saved_location_t saved_location;
+ off_t saved_offset;
} signed_descriptor_t;
/** Information about another onion router in the network. */
@@ -809,6 +900,8 @@ typedef struct {
char *contact_info; /**< Declared contact info for this router. */
unsigned int is_hibernating:1; /**< Whether the router claims to be
* hibernating */
+ unsigned int has_old_dnsworkers:1; /**< Whether the router is using
+ * dnsworker code. */
/* local info */
unsigned int is_running:1; /**< As far as we know, is this OR currently
@@ -837,6 +930,10 @@ typedef struct {
/** How many times has a descriptor been posted and we believed
* this router to be unreachable? We only actually warn on the third. */
int num_unreachable_notifications;
+
+ /** What position is this descriptor within routerlist->routers? -1 for
+ * none. */
+ int routerlist_index;
} routerinfo_t;
/** Contents of a single router entry in a network status object.
@@ -940,6 +1037,8 @@ typedef struct {
/** List of signed_descriptor_t for older router descriptors we're
* caching. */
smartlist_t *old_routers;
+ /** DOCDOC */
+ tor_mmap_t *mmap_descriptors;
} routerlist_t;
/** Information on router used when extending a circuit. (We don't need a
@@ -1039,7 +1138,10 @@ typedef struct {
time_t expiry_time;
} cpath_build_state_t;
-#define CIRCUIT_MAGIC 0x35315243u
+#define ORIGIN_CIRCUIT_MAGIC 0x35315243u
+#define OR_CIRCUIT_MAGIC 0x98ABC04Fu
+
+typedef uint16_t circid_t;
/**
* A circuit is a path over the onion routing
@@ -1050,42 +1152,34 @@ typedef struct {
* OR connections multiplex many circuits at once, and stay standing even
* when there are no circuits running over them.
*
- * A circuit_t structure fills two roles. First, a circuit_t links two
- * connections together: either an edge connection and an OR connection,
- * or two OR connections. (When joined to an OR connection, a circuit_t
- * affects only cells sent to a particular circID on that connection. When
- * joined to an edge connection, a circuit_t affects all data.)
-
- * Second, a circuit_t holds the cipher keys and state for sending data
+ * A circuit_t structure cann fill one of two roles. First, a or_circuit_t
+ * links two connections together: either an edge connection and an OR
+ * connection, or two OR connections. (When joined to an OR connection, a
+ * circuit_t affects only cells sent to a particular circID on that
+ * connection. When joined to an edge connection, a circuit_t affects all
+ * data.)
+
+ * Second, an origin_circuit_t holds the cipher keys and state for sending data
* along a given circuit. At the OP, it has a sequence of ciphers, each
* of which is shared with a single OR along the circuit. Separate
* ciphers are used for data going "forward" (away from the OP) and
* "backward" (towards the OP). At the OR, a circuit has only two stream
* ciphers: one for data going forward, and one for data going backward.
*/
-struct circuit_t {
- uint32_t magic; /**< For memory debugging: must equal CIRCUIT_MAGIC. */
+typedef struct circuit_t {
+ uint32_t magic; /**< For memory and type debugging: must equal
+ * ORIGIN_CIRCUIT_MAGIC or OR_CIRCUIT_MAGIC. */
- /** The OR connection that is previous in this circuit. */
- connection_t *p_conn;
/** The OR connection that is next in this circuit. */
- connection_t *n_conn;
+ or_connection_t *n_conn;
/** The identity hash of n_conn. */
char n_conn_id_digest[DIGEST_LEN];
- /** Linked list of AP streams associated with this circuit. */
- connection_t *p_streams;
- /** Linked list of Exit streams associated with this circuit. */
- connection_t *n_streams;
- /** Linked list of Exit streams associated with this circuit that are
- * still being resolved. */
- connection_t *resolving_streams;
- /** The IPv4 address of the OR that is next in this circuit. */
- uint32_t n_addr;
+ /** The circuit_id used in the next (forward) hop of this circuit. */
+ uint16_t n_circ_id;
/** The port for the OR that is next in this circuit. */
uint16_t n_port;
- /** The next stream_id that will be tried when we're attempting to
- * construct a new AP stream originating at this circuit. */
- uint16_t next_stream_id;
+ /** The IPv4 address of the OR that is next in this circuit. */
+ uint32_t n_addr;
/** How many relay data cells can we package (read from edge streams)
* on this circuit before we receive a circuit-level sendme cell asking
* for more? */
@@ -1096,48 +1190,12 @@ struct circuit_t {
* more. */
int deliver_window;
- /** The circuit_id used in the previous (backward) hop of this circuit. */
- uint16_t p_circ_id;
- /** The circuit_id used in the next (forward) hop of this circuit. */
- uint16_t n_circ_id;
-
- /** The cipher used by intermediate hops for cells heading toward the
- * OP. */
- crypto_cipher_env_t *p_crypto;
- /** The cipher used by intermediate hops for cells heading away from
- * the OP. */
- crypto_cipher_env_t *n_crypto;
-
- /** The integrity-checking digest used by intermediate hops, for
- * cells packaged here and heading towards the OP.
- */
- crypto_digest_env_t *p_digest;
- /** The integrity-checking digest used by intermediate hops, for
- * cells packaged at the OP and arriving here.
- */
- crypto_digest_env_t *n_digest;
-
- /** Build state for this circuit. It includes the intended path
- * length, the chosen exit router, rendezvous information, etc.
- */
- cpath_build_state_t *build_state;
- /** The doubly-linked list of crypt_path_t entries, one per hop,
- * for this circuit. This includes ciphers for each hop,
- * integrity-checking digests for each hop, and package/delivery
- * windows for each hop.
- *
- * The cpath field is defined only when we are the circuit's origin.
- */
- crypt_path_t *cpath;
-
/** For storage while passing to cpuworker (state
* CIRCUIT_STATE_ONIONSKIN_PENDING), or while n_conn is pending
* (state CIRCUIT_STATE_OR_WAIT). When defined, it is always
* length ONIONSKIN_CHALLENGE_LEN. */
char *onionskin;
- char handshake_digest[DIGEST_LEN]; /**< Stores KH for intermediate hops. */
-
time_t timestamp_created; /**< When was this circuit created? */
time_t timestamp_dirty; /**< When the circuit was first used, or 0 if the
* circuit is clean. */
@@ -1151,35 +1209,129 @@ struct circuit_t {
const char *marked_for_close_file; /**< For debugging: in which file was this
* circuit marked for close? */
- /**
- * The rend_query field holds the y portion of y.onion (nul-terminated)
- * if purpose is C_INTRODUCING or C_ESTABLISH_REND, or is a C_GENERAL
- * for a hidden service, or is S_*.
+ struct circuit_t *next; /**< Next circuit in linked list. */
+} circuit_t;
+
+/** An origin_circuit_t holds data necessary to build and use a circuit.
+ */
+typedef struct origin_circuit_t {
+ circuit_t _base;
+
+ /** Linked list of AP streams (or EXIT streams if hidden service)
+ * associated with this circuit. */
+ edge_connection_t *p_streams;
+ /** Build state for this circuit. It includes the intended path
+ * length, the chosen exit router, rendezvous information, etc.
*/
- char rend_query[REND_SERVICE_ID_LEN+1];
+ cpath_build_state_t *build_state;
+ /** The doubly-linked list of crypt_path_t entries, one per hop,
+ * for this circuit. This includes ciphers for each hop,
+ * integrity-checking digests for each hop, and package/delivery
+ * windows for each hop.
+ *
+ * The cpath field is defined only when we are the circuit's origin.
+ */
+ crypt_path_t *cpath;
/** The rend_pk_digest field holds a hash of location-hidden service's
- * PK if purpose is INTRO_POINT or S_ESTABLISH_INTRO or S_RENDEZVOUSING.
+ * PK if purpose is S_ESTABLISH_INTRO or S_RENDEZVOUSING.
*/
char rend_pk_digest[DIGEST_LEN];
- /** Holds rendezvous cookie if purpose is REND_POINT_WAITING or
- * C_ESTABLISH_REND. Filled with zeroes otherwise.
+ /** Holds rendezvous cookie if purpose is C_ESTABLISH_REND. Filled with
+ * zeroes otherwise.
*/
char rend_cookie[REND_COOKIE_LEN];
- /** Points to spliced circuit if purpose is REND_ESTABLISHED, and circuit
- * is not marked for close. */
- struct circuit_t *rend_splice;
+ /**
+ * The rend_query field holds the y portion of y.onion (nul-terminated)
+ * if purpose is C_INTRODUCING or C_ESTABLISH_REND, or is a C_GENERAL
+ * for a hidden service, or is S_*.
+ */
+ char rend_query[REND_SERVICE_ID_LEN+1];
+
+ /** The next stream_id that will be tried when we're attempting to
+ * construct a new AP stream originating at this circuit. */
+ uint16_t next_stream_id;
/** Quasi-global identifier for this circuit; used for control.c */
/* XXXX NM This can get re-used after 2**32 circuits. */
uint32_t global_identifier;
- struct circuit_t *next; /**< Next circuit in linked list. */
-};
+} origin_circuit_t;
+
+/** An or_circuit_t holds information needed to implement a circuit at an
+ * OR. */
+typedef struct or_circuit_t {
+ circuit_t _base;
+
+ /** The circuit_id used in the previous (backward) hop of this circuit. */
+ circid_t p_circ_id;
+ /** The OR connection that is previous in this circuit. */
+ or_connection_t *p_conn;
+ /** Linked list of Exit streams associated with this circuit. */
+ edge_connection_t *n_streams;
+ /** Linked list of Exit streams associated with this circuit that are
+ * still being resolved. */
+ edge_connection_t *resolving_streams;
+ /** The cipher used by intermediate hops for cells heading toward the
+ * OP. */
+ crypto_cipher_env_t *p_crypto;
+ /** The cipher used by intermediate hops for cells heading away from
+ * the OP. */
+ crypto_cipher_env_t *n_crypto;
+
+ /** The integrity-checking digest used by intermediate hops, for
+ * cells packaged here and heading towards the OP.
+ */
+ crypto_digest_env_t *p_digest;
+ /** The integrity-checking digest used by intermediate hops, for
+ * cells packaged at the OP and arriving here.
+ */
+ crypto_digest_env_t *n_digest;
+
+ /** Points to spliced circuit if purpose is REND_ESTABLISHED, and circuit
+ * is not marked for close. */
+ struct or_circuit_t *rend_splice;
+
+#if REND_COOKIE_LEN >= DIGEST_LEN
+#define REND_TOKEN_LEN REND_COOKIE_LEN
+#else
+#define REND_TOKEN_LEN DIGEST_LEN
+#endif
-typedef struct circuit_t circuit_t;
+ /** A hash of location-hidden service's PK if purpose is INTRO_POINT, or a
+ * rendezvous cookie if purpose is REND_POINT_WAITING. Filled with zeroes
+ * otherwise.
+ */
+ char rend_token[REND_TOKEN_LEN];
+
+ char handshake_digest[DIGEST_LEN]; /**< Stores KH for the handshake. */
+} or_circuit_t;
+
+/** Convert a circuit subtype to a circuit_t.*/
+#define TO_CIRCUIT(x) (&((x)->_base))
+
+/** Convert a circuit_t* to a pointer to the enclosing or_circuit_t. Asserts
+ * if the cast is impossible. */
+static or_circuit_t *TO_OR_CIRCUIT(circuit_t *);
+/** Convert a circuit_t* to a pointer to the enclosing origin_circuit_t.
+ * Asserts if the cast is impossible. */
+static origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *);
+
+static INLINE or_circuit_t *TO_OR_CIRCUIT(circuit_t *x)
+{
+ tor_assert(x->magic == OR_CIRCUIT_MAGIC);
+ //return (or_circuit_t*) (((char*)x) - STRUCT_OFFSET(or_circuit_t, _base));
+ return DOWNCAST(or_circuit_t, x);
+}
+static INLINE origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *x)
+{
+ tor_assert(x->magic == ORIGIN_CIRCUIT_MAGIC);
+ //return (origin_circuit_t*)
+ // (((char*)x) - STRUCT_OFFSET(origin_circuit_t, _base));
+ return DOWNCAST(origin_circuit_t, x);
+}
#define ALLOW_INVALID_ENTRY 1
#define ALLOW_INVALID_EXIT 2
@@ -1254,6 +1406,8 @@ typedef struct {
config_line_t *DirPolicy; /**< Lists of dir policy components */
/** Addresses to bind for listening for SOCKS connections. */
config_line_t *SocksListenAddress;
+ /** Addresses to bind for listening for transparent connections. */
+ config_line_t *TransListenAddress;
/** Addresses to bind for listening for OR connections. */
config_line_t *ORListenAddress;
/** Addresses to bind for listening for directory connections. */
@@ -1275,6 +1429,7 @@ typedef struct {
* length (alpha in geometric distribution). */
int ORPort; /**< Port to listen on for OR connections. */
int SocksPort; /**< Port to listen on for SOCKS connections. */
+ int TransPort; /**< Port to listen on for transparent connections. */
int ControlPort; /**< Port to listen on for control connections. */
int DirPort; /**< Port to listen on for directory connections. */
int AssumeReachable; /**< Whether to publish our descriptor regardless. */
@@ -1286,6 +1441,8 @@ typedef struct {
int VersioningAuthoritativeDir; /**< Boolean: is this an authoritative
* directory that's willing to recommend
* versions? */
+ int AvoidDiskWrites; /**< Boolean: should we never cache things to disk?
+ * Not used yet. */
int ClientOnly; /**< Boolean: should we never evolve into a server role? */
int NoPublish; /**< Boolean: should we never publish a descriptor? */
int PublishServerDescriptor; /**< Do we publish our descriptor as normal? */
@@ -1314,12 +1471,8 @@ typedef struct {
int TrackHostExitsExpire; /**< Number of seconds until we expire an
* addressmap */
config_line_t *AddressMap; /**< List of address map directives. */
- int DirFetchPeriod; /**< How often do we fetch new directories? */
- int DirPostPeriod; /**< How often do we post our server descriptor to the
- * authoritative directory servers? */
int RendPostPeriod; /**< How often do we post each rendezvous service
* descriptor? Remember to publish them independently. */
- int StatusFetchPeriod; /**< How often do we fetch running-routers lists? */
int KeepalivePeriod; /**< How often do we send padding cells to keep
* connections alive? */
int SocksTimeout; /**< How long do we let a socks connection wait
@@ -1341,6 +1494,10 @@ typedef struct {
* to use in a second? */
uint64_t MaxAdvertisedBandwidth; /**< How much bandwidth are we willing to
* tell people we have? */
+ uint64_t RelayBandwidthRate; /**< How much bandwidth, on average, are we
+ * willing to use for all relayed conns? */
+ uint64_t RelayBandwidthBurst; /**< How much bandwidth, at maximum, will we
+ * use in a second for all relayed conns? */
int NumCpus; /**< How many CPUs should we try to use? */
int RunTesting; /**< If true, create testing circuits to measure how well the
* other ORs are running. */
@@ -1414,6 +1571,14 @@ typedef struct {
char *VirtualAddrNetwork; /**< Address and mask to hand out for virtual
* MAPADDRESS requests. */
+ int ServerDNSSearchDomains; /**< Boolean: If set, we don't force exit
+ * addresses to be FQDNs, but rather search for them in
+ * the local domains. */
+ int ServerDNSDetectHijacking; /**< Boolean: If true, check for DNS failure
+ * hijacking */
+ char *ServerDNSResolvConfFile; /**< If provided, we configure our internal
+ * resolver from the file here rather than from
+ * /etc/resolv.conf (unix) or the registry (windows) */
} or_options_t;
/** Persistent state for an onion router, as saved to disk. */
@@ -1447,6 +1612,7 @@ typedef struct {
#define MAX_SOCKS_ADDR_LEN 256
#define SOCKS_COMMAND_CONNECT 0x01
#define SOCKS_COMMAND_RESOLVE 0xF0
+#define SOCKS_COMMAND_RESOLVE_PTR 0xF1
/** State of a SOCKS request from a user to an OP */
struct socks_request_t {
char socks_version; /**< Which version of SOCKS did the client use? */
@@ -1485,6 +1651,8 @@ int flush_buf(int s, buf_t *buf, size_t sz, size_t *buf_flushlen);
int flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t sz, size_t *buf_flushlen);
int write_to_buf(const char *string, size_t string_len, buf_t *buf);
+int write_to_buf_zlib(buf_t *buf, tor_zlib_state_t *state,
+ const char *data, size_t data_len, int done);
int fetch_from_buf(char *string, size_t string_len, buf_t *buf);
int fetch_from_buf_http(buf_t *buf,
char **headers_out, size_t max_headerlen,
@@ -1500,32 +1668,34 @@ void assert_buf_ok(buf_t *buf);
/********************************* circuitbuild.c **********************/
-char *circuit_list_path(circuit_t *circ, int verbose);
-void circuit_log_path(int severity, unsigned int domain, circuit_t *circ);
-void circuit_rep_hist_note_result(circuit_t *circ);
-void circuit_dump_by_conn(connection_t *conn, int severity);
-circuit_t *circuit_init(uint8_t purpose, int need_uptime,
- int need_capacity, int internal);
-circuit_t *circuit_establish_circuit(uint8_t purpose, extend_info_t *exit,
+char *circuit_list_path(origin_circuit_t *circ, int verbose);
+void circuit_log_path(int severity, unsigned int domain,
+ origin_circuit_t *circ);
+void circuit_rep_hist_note_result(origin_circuit_t *circ);
+origin_circuit_t *origin_circuit_init(uint8_t purpose, int need_uptime,
+ int need_capacity, int internal);
+origin_circuit_t *circuit_establish_circuit(uint8_t purpose,
+ extend_info_t *exit,
int need_uptime, int need_capacity,
int internal);
-int circuit_handle_first_hop(circuit_t *circ);
-void circuit_n_conn_done(connection_t *or_conn, int status);
+int circuit_handle_first_hop(origin_circuit_t *circ);
+void circuit_n_conn_done(or_connection_t *or_conn, int status);
int inform_testing_reachability(void);
-int circuit_send_next_onion_skin(circuit_t *circ);
+int circuit_send_next_onion_skin(origin_circuit_t *circ);
void circuit_note_clock_jumped(int seconds_elapsed);
int circuit_extend(cell_t *cell, circuit_t *circ);
int circuit_init_cpath_crypto(crypt_path_t *cpath, char *key_data,
int reverse);
-int circuit_finish_handshake(circuit_t *circ, uint8_t cell_type, char *reply);
-int circuit_truncated(circuit_t *circ, crypt_path_t *layer);
-int onionskin_answer(circuit_t *circ, uint8_t cell_type, char *payload,
+int circuit_finish_handshake(origin_circuit_t *circ, uint8_t cell_type,
+ char *reply);
+int circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer);
+int onionskin_answer(or_circuit_t *circ, uint8_t cell_type, char *payload,
char *keys);
int circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
int *need_capacity);
-int circuit_append_new_exit(circuit_t *circ, extend_info_t *info);
-int circuit_extend_to_new_exit(circuit_t *circ, extend_info_t *info);
+int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info);
+int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info);
void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop);
extend_info_t *extend_info_from_router(routerinfo_t *r);
extend_info_t *extend_info_dup(extend_info_t *info);
@@ -1546,24 +1716,29 @@ void entry_guards_free_all(void);
circuit_t * _circuit_get_global_list(void);
const char *circuit_state_to_string(int state);
-enum which_conn_changed_t { P_CONN_CHANGED=1, N_CONN_CHANGED=0 };
-void circuit_set_circid_orconn(circuit_t *circ, uint16_t id,
- connection_t *conn,
- enum which_conn_changed_t which);
+void circuit_dump_by_conn(connection_t *conn, int severity);
+void circuit_set_p_circid_orconn(or_circuit_t *circ, uint16_t id,
+ or_connection_t *conn);
+void circuit_set_n_circid_orconn(circuit_t *circ, uint16_t id,
+ or_connection_t *conn);
void circuit_set_state(circuit_t *circ, int state);
void circuit_close_all_marked(void);
-circuit_t *circuit_new(uint16_t p_circ_id, connection_t *p_conn);
-circuit_t *circuit_get_by_circid_orconn(uint16_t circ_id, connection_t *conn);
-int circuit_id_used_on_conn(uint16_t circ_id, connection_t *conn);
-circuit_t *circuit_get_by_edge_conn(connection_t *conn);
-void circuit_unlink_all_from_or_conn(connection_t *conn, int reason);
-circuit_t *circuit_get_by_global_id(uint32_t id);
-circuit_t *circuit_get_by_rend_query_and_purpose(const char *rend_query,
- uint8_t purpose);
-circuit_t *circuit_get_next_by_pk_and_purpose(circuit_t *start,
+origin_circuit_t *origin_circuit_new(void);
+or_circuit_t *or_circuit_new(uint16_t p_circ_id, or_connection_t *p_conn);
+circuit_t *circuit_get_by_circid_orconn(uint16_t circ_id,
+ or_connection_t *conn);
+int circuit_id_used_on_conn(uint16_t circ_id, or_connection_t *conn);
+circuit_t *circuit_get_by_edge_conn(edge_connection_t *conn);
+void circuit_unlink_all_from_or_conn(or_connection_t *conn, int reason);
+origin_circuit_t *circuit_get_by_global_id(uint32_t id);
+origin_circuit_t *circuit_get_by_rend_query_and_purpose(const char *rend_query,
+ uint8_t purpose);
+origin_circuit_t *circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
const char *digest, uint8_t purpose);
-circuit_t *circuit_get_rendezvous(const char *cookie);
-circuit_t *circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
+or_circuit_t *circuit_get_rendezvous(const char *cookie);
+or_circuit_t *circuit_get_intro_point(const char *digest);
+origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose,
+ extend_info_t *info,
int need_uptime,
int need_capacity, int internal);
void circuit_mark_all_unused_circs(void);
@@ -1582,32 +1757,36 @@ void circuit_free_all(void);
void circuit_expire_building(time_t now);
void circuit_remove_handled_ports(smartlist_t *needed_ports);
-int circuit_stream_is_being_handled(connection_t *conn, uint16_t port,
+int circuit_stream_is_being_handled(edge_connection_t *conn, uint16_t port,
int min);
void circuit_build_needed_circs(time_t now);
-void circuit_detach_stream(circuit_t *circ, connection_t *conn);
+void circuit_detach_stream(circuit_t *circ, edge_connection_t *conn);
void circuit_about_to_close_connection(connection_t *conn);
-void circuit_has_opened(circuit_t *circ);
-void circuit_build_failed(circuit_t *circ);
-circuit_t *circuit_launch_by_nickname(uint8_t purpose,
+
+void reset_bandwidth_test(void);
+int circuit_enough_testing_circs(void);
+
+void circuit_has_opened(origin_circuit_t *circ);
+void circuit_build_failed(origin_circuit_t *circ);
+origin_circuit_t *circuit_launch_by_nickname(uint8_t purpose,
const char *exit_nickname,
int need_uptime, int need_capacity,
int is_internal);
-circuit_t *circuit_launch_by_extend_info(uint8_t purpose,
+origin_circuit_t *circuit_launch_by_extend_info(uint8_t purpose,
extend_info_t *info,
int need_uptime, int need_capacity,
int is_internal);
-circuit_t *circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit,
+origin_circuit_t *circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit,
int need_uptime, int need_capacity,
int is_internal);
void circuit_reset_failure_count(int timeout);
-int connection_ap_handshake_attach_chosen_circuit(connection_t *conn,
- circuit_t *circ);
-int connection_ap_handshake_attach_circuit(connection_t *conn);
+int connection_ap_handshake_attach_chosen_circuit(edge_connection_t *conn,
+ origin_circuit_t *circ);
+int connection_ap_handshake_attach_circuit(edge_connection_t *conn);
/********************************* command.c ***************************/
-void command_process_cell(cell_t *cell, connection_t *conn);
+void command_process_cell(cell_t *cell, or_connection_t *conn);
extern uint64_t stats_n_padding_cells_processed;
extern uint64_t stats_n_create_cells_processed;
@@ -1627,8 +1806,8 @@ int config_get_lines(char *string, config_line_t **result);
void config_free_lines(config_line_t *front);
int options_trial_assign(config_line_t *list, int use_defaults,
int clear_first, char **msg);
-int resolve_my_address(or_options_t *options, uint32_t *addr,
- char **hostname_out);
+int resolve_my_address(int warn_severity, or_options_t *options,
+ uint32_t *addr, char **hostname_out);
void options_init(or_options_t *options);
int options_init_from_torrc(int argc, char **argv);
int options_init_logs(or_options_t *options, int validate_only);
@@ -1681,13 +1860,16 @@ int connection_fetch_from_buf(char *string, size_t len, connection_t *conn);
int connection_wants_to_flush(connection_t *conn);
int connection_outbuf_too_full(connection_t *conn);
int connection_handle_write(connection_t *conn);
-void _connection_controller_force_write(connection_t *conn);
+void _connection_controller_force_write(control_connection_t *conn);
void connection_write_to_buf(const char *string, size_t len,
connection_t *conn);
+void connection_write_to_buf_zlib(dir_connection_t *conn,
+ const char *data, size_t data_len,
+ int done);
-connection_t *connection_or_exact_get_by_addr_port(uint32_t addr,
+or_connection_t *connection_or_exact_get_by_addr_port(uint32_t addr,
uint16_t port);
-connection_t *connection_get_by_global_id(uint32_t id);
+edge_connection_t *connection_get_by_global_id(uint32_t id);
connection_t *connection_get_by_type(int type);
connection_t *connection_get_by_type_purpose(int type, int purpose);
@@ -1706,46 +1888,50 @@ int connection_state_is_connecting(connection_t *conn);
char *alloc_http_authenticator(const char *authenticator);
void assert_connection_ok(connection_t *conn, time_t now);
-int connection_or_nonopen_was_started_here(connection_t *conn);
+int connection_or_nonopen_was_started_here(or_connection_t *conn);
/********************************* connection_edge.c *************************/
#define connection_mark_unattached_ap(conn, endreason) \
_connection_mark_unattached_ap((conn), (endreason), __LINE__, _SHORT_FILE_)
-void _connection_mark_unattached_ap(connection_t *conn, int endreason,
+void _connection_mark_unattached_ap(edge_connection_t *conn, int endreason,
int line, const char *file);
-int connection_edge_reached_eof(connection_t *conn);
-int connection_edge_process_inbuf(connection_t *conn, int package_partial);
-int connection_edge_destroy(uint16_t circ_id, connection_t *conn);
-int connection_edge_end(connection_t *conn, char reason,
+int connection_edge_reached_eof(edge_connection_t *conn);
+int connection_edge_process_inbuf(edge_connection_t *conn,
+ int package_partial);
+int connection_edge_destroy(uint16_t circ_id, edge_connection_t *conn);
+int connection_edge_end(edge_connection_t *conn, char reason,
crypt_path_t *cpath_layer);
-int connection_edge_end_errno(connection_t *conn, crypt_path_t *cpath_layer);
-int connection_edge_finished_flushing(connection_t *conn);
-int connection_edge_finished_connecting(connection_t *conn);
+int connection_edge_end_errno(edge_connection_t *conn,
+ crypt_path_t *cpath_layer);
+int connection_edge_finished_flushing(edge_connection_t *conn);
+int connection_edge_finished_connecting(edge_connection_t *conn);
-int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ);
-int connection_ap_handshake_send_resolve(connection_t *ap_conn,
- circuit_t *circ);
+int connection_ap_handshake_send_begin(edge_connection_t *ap_conn,
+ origin_circuit_t *circ);
+int connection_ap_handshake_send_resolve(edge_connection_t *ap_conn,
+ origin_circuit_t *circ);
int connection_ap_make_bridge(char *address, uint16_t port);
-void connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
+void connection_ap_handshake_socks_reply(edge_connection_t *conn, char *reply,
size_t replylen,
socks5_reply_status_t status);
-void connection_ap_handshake_socks_resolved(connection_t *conn,
+void connection_ap_handshake_socks_resolved(edge_connection_t *conn,
int answer_type,
size_t answer_len,
const char *answer,
int ttl);
int connection_exit_begin_conn(cell_t *cell, circuit_t *circ);
-int connection_exit_begin_resolve(cell_t *cell, circuit_t *circ);
-void connection_exit_connect(connection_t *conn);
-int connection_edge_is_rendezvous_stream(connection_t *conn);
-int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit);
+int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ);
+void connection_exit_connect(edge_connection_t *conn);
+int connection_edge_is_rendezvous_stream(edge_connection_t *conn);
+int connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit);
void connection_ap_expire_beginning(void);
void connection_ap_attach_pending(void);
-int connection_ap_detach_retriable(connection_t *conn, circuit_t *circ);
+int connection_ap_detach_retriable(edge_connection_t *conn,
+ origin_circuit_t *circ);
void addressmap_init(void);
void addressmap_clean(time_t now);
@@ -1753,7 +1939,7 @@ void addressmap_clear_configured(void);
void addressmap_clear_transient(void);
void addressmap_free_all(void);
void addressmap_rewrite(char *address, size_t maxlen);
-int addressmap_already_mapped(const char *address);
+int addressmap_have_mapping(const char *address);
void addressmap_register(const char *address, char *new_address,
time_t expires);
int parse_virtual_addr_network(const char *val, int validate_only,
@@ -1766,8 +1952,8 @@ int address_is_in_virtual_range(const char *addr);
const char *addressmap_register_virtual_address(int type, char *new_address);
void addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
time_t max_expires);
-int connection_ap_handshake_rewrite_and_attach(connection_t *conn,
- circuit_t *circ);
+int connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
+ origin_circuit_t *circ);
void set_exit_redirects(smartlist_t *lst);
typedef enum hostname_type_t {
@@ -1777,23 +1963,24 @@ hostname_type_t parse_extended_hostname(char *address);
/********************************* connection_or.c ***************************/
-void connection_or_remove_from_identity_map(connection_t *conn);
+void connection_or_remove_from_identity_map(or_connection_t *conn);
void connection_or_clear_identity_map(void);
-connection_t *connection_or_get_by_identity_digest(const char *digest);
+or_connection_t *connection_or_get_by_identity_digest(const char *digest);
-int connection_or_reached_eof(connection_t *conn);
-int connection_or_process_inbuf(connection_t *conn);
-int connection_or_finished_flushing(connection_t *conn);
-int connection_or_finished_connecting(connection_t *conn);
+int connection_or_reached_eof(or_connection_t *conn);
+int connection_or_process_inbuf(or_connection_t *conn);
+int connection_or_finished_flushing(or_connection_t *conn);
+int connection_or_finished_connecting(or_connection_t *conn);
-connection_t *connection_or_connect(uint32_t addr, uint16_t port,
+or_connection_t *connection_or_connect(uint32_t addr, uint16_t port,
const char *id_digest);
-int connection_tls_start_handshake(connection_t *conn, int receiving);
-int connection_tls_continue_handshake(connection_t *conn);
+int connection_tls_start_handshake(or_connection_t *conn, int receiving);
+int connection_tls_continue_handshake(or_connection_t *conn);
-void connection_or_write_cell_to_buf(const cell_t *cell, connection_t *conn);
-int connection_or_send_destroy(uint16_t circ_id, connection_t *conn,
+void connection_or_write_cell_to_buf(const cell_t *cell,
+ or_connection_t *conn);
+int connection_or_send_destroy(uint16_t circ_id, or_connection_t *conn,
int reason);
/********************************* control.c ***************************/
@@ -1852,13 +2039,16 @@ void control_adjust_event_log_severity(void);
#define LOG_FN_CONN(conn, args) \
CONN_LOG_PROTECT(conn, log_fn args)
-int connection_control_finished_flushing(connection_t *conn);
-int connection_control_reached_eof(connection_t *conn);
-int connection_control_process_inbuf(connection_t *conn);
+int connection_control_finished_flushing(control_connection_t *conn);
+int connection_control_reached_eof(control_connection_t *conn);
+int connection_control_process_inbuf(control_connection_t *conn);
-int control_event_circuit_status(circuit_t *circ, circuit_status_event_t e);
-int control_event_stream_status(connection_t *conn, stream_status_event_t e);
-int control_event_or_conn_status(connection_t *conn, or_conn_status_event_t e);
+int control_event_circuit_status(origin_circuit_t *circ,
+ circuit_status_event_t e);
+int control_event_stream_status(edge_connection_t *conn,
+ stream_status_event_t e);
+int control_event_or_conn_status(or_connection_t *conn,
+ or_conn_status_event_t e);
int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written);
void control_event_logmsg(int severity, unsigned int domain, const char *msg);
int control_event_descriptors_changed(smartlist_t *routers);
@@ -1904,20 +2094,21 @@ void directory_initiate_command_routerstatus(routerstatus_t *status,
int parse_http_response(const char *headers, int *code, time_t *date,
int *compression, char **response);
-int connection_dir_reached_eof(connection_t *conn);
-int connection_dir_process_inbuf(connection_t *conn);
-int connection_dir_finished_flushing(connection_t *conn);
-int connection_dir_finished_connecting(connection_t *conn);
-void connection_dir_request_failed(connection_t *conn);
+int connection_dir_reached_eof(dir_connection_t *conn);
+int connection_dir_process_inbuf(dir_connection_t *conn);
+int connection_dir_finished_flushing(dir_connection_t *conn);
+int connection_dir_finished_connecting(dir_connection_t *conn);
+void connection_dir_request_failed(dir_connection_t *conn);
int dir_split_resource_into_fingerprints(const char *resource,
smartlist_t *fp_out, int *compresseed_out,
- int decode_hex);
+ int decode_hex, int sort_uniq);
char *directory_dump_request_log(void);
/********************************* dirserv.c ***************************/
+int connection_dirserv_flushed_some(dir_connection_t *conn);
int dirserv_add_own_fingerprint(const char *nickname, crypto_pk_env_t *pk);
-int dirserv_parse_fingerprint_file(const char *fname);
+int dirserv_load_fingerprint_file(void);
void dirserv_free_fingerprint_list(void);
const char *dirserv_get_nickname_by_digest(const char *digest);
int dirserv_add_descriptor(const char *desc, const char **msg);
@@ -1927,9 +2118,10 @@ int dirserv_thinks_router_is_blatantly_unreachable(routerinfo_t *router,
time_t now);
int list_server_status(smartlist_t *routers, char **router_status_out);
int dirserv_dump_directory_to_string(char **dir_out,
- crypto_pk_env_t *private_key);
+ crypto_pk_env_t *private_key,
+ int complete);
void directory_set_dirty(void);
-size_t dirserv_get_directory(const char **cp, int compress);
+cached_dir_t *dirserv_get_directory(void);
size_t dirserv_get_runningrouters(const char **rr, int compress);
void dirserv_set_cached_directory(const char *directory, time_t when,
int is_running_routers);
@@ -1937,6 +2129,10 @@ void dirserv_set_cached_networkstatus_v2(const char *directory,
const char *identity,
time_t published);
void dirserv_get_networkstatus_v2(smartlist_t *result, const char *key);
+void dirserv_get_networkstatus_v2_fingerprints(smartlist_t *result,
+ const char *key);
+int dirserv_get_routerdesc_fingerprints(smartlist_t *fps_out, const char *key,
+ const char **msg);
int dirserv_get_routerdescs(smartlist_t *descs_out, const char *key,
const char **msg);
void dirserv_orconn_tls_done(const char *address,
@@ -1944,24 +2140,28 @@ void dirserv_orconn_tls_done(const char *address,
const char *digest_rcvd,
const char *nickname,
int as_advertised);
+void dirserv_test_reachability(int try_all);
int authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg,
int complain);
int dirserv_would_reject_router(routerstatus_t *rs);
void dirserv_free_all(void);
+void cached_dir_decref(cached_dir_t *d);
/********************************* dns.c ***************************/
-void dns_init(void);
+int dns_init(void);
void dns_free_all(void);
+uint32_t dns_clip_ttl(uint32_t ttl);
int connection_dns_finished_flushing(connection_t *conn);
int connection_dns_reached_eof(connection_t *conn);
int connection_dns_process_inbuf(connection_t *conn);
-void dnsworkers_rotate(void);
-void connection_dns_remove(connection_t *conn);
-void assert_connection_edge_not_dns_pending(connection_t *conn);
+void dns_reset(void);
+void connection_dns_remove(edge_connection_t *conn);
+void assert_connection_edge_not_dns_pending(edge_connection_t *conn);
void assert_all_pending_dns_resolves_ok(void);
-void dns_cancel_pending_resolve(char *question);
-int dns_resolve(connection_t *exitconn);
+void dns_cancel_pending_resolve(const char *question);
+int dns_resolve(edge_connection_t *exitconn);
+void dns_launch_wildcard_checks(void);
/********************************* hibernate.c **********************/
@@ -1979,6 +2179,8 @@ void accounting_set_bandwidth_usage_from_state(or_state_t *state);
/********************************* main.c ***************************/
+extern int has_completed_circuit;
+
int connection_add(connection_t *conn);
int connection_remove(connection_t *conn);
int connection_in_array(connection_t *conn);
@@ -1999,7 +2201,8 @@ void connection_start_writing(connection_t *conn);
void directory_all_unreachable(time_t now);
void directory_info_has_arrived(time_t now, int from_cache);
-int control_signal_act(int the_signal);
+int control_signal_check(int the_signal);
+void control_signal_act(int the_signal);
void handle_signals(int is_parent);
void tor_cleanup(void);
void tor_free_all(int postfork);
@@ -2008,9 +2211,9 @@ int tor_main(int argc, char *argv[]);
/********************************* onion.c ***************************/
-int onion_pending_add(circuit_t *circ);
-circuit_t *onion_next_task(void);
-void onion_pending_remove(circuit_t *circ);
+int onion_pending_add(or_circuit_t *circ);
+or_circuit_t *onion_next_task(void);
+void onion_pending_remove(or_circuit_t *circ);
int onion_skin_create(crypto_pk_env_t *router_key,
crypto_dh_env_t **handshake_state_out,
@@ -2067,6 +2270,8 @@ int policies_parse_exit_policy(config_line_t *cfg,
addr_policy_t **dest,
int rejectprivate);
int exit_policy_is_general_exit(addr_policy_t *policy);
+int policy_is_reject_star(addr_policy_t *policy);
+int policies_getinfo_helper(const char *question, char **answer);
void addr_policy_free(addr_policy_t *p);
void policies_free_all(void);
@@ -2081,12 +2286,13 @@ int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
void relay_header_pack(char *dest, const relay_header_t *src);
void relay_header_unpack(relay_header_t *dest, const char *src);
-int connection_edge_send_command(connection_t *fromconn, circuit_t *circ,
+int connection_edge_send_command(edge_connection_t *fromconn, circuit_t *circ,
int relay_command, const char *payload,
size_t payload_len,
crypt_path_t *cpath_layer);
-int connection_edge_package_raw_inbuf(connection_t *conn, int package_partial);
-void connection_edge_consider_sending_sendme(connection_t *conn);
+int connection_edge_package_raw_inbuf(edge_connection_t *conn,
+ int package_partial);
+void connection_edge_consider_sending_sendme(edge_connection_t *conn);
socks5_reply_status_t connection_edge_end_reason_socks5_response(int reason);
int errno_to_end_reason(int e);
@@ -2110,6 +2316,8 @@ void rep_hist_note_bytes_read(int num_bytes, time_t when);
void rep_hist_note_bytes_written(int num_bytes, time_t when);
int rep_hist_bandwidth_assess(void);
char *rep_hist_get_bandwidth_lines(void);
+void rep_hist_update_state(or_state_t *state);
+int rep_hist_load_state(or_state_t *state, char **err);
void rep_history_clean(time_t before);
void rep_hist_note_used_port(uint16_t port, time_t now);
@@ -2120,8 +2328,8 @@ void rep_hist_note_used_internal(time_t now, int need_uptime,
int rep_hist_get_predicted_internal(time_t now, int *need_uptime,
int *need_capacity);
-void rep_hist_update_state(or_state_t *state);
-int rep_hist_load_state(or_state_t *state, char **err);
+int any_predicted_circuits(time_t now);
+int rep_hist_circbuilding_dormant(time_t now);
int any_predicted_circuits(time_t now);
@@ -2129,22 +2337,23 @@ void rep_hist_free_all(void);
/********************************* rendclient.c ***************************/
-void rend_client_introcirc_has_opened(circuit_t *circ);
-void rend_client_rendcirc_has_opened(circuit_t *circ);
-int rend_client_introduction_acked(circuit_t *circ, const char *request,
+void rend_client_introcirc_has_opened(origin_circuit_t *circ);
+void rend_client_rendcirc_has_opened(origin_circuit_t *circ);
+int rend_client_introduction_acked(origin_circuit_t *circ, const char *request,
size_t request_len);
void rend_client_refetch_renddesc(const char *query);
int rend_client_remove_intro_point(extend_info_t *failed_intro,
const char *query);
-int rend_client_rendezvous_acked(circuit_t *circ, const char *request,
+int rend_client_rendezvous_acked(origin_circuit_t *circ, const char *request,
size_t request_len);
-int rend_client_receive_rendezvous(circuit_t *circ, const char *request,
+int rend_client_receive_rendezvous(origin_circuit_t *circ, const char *request,
size_t request_len);
void rend_client_desc_here(const char *query);
extend_info_t *rend_client_get_random_intro(const char *query);
-int rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc);
+int rend_client_send_introduction(origin_circuit_t *introcirc,
+ origin_circuit_t *rendcirc);
/********************************* rendcommon.c ***************************/
@@ -2209,25 +2418,27 @@ void rend_services_init(void);
void rend_services_introduce(void);
void rend_consider_services_upload(time_t now);
-void rend_service_intro_has_opened(circuit_t *circuit);
-int rend_service_intro_established(circuit_t *circuit, const char *request,
+void rend_service_intro_has_opened(origin_circuit_t *circuit);
+int rend_service_intro_established(origin_circuit_t *circuit,
+ const char *request,
size_t request_len);
-void rend_service_rendezvous_has_opened(circuit_t *circuit);
-int rend_service_introduce(circuit_t *circuit, const char *request,
+void rend_service_rendezvous_has_opened(origin_circuit_t *circuit);
+int rend_service_introduce(origin_circuit_t *circuit, const char *request,
size_t request_len);
-void rend_service_relaunch_rendezvous(circuit_t *oldcirc);
-int rend_service_set_connection_addr_port(connection_t *conn, circuit_t *circ);
+void rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc);
+int rend_service_set_connection_addr_port(edge_connection_t *conn,
+ origin_circuit_t *circ);
void rend_service_dump_stats(int severity);
void rend_service_free_all(void);
/********************************* rendmid.c *******************************/
-int rend_mid_establish_intro(circuit_t *circ, const char *request,
+int rend_mid_establish_intro(or_circuit_t *circ, const char *request,
size_t request_len);
-int rend_mid_introduce(circuit_t *circ, const char *request,
+int rend_mid_introduce(or_circuit_t *circ, const char *request,
size_t request_len);
-int rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
+int rend_mid_establish_rendezvous(or_circuit_t *circ, const char *request,
size_t request_len);
-int rend_mid_rendezvous(circuit_t *circ, const char *request,
+int rend_mid_rendezvous(or_circuit_t *circ, const char *request,
size_t request_len);
/********************************* router.c ***************************/
@@ -2245,31 +2456,33 @@ int init_keys(void);
int check_whether_orport_reachable(void);
int check_whether_dirport_reachable(void);
-void consider_testing_reachability(void);
+void consider_testing_reachability(int test_or, int test_dir);
void router_orport_found_reachable(void);
void router_dirport_found_reachable(void);
void server_has_changed_ip(void);
-void consider_publishable_server(time_t now, int force);
+void router_perform_bandwidth_test(int num_circs, time_t now);
int authdir_mode(or_options_t *options);
int clique_mode(or_options_t *options);
int server_mode(or_options_t *options);
int advertised_server_mode(void);
int proxy_mode(or_options_t *options);
+void consider_publishable_server(int force);
-void router_retry_connections(int testing_reachability, int try_all);
int router_is_clique_mode(routerinfo_t *router);
void router_upload_dir_desc_to_dirservers(int force);
void mark_my_descriptor_dirty_if_older_than(time_t when);
void mark_my_descriptor_dirty(void);
void check_descriptor_bandwidth_changed(time_t now);
void check_descriptor_ipaddress_changed(time_t now);
-int router_compare_to_my_exit_policy(connection_t *conn);
+void router_new_address_suggestion(const char *suggestion);
+int router_compare_to_my_exit_policy(edge_connection_t *conn);
routerinfo_t *router_get_my_routerinfo(void);
const char *router_get_my_descriptor(void);
int router_digest_is_me(const char *digest);
int router_is_me(routerinfo_t *router);
int router_fingerprint_is_me(const char *fp);
+int router_pick_published_address(or_options_t *options, uint32_t *addr);
int router_rebuild_descriptor(int force);
int router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
crypto_pk_env_t *ident_key);
@@ -2360,10 +2573,11 @@ int router_add_to_routerlist(routerinfo_t *router, const char **msg,
int from_cache, int from_fetch);
int router_load_single_router(const char *s, uint8_t purpose,
const char **msg);
-void router_load_routers_from_string(const char *s, int from_cache,
+void router_load_routers_from_string(const char *s,
+ saved_location_t saved_location,
smartlist_t *requested_fingerprints);
typedef enum {
- NS_FROM_CACHE, NS_FROM_DIR, NS_GENERATED
+ NS_FROM_CACHE, NS_FROM_DIR_BY_FP, NS_FROM_DIR_ALL, NS_GENERATED
} networkstatus_source_t;
int router_set_networkstatus(const char *s, time_t arrived_at,
networkstatus_source_t source,
@@ -2409,9 +2623,6 @@ typedef struct tor_version_t {
* VER_RELEASE. */
enum { VER_PRE=0, VER_RC=1, VER_RELEASE=2, } status;
int patchlevel;
- /** CVS status. For version in the post-0.1 format, this is always
- * IS_NOT_CVS */
- enum { IS_CVS=0, IS_NOT_CVS=1} cvs;
char status_tag[MAX_STATUS_TAG_LEN];
} tor_version_t;
@@ -2432,7 +2643,8 @@ int router_append_dirobj_signature(char *buf, size_t buf_len,
const char *digest,
crypto_pk_env_t *private_key);
int router_parse_list_from_string(const char **s,
- smartlist_t *dest);
+ smartlist_t *dest,
+ saved_location_t saved_location);
int router_parse_routerlist_from_directory(const char *s,
routerlist_t **dest,
crypto_pk_env_t *pkey,
@@ -2440,7 +2652,8 @@ int router_parse_routerlist_from_directory(const char *s,
int write_to_cache);
int router_parse_runningrouters(const char *str);
int router_parse_directory(const char *str);
-routerinfo_t *router_parse_entry_from_string(const char *s, const char *end);
+routerinfo_t *router_parse_entry_from_string(const char *s, const char *end,
+ int cache_copy);
addr_policy_t *router_parse_addr_policy_from_string(const char *s,
int assume_action);
version_status_t tor_version_is_obsolete(const char *myversion,
diff --git a/src/or/policies.c b/src/or/policies.c
index b7946f9204..327af18d62 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -128,7 +128,7 @@ parse_reachable_addresses(void)
int
firewall_is_fascist_or(void)
{
- return !!reachable_or_addr_policy;
+ return reachable_or_addr_policy != NULL;
}
/** Return true iff <b>policy</b> (possibly NULL) will allow a
@@ -603,7 +603,7 @@ policies_parse_exit_policy(config_line_t *cfg, addr_policy_t **dest,
/** Return true iff <b>ri</b> is "useful as an exit node", meaning
* it allows exit to at least one /8 address space for at least
- * one of ports 80, 443, and 6667. */
+ * two of ports 80, 443, and 6667. */
int
exit_policy_is_general_exit(addr_policy_t *policy)
{
@@ -619,10 +619,40 @@ exit_policy_is_general_exit(addr_policy_t *policy)
if ((p->addr & 0xff000000ul) == 0x7f000000ul)
continue; /* 127.x */
/* We have a match that is at least a /8. */
- if (p->policy_type == ADDR_POLICY_ACCEPT)
- return 1;
+ if (p->policy_type == ADDR_POLICY_ACCEPT) {
+ ++n_allowed;
+ break; /* stop considering this port */
+ }
}
}
+ return n_allowed >= 2;
+}
+
+/** Return false if <b>policy</b> might permit access to some addr:port;
+ * otherwise if we are certain it rejects everything, return true. */
+int
+policy_is_reject_star(addr_policy_t *p)
+{
+ for ( ; p; p = p->next) {
+ if (p->policy_type == ADDR_POLICY_ACCEPT)
+ return 0;
+ else if (p->policy_type == ADDR_POLICY_REJECT &&
+ p->prt_min <= 1 && p->prt_max == 65535 &&
+ p->msk == 0)
+ return 1;
+ }
+ return 1;
+}
+
+int
+policies_getinfo_helper(const char *question, char **answer)
+{
+ if (!strcmp(question, "exit-policy/default")) {
+ *answer = tor_strdup(DEFAULT_EXIT_POLICY);
+// } else if (!strcmp(question, "exit-policy/prepend")) {
+ } else {
+ *answer = NULL;
+ }
return 0;
}
diff --git a/src/or/relay.c b/src/or/relay.c
index 8dbe4acc12..8d9ce04fb1 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -16,19 +16,19 @@ const char relay_c_id[] =
static int relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction,
crypt_path_t **layer_hint, char *recognized);
-static connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell,
+static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell,
int cell_direction);
static int
connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
- connection_t *conn,
+ edge_connection_t *conn,
crypt_path_t *layer_hint);
static void
circuit_consider_sending_sendme(circuit_t *circ, crypt_path_t *layer_hint);
static void
circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint);
static int
-circuit_resume_edge_reading_helper(connection_t *conn,
+circuit_resume_edge_reading_helper(edge_connection_t *conn,
circuit_t *circ,
crypt_path_t *layer_hint);
static int
@@ -144,7 +144,7 @@ relay_crypt_one_payload(crypto_cipher_env_t *cipher, char *in,
int
circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction)
{
- connection_t *conn=NULL;
+ or_connection_t *or_conn=NULL;
crypt_path_t *layer_hint=NULL;
char recognized=0;
int reason;
@@ -162,7 +162,7 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction)
}
if (recognized) {
- conn = relay_lookup_conn(circ, cell, cell_direction);
+ edge_connection_t *conn = relay_lookup_conn(circ, cell, cell_direction);
if (cell_direction == CELL_DIRECTION_OUT) {
++stats_n_relay_cells_delivered;
log_debug(LD_OR,"Sending away from origin.");
@@ -190,19 +190,25 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction)
/* not recognized. pass it on. */
if (cell_direction == CELL_DIRECTION_OUT) {
cell->circ_id = circ->n_circ_id; /* switch it */
- conn = circ->n_conn;
+ or_conn = circ->n_conn;
+ } else if (! CIRCUIT_IS_ORIGIN(circ)) {
+ cell->circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; /* switch it */
+ or_conn = TO_OR_CIRCUIT(circ)->p_conn;
} else {
- cell->circ_id = circ->p_circ_id; /* switch it */
- conn = circ->p_conn;
+ // XXXX NM WARN.
+ return 0;
}
- if (!conn) {
- if (circ->rend_splice && cell_direction == CELL_DIRECTION_OUT) {
+ if (!or_conn) {
+ // XXXX Can this splice stuff be done more cleanly?
+ if (! CIRCUIT_IS_ORIGIN(circ) &&
+ TO_OR_CIRCUIT(circ)->rend_splice &&
+ cell_direction == CELL_DIRECTION_OUT) {
+ or_circuit_t *splice = TO_OR_CIRCUIT(circ)->rend_splice;
tor_assert(circ->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED);
- tor_assert(circ->rend_splice->purpose ==
- CIRCUIT_PURPOSE_REND_ESTABLISHED);
- cell->circ_id = circ->rend_splice->p_circ_id;
- if ((reason = circuit_receive_relay_cell(cell, circ->rend_splice,
+ tor_assert(splice->_base.purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED);
+ cell->circ_id = splice->p_circ_id;
+ if ((reason = circuit_receive_relay_cell(cell, TO_CIRCUIT(splice),
CELL_DIRECTION_IN)) < 0) {
log_warn(LD_REND, "Error relaying cell across rendezvous; closing "
"circuits");
@@ -219,7 +225,7 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction)
log_debug(LD_OR,"Passing on unrecognized cell.");
++stats_n_relay_cells_relayed;
- connection_or_write_cell_to_buf(cell, conn);
+ connection_or_write_cell_to_buf(cell, or_conn);
return 0;
}
@@ -240,12 +246,10 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction)
* Return -1 to indicate that we should mark the circuit for close,
* else return 0.
*/
-/* wrap this into receive_relay_cell one day */
static int
relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction,
crypt_path_t **layer_hint, char *recognized)
{
- crypt_path_t *thishop;
relay_header_t rh;
tor_assert(circ);
@@ -257,8 +261,8 @@ relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction,
if (cell_direction == CELL_DIRECTION_IN) {
if (CIRCUIT_IS_ORIGIN(circ)) { /* We're at the beginning of the circuit.
* We'll want to do layered decrypts. */
- tor_assert(circ->cpath);
- thishop = circ->cpath;
+ crypt_path_t *thishop, *cpath = TO_ORIGIN_CIRCUIT(circ)->cpath;
+ thishop = cpath;
if (thishop->state != CPATH_STATE_OPEN) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Relay cell before first created cell? Closing.");
@@ -281,25 +285,27 @@ relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction,
}
thishop = thishop->next;
- } while (thishop != circ->cpath && thishop->state == CPATH_STATE_OPEN);
- log_warn(LD_OR,"in-cell at OP not recognized. Closing.");
+ } while (thishop != cpath && thishop->state == CPATH_STATE_OPEN);
+ log_warn(LD_OR,"in-cell at client not recognized. Closing.");
return -1;
} else { /* we're in the middle. Just one crypt. */
- if (relay_crypt_one_payload(circ->p_crypto, cell->payload, 1) < 0)
+ if (relay_crypt_one_payload(TO_OR_CIRCUIT(circ)->p_crypto,
+ cell->payload, 1) < 0)
return -1;
// log_fn(LOG_DEBUG,"Skipping recognized check, because we're not "
-// "the OP.");
+// "the client.");
}
} else /* cell_direction == CELL_DIRECTION_OUT */ {
/* we're in the middle. Just one crypt. */
- if (relay_crypt_one_payload(circ->n_crypto, cell->payload, 0) < 0)
+ if (relay_crypt_one_payload(TO_OR_CIRCUIT(circ)->n_crypto,
+ cell->payload, 0) < 0)
return -1;
relay_header_unpack(&rh, cell->payload);
if (rh.recognized == 0) {
/* it's possibly recognized. have to check digest to be sure. */
- if (relay_digest_matches(circ->n_digest, cell)) {
+ if (relay_digest_matches(TO_OR_CIRCUIT(circ)->n_digest, cell)) {
*recognized = 1;
return 0;
}
@@ -308,7 +314,7 @@ relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction,
return 0;
}
-/** Package a relay cell:
+/** Package a relay cell from an edge:
* - Encrypt it to the right layer
* - connection_or_write_cell_to_buf to the right conn
*/
@@ -317,12 +323,12 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
int cell_direction,
crypt_path_t *layer_hint)
{
- connection_t *conn; /* where to send the cell */
- crypt_path_t *thishop; /* counter for repeated crypts */
+ or_connection_t *conn; /* where to send the cell */
if (cell_direction == CELL_DIRECTION_OUT) {
+ crypt_path_t *thishop; /* counter for repeated crypts */
conn = circ->n_conn;
- if (!conn) {
+ if (!CIRCUIT_IS_ORIGIN(circ) || !conn) {
log_warn(LD_BUG,"outgoing relay cell has n_conn==NULL. Dropping.");
return 0; /* just drop it */
}
@@ -339,18 +345,20 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
}
thishop = thishop->prev;
- } while (thishop != circ->cpath->prev);
+ } while (thishop != TO_ORIGIN_CIRCUIT(circ)->cpath->prev);
} else { /* incoming cell */
- conn = circ->p_conn;
- if (!conn) {
+ or_circuit_t *or_circ;
+ if (CIRCUIT_IS_ORIGIN(circ)) {
/* XXXX RD This is a bug, right? */
- log_warn(LD_BUG,"incoming relay cell has p_conn==NULL. Dropping.");
+ log_warn(LD_BUG,"incoming relay cell at origin circuit. Dropping.");
assert_circuit_ok(circ);
return 0; /* just drop it */
}
- relay_set_digest(circ->p_digest, cell);
- if (relay_crypt_one_payload(circ->p_crypto, cell->payload, 1) < 0)
+ or_circ = TO_OR_CIRCUIT(circ);
+ conn = or_circ->p_conn;
+ relay_set_digest(or_circ->p_digest, cell);
+ if (relay_crypt_one_payload(or_circ->p_crypto, cell->payload, 1) < 0)
return -1;
}
++stats_n_relay_cells_relayed;
@@ -361,10 +369,10 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
/** If cell's stream_id matches the stream_id of any conn that's
* attached to circ, return that conn, else return NULL.
*/
-static connection_t *
+static edge_connection_t *
relay_lookup_conn(circuit_t *circ, cell_t *cell, int cell_direction)
{
- connection_t *tmpconn;
+ edge_connection_t *tmpconn;
relay_header_t rh;
relay_header_unpack(&rh, cell->payload);
@@ -376,25 +384,33 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell, int cell_direction)
* that we allow rendezvous *to* an OP.
*/
- for (tmpconn = circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream) {
- if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
- log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
- if (cell_direction == CELL_DIRECTION_OUT ||
- connection_edge_is_rendezvous_stream(tmpconn))
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ for (tmpconn = TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn;
+ tmpconn=tmpconn->next_stream) {
+ if (rh.stream_id == tmpconn->stream_id &&
+ !tmpconn->_base.marked_for_close) {
+ log_debug(LD_APP,"found conn for stream %d.", rh.stream_id);
return tmpconn;
+ }
}
- }
- for (tmpconn = circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream) {
- if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
- log_debug(LD_APP,"found conn for stream %d.", rh.stream_id);
- return tmpconn;
+ } else {
+ for (tmpconn = TO_OR_CIRCUIT(circ)->n_streams; tmpconn;
+ tmpconn=tmpconn->next_stream) {
+ if (rh.stream_id == tmpconn->stream_id &&
+ !tmpconn->_base.marked_for_close) {
+ log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
+ if (cell_direction == CELL_DIRECTION_OUT ||
+ connection_edge_is_rendezvous_stream(tmpconn))
+ return tmpconn;
+ }
}
- }
- for (tmpconn = circ->resolving_streams; tmpconn;
- tmpconn=tmpconn->next_stream) {
- if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
- log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
- return tmpconn;
+ for (tmpconn = TO_OR_CIRCUIT(circ)->resolving_streams; tmpconn;
+ tmpconn=tmpconn->next_stream) {
+ if (rh.stream_id == tmpconn->stream_id &&
+ !tmpconn->_base.marked_for_close) {
+ log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
+ return tmpconn;
+ }
}
}
return NULL; /* probably a begin relay cell */
@@ -439,30 +455,32 @@ relay_header_unpack(relay_header_t *dest, const char *src)
* return -1. Else return 0.
*/
int
-connection_edge_send_command(connection_t *fromconn, circuit_t *circ,
+connection_edge_send_command(edge_connection_t *fromconn, circuit_t *circ,
int relay_command, const char *payload,
size_t payload_len, crypt_path_t *cpath_layer)
{
cell_t cell;
relay_header_t rh;
int cell_direction;
+ /* XXXX NM Split this function into a separate versions per circuit type? */
- if (fromconn && fromconn->marked_for_close) {
+ if (fromconn && fromconn->_base.marked_for_close) {
log_warn(LD_BUG,
"Bug: called on conn that's already marked for close at %s:%d.",
- fromconn->marked_for_close_file, fromconn->marked_for_close);
+ fromconn->_base.marked_for_close_file,
+ fromconn->_base.marked_for_close);
return 0;
}
if (!circ) {
tor_assert(fromconn);
- if (fromconn->type == CONN_TYPE_AP) {
+ if (fromconn->_base.type == CONN_TYPE_AP) {
log_info(LD_APP,"no circ. Closing conn.");
connection_mark_unattached_ap(fromconn, END_STREAM_REASON_INTERNAL);
} else {
log_info(LD_EXIT,"no circ. Closing conn.");
- fromconn->has_sent_end = 1; /* no circ to send to */
- connection_mark_for_close(fromconn);
+ fromconn->_base.edge_has_sent_end = 1; /* no circ to send to */
+ connection_mark_for_close(TO_CONN(fromconn));
}
return -1;
}
@@ -472,9 +490,11 @@ connection_edge_send_command(connection_t *fromconn, circuit_t *circ,
if (cpath_layer) {
cell.circ_id = circ->n_circ_id;
cell_direction = CELL_DIRECTION_OUT;
- } else {
- cell.circ_id = circ->p_circ_id;
+ } else if (! CIRCUIT_IS_ORIGIN(circ)) {
+ cell.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
cell_direction = CELL_DIRECTION_IN;
+ } else {
+ return -1;
}
memset(&rh, 0, sizeof(rh));
@@ -619,8 +639,8 @@ errno_to_end_reason(int e)
E_CASE(EMFILE):
return END_STREAM_REASON_RESOURCELIMIT;
default:
- log_info(LD_EXIT, "Didn't recognize errno %d (%s); telling the OP that "
- "we are ending a stream for 'misc' reason.",
+ log_info(LD_EXIT, "Didn't recognize errno %d (%s); telling the client "
+ "that we are ending a stream for 'misc' reason.",
e, tor_socket_strerror(e));
return END_STREAM_REASON_MISC;
}
@@ -648,15 +668,16 @@ edge_reason_is_retriable(int reason)
*/
static int
connection_edge_process_end_not_open(
- relay_header_t *rh, cell_t *cell, circuit_t *circ,
- connection_t *conn, crypt_path_t *layer_hint)
+ relay_header_t *rh, cell_t *cell, origin_circuit_t *circ,
+ edge_connection_t *conn, crypt_path_t *layer_hint)
{
struct in_addr in;
routerinfo_t *exitrouter;
int reason = *(cell->payload+RELAY_HEADER_SIZE);
+ (void) layer_hint; /* unused */
if (rh->length > 0 && edge_reason_is_retriable(reason) &&
- conn->type == CONN_TYPE_AP) {
+ conn->_base.type == CONN_TYPE_AP) {
log_info(LD_APP,"Address '%s' refused due to '%s'. Considering retrying.",
safe_str(conn->socks_request->address),
connection_edge_end_reason_str(reason));
@@ -696,19 +717,35 @@ connection_edge_process_end_not_open(
/* rewrite it to an IP if we learned one. */
addressmap_rewrite(conn->socks_request->address,
sizeof(conn->socks_request->address));
+ if (conn->_base.chosen_exit_optional) {
+ /* stop wanting a specific exit */
+ conn->_base.chosen_exit_optional = 0;
+ tor_free(conn->chosen_exit_name);
+ }
if (connection_ap_detach_retriable(conn, circ) >= 0)
return 0;
/* else, conn will get closed below */
break;
+ case END_STREAM_REASON_CONNECTREFUSED:
+ if (!conn->_base.chosen_exit_optional)
+ break; /* break means it'll close, below */
+ /* Else fall through: expire this circuit, clear the
+ * chosen_exit_name field, and try again. */
case END_STREAM_REASON_RESOLVEFAILED:
+ case END_STREAM_REASON_TIMEOUT:
case END_STREAM_REASON_MISC:
if (client_dns_incr_failures(conn->socks_request->address)
< MAX_RESOLVE_FAILURES) {
/* We haven't retried too many times; reattach the connection. */
circuit_log_path(LOG_INFO,LD_APP,circ);
- tor_assert(circ->timestamp_dirty);
- circ->timestamp_dirty -= get_options()->MaxCircuitDirtiness;
+ tor_assert(circ->_base.timestamp_dirty);
+ circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
+ if (conn->_base.chosen_exit_optional) {
+ /* stop wanting a specific exit */
+ conn->_base.chosen_exit_optional = 0;
+ tor_free(conn->chosen_exit_name);
+ }
if (connection_ap_detach_retriable(conn, circ) >= 0)
return 0;
/* else, conn will get closed below */
@@ -729,6 +766,11 @@ connection_edge_process_end_not_open(
exitrouter->exit_policy =
router_parse_addr_policy_from_string("reject *:*", -1);
}
+ if (conn->_base.chosen_exit_optional) {
+ /* stop wanting a specific exit */
+ conn->_base.chosen_exit_optional = 0;
+ tor_free(conn->chosen_exit_name);
+ }
if (connection_ap_detach_retriable(conn, circ) >= 0)
return 0;
/* else, will close below */
@@ -740,12 +782,13 @@ connection_edge_process_end_not_open(
log_info(LD_APP,
"Edge got end (%s) before we're connected. Marking for close.",
connection_edge_end_reason_str(rh->length > 0 ? reason : -1));
- if (conn->type == CONN_TYPE_AP) {
+ if (conn->_base.type == CONN_TYPE_AP) {
circuit_log_path(LOG_INFO,LD_APP,circ);
connection_mark_unattached_ap(conn, reason);
} else {
- conn->has_sent_end = 1; /* we just got an 'end', don't need to send one */
- connection_mark_for_close(conn);
+ /* we just got an 'end', don't need to send one */
+ conn->_base.edge_has_sent_end = 1;
+ connection_mark_for_close(TO_CONN(conn));
}
return 0;
}
@@ -760,22 +803,29 @@ connection_edge_process_end_not_open(
static int
connection_edge_process_relay_cell_not_open(
relay_header_t *rh, cell_t *cell, circuit_t *circ,
- connection_t *conn, crypt_path_t *layer_hint)
+ edge_connection_t *conn, crypt_path_t *layer_hint)
{
- if (rh->command == RELAY_COMMAND_END)
- return connection_edge_process_end_not_open(rh, cell, circ, conn,
- layer_hint);
+ if (rh->command == RELAY_COMMAND_END) {
+ if (CIRCUIT_IS_ORIGIN(circ))
+ return connection_edge_process_end_not_open(rh, cell,
+ TO_ORIGIN_CIRCUIT(circ), conn,
+ layer_hint);
+ else
+ return 0;
+ }
- if (conn->type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_CONNECTED) {
- if (conn->state != AP_CONN_STATE_CONNECT_WAIT) {
+ if (conn->_base.type == CONN_TYPE_AP &&
+ rh->command == RELAY_COMMAND_CONNECTED) {
+ tor_assert(CIRCUIT_IS_ORIGIN(circ));
+ if (conn->_base.state != AP_CONN_STATE_CONNECT_WAIT) {
log_warn(LD_APP,"Got 'connected' while not in state connect_wait. "
"Dropping.");
return 0;
}
// log_fn(LOG_INFO,"Connected! Notifying application.");
- conn->state = AP_CONN_STATE_OPEN;
+ conn->_base.state = AP_CONN_STATE_OPEN;
log_info(LD_APP,"'connected' received after %d seconds.",
- (int)(time(NULL) - conn->timestamp_lastread));
+ (int)(time(NULL) - conn->_base.timestamp_lastread));
if (rh->length >= 4) {
uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE));
int ttl;
@@ -794,25 +844,29 @@ connection_edge_process_relay_cell_not_open(
client_dns_set_addressmap(conn->socks_request->address, addr,
conn->chosen_exit_name, ttl);
}
- circuit_log_path(LOG_INFO,LD_APP,circ);
- connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_SUCCEEDED);
+ circuit_log_path(LOG_INFO,LD_APP,TO_ORIGIN_CIRCUIT(circ));
+ /* don't send a socks reply to transparent conns */
+ if (!conn->socks_request->has_finished)
+ connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_SUCCEEDED);
/* handle anything that might have queued */
if (connection_edge_package_raw_inbuf(conn, 1) < 0) {
/* (We already sent an end cell if possible) */
- connection_mark_for_close(conn);
+ connection_mark_for_close(TO_CONN(conn));
return 0;
}
return 0;
}
- if (conn->type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_RESOLVED) {
+ if (conn->_base.type == CONN_TYPE_AP &&
+ rh->command == RELAY_COMMAND_RESOLVED) {
int ttl;
int answer_len;
- if (conn->state != AP_CONN_STATE_RESOLVE_WAIT) {
+ if (conn->_base.state != AP_CONN_STATE_RESOLVE_WAIT) {
log_warn(LD_APP,"Got a 'resolved' cell while not in state resolve_wait. "
"Dropping.");
return 0;
}
- tor_assert(conn->socks_request->command == SOCKS_COMMAND_RESOLVE);
+ tor_assert(conn->socks_request->command == SOCKS_COMMAND_RESOLVE ||
+ conn->socks_request->command == SOCKS_COMMAND_RESOLVE_PTR);
answer_len = cell->payload[RELAY_HEADER_SIZE+1];
if (rh->length < 2 || answer_len+2>rh->length) {
log_warn(LD_PROTOCOL, "Dropping malformed 'resolved' cell");
@@ -836,8 +890,8 @@ connection_edge_process_relay_cell_not_open(
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Got an unexpected relay command %d, in state %d (%s). Dropping.",
- rh->command, conn->state,
- conn_state_to_string(conn->type, conn->state));
+ rh->command, conn->_base.state,
+ conn_state_to_string(conn->_base.type, conn->_base.state));
return 0; /* for forward compatibility, don't kill the circuit */
// connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL,
// conn->cpath_layer);
@@ -856,7 +910,7 @@ connection_edge_process_relay_cell_not_open(
*/
static int
connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
- connection_t *conn,
+ edge_connection_t *conn,
crypt_path_t *layer_hint)
{
static int num_seen=0;
@@ -881,13 +935,13 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
/* either conn is NULL, in which case we've got a control cell, or else
* conn points to the recognized stream. */
- if (conn && !connection_state_is_open(conn))
+ if (conn && !connection_state_is_open(TO_CONN(conn)))
return connection_edge_process_relay_cell_not_open(
&rh, cell, circ, conn, layer_hint);
switch (rh.command) {
case RELAY_COMMAND_DROP:
- log_info(domain,"Got a relay-level padding cell. Dropping.");
+// log_info(domain,"Got a relay-level padding cell. Dropping.");
return 0;
case RELAY_COMMAND_BEGIN:
if (layer_hint &&
@@ -909,7 +963,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
"(relay data) circ deliver_window below 0. Killing.");
connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL,
conn->cpath_layer);
- connection_mark_for_close(conn);
+ connection_mark_for_close(TO_CONN(conn));
return -END_CIRC_REASON_TORPROTOCOL;
}
log_debug(domain,"circ deliver_window now %d.", layer_hint ?
@@ -930,7 +984,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
stats_n_data_bytes_received += rh.length;
connection_write_to_buf(cell->payload + RELAY_HEADER_SIZE,
- rh.length, conn);
+ rh.length, TO_CONN(conn));
connection_edge_consider_sending_sendme(conn);
return 0;
case RELAY_COMMAND_END:
@@ -942,32 +996,21 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
}
/* XXX add to this log_fn the exit node's nickname? */
log_info(domain,"%d: end cell (%s) for stream %d. Removing stream.",
- conn->s,
+ conn->_base.s,
connection_edge_end_reason_str(rh.length > 0 ?
*(char *)(cell->payload+RELAY_HEADER_SIZE) : -1),
conn->stream_id);
if (conn->socks_request && !conn->socks_request->has_finished)
log_warn(LD_BUG,
"Bug: open stream hasn't sent socks answer yet? Closing.");
-#ifdef HALF_OPEN
- conn->done_sending = 1;
- shutdown(conn->s, 1); /* XXX check return; refactor NM */
- if (conn->done_receiving) {
- /* We just *got* an end; no reason to send one. */
- conn->has_sent_end = 1;
- connection_mark_for_close(conn);
- conn->hold_open_until_flushed = 1;
- }
-#else
/* We just *got* an end; no reason to send one. */
- conn->has_sent_end = 1;
- if (!conn->marked_for_close) {
+ conn->_base.edge_has_sent_end = 1;
+ if (!conn->_base.marked_for_close) {
/* only mark it if not already marked. it's possible to
* get the 'end' right around when the client hangs up on us. */
- connection_mark_for_close(conn);
- conn->hold_open_until_flushed = 1;
+ connection_mark_for_close(TO_CONN(conn));
+ conn->_base.hold_open_until_flushed = 1;
}
-#endif
return 0;
case RELAY_COMMAND_EXTEND:
if (conn) {
@@ -982,12 +1025,13 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
return 0;
}
log_debug(domain,"Got an extended cell! Yay.");
- if ((reason = circuit_finish_handshake(circ, CELL_CREATED,
+ if ((reason = circuit_finish_handshake(TO_ORIGIN_CIRCUIT(circ),
+ CELL_CREATED,
cell->payload+RELAY_HEADER_SIZE)) < 0) {
log_warn(domain,"circuit_finish_handshake failed.");
return reason;
}
- if ((reason=circuit_send_next_onion_skin(circ))<0) {
+ if ((reason=circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)))<0) {
log_info(domain,"circuit_send_next_onion_skin() failed.");
return reason;
}
@@ -1000,7 +1044,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
if (circ->n_conn) {
uint8_t reason = *(uint8_t*)(cell->payload + RELAY_HEADER_SIZE);
connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason);
- circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
+ circuit_set_n_circid_orconn(circ, 0, NULL);
}
log_debug(LD_EXIT, "Processed 'truncate', replying.");
{
@@ -1015,7 +1059,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
log_warn(LD_EXIT,"'truncated' unsupported at non-origin. Dropping.");
return 0;
}
- circuit_truncated(circ, layer_hint);
+ circuit_truncated(TO_ORIGIN_CIRCUIT(circ), layer_hint);
return 0;
case RELAY_COMMAND_CONNECTED:
if (conn) {
@@ -1045,11 +1089,11 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
conn->package_window += STREAMWINDOW_INCREMENT;
log_debug(domain,"stream-level sendme, packagewindow now %d.",
conn->package_window);
- connection_start_reading(conn);
+ connection_start_reading(TO_CONN(conn));
/* handle whatever might still be on the inbuf */
if (connection_edge_package_raw_inbuf(conn, 1) < 0) {
/* (We already sent an end cell if possible) */
- connection_mark_for_close(conn);
+ connection_mark_for_close(TO_CONN(conn));
return 0;
}
return 0;
@@ -1065,7 +1109,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
circ->purpose);
return 0;
}
- connection_exit_begin_resolve(cell, circ);
+ connection_exit_begin_resolve(cell, TO_OR_CIRCUIT(circ));
return 0;
case RELAY_COMMAND_RESOLVED:
if (conn) {
@@ -1108,7 +1152,7 @@ uint64_t stats_n_data_bytes_received = 0;
* be marked for close, else return 0.
*/
int
-connection_edge_package_raw_inbuf(connection_t *conn, int package_partial)
+connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial)
{
size_t amount_to_process, length;
char payload[CELL_PAYLOAD_SIZE];
@@ -1116,11 +1160,11 @@ connection_edge_package_raw_inbuf(connection_t *conn, int package_partial)
unsigned domain = conn->cpath_layer ? LD_APP : LD_EXIT;
tor_assert(conn);
- tor_assert(!connection_speaks_cells(conn));
- if (conn->marked_for_close) {
+
+ if (conn->_base.marked_for_close) {
log_warn(LD_BUG,
"Bug: called on conn that's already marked for close at %s:%d.",
- conn->marked_for_close_file, conn->marked_for_close);
+ conn->_base.marked_for_close_file, conn->_base.marked_for_close);
return 0;
}
@@ -1138,11 +1182,11 @@ repeat_connection_edge_package_raw_inbuf:
if (conn->package_window <= 0) {
log_info(domain,"called with package_window %d. Skipping.",
conn->package_window);
- connection_stop_reading(conn);
+ connection_stop_reading(TO_CONN(conn));
return 0;
}
- amount_to_process = buf_datalen(conn->inbuf);
+ amount_to_process = buf_datalen(conn->_base.inbuf);
if (!amount_to_process)
return 0;
@@ -1158,10 +1202,10 @@ repeat_connection_edge_package_raw_inbuf:
stats_n_data_bytes_packaged += length;
stats_n_data_cells_packaged += 1;
- connection_fetch_from_buf(payload, length, conn);
+ connection_fetch_from_buf(payload, length, TO_CONN(conn));
- log_debug(domain,"(%d) Packaging %d bytes (%d waiting).", conn->s,
- (int)length, (int)buf_datalen(conn->inbuf));
+ log_debug(domain,"(%d) Packaging %d bytes (%d waiting).", conn->_base.s,
+ (int)length, (int)buf_datalen(conn->_base.inbuf));
if (connection_edge_send_command(conn, circ, RELAY_COMMAND_DATA,
payload, length, conn->cpath_layer) < 0)
@@ -1177,7 +1221,7 @@ repeat_connection_edge_package_raw_inbuf:
}
if (--conn->package_window <= 0) { /* is it 0 after decrement? */
- connection_stop_reading(conn);
+ connection_stop_reading(TO_CONN(conn));
log_debug(domain,"conn->package_window reached 0.");
circuit_consider_stop_edge_reading(circ, conn->cpath_layer);
return 0; /* don't process the inbuf any more */
@@ -1195,11 +1239,11 @@ repeat_connection_edge_package_raw_inbuf:
* low, send back a suitable number of stream-level sendme cells.
*/
void
-connection_edge_consider_sending_sendme(connection_t *conn)
+connection_edge_consider_sending_sendme(edge_connection_t *conn)
{
circuit_t *circ;
- if (connection_outbuf_too_full(conn))
+ if (connection_outbuf_too_full(TO_CONN(conn)))
return;
circ = circuit_get_by_edge_conn(conn);
@@ -1213,7 +1257,7 @@ connection_edge_consider_sending_sendme(connection_t *conn)
while (conn->deliver_window < STREAMWINDOW_START - STREAMWINDOW_INCREMENT) {
log_debug(conn->cpath_layer?LD_APP:LD_EXIT,
"Outbuf %d, Queueing stream sendme.",
- (int)conn->outbuf_flushlen);
+ (int)conn->_base.outbuf_flushlen);
conn->deliver_window += STREAMWINDOW_INCREMENT;
if (connection_edge_send_command(conn, circ, RELAY_COMMAND_SENDME,
NULL, 0, conn->cpath_layer) < 0) {
@@ -1234,10 +1278,12 @@ circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint)
log_debug(layer_hint?LD_APP:LD_EXIT,"resuming");
- /* have to check both n_streams and p_streams, to handle rendezvous */
- if (circuit_resume_edge_reading_helper(circ->n_streams, circ, layer_hint)
- >= 0)
- circuit_resume_edge_reading_helper(circ->p_streams, circ, layer_hint);
+ if (CIRCUIT_IS_ORIGIN(circ))
+ circuit_resume_edge_reading_helper(TO_ORIGIN_CIRCUIT(circ)->p_streams,
+ circ, layer_hint);
+ else
+ circuit_resume_edge_reading_helper(TO_OR_CIRCUIT(circ)->n_streams,
+ circ, layer_hint);
}
/** A helper function for circuit_resume_edge_reading() above.
@@ -1245,21 +1291,21 @@ circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint)
* of a linked list of edge streams that should each be considered.
*/
static int
-circuit_resume_edge_reading_helper(connection_t *conn,
+circuit_resume_edge_reading_helper(edge_connection_t *conn,
circuit_t *circ,
crypt_path_t *layer_hint)
{
for ( ; conn; conn=conn->next_stream) {
- if (conn->marked_for_close)
+ if (conn->_base.marked_for_close)
continue;
if ((!layer_hint && conn->package_window > 0) ||
(layer_hint && conn->package_window > 0 &&
conn->cpath_layer == layer_hint)) {
- connection_start_reading(conn);
+ connection_start_reading(TO_CONN(conn));
/* handle whatever might still be on the inbuf */
if (connection_edge_package_raw_inbuf(conn, 1)<0) {
/* (We already sent an end cell if possible) */
- connection_mark_for_close(conn);
+ connection_mark_for_close(TO_CONN(conn));
continue;
}
@@ -1282,16 +1328,17 @@ circuit_resume_edge_reading_helper(connection_t *conn,
static int
circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint)
{
- connection_t *conn = NULL;
+ edge_connection_t *conn = NULL;
unsigned domain = layer_hint ? LD_APP : LD_EXIT;
if (!layer_hint) {
+ or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
log_debug(domain,"considering circ->package_window %d",
circ->package_window);
if (circ->package_window <= 0) {
log_debug(domain,"yes, not-at-origin. stopped.");
- for (conn = circ->n_streams; conn; conn=conn->next_stream)
- connection_stop_reading(conn);
+ for (conn = or_circ->n_streams; conn; conn=conn->next_stream)
+ connection_stop_reading(TO_CONN(conn));
return 1;
}
return 0;
@@ -1301,12 +1348,16 @@ circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint)
layer_hint->package_window);
if (layer_hint->package_window <= 0) {
log_debug(domain,"yes, at-origin. stopped.");
+#if 0
+ // XXXX NM DEAD CODE.
for (conn = circ->n_streams; conn; conn=conn->next_stream)
if (conn->cpath_layer == layer_hint)
connection_stop_reading(conn);
- for (conn = circ->p_streams; conn; conn=conn->next_stream)
+#endif
+ for (conn = TO_ORIGIN_CIRCUIT(circ)->p_streams; conn;
+ conn=conn->next_stream)
if (conn->cpath_layer == layer_hint)
- connection_stop_reading(conn);
+ connection_stop_reading(TO_CONN(conn));
return 1;
}
return 0;
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index ec6f299165..0b61004d0a 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -14,10 +14,9 @@ const char rendclient_c_id[] =
/** Called when we've established a circuit to an introduction point:
* send the introduction request. */
void
-rend_client_introcirc_has_opened(circuit_t *circ)
+rend_client_introcirc_has_opened(origin_circuit_t *circ)
{
- tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
+ tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
tor_assert(circ->cpath);
log_info(LD_REND,"introcirc is open");
@@ -28,17 +27,17 @@ rend_client_introcirc_has_opened(circuit_t *circ)
* it fails, mark the circ for close and return -1. else return 0.
*/
static int
-rend_client_send_establish_rendezvous(circuit_t *circ)
+rend_client_send_establish_rendezvous(origin_circuit_t *circ)
{
- tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
+ tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
log_info(LD_REND, "Sending an ESTABLISH_RENDEZVOUS cell");
if (crypto_rand(circ->rend_cookie, REND_COOKIE_LEN) < 0) {
log_warn(LD_BUG, "Internal error: Couldn't produce random cookie.");
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1;
}
- if (connection_edge_send_command(NULL,circ,
+ if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
RELAY_COMMAND_ESTABLISH_RENDEZVOUS,
circ->rend_cookie, REND_COOKIE_LEN,
circ->cpath->prev)<0) {
@@ -54,7 +53,8 @@ rend_client_send_establish_rendezvous(circuit_t *circ)
* down introcirc if possible.
*/
int
-rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc)
+rend_client_send_introduction(origin_circuit_t *introcirc,
+ origin_circuit_t *rendcirc)
{
size_t payload_len;
int r;
@@ -64,8 +64,8 @@ rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc)
crypt_path_t *cpath;
off_t dh_offset;
- tor_assert(introcirc->purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
- tor_assert(rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY);
+ tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
+ tor_assert(rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY);
tor_assert(!rend_cmp_service_ids(introcirc->rend_query,
rendcirc->rend_query));
@@ -111,13 +111,15 @@ rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc)
klen = crypto_pk_asn1_encode(extend_info->onion_key, tmp+7+DIGEST_LEN+2,
sizeof(tmp)-(7+DIGEST_LEN+2));
set_uint16(tmp+7+DIGEST_LEN, htons(klen));
- memcpy(tmp+7+DIGEST_LEN+2+klen, rendcirc->rend_cookie, REND_COOKIE_LEN);
+ memcpy(tmp+7+DIGEST_LEN+2+klen, rendcirc->rend_cookie,
+ REND_COOKIE_LEN);
dh_offset = 7+DIGEST_LEN+2+klen+REND_COOKIE_LEN;
} else {
/* Version 0. */
strncpy(tmp, rendcirc->build_state->chosen_exit->nickname,
(MAX_NICKNAME_LEN+1)); /* nul pads */
- memcpy(tmp+MAX_NICKNAME_LEN+1, rendcirc->rend_cookie, REND_COOKIE_LEN);
+ memcpy(tmp+MAX_NICKNAME_LEN+1, rendcirc->rend_cookie,
+ REND_COOKIE_LEN);
dh_offset = MAX_NICKNAME_LEN+1+REND_COOKIE_LEN;
}
@@ -141,7 +143,7 @@ rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc)
tor_assert(DIGEST_LEN + r <= RELAY_PAYLOAD_SIZE); /* we overran something */
payload_len = DIGEST_LEN + r;
- if (connection_edge_send_command(NULL, introcirc,
+ if (connection_edge_send_command(NULL, TO_CIRCUIT(introcirc),
RELAY_COMMAND_INTRODUCE1,
payload, payload_len,
introcirc->cpath->prev)<0) {
@@ -151,22 +153,21 @@ rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc)
}
/* Now, we wait for an ACK or NAK on this circuit. */
- introcirc->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT;
+ introcirc->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT;
return 0;
err:
- circuit_mark_for_close(introcirc, END_CIRC_AT_ORIGIN);
- circuit_mark_for_close(rendcirc, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_AT_ORIGIN);
return -1;
}
/** Called when a rendezvous circuit is open; sends a establish
* rendezvous circuit as appropriate. */
void
-rend_client_rendcirc_has_opened(circuit_t *circ)
+rend_client_rendcirc_has_opened(origin_circuit_t *circ)
{
- tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
+ tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
log_info(LD_REND,"rendcirc is open");
@@ -179,21 +180,21 @@ rend_client_rendcirc_has_opened(circuit_t *circ)
/** Called when get an ACK or a NAK for a REND_INTRODUCE1 cell.
*/
int
-rend_client_introduction_acked(circuit_t *circ,
+rend_client_introduction_acked(origin_circuit_t *circ,
const char *request, size_t request_len)
{
- circuit_t *rendcirc;
+ origin_circuit_t *rendcirc;
+ (void) request; // XXXX Use this.
- if (circ->purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
+ if (circ->_base.purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
log_warn(LD_PROTOCOL,
"Received REND_INTRODUCE_ACK on unexpected circuit %d.",
- circ->n_circ_id);
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circ->_base.n_circ_id);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1;
}
tor_assert(circ->build_state->chosen_exit);
- tor_assert(circ->build_state->chosen_exit->nickname);
if (request_len == 0) {
/* It's an ACK; the introduction point relayed our introduction request. */
@@ -204,16 +205,16 @@ rend_client_introduction_acked(circuit_t *circ,
rendcirc = circuit_get_by_rend_query_and_purpose(
circ->rend_query, CIRCUIT_PURPOSE_C_REND_READY);
if (rendcirc) { /* remember the ack */
- rendcirc->purpose = CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED;
+ rendcirc->_base.purpose = CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED;
} else {
log_info(LD_REND,"...Found no rend circ. Dropping on the floor.");
}
/* close the circuit: we won't need it anymore. */
- circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACKED;
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circ->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACKED;
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
} else {
/* It's a NAK; the introduction point didn't relay our request. */
- circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
+ circ->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
/* Remove this intro point from the set of viable introduction
* points. If any remain, extend to a new one and try again.
* If none remain, refetch the service descriptor.
@@ -228,14 +229,14 @@ rend_client_introduction_acked(circuit_t *circ,
if (!extend_info) {
log_warn(LD_REND, "No introduction points left for %s. Closing.",
escaped_safe_str(circ->rend_query));
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1;
}
log_info(LD_REND,
"Got nack for %s from %s. Re-extending circ %d, "
"this time to %s.",
escaped_safe_str(circ->rend_query),
- circ->build_state->chosen_exit->nickname, circ->n_circ_id,
+ circ->build_state->chosen_exit->nickname, circ->_base.n_circ_id,
extend_info->nickname);
result = circuit_extend_to_new_exit(circ, extend_info);
extend_info_free(extend_info);
@@ -339,36 +340,38 @@ rend_client_remove_intro_point(extend_info_t *failed_intro, const char *query)
* the circuit to C_REND_READY.
*/
int
-rend_client_rendezvous_acked(circuit_t *circ, const char *request,
+rend_client_rendezvous_acked(origin_circuit_t *circ, const char *request,
size_t request_len)
{
+ (void) request;
+ (void) request_len;
/* we just got an ack for our establish-rendezvous. switch purposes. */
- if (circ->purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
+ if (circ->_base.purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
log_warn(LD_PROTOCOL,"Got a rendezvous ack when we weren't expecting one. "
"Closing circ.");
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1;
}
log_info(LD_REND,"Got rendezvous ack. This circuit is now ready for "
"rendezvous.");
- circ->purpose = CIRCUIT_PURPOSE_C_REND_READY;
+ circ->_base.purpose = CIRCUIT_PURPOSE_C_REND_READY;
return 0;
}
/** Bob sent us a rendezvous cell; join the circuits. */
int
-rend_client_receive_rendezvous(circuit_t *circ, const char *request,
+rend_client_receive_rendezvous(origin_circuit_t *circ, const char *request,
size_t request_len)
{
crypt_path_t *hop;
char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];
- if ((circ->purpose != CIRCUIT_PURPOSE_C_REND_READY &&
- circ->purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
+ if ((circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY &&
+ circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
|| !circ->build_state->pending_final_cpath) {
log_warn(LD_PROTOCOL,"Got rendezvous2 cell from hidden service, but not "
"expecting it. Closing.");
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1;
}
@@ -402,7 +405,7 @@ rend_client_receive_rendezvous(circuit_t *circ, const char *request,
hop->dh_handshake_state = NULL;
/* All is well. Extend the circuit. */
- circ->purpose = CIRCUIT_PURPOSE_C_REND_JOINED;
+ circ->_base.purpose = CIRCUIT_PURPOSE_C_REND_JOINED;
hop->state = CPATH_STATE_OPEN;
/* set the windows to default. these are the windows
* that alice thinks bob has.
@@ -414,7 +417,7 @@ rend_client_receive_rendezvous(circuit_t *circ, const char *request,
circ->build_state->pending_final_cpath = NULL; /* prevent double-free */
return 0;
err:
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1;
}
@@ -426,7 +429,7 @@ rend_client_receive_rendezvous(circuit_t *circ, const char *request,
void
rend_client_desc_here(const char *query)
{
- connection_t *conn;
+ edge_connection_t *conn;
rend_cache_entry_t *entry;
time_t now = time(NULL);
int i, n_conns;
@@ -435,25 +438,26 @@ rend_client_desc_here(const char *query)
get_connection_array(&carray, &n_conns);
for (i = 0; i < n_conns; ++i) {
- conn = carray[i];
- if (conn->type != CONN_TYPE_AP ||
- conn->state != AP_CONN_STATE_RENDDESC_WAIT ||
- conn->marked_for_close ||
- rend_cmp_service_ids(query, conn->rend_query))
+ if (carray[i]->type != CONN_TYPE_AP ||
+ carray[i]->state != AP_CONN_STATE_RENDDESC_WAIT ||
+ carray[i]->marked_for_close)
+ continue;
+ conn = TO_EDGE_CONN(carray[i]);
+ if (rend_cmp_service_ids(query, conn->rend_query))
continue;
- assert_connection_ok(conn, now);
+ assert_connection_ok(TO_CONN(conn), now);
if (rend_cache_lookup_entry(conn->rend_query, -1, &entry) == 1 &&
entry->parsed->n_intro_points > 0) {
/* either this fetch worked, or it failed but there was a
* valid entry from before which we should reuse */
log_info(LD_REND,"Rend desc is usable. Launching circuits.");
- conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
+ conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
/* restart their timeout values, so they get a fair shake at
* connecting to the hidden service. */
- conn->timestamp_created = now;
- conn->timestamp_lastread = now;
- conn->timestamp_lastwritten = now;
+ conn->_base.timestamp_created = now;
+ conn->_base.timestamp_lastread = now;
+ conn->_base.timestamp_lastwritten = now;
if (connection_ap_handshake_attach_circuit(conn) < 0) {
/* it will never work */
diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c
index 4c60bac803..ab38e9f3a6 100644
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@ -234,7 +234,7 @@ rend_get_service_id(crypto_pk_env_t *pk, char *out)
/** How old do we let hidden service descriptors get discarding them as too
* old? */
#define REND_CACHE_MAX_AGE (2*24*60*60)
-/** How wrong to we assume our clock may be when checking whether hidden
+/** How wrong do we assume our clock may be when checking whether hidden
* services are too old or too new? */
#define REND_CACHE_MAX_SKEW (24*60*60)
@@ -432,34 +432,41 @@ void
rend_process_relay_cell(circuit_t *circ, int command, size_t length,
const char *payload)
{
+ or_circuit_t *or_circ = NULL;
+ origin_circuit_t *origin_circ = NULL;
int r;
+ if (CIRCUIT_IS_ORIGIN(circ))
+ origin_circ = TO_ORIGIN_CIRCUIT(circ);
+ else
+ or_circ = TO_OR_CIRCUIT(circ);
+
switch (command) {
case RELAY_COMMAND_ESTABLISH_INTRO:
- r = rend_mid_establish_intro(circ,payload,length);
+ r = rend_mid_establish_intro(or_circ,payload,length);
break;
case RELAY_COMMAND_ESTABLISH_RENDEZVOUS:
- r = rend_mid_establish_rendezvous(circ,payload,length);
+ r = rend_mid_establish_rendezvous(or_circ,payload,length);
break;
case RELAY_COMMAND_INTRODUCE1:
- r = rend_mid_introduce(circ,payload,length);
+ r = rend_mid_introduce(or_circ,payload,length);
break;
case RELAY_COMMAND_INTRODUCE2:
- r = rend_service_introduce(circ,payload,length);
+ r = rend_service_introduce(origin_circ,payload,length);
break;
case RELAY_COMMAND_INTRODUCE_ACK:
- r = rend_client_introduction_acked(circ,payload,length);
+ r = rend_client_introduction_acked(origin_circ,payload,length);
break;
case RELAY_COMMAND_RENDEZVOUS1:
- r = rend_mid_rendezvous(circ,payload,length);
+ r = rend_mid_rendezvous(or_circ,payload,length);
break;
case RELAY_COMMAND_RENDEZVOUS2:
- r = rend_client_receive_rendezvous(circ,payload,length);
+ r = rend_client_receive_rendezvous(origin_circ,payload,length);
break;
case RELAY_COMMAND_INTRO_ESTABLISHED:
- r = rend_service_intro_established(circ,payload,length);
+ r = rend_service_intro_established(origin_circ,payload,length);
break;
case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED:
- r = rend_client_rendezvous_acked(circ,payload,length);
+ r = rend_client_rendezvous_acked(origin_circ,payload,length);
break;
default:
tor_assert(0);
diff --git a/src/or/rendmid.c b/src/or/rendmid.c
index c1252289bc..e96d608d59 100644
--- a/src/or/rendmid.c
+++ b/src/or/rendmid.c
@@ -15,7 +15,7 @@ const char rendmid_c_id[] =
* setting the circuit's purpose and service pk digest.
*/
int
-rend_mid_establish_intro(circuit_t *circ, const char *request,
+rend_mid_establish_intro(or_circuit_t *circ, const char *request,
size_t request_len)
{
crypto_pk_env_t *pk = NULL;
@@ -23,7 +23,7 @@ rend_mid_establish_intro(circuit_t *circ, const char *request,
char expected_digest[DIGEST_LEN];
char pk_digest[DIGEST_LEN];
size_t asn1len;
- circuit_t *c;
+ or_circuit_t *c;
char serviceid[REND_SERVICE_ID_LEN+1];
int reason = END_CIRC_REASON_INTERNAL;
@@ -31,7 +31,7 @@ rend_mid_establish_intro(circuit_t *circ, const char *request,
"Received an ESTABLISH_INTRO request on circuit %d",
circ->p_circ_id);
- if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
+ if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Rejecting ESTABLISH_INTRO on non-OR or non-edge circuit.");
reason = END_CIRC_REASON_TORPROTOCOL;
@@ -87,15 +87,15 @@ rend_mid_establish_intro(circuit_t *circ, const char *request,
/* Close any other intro circuits with the same pk. */
c = NULL;
- while ((c = circuit_get_next_by_pk_and_purpose(
- c,pk_digest,CIRCUIT_PURPOSE_INTRO_POINT))) {
- log_info(LD_REND, "Replacing old circuit %d for service %s",
- c->p_circ_id, safe_str(serviceid));
- circuit_mark_for_close(c, END_CIRC_REASON_REQUESTED);
+ while ((c = circuit_get_intro_point(pk_digest))) {
+ log_info(LD_REND, "Replacing old circuit for service %s",
+ safe_str(serviceid));
+ circuit_mark_for_close(TO_CIRCUIT(c), END_CIRC_REASON_REQUESTED);
+ /* Now it's marked, and it won't be returned next time. */
}
/* Acknowledge the request. */
- if (connection_edge_send_command(NULL,circ,
+ if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
RELAY_COMMAND_INTRO_ESTABLISHED,
"", 0, NULL)<0) {
log_info(LD_GENERAL, "Couldn't send INTRO_ESTABLISHED cell.");
@@ -103,8 +103,8 @@ rend_mid_establish_intro(circuit_t *circ, const char *request,
}
/* Now, set up this circuit. */
- circ->purpose = CIRCUIT_PURPOSE_INTRO_POINT;
- memcpy(circ->rend_pk_digest, pk_digest, DIGEST_LEN);
+ circ->_base.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
+ memcpy(circ->rend_token, pk_digest, DIGEST_LEN);
log_info(LD_REND,
"Established introduction point on circuit %d for service %s",
@@ -116,7 +116,7 @@ rend_mid_establish_intro(circuit_t *circ, const char *request,
reason = END_CIRC_REASON_TORPROTOCOL;
err:
if (pk) crypto_free_pk_env(pk);
- circuit_mark_for_close(circ, reason);
+ circuit_mark_for_close(TO_CIRCUIT(circ), reason);
return -1;
}
@@ -125,20 +125,23 @@ rend_mid_establish_intro(circuit_t *circ, const char *request,
* INTRODUCE2 cell.
*/
int
-rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len)
+rend_mid_introduce(or_circuit_t *circ, const char *request, size_t request_len)
{
- circuit_t *intro_circ;
+ or_circuit_t *intro_circ;
char serviceid[REND_SERVICE_ID_LEN+1];
char nak_body[1];
- if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
+ if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
log_warn(LD_PROTOCOL,
"Rejecting INTRODUCE1 on non-OR or non-edge circuit %d.",
circ->p_circ_id);
goto err;
}
- /* change to MAX_HEX_NICKNAME_LEN once 0.0.9.x is obsolete */
+ /* We could change this to MAX_HEX_NICKNAME_LEN now that 0.0.9.x is
+ * obsolete; however, there isn't much reason to do so, and we're going
+ * to revise this protocol anyway.
+ */
if (request_len < (DIGEST_LEN+(MAX_NICKNAME_LEN+1)+REND_COOKIE_LEN+
DH_KEY_LEN+CIPHER_KEY_LEN+PKCS1_OAEP_PADDING_OVERHEAD)) {
log_warn(LD_PROTOCOL, "Impossibly short INTRODUCE1 cell on circuit %d; "
@@ -150,8 +153,7 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len)
base32_encode(serviceid, REND_SERVICE_ID_LEN+1, request,10);
/* The first 20 bytes are all we look at: they have a hash of Bob's PK. */
- intro_circ = circuit_get_next_by_pk_and_purpose(
- NULL, request, CIRCUIT_PURPOSE_INTRO_POINT);
+ intro_circ = circuit_get_intro_point(request);
if (!intro_circ) {
log_info(LD_REND,
"No intro circ found for INTRODUCE1 cell (%s) from circuit %d; "
@@ -163,10 +165,11 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len)
log_info(LD_REND,
"Sending introduction request for service %s "
"from circ %d to circ %d",
- safe_str(serviceid), circ->p_circ_id, intro_circ->p_circ_id);
+ safe_str(serviceid), circ->p_circ_id,
+ intro_circ->p_circ_id);
/* Great. Now we just relay the cell down the circuit. */
- if (connection_edge_send_command(NULL, intro_circ,
+ if (connection_edge_send_command(NULL, TO_CIRCUIT(intro_circ),
RELAY_COMMAND_INTRODUCE2,
request, request_len, NULL)) {
log_warn(LD_GENERAL,
@@ -174,10 +177,11 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len)
goto err;
}
/* And sent an ack down Alice's circuit. Empty body means succeeded. */
- if (connection_edge_send_command(NULL,circ,RELAY_COMMAND_INTRODUCE_ACK,
+ if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
+ RELAY_COMMAND_INTRODUCE_ACK,
NULL,0,NULL)) {
log_warn(LD_GENERAL, "Unable to send INTRODUCE_ACK cell to Tor client.");
- circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
return -1;
}
@@ -185,11 +189,12 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len)
err:
/* Send the client an NACK */
nak_body[0] = 1;
- if (connection_edge_send_command(NULL,circ,RELAY_COMMAND_INTRODUCE_ACK,
+ if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
+ RELAY_COMMAND_INTRODUCE_ACK,
nak_body, 1, NULL)) {
log_warn(LD_GENERAL, "Unable to send NAK to Tor client.");
/* Is this right? */
- circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
}
return -1;
}
@@ -198,13 +203,13 @@ rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len)
* rendezvous cookie.
*/
int
-rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
+rend_mid_establish_rendezvous(or_circuit_t *circ, const char *request,
size_t request_len)
{
char hexid[9];
int reason = END_CIRC_REASON_TORPROTOCOL;
- if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
+ if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
log_warn(LD_PROTOCOL,
"Tried to establish rendezvous on non-OR or non-edge circuit.");
goto err;
@@ -222,7 +227,7 @@ rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
}
/* Acknowledge the request. */
- if (connection_edge_send_command(NULL,circ,
+ if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
RELAY_COMMAND_RENDEZVOUS_ESTABLISHED,
"", 0, NULL)<0) {
log_warn(LD_PROTOCOL, "Couldn't send RENDEZVOUS_ESTABLISHED cell.");
@@ -230,8 +235,8 @@ rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
goto err;
}
- circ->purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
- memcpy(circ->rend_cookie, request, REND_COOKIE_LEN);
+ circ->_base.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
+ memcpy(circ->rend_token, request, REND_COOKIE_LEN);
base16_encode(hexid,9,request,4);
@@ -241,7 +246,7 @@ rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
return 0;
err:
- circuit_mark_for_close(circ, reason);
+ circuit_mark_for_close(TO_CIRCUIT(circ), reason);
return -1;
}
@@ -250,9 +255,10 @@ rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
* connecting the two circuits.
*/
int
-rend_mid_rendezvous(circuit_t *circ, const char *request, size_t request_len)
+rend_mid_rendezvous(or_circuit_t *circ, const char *request,
+ size_t request_len)
{
- circuit_t *rend_circ;
+ or_circuit_t *rend_circ;
char hexid[9];
int reason = END_CIRC_REASON_INTERNAL;
base16_encode(hexid,9,request,request_len<4?request_len:4);
@@ -263,7 +269,7 @@ rend_mid_rendezvous(circuit_t *circ, const char *request, size_t request_len)
circ->p_circ_id, hexid);
}
- if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
+ if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
log_info(LD_REND,
"Tried to complete rendezvous on non-OR or non-edge circuit %d.",
circ->p_circ_id);
@@ -289,12 +295,12 @@ rend_mid_rendezvous(circuit_t *circ, const char *request, size_t request_len)
}
/* Send the RENDEZVOUS2 cell to Alice. */
- if (connection_edge_send_command(NULL, rend_circ,
+ if (connection_edge_send_command(NULL, TO_CIRCUIT(rend_circ),
RELAY_COMMAND_RENDEZVOUS2,
request+REND_COOKIE_LEN,
request_len-REND_COOKIE_LEN, NULL)) {
log_warn(LD_GENERAL,
- "Unable to send RENDEZVOUS2 cell to OP on circuit %d.",
+ "Unable to send RENDEZVOUS2 cell to client on circuit %d.",
rend_circ->p_circ_id);
goto err;
}
@@ -304,16 +310,16 @@ rend_mid_rendezvous(circuit_t *circ, const char *request, size_t request_len)
"Completing rendezvous: circuit %d joins circuit %d (cookie %s)",
circ->p_circ_id, rend_circ->p_circ_id, hexid);
- circ->purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
- rend_circ->purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
- memset(circ->rend_cookie, 0, REND_COOKIE_LEN);
+ circ->_base.purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
+ rend_circ->_base.purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
+ memset(circ->rend_token, 0, REND_COOKIE_LEN);
rend_circ->rend_splice = circ;
circ->rend_splice = rend_circ;
return 0;
err:
- circuit_mark_for_close(circ, reason);
+ circuit_mark_for_close(TO_CIRCUIT(circ), reason);
return -1;
}
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index 45454985ed..0cda1d95c0 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -11,8 +11,8 @@ const char rendservice_c_id[] =
#include "or.h"
-static circuit_t *find_intro_circuit(routerinfo_t *router,
- const char *pk_digest);
+static origin_circuit_t *find_intro_circuit(routerinfo_t *router,
+ const char *pk_digest);
/** Represents the mapping from a virtual port of a rendezvous service to
* a real port on some IP.
@@ -179,7 +179,7 @@ parse_port_config(const char *string)
} else {
addrport = smartlist_get(sl,1);
if (strchr(addrport, ':') || strchr(addrport, '.')) {
- if (parse_addr_port(addrport, NULL, &addr, &p)<0) {
+ if (parse_addr_port(LOG_WARN, addrport, NULL, &addr, &p)<0) {
log_warn(LD_CONFIG,"Unparseable address in hidden service port "
"configuration.");
goto err;
@@ -285,7 +285,7 @@ static void
rend_service_update_descriptor(rend_service_t *service)
{
rend_service_descriptor_t *d;
- circuit_t *circ;
+ origin_circuit_t *circ;
int i,n;
routerinfo_t *router;
@@ -310,7 +310,7 @@ rend_service_update_descriptor(rend_service_t *service)
continue;
}
circ = find_intro_circuit(router, service->pk_digest);
- if (circ && circ->purpose == CIRCUIT_PURPOSE_S_INTRO) {
+ if (circ && circ->_base.purpose == CIRCUIT_PURPOSE_S_INTRO) {
/* We have an entirely established intro circuit. */
d->intro_points[d->n_intro_points] = tor_strdup(router->nickname);
d->intro_point_extend_info[d->n_intro_points] =
@@ -410,7 +410,7 @@ rend_service_requires_uptime(rend_service_t *service)
* rendezvous point.
*/
int
-rend_service_introduce(circuit_t *circuit, const char *request,
+rend_service_introduce(origin_circuit_t *circuit, const char *request,
size_t request_len)
{
char *ptr, *r_cookie;
@@ -421,7 +421,7 @@ rend_service_introduce(circuit_t *circuit, const char *request,
int r, i;
size_t len, keylen;
crypto_dh_env_t *dh = NULL;
- circuit_t *launched = NULL;
+ origin_circuit_t *launched = NULL;
crypt_path_t *cpath = NULL;
char serviceid[REND_SERVICE_ID_LEN+1];
char hexcookie[9];
@@ -430,12 +430,12 @@ rend_service_introduce(circuit_t *circuit, const char *request,
base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
circuit->rend_pk_digest,10);
log_info(LD_REND, "Received INTRODUCE2 cell for service %s on circ %d.",
- escaped(serviceid), circuit->n_circ_id);
+ escaped(serviceid), circuit->_base.n_circ_id);
- if (circuit->purpose != CIRCUIT_PURPOSE_S_INTRO) {
+ if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_INTRO) {
log_warn(LD_PROTOCOL,
"Got an INTRODUCE2 over a non-introduction circuit %d.",
- circuit->n_circ_id);
+ circuit->_base.n_circ_id);
return -1;
}
@@ -443,7 +443,7 @@ rend_service_introduce(circuit_t *circuit, const char *request,
if (request_len < DIGEST_LEN+REND_COOKIE_LEN+(MAX_NICKNAME_LEN+1)+
DH_KEY_LEN+42) {
log_warn(LD_PROTOCOL, "Got a truncated INTRODUCE2 cell on circ %d.",
- circuit->n_circ_id);
+ circuit->_base.n_circ_id);
return -1;
}
@@ -518,7 +518,7 @@ rend_service_introduce(circuit_t *circuit, const char *request,
ptr=memchr(rp_nickname,0,nickname_field_len);
if (!ptr || ptr == rp_nickname) {
log_warn(LD_PROTOCOL,
- "Couldn't find a null-padded nickname in INTRODUCE2 cell.");
+ "Couldn't find a nul-padded nickname in INTRODUCE2 cell.");
return -1;
}
if ((version == 0 && !is_legal_nickname(rp_nickname)) ||
@@ -609,7 +609,8 @@ rend_service_introduce(circuit_t *circuit, const char *request,
return 0;
err:
if (dh) crypto_dh_free(dh);
- if (launched) circuit_mark_for_close(launched, END_CIRC_AT_ORIGIN);
+ if (launched)
+ circuit_mark_for_close(TO_CIRCUIT(launched), END_CIRC_AT_ORIGIN);
if (extend_info) extend_info_free(extend_info);
return -1;
}
@@ -618,12 +619,12 @@ rend_service_introduce(circuit_t *circuit, const char *request,
* than the last hop: launches a new circuit to the same rendezvous point.
*/
void
-rend_service_relaunch_rendezvous(circuit_t *oldcirc)
+rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc)
{
- circuit_t *newcirc;
+ origin_circuit_t *newcirc;
cpath_build_state_t *newstate, *oldstate;
- tor_assert(oldcirc->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
+ tor_assert(oldcirc->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
if (!oldcirc->build_state ||
oldcirc->build_state->failure_count > MAX_REND_FAILURES ||
@@ -663,8 +664,10 @@ rend_service_relaunch_rendezvous(circuit_t *oldcirc)
oldstate->pending_final_cpath = NULL;
memcpy(newcirc->rend_query, oldcirc->rend_query, REND_SERVICE_ID_LEN+1);
- memcpy(newcirc->rend_pk_digest, oldcirc->rend_pk_digest, DIGEST_LEN);
- memcpy(newcirc->rend_cookie, oldcirc->rend_cookie, REND_COOKIE_LEN);
+ memcpy(newcirc->rend_pk_digest, oldcirc->rend_pk_digest,
+ DIGEST_LEN);
+ memcpy(newcirc->rend_cookie, oldcirc->rend_cookie,
+ REND_COOKIE_LEN);
}
/** Launch a circuit to serve as an introduction point for the service
@@ -674,7 +677,7 @@ static int
rend_service_launch_establish_intro(rend_service_t *service,
const char *nickname)
{
- circuit_t *launched;
+ origin_circuit_t *launched;
log_info(LD_REND,
"Launching circuit to introduction point %s for service %s",
@@ -695,7 +698,7 @@ rend_service_launch_establish_intro(rend_service_t *service,
sizeof(launched->rend_query));
memcpy(launched->rend_pk_digest, service->pk_digest, DIGEST_LEN);
- if (launched->state == CIRCUIT_STATE_OPEN)
+ if (launched->_base.state == CIRCUIT_STATE_OPEN)
rend_service_intro_has_opened(launched);
return 0;
}
@@ -704,7 +707,7 @@ rend_service_launch_establish_intro(rend_service_t *service,
* sends a RELAY_ESTABLISH_INTRO cell.
*/
void
-rend_service_intro_has_opened(circuit_t *circuit)
+rend_service_intro_has_opened(origin_circuit_t *circuit)
{
rend_service_t *service;
size_t len;
@@ -713,8 +716,7 @@ rend_service_intro_has_opened(circuit_t *circuit)
char auth[DIGEST_LEN + 9];
char serviceid[REND_SERVICE_ID_LEN+1];
- tor_assert(circuit->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
- tor_assert(CIRCUIT_IS_ORIGIN(circuit));
+ tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
tor_assert(circuit->cpath);
base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
@@ -723,13 +725,13 @@ rend_service_intro_has_opened(circuit_t *circuit)
service = rend_service_get_by_pk_digest(circuit->rend_pk_digest);
if (!service) {
log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %d.",
- serviceid, circuit->n_circ_id);
+ serviceid, circuit->_base.n_circ_id);
goto err;
}
log_info(LD_REND,
"Established circuit %d as introduction point for service %s",
- circuit->n_circ_id, serviceid);
+ circuit->_base.n_circ_id, serviceid);
/* Build the payload for a RELAY_ESTABLISH_INTRO cell. */
len = crypto_pk_asn1_encode(service->private_key, buf+2,
@@ -748,29 +750,32 @@ rend_service_intro_has_opened(circuit_t *circuit)
}
len += r;
- if (connection_edge_send_command(NULL, circuit,RELAY_COMMAND_ESTABLISH_INTRO,
+ if (connection_edge_send_command(NULL, TO_CIRCUIT(circuit),
+ RELAY_COMMAND_ESTABLISH_INTRO,
buf, len, circuit->cpath->prev)<0) {
log_info(LD_GENERAL,
"Couldn't send introduction request for service %s on circuit %d",
- serviceid, circuit->n_circ_id);
+ serviceid, circuit->_base.n_circ_id);
goto err;
}
return;
err:
- circuit_mark_for_close(circuit, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_AT_ORIGIN);
}
/** Called when we get an INTRO_ESTABLISHED cell; mark the circuit as a
* live introduction point, and note that the service descriptor is
* now out-of-date.*/
int
-rend_service_intro_established(circuit_t *circuit, const char *request,
+rend_service_intro_established(origin_circuit_t *circuit, const char *request,
size_t request_len)
{
rend_service_t *service;
+ (void) request;
+ (void) request_len;
- if (circuit->purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
+ if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
log_warn(LD_PROTOCOL,
"received INTRO_ESTABLISHED cell on non-intro circuit.");
goto err;
@@ -778,15 +783,15 @@ rend_service_intro_established(circuit_t *circuit, const char *request,
service = rend_service_get_by_pk_digest(circuit->rend_pk_digest);
if (!service) {
log_warn(LD_REND, "Unknown service on introduction circuit %d.",
- circuit->n_circ_id);
+ circuit->_base.n_circ_id);
goto err;
}
service->desc_is_dirty = time(NULL);
- circuit->purpose = CIRCUIT_PURPOSE_S_INTRO;
+ circuit->_base.purpose = CIRCUIT_PURPOSE_S_INTRO;
return 0;
err:
- circuit_mark_for_close(circuit, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_AT_ORIGIN);
return -1;
}
@@ -794,7 +799,7 @@ rend_service_intro_established(circuit_t *circuit, const char *request,
* RELAY_COMMAND_RENDEZVOUS1 cell.
*/
void
-rend_service_rendezvous_has_opened(circuit_t *circuit)
+rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
{
rend_service_t *service;
char buf[RELAY_PAYLOAD_SIZE];
@@ -802,7 +807,7 @@ rend_service_rendezvous_has_opened(circuit_t *circuit)
char serviceid[REND_SERVICE_ID_LEN+1];
char hexcookie[9];
- tor_assert(circuit->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
+ tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
tor_assert(circuit->cpath);
tor_assert(circuit->build_state);
hop = circuit->build_state->pending_final_cpath;
@@ -815,7 +820,7 @@ rend_service_rendezvous_has_opened(circuit_t *circuit)
log_info(LD_REND,
"Done building circuit %d to rendezvous with "
"cookie %s for service %s",
- circuit->n_circ_id, hexcookie, serviceid);
+ circuit->_base.n_circ_id, hexcookie, serviceid);
service = rend_service_get_by_pk_digest(circuit->rend_pk_digest);
if (!service) {
@@ -835,7 +840,8 @@ rend_service_rendezvous_has_opened(circuit_t *circuit)
DIGEST_LEN);
/* Send the cell */
- if (connection_edge_send_command(NULL, circuit, RELAY_COMMAND_RENDEZVOUS1,
+ if (connection_edge_send_command(NULL, TO_CIRCUIT(circuit),
+ RELAY_COMMAND_RENDEZVOUS1,
buf, REND_COOKIE_LEN+DH_KEY_LEN+DIGEST_LEN,
circuit->cpath->prev)<0) {
log_warn(LD_GENERAL, "Couldn't send RENDEZVOUS1 cell.");
@@ -857,11 +863,11 @@ rend_service_rendezvous_has_opened(circuit_t *circuit)
circuit->build_state->pending_final_cpath = NULL; /* prevent double-free */
/* Change the circuit purpose. */
- circuit->purpose = CIRCUIT_PURPOSE_S_REND_JOINED;
+ circuit->_base.purpose = CIRCUIT_PURPOSE_S_REND_JOINED;
return;
err:
- circuit_mark_for_close(circuit, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_AT_ORIGIN);
}
/*
@@ -872,15 +878,14 @@ rend_service_rendezvous_has_opened(circuit_t *circuit)
* <b>router</b> for the service whose public key is <b>pk_digest</b>. Return
* NULL if no such service is found.
*/
-static circuit_t *
+static origin_circuit_t *
find_intro_circuit(routerinfo_t *router, const char *pk_digest)
{
- circuit_t *circ = NULL;
+ origin_circuit_t *circ = NULL;
tor_assert(router);
while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest,
CIRCUIT_PURPOSE_S_INTRO))) {
- tor_assert(circ->cpath);
if (!strcasecmp(circ->build_state->chosen_exit->nickname,
router->nickname)) {
return circ;
@@ -890,7 +895,6 @@ find_intro_circuit(routerinfo_t *router, const char *pk_digest)
circ = NULL;
while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest,
CIRCUIT_PURPOSE_S_ESTABLISH_INTRO))) {
- tor_assert(circ->cpath);
if (!strcasecmp(circ->build_state->chosen_exit->nickname,
router->nickname)) {
return circ;
@@ -1086,7 +1090,7 @@ rend_service_dump_stats(int severity)
routerinfo_t *router;
rend_service_t *service;
char *nickname;
- circuit_t *circ;
+ origin_circuit_t *circ;
for (i=0; i < smartlist_len(rend_service_list); ++i) {
service = smartlist_get(rend_service_list, i);
@@ -1106,7 +1110,7 @@ rend_service_dump_stats(int severity)
continue;
}
log(severity, LD_GENERAL, " Intro point at %s: circuit is %s",nickname,
- circuit_state_to_string(circ->state));
+ circuit_state_to_string(circ->_base.state));
}
}
}
@@ -1117,14 +1121,15 @@ rend_service_dump_stats(int severity)
* or 0 for success.
*/
int
-rend_service_set_connection_addr_port(connection_t *conn, circuit_t *circ)
+rend_service_set_connection_addr_port(edge_connection_t *conn,
+ origin_circuit_t *circ)
{
rend_service_t *service;
int i;
rend_service_port_config_t *p;
char serviceid[REND_SERVICE_ID_LEN+1];
- tor_assert(circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED);
+ tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_S_REND_JOINED);
log_debug(LD_REND,"beginning to hunt for addr/port");
base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
circ->rend_pk_digest,10);
@@ -1132,19 +1137,19 @@ rend_service_set_connection_addr_port(connection_t *conn, circuit_t *circ)
if (!service) {
log_warn(LD_REND, "Couldn't find any service associated with pk %s on "
"rendezvous circuit %d; closing.",
- serviceid, circ->n_circ_id);
+ serviceid, circ->_base.n_circ_id);
return -1;
}
for (i = 0; i < smartlist_len(service->ports); ++i) {
p = smartlist_get(service->ports, i);
- if (conn->port == p->virtual_port) {
- conn->addr = p->real_addr;
- conn->port = p->real_port;
+ if (conn->_base.port == p->virtual_port) {
+ conn->_base.addr = p->real_addr;
+ conn->_base.port = p->real_port;
return 0;
}
}
log_info(LD_REND, "No virtual port mapping exists for port %d on service %s",
- conn->port,serviceid);
+ conn->_base.port,serviceid);
return -1;
}
diff --git a/src/or/rephist.c b/src/or/rephist.c
index 8caad25ce4..2dceb143b1 100644
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@ -59,14 +59,13 @@ typedef struct or_history_t {
/** Map from hex OR identity digest to or_history_t. */
static digestmap_t *history_map = NULL;
-/** Return the or_history_t for the named OR, creating it if necessary.
- */
+/** Return the or_history_t for the named OR, creating it if necessary. */
static or_history_t *
get_or_history(const char* id)
{
or_history_t *hist;
- if (!memcmp(id, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", DIGEST_LEN))
+ if (tor_mem_is_zero(id, DIGEST_LEN))
return NULL;
hist = digestmap_get(history_map, id);
@@ -83,7 +82,7 @@ get_or_history(const char* id)
/** Return the link_history_t for the link from the first named OR to
* the second, creating it if necessary. (ORs are identified by
- * identity digest)
+ * identity digest.)
*/
static link_history_t *
get_link_history(const char *from_id, const char *to_id)
@@ -93,7 +92,7 @@ get_link_history(const char *from_id, const char *to_id)
orhist = get_or_history(from_id);
if (!orhist)
return NULL;
- if (!memcmp(to_id, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", DIGEST_LEN))
+ if (tor_mem_is_zero(to_id, DIGEST_LEN))
return NULL;
lhist = (link_history_t*) digestmap_get(orhist->link_history_map, to_id);
if (!lhist) {
@@ -105,7 +104,7 @@ get_link_history(const char *from_id, const char *to_id)
return lhist;
}
-/** Helper: free storage held by a single link history entry */
+/** Helper: free storage held by a single link history entry. */
static void
_free_link_history(void *val)
{
@@ -113,7 +112,7 @@ _free_link_history(void *val)
tor_free(val);
}
-/** Helper: free storage held by a single OR history entry */
+/** Helper: free storage held by a single OR history entry. */
static void
free_or_history(void *_hist)
{
@@ -141,8 +140,7 @@ update_or_history(or_history_t *hist, time_t when)
}
}
-/** Initialize the static data structures for tracking history.
- */
+/** Initialize the static data structures for tracking history. */
void
rep_hist_init(void)
{
@@ -236,7 +234,7 @@ rep_hist_note_connection_died(const char* id, time_t when)
/** Remember that we successfully extended from the OR with identity
* digest <b>from_id</b> to the OR with identity digest
- * <b>to_name</b>.
+ * <b>to_name</b>.
*/
void
rep_hist_note_extend_succeeded(const char *from_id, const char *to_id)
@@ -344,7 +342,8 @@ rep_hist_dump_stats(time_t now, int severity)
}
/** Remove history info for routers/links that haven't changed since
- * <b>before</b> */
+ * <b>before</b>.
+ */
void
rep_history_clean(time_t before)
{
@@ -387,11 +386,10 @@ rep_history_clean(time_t before)
#define NUM_SECS_BW_SUM_INTERVAL (15*60)
/** How far in the past do we remember and publish bandwidth use? */
#define NUM_SECS_BW_SUM_IS_VALID (24*60*60)
-/** How many bandwidth usage intervals do we remember? (derived.) */
+/** How many bandwidth usage intervals do we remember? (derived) */
#define NUM_TOTALS (NUM_SECS_BW_SUM_IS_VALID/NUM_SECS_BW_SUM_INTERVAL)
-/**
- * Structure to track bandwidth use, and remember the maxima for a given
+/** Structure to track bandwidth use, and remember the maxima for a given
* time period.
*/
typedef struct bw_array_t {
@@ -423,8 +421,7 @@ typedef struct bw_array_t {
uint64_t totals[NUM_TOTALS];
} bw_array_t;
-/** Shift the current period of b forward by one.
- */
+/** Shift the current period of b forward by one. */
static void
commit_max(bw_array_t *b)
{
@@ -444,8 +441,7 @@ commit_max(bw_array_t *b)
b->total_in_period = 0;
}
-/** Shift the current observation time of 'b' forward by one second.
- */
+/** Shift the current observation time of 'b' forward by one second. */
static INLINE void
advance_obs(bw_array_t *b)
{
@@ -470,8 +466,7 @@ advance_obs(bw_array_t *b)
commit_max(b);
}
-/** Add 'n' bytes to the number of bytes in b for second 'when'.
- */
+/** Add 'n' bytes to the number of bytes in b for second 'when'. */
static INLINE void
add_obs(bw_array_t *b, time_t when, uint64_t n)
{
@@ -488,8 +483,7 @@ add_obs(bw_array_t *b, time_t when, uint64_t n)
b->total_in_period += n;
}
-/** Allocate, initialize, and return a new bw_array.
- */
+/** Allocate, initialize, and return a new bw_array. */
static bw_array_t *
bw_array_new(void)
{
@@ -506,8 +500,7 @@ bw_array_new(void)
static bw_array_t *read_array = NULL;
static bw_array_t *write_array = NULL;
-/** Set up read_array and write_array
- */
+/** Set up read_array and write_array. */
static void
bw_arrays_init(void)
{
@@ -563,8 +556,7 @@ find_largest_max(bw_array_t *b)
return max;
}
-/**
- * Find the largest sums in the past NUM_SECS_BW_SUM_IS_VALID (roughly)
+/** Find the largest sums in the past NUM_SECS_BW_SUM_IS_VALID (roughly)
* seconds. Find one sum for reading and one for writing. They don't have
* to be at the same time).
*
@@ -577,15 +569,12 @@ rep_hist_bandwidth_assess(void)
r = find_largest_max(read_array);
w = find_largest_max(write_array);
if (r>w)
- return (int)(w/(double)NUM_SECS_ROLLING_MEASURE);
+ return (int)(U64_TO_DBL(w)/NUM_SECS_ROLLING_MEASURE);
else
- return (int)(r/(double)NUM_SECS_ROLLING_MEASURE);
-
- return 0;
+ return (int)(U64_TO_DBL(r)/NUM_SECS_ROLLING_MEASURE);
}
-/**
- * Print the bandwidth history of b (either read_array or write_array)
+/** Print the bandwidth history of b (either read_array or write_array)
* into the buffer pointed to by buf. The format is simply comma
* separated numbers, from oldest to newest.
*
@@ -619,8 +608,7 @@ rep_hist_fill_bandwidth_history(char *buf, size_t len, bw_array_t *b)
return cp-buf;
}
-/**
- * Allocate and return lines for representing this server's bandwidth
+/** Allocate and return lines for representing this server's bandwidth
* history in its descriptor.
*/
char *
@@ -689,8 +677,7 @@ rep_hist_update_state(or_state_t *state)
state->dirty = 1;
}
-/** Set bandwidth history from our saved state.
- */
+/** Set bandwidth history from our saved state. */
int
rep_hist_load_state(or_state_t *state, char **err)
{
@@ -751,12 +738,17 @@ rep_hist_load_state(or_state_t *state, char **err)
return 0;
}
+/*********************************************************************/
+
/** A list of port numbers that have been used recently. */
static smartlist_t *predicted_ports_list=NULL;
/** The corresponding most recently used time for each port. */
static smartlist_t *predicted_ports_times=NULL;
-/** DOCDOC */
+/** We just got an application request for a connection with
+ * port <b>port</b>. Remember it for the future, so we can keep
+ * some circuits open that will exit to this port.
+ */
static void
add_predicted_port(uint16_t port, time_t now)
{
@@ -770,7 +762,10 @@ add_predicted_port(uint16_t port, time_t now)
smartlist_add(predicted_ports_times, tmp_time);
}
-/** DOCDOC */
+/** Initialize whatever memory and structs are needed for predicting
+ * which ports will be used. Also seed it with port 80, so we'll build
+ * circuits on start-up.
+ */
static void
predicted_ports_init(void)
{
@@ -779,7 +774,9 @@ predicted_ports_init(void)
add_predicted_port(80, time(NULL)); /* add one to kickstart us */
}
-/** DOCDOC */
+/** Free whatever memory is needed for predicting which ports will
+ * be used.
+ */
static void
predicted_ports_free(void)
{
@@ -921,6 +918,22 @@ any_predicted_circuits(time_t now)
predicted_internal_time + PREDICTED_CIRCS_RELEVANCE_TIME >= now;
}
+/** Return 1 if we have no need for circuits currently, else return 0. */
+int
+rep_hist_circbuilding_dormant(time_t now)
+{
+ if (any_predicted_circuits(now))
+ return 0;
+
+ /* see if we'll still need to build testing circuits */
+ if (server_mode(get_options()) && !check_whether_orport_reachable())
+ return 0;
+ if (!check_whether_dirport_reachable())
+ return 0;
+
+ return 1;
+}
+
/** Free all storage held by the OR/link history caches, by the
* bandwidth history arrays, or by the port history. */
void
diff --git a/src/or/router.c b/src/or/router.c
index dd9bde6ff3..a5f8db09ae 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -232,7 +232,8 @@ init_key_from_file(const char *fname)
}
/** Initialize all OR private keys, and the TLS context, as necessary.
- * On OPs, this only initializes the tls context.
+ * On OPs, this only initializes the tls context. Return 0 on success,
+ * or -1 if Tor should die.
*/
int
init_keys(void)
@@ -260,10 +261,10 @@ init_keys(void)
return -1;
set_identity_key(prkey);
/* Create a TLS context; default the client nickname to "client". */
- if (tor_tls_context_new(get_identity_key(), 1,
+ if (tor_tls_context_new(get_identity_key(),
options->Nickname ? options->Nickname : "client",
MAX_SSL_KEY_LIFETIME) < 0) {
- log_err(LD_GENERAL,"Error creating TLS context for OP.");
+ log_err(LD_GENERAL,"Error creating TLS context for Tor client.");
return -1;
}
return 0;
@@ -302,7 +303,7 @@ init_keys(void)
}
/* 3. Initialize link key and TLS context. */
- if (tor_tls_context_new(get_identity_key(), 1, options->Nickname,
+ if (tor_tls_context_new(get_identity_key(), options->Nickname,
MAX_SSL_KEY_LIFETIME) < 0) {
log_err(LD_GENERAL,"Error initializing TLS context");
return -1;
@@ -310,10 +311,6 @@ init_keys(void)
/* 4. Build our router descriptor. */
/* Must be called after keys are initialized. */
mydesc = router_get_my_descriptor();
- if (!mydesc) {
- log_err(LD_GENERAL,"Error initializing descriptor.");
- return -1;
- }
if (authdir_mode(options)) {
const char *m;
/* We need to add our own fingerprint so it gets recognized. */
@@ -321,6 +318,10 @@ init_keys(void)
log_err(LD_GENERAL,"Error adding own fingerprint to approved set");
return -1;
}
+ if (!mydesc) {
+ log_err(LD_GENERAL,"Error initializing descriptor.");
+ return -1;
+ }
if (dirserv_add_descriptor(mydesc, &m) < 0) {
log_err(LD_GENERAL,"Unable to add own descriptor to directory: %s",
m?m:"<unknown error>");
@@ -328,13 +329,6 @@ init_keys(void)
}
}
-#if 0
- tor_snprintf(keydir,sizeof(keydir),"%s/router.desc", datadir);
- log_info(LD_GENERAL,"Dumping descriptor to \"%s\"...",keydir);
- if (write_str_to_file(keydir, mydesc,0)) {
- return -1;
- }
-#endif
/* 5. Dump fingerprint to 'fingerprint' */
tor_snprintf(keydir,sizeof(keydir),"%s/fingerprint", datadir);
log_info(LD_GENERAL,"Dumping fingerprint to \"%s\"...",keydir);
@@ -359,9 +353,7 @@ init_keys(void)
if (!authdir_mode(options))
return 0;
/* 6. [authdirserver only] load approved-routers file */
- tor_snprintf(keydir,sizeof(keydir),"%s/approved-routers", datadir);
- log_info(LD_DIRSERV,"Loading approved fingerprints from \"%s\"...",keydir);
- if (dirserv_parse_fingerprint_file(keydir) < 0) {
+ if (dirserv_load_fingerprint_file() < 0) {
log_err(LD_GENERAL,"Error loading fingerprints");
return -1;
}
@@ -372,8 +364,7 @@ init_keys(void)
(uint16_t)options->DirPort, digest,
options->V1AuthoritativeDir);
}
- /* success */
- return 0;
+ return 0; /* success */
}
/* Keep track of whether we should upload our server descriptor,
@@ -385,13 +376,12 @@ static int can_reach_or_port = 0;
/** Whether we can reach our DirPort from the outside. */
static int can_reach_dir_port = 0;
-/** Return 1 if or port is known reachable; else return 0. */
+/** Return 1 if ORPort is known reachable; else return 0. */
int
check_whether_orport_reachable(void)
{
or_options_t *options = get_options();
- return clique_mode(options) ||
- options->AssumeReachable ||
+ return options->AssumeReachable ||
can_reach_or_port;
}
@@ -446,22 +436,23 @@ decide_to_advertise_dirport(or_options_t *options, routerinfo_t *router)
* Success is noticed in connection_dir_client_reached_eof().
*/
void
-consider_testing_reachability(void)
+consider_testing_reachability(int test_or, int test_dir)
{
routerinfo_t *me = router_get_my_routerinfo();
- if (!me) {
- log_warn(LD_BUG,
- "Bug: router_get_my_routerinfo() did not find my routerinfo?");
+ int orport_reachable = check_whether_orport_reachable();
+ if (!me)
return;
- }
- if (!check_whether_orport_reachable()) {
+ if (test_or && (!orport_reachable || !circuit_enough_testing_circs())) {
+ log_info(LD_CIRC, "Testing %s of my ORPort: %s:%d.",
+ !orport_reachable ? "reachability" : "bandwidth",
+ me->address, me->or_port);
log_info(LD_CIRC, "Testing reachability of my ORPort: %s:%d.",
me->address, me->or_port);
circuit_launch_by_router(CIRCUIT_PURPOSE_TESTING, me, 0, 1, 1);
}
- if (!check_whether_dirport_reachable()) {
+ if (test_dir && !check_whether_dirport_reachable()) {
/* ask myself, via tor, for my server descriptor. */
directory_initiate_command_router(me, DIR_PURPOSE_FETCH_SERVERDESC,
1, "authority", NULL, 0);
@@ -473,14 +464,12 @@ void
router_orport_found_reachable(void)
{
if (!can_reach_or_port) {
- if (!clique_mode(get_options()))
- log_notice(LD_OR,"Self-testing indicates your ORPort is reachable from "
- "the outside. Excellent.%s",
- get_options()->PublishServerDescriptor ?
- " Publishing server descriptor." : "");
+ log_notice(LD_OR,"Self-testing indicates your ORPort is reachable from "
+ "the outside. Excellent.%s",
+ get_options()->PublishServerDescriptor ?
+ " Publishing server descriptor." : "");
can_reach_or_port = 1;
mark_my_descriptor_dirty();
- consider_publishable_server(time(NULL), 1);
}
}
@@ -492,19 +481,53 @@ router_dirport_found_reachable(void)
log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable "
"from the outside. Excellent.");
can_reach_dir_port = 1;
+ mark_my_descriptor_dirty();
}
}
+#define UPTIME_CUTOFF_FOR_NEW_BANDWIDTH_TEST (6*60*60)
+
/** Our router has just moved to a new IP. Reset stats. */
void
server_has_changed_ip(void)
{
+ if (stats_n_seconds_working > UPTIME_CUTOFF_FOR_NEW_BANDWIDTH_TEST)
+ reset_bandwidth_test();
stats_n_seconds_working = 0;
can_reach_or_port = 0;
can_reach_dir_port = 0;
mark_my_descriptor_dirty();
}
+/** We have enough testing circuit open. Send a bunch of "drop"
+ * cells down each of them, to exercise our bandwidth. */
+void
+router_perform_bandwidth_test(int num_circs, time_t now)
+{
+ int num_cells = get_options()->BandwidthRate * 10 / CELL_NETWORK_SIZE;
+ int max_cells = num_cells < CIRCWINDOW_START ?
+ num_cells : CIRCWINDOW_START;
+ int cells_per_circuit = max_cells / num_circs;
+ origin_circuit_t *circ = NULL;
+
+ log_notice(LD_OR,"Performing bandwidth self-test.");
+ while ((circ = circuit_get_next_by_pk_and_purpose(circ, NULL,
+ CIRCUIT_PURPOSE_TESTING))) {
+ /* dump cells_per_circuit drop cells onto this circ */
+ int i = cells_per_circuit;
+ if (circ->_base.state != CIRCUIT_STATE_OPEN)
+ continue;
+ circ->_base.timestamp_dirty = now;
+ while (i-- > 0) {
+ if (connection_edge_send_command(NULL, TO_CIRCUIT(circ),
+ RELAY_COMMAND_DROP,
+ NULL, 0, circ->cpath->prev)<0) {
+ return; /* stop if error */
+ }
+ }
+ }
+}
+
/** Return true iff we believe ourselves to be an authoritative
* directory server.
*/
@@ -569,7 +592,7 @@ proxy_mode(or_options_t *options)
* - We have the AuthoritativeDirectory option set.
*/
static int
-decide_if_publishable_server(time_t now)
+decide_if_publishable_server(void)
{
or_options_t *options = get_options();
@@ -593,7 +616,7 @@ decide_if_publishable_server(time_t now)
* determine what IP address and ports to test.
*/
void
-consider_publishable_server(time_t now, int force)
+consider_publishable_server(int force)
{
int rebuilt;
@@ -601,7 +624,7 @@ consider_publishable_server(time_t now, int force)
return;
rebuilt = router_rebuild_descriptor(0);
- if (decide_if_publishable_server(now)) {
+ if (decide_if_publishable_server()) {
set_server_advertised(1);
if (rebuilt == 0)
router_upload_dir_desc_to_dirservers(force);
@@ -611,58 +634,9 @@ consider_publishable_server(time_t now, int force)
}
/*
- * Clique maintenance
+ * Clique maintenance -- to be phased out.
*/
-/** OR only: if in clique mode, try to open connections to all of the
- * other ORs we know about. Otherwise, open connections to those we
- * think are in clique mode.
- *
- * If <b>testing_reachability</b> is 0, try to open the connections
- * but only if we don't already have one. If it's 1, then we're an
- * auth dir server, and we should try to connect regardless of
- * whether we already have a connection open -- but if <b>try_all</b>
- * is 0, we want to load balance such that we only try a few connections
- * per call.
- *
- * The load balancing is such that if we get called once every ten
- * seconds, we will cycle through all the tests in 1280 seconds (a
- * bit over 20 minutes).
- */
-void
-router_retry_connections(int testing_reachability, int try_all)
-{
- time_t now = time(NULL);
- routerlist_t *rl = router_get_routerlist();
- or_options_t *options = get_options();
- static char ctr = 0;
-
- tor_assert(server_mode(options));
-
- SMARTLIST_FOREACH(rl->routers, routerinfo_t *, router, {
- const char *id_digest = router->cache_info.identity_digest;
- if (router_is_me(router))
- continue;
- if (!clique_mode(options) && !router_is_clique_mode(router))
- continue;
- if ((testing_reachability &&
- (try_all || (((uint8_t)id_digest[0]) % 128) == ctr)) ||
- (!testing_reachability &&
- !connection_or_get_by_identity_digest(id_digest))) {
- log_debug(LD_OR,"%sconnecting to %s at %s:%u.",
- clique_mode(options) ? "(forced) " : "",
- router->nickname, router->address, router->or_port);
- /* Remember when we started trying to determine reachability */
- if (!router->testing_since)
- router->testing_since = now;
- connection_or_connect(router->addr, router->or_port,
- id_digest);
- }
- });
- if (testing_reachability && !try_all) /* increment ctr */
- ctr = (ctr + 1) % 128;
-}
-
/** Return true iff this OR should try to keep connections open to all
* other ORs. */
int
@@ -696,7 +670,7 @@ router_upload_dir_desc_to_dirservers(int force)
s = router_get_my_descriptor();
if (!s) {
- log_warn(LD_GENERAL, "No descriptor; skipping upload");
+ log_info(LD_GENERAL, "No descriptor; skipping upload");
return;
}
if (!get_options()->PublishServerDescriptor)
@@ -711,16 +685,16 @@ router_upload_dir_desc_to_dirservers(int force)
* conn. Return 0 if we accept; non-0 if we reject.
*/
int
-router_compare_to_my_exit_policy(connection_t *conn)
+router_compare_to_my_exit_policy(edge_connection_t *conn)
{
tor_assert(desc_routerinfo);
/* make sure it's resolved to something. this way we can't get a
'maybe' below. */
- if (!conn->addr)
+ if (!conn->_base.addr)
return -1;
- return compare_addr_to_addr_policy(conn->addr, conn->port,
+ return compare_addr_to_addr_policy(conn->_base.addr, conn->_base.port,
desc_routerinfo->exit_policy) != ADDR_POLICY_ACCEPTED;
}
@@ -777,7 +751,10 @@ router_get_my_descriptor(void)
const char *body;
if (!router_get_my_routerinfo())
return NULL;
+ /* Make sure this is nul-terminated. */
+ tor_assert(desc_routerinfo->cache_info.saved_location == SAVED_NOWHERE);
body = signed_descriptor_get_body(&desc_routerinfo->cache_info);
+ tor_assert(!body[desc_routerinfo->cache_info.signed_descriptor_len]);
log_debug(LD_GENERAL,"my desc is '%s'", body);
return body;
}
@@ -785,9 +762,29 @@ router_get_my_descriptor(void)
/*DOCDOC*/
static smartlist_t *warned_nonexistent_family = NULL;
+static int router_guess_address_from_dir_headers(uint32_t *guess);
+
+/** Return our current best guess at our address, either because
+ * it's configured in torrc, or because we've learned it from
+ * dirserver headers. */
+int
+router_pick_published_address(or_options_t *options, uint32_t *addr)
+{
+ if (resolve_my_address(LOG_INFO, options, addr, NULL) < 0) {
+ log_info(LD_CONFIG, "Could not determine our address locally. "
+ "Checking if directory headers provide any hints.");
+ if (router_guess_address_from_dir_headers(addr) < 0) {
+ log_info(LD_CONFIG, "No hints from directory headers either. "
+ "Will try again later.");
+ return -1;
+ }
+ }
+ return 0;
+}
+
/** If <b>force</b> is true, or our descriptor is out-of-date, rebuild
* a fresh routerinfo and signed server descriptor for this OR.
- * Return 0 on success, -1 on error.
+ * Return 0 on success, -1 on temporary error.
*/
int
router_rebuild_descriptor(int force)
@@ -801,12 +798,16 @@ router_rebuild_descriptor(int force)
if (desc_clean_since && !force)
return 0;
- if (resolve_my_address(options, &addr, NULL) < 0) {
- log_warn(LD_CONFIG,"options->Address didn't resolve into an IP.");
+ if (router_pick_published_address(options, &addr) < 0) {
+ /* Stop trying to rebuild our descriptor every second. We'll
+ * learn that it's time to try again when server_has_changed_ip()
+ * marks it dirty. */
+ desc_clean_since = time(NULL);
return -1;
}
ri = tor_malloc_zero(sizeof(routerinfo_t));
+ ri->routerlist_index = -1;
ri->address = tor_dup_addr(addr);
ri->nickname = tor_strdup(options->Nickname);
ri->addr = addr;
@@ -877,6 +878,11 @@ router_rebuild_descriptor(int force)
}
tor_free(name);
});
+
+ /* remove duplicates from the list */
+ smartlist_sort_strings(ri->declared_family);
+ smartlist_uniq_strings(ri->declared_family);
+
smartlist_free(family);
}
ri->cache_info.signed_descriptor_body = tor_malloc(8192);
@@ -943,6 +949,31 @@ check_descriptor_bandwidth_changed(time_t now)
}
}
+static void
+log_addr_has_changed(int severity, uint32_t prev, uint32_t cur)
+{
+ char addrbuf_prev[INET_NTOA_BUF_LEN];
+ char addrbuf_cur[INET_NTOA_BUF_LEN];
+ struct in_addr in_prev;
+ struct in_addr in_cur;
+
+ in_prev.s_addr = htonl(prev);
+ tor_inet_ntoa(&in_prev, addrbuf_prev, sizeof(addrbuf_prev));
+
+ in_cur.s_addr = htonl(cur);
+ tor_inet_ntoa(&in_cur, addrbuf_cur, sizeof(addrbuf_cur));
+
+ if (prev)
+ log_fn(severity, LD_GENERAL,
+ "Our IP Address has changed from %s to %s; "
+ "rebuilding descriptor.",
+ addrbuf_prev, addrbuf_cur);
+ else
+ log_notice(LD_GENERAL,
+ "Guessed our IP address as %s.",
+ addrbuf_cur);
+}
+
/** Check whether our own address as defined by the Address configuration
* has changed. This is for routers that get their address from a service
* like dyndns. If our address has changed, mark our descriptor dirty. */
@@ -951,36 +982,74 @@ check_descriptor_ipaddress_changed(time_t now)
{
uint32_t prev, cur;
or_options_t *options = get_options();
+ (void) now;
if (!desc_routerinfo)
return;
prev = desc_routerinfo->addr;
- if (resolve_my_address(options, &cur, NULL) < 0) {
- log_warn(LD_CONFIG,"options->Address didn't resolve into an IP.");
+ if (resolve_my_address(LOG_INFO, options, &cur, NULL) < 0) {
+ log_info(LD_CONFIG,"options->Address didn't resolve into an IP.");
return;
}
if (prev != cur) {
- char addrbuf_prev[INET_NTOA_BUF_LEN];
- char addrbuf_cur[INET_NTOA_BUF_LEN];
- struct in_addr in_prev;
- struct in_addr in_cur;
+ log_addr_has_changed(LOG_INFO, prev, cur);
+ mark_my_descriptor_dirty();
+ /* the above call is probably redundant, since resolve_my_address()
+ * probably already noticed and marked it dirty. */
+ }
+}
+
+static uint32_t last_guessed_ip = 0;
+
+/** A directory authority told us our IP address is <b>suggestion</b>.
+ * If this address is different from the one we think we are now, and
+ * if our computer doesn't actually know its IP address, then switch. */
+void
+router_new_address_suggestion(const char *suggestion)
+{
+ uint32_t addr, cur;
+ struct in_addr in;
+ or_options_t *options = get_options();
- in_prev.s_addr = htonl(prev);
- tor_inet_ntoa(&in_prev, addrbuf_prev, sizeof(addrbuf_prev));
+ /* first, learn what the IP address actually is */
+ if (!tor_inet_aton(suggestion, &in)) {
+ log_debug(LD_DIR, "Malformed X-Your-Address-Is header. Ignoring.");
+ return;
+ }
+ addr = ntohl(in.s_addr);
- in_cur.s_addr = htonl(cur);
- tor_inet_ntoa(&in_cur, addrbuf_cur, sizeof(addrbuf_cur));
+ log_debug(LD_DIR, "Got X-Your-Address-Is: %s.", suggestion);
- log_info(LD_GENERAL,
- "Our IP Address has changed from %s to %s; "
- "rebuilding descriptor.",
- addrbuf_prev, addrbuf_cur);
- mark_my_descriptor_dirty();
+ if (!server_mode(options) ||
+ resolve_my_address(LOG_INFO, options, &cur, NULL) >= 0) {
+ /* We're all set -- we already know our address. Great. */
+ last_guessed_ip = cur; /* store it in case we need it later */
+ return;
+ }
+
+ if (last_guessed_ip != addr) {
+ log_addr_has_changed(LOG_NOTICE, last_guessed_ip, addr);
+ server_has_changed_ip();
+ last_guessed_ip = addr; /* router_rebuild_descriptor() will fetch it */
}
}
+/** We failed to resolve our address locally, but we'd like to build
+ * a descriptor and publish / test reachability. If we have a guess
+ * about our address based on directory headers, answer it and return
+ * 0; else return -1. */
+static int
+router_guess_address_from_dir_headers(uint32_t *guess)
+{
+ if (last_guessed_ip) {
+ *guess = last_guessed_ip;
+ return 0;
+ }
+ return -1;
+}
+
/** Set <b>platform</b> (max length <b>len</b>) to a NUL-terminated short
* string describing the version of Tor and the operating system we're
* currently running on.
@@ -1082,7 +1151,13 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
"uptime %ld\n"
"bandwidth %d %d %d\n"
"onion-key\n%s"
- "signing-key\n%s%s%s%s",
+ "signing-key\n%s"
+#ifdef USE_EVENTDNS
+ "opt eventdns 1\n"
+#else
+ "opt eventdns 0\n"
+#endif
+ "%s%s%s",
router->nickname,
router->address,
router->or_port,
@@ -1161,6 +1236,7 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
written += result;
}
} /* end for */
+
if (written+256 > maxlen) /* Not enough room for signature. */
return -1;
@@ -1186,7 +1262,7 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
#ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
cp = s_tmp = s_dup = tor_strdup(s);
- ri_tmp = router_parse_entry_from_string(cp, NULL);
+ ri_tmp = router_parse_entry_from_string(cp, NULL, 1);
if (!ri_tmp) {
log_err(LD_BUG,
"We just generated a router descriptor we can't parse: <<%s>>",
@@ -1229,10 +1305,10 @@ is_legal_hexdigest(const char *s)
{
size_t len;
tor_assert(s);
+ if (s[0] == '$') s++;
len = strlen(s);
- return (len == HEX_DIGEST_LEN+1 &&
- s[0] == '$' &&
- strspn(s+1,HEX_CHARACTERS)==len-1);
+ return (len == HEX_DIGEST_LEN &&
+ strspn(s,HEX_CHARACTERS)==len);
}
/** Forget that we have issued any router-related warnings, so that we'll
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index a68ed86e6c..71cc367af1 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -55,9 +55,13 @@ static routerlist_t *routerlist = NULL;
* about. This list is kept sorted by published_on. */
static smartlist_t *networkstatus_list = NULL;
-/** Global list of local_routerstatus_t for each router, known or unknown. */
+/** Global list of local_routerstatus_t for each router, known or unknown.
+ * Kept sorted by digest. */
static smartlist_t *routerstatus_list = NULL;
+/** Map from lowercase nickname to digest of named server, if any. */
+static strmap_t *named_server_map = NULL;
+
/** True iff any member of networkstatus_list has changed since the last time
* we called routerstatus_list_update_from_networkstatus(). */
static int networkstatus_list_has_changed = 0;
@@ -183,17 +187,33 @@ router_append_to_journal(signed_descriptor_t *desc)
tor_assert(len == strlen(body));
- if (append_bytes_to_file(fname, body, len, 0)) {
+ if (append_bytes_to_file(fname, body, len, 1)) {
log_warn(LD_FS, "Unable to store router descriptor");
tor_free(fname);
return -1;
}
+ desc->saved_location = SAVED_IN_JOURNAL;
+ desc->saved_offset = router_journal_len;
tor_free(fname);
router_journal_len += len;
return 0;
}
+static int
+_compare_old_routers_by_age(const void **_a, const void **_b)
+{
+ const signed_descriptor_t *r1 = *_a, *r2 = *_b;
+ return r1->published_on - r2->published_on;
+}
+
+static int
+_compare_routers_by_age(const void **_a, const void **_b)
+{
+ const routerinfo_t *r1 = *_a, *r2 = *_b;
+ return r1->cache_info.published_on - r2->cache_info.published_on;
+}
+
/** If the journal is too long, or if <b>force</b> is true, then atomically
* replace the router store with the routers currently in our routerlist, and
* clear the journal. Return 0 on success, -1 on failure.
@@ -207,6 +227,8 @@ router_rebuild_store(int force)
smartlist_t *chunk_list = NULL;
char *fname = NULL;
int r = -1, i;
+ off_t offset = 0;
+ smartlist_t *old_routers, *routers;
if (!force && !router_should_rebuild_store())
return 0;
@@ -216,15 +238,28 @@ router_rebuild_store(int force)
/* Don't save deadweight. */
routerlist_remove_old_routers();
+ log_info(LD_DIR, "Rebuilding router descriptor cache");
+
options = get_options();
fname_len = strlen(options->DataDirectory)+32;
fname = tor_malloc(fname_len);
tor_snprintf(fname, fname_len, "%s/cached-routers", options->DataDirectory);
chunk_list = smartlist_create();
+ old_routers = smartlist_create();
+ smartlist_add_all(old_routers, routerlist->old_routers);
+ smartlist_sort(old_routers, _compare_old_routers_by_age);
+ routers = smartlist_create();
+ smartlist_add_all(routers, routerlist->routers);
+ smartlist_sort(routers, _compare_routers_by_age);
for (i = 0; i < 2; ++i) {
- smartlist_t *lst = (i == 0) ? routerlist->old_routers :
- routerlist->routers;
+ smartlist_t *lst = smartlist_create();
+ /* We sort the routers by age to enhance locality on disk. */
+ if (i==0)
+ lst = old_routers;
+ else
+ lst = routers;
+ /* Now, add the appropriate members to chunk_list */
SMARTLIST_FOREACH(lst, void *, ptr,
{
signed_descriptor_t *sd = (i==0) ?
@@ -233,6 +268,7 @@ router_rebuild_store(int force)
const char *body = signed_descriptor_get_body(sd);
if (!body) {
log_warn(LD_BUG, "Bug! No descriptor available for router.");
+ smartlist_free(lst);
goto done;
}
c = tor_malloc(sizeof(sized_chunk_t));
@@ -241,15 +277,42 @@ router_rebuild_store(int force)
smartlist_add(chunk_list, c);
});
}
- if (write_chunks_to_file(fname, chunk_list, 0)<0) {
+ if (write_chunks_to_file(fname, chunk_list, 1)<0) {
log_warn(LD_FS, "Error writing router store to disk.");
goto done;
}
+ /* Our mmap is now invalid. */
+ if (routerlist->mmap_descriptors) {
+ tor_munmap_file(routerlist->mmap_descriptors);
+ routerlist->mmap_descriptors = tor_mmap_file(fname);
+ if (! routerlist->mmap_descriptors)
+ log_warn(LD_FS, "Unable to mmap new descriptor file at '%s'.",fname);
+ }
+
+ offset = 0;
+ for (i = 0; i < 2; ++i) {
+ smartlist_t *lst = (i == 0) ? old_routers : routers;
+ SMARTLIST_FOREACH(lst, void *, ptr,
+ {
+ signed_descriptor_t *sd = (i==0) ?
+ ((signed_descriptor_t*)ptr): &((routerinfo_t*)ptr)->cache_info;
+
+ sd->saved_location = SAVED_IN_CACHE;
+ if (routerlist->mmap_descriptors) {
+ tor_free(sd->signed_descriptor_body); // sets it to null
+ sd->saved_offset = offset;
+ }
+ offset += sd->signed_descriptor_len;
+ signed_descriptor_get_body(sd);
+ });
+ }
+ smartlist_free(old_routers);
+ smartlist_free(routers);
tor_snprintf(fname, fname_len, "%s/cached-routers.new",
options->DataDirectory);
- write_str_to_file(fname, "", 0);
+ write_str_to_file(fname, "", 1);
r = 0;
router_store_len = len;
@@ -272,31 +335,36 @@ router_reload_router_list(void)
{
or_options_t *options = get_options();
size_t fname_len = strlen(options->DataDirectory)+32;
- char *fname = tor_malloc(fname_len);
+ char *fname = tor_malloc(fname_len), *contents;
struct stat st;
- int j;
if (!routerlist)
router_get_routerlist(); /* mallocs and inits it in place */
router_journal_len = router_store_len = 0;
- for (j = 0; j < 2; ++j) {
- char *contents;
- tor_snprintf(fname, fname_len,
- (j==0)?"%s/cached-routers":"%s/cached-routers.new",
- options->DataDirectory);
- contents = read_file_to_str(fname, 0);
- if (contents) {
- stat(fname, &st);
- if (j==0)
- router_store_len = st.st_size;
- else
- router_journal_len = st.st_size;
- router_load_routers_from_string(contents, 1, NULL);
- tor_free(contents);
- }
+ tor_snprintf(fname, fname_len, "%s/cached-routers", options->DataDirectory);
+
+ if (routerlist->mmap_descriptors) /* get rid of it first */
+ tor_munmap_file(routerlist->mmap_descriptors);
+
+ routerlist->mmap_descriptors = tor_mmap_file(fname);
+ if (routerlist->mmap_descriptors) {
+ router_store_len = routerlist->mmap_descriptors->size;
+ router_load_routers_from_string(routerlist->mmap_descriptors->data,
+ SAVED_IN_CACHE, NULL);
}
+
+ tor_snprintf(fname, fname_len, "%s/cached-routers.new",
+ options->DataDirectory);
+ contents = read_file_to_str(fname, 1);
+ if (contents) {
+ stat(fname, &st);
+ router_load_routers_from_string(contents,
+ SAVED_IN_JOURNAL, NULL);
+ tor_free(contents);
+ }
+
tor_free(fname);
if (router_journal_len) {
@@ -538,6 +606,21 @@ router_reset_status_download_failures(void)
mark_all_trusteddirservers_up();
}
+/** Look through the routerlist and identify routers that
+ * advertise the same /16 network address as <b>router</b>.
+ * Add each of them to <b>sl</b>.
+ */
+static void
+routerlist_add_network_family(smartlist_t *sl, routerinfo_t *router)
+{
+ SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, r,
+ {
+ if (router != r &&
+ (router->addr & 0xffff0000) == (r->addr & 0xffff0000))
+ smartlist_add(sl, r);
+ });
+}
+
/** Add all the family of <b>router</b> to the smartlist <b>sl</b>.
* This is used to make sure we don't pick siblings in a single path.
*/
@@ -547,6 +630,10 @@ routerlist_add_family(smartlist_t *sl, routerinfo_t *router)
routerinfo_t *r;
config_line_t *cl;
+ /* First, add any routers with similar network addresses.
+ * XXX It's possible this will be really expensive; we'll see. */
+ routerlist_add_network_family(sl, router);
+
if (!router->declared_family)
return;
@@ -931,6 +1018,7 @@ router_get_by_nickname(const char *nickname, int warn_if_unnamed)
char digest[DIGEST_LEN];
routerinfo_t *best_match=NULL;
int n_matches = 0;
+ char *named_digest = NULL;
tor_assert(nickname);
if (!routerlist)
@@ -944,16 +1032,17 @@ router_get_by_nickname(const char *nickname, int warn_if_unnamed)
maybedigest = (strlen(nickname) == HEX_DIGEST_LEN) &&
(base16_decode(digest,DIGEST_LEN,nickname,HEX_DIGEST_LEN) == 0);
+ if (named_server_map &&
+ (named_digest = strmap_get_lc(named_server_map, nickname))) {
+ return digestmap_get(routerlist->identity_map, named_digest);
+ }
+
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
{
if (!strcasecmp(router->nickname, nickname)) {
- if (router->is_named)
- return router;
- else {
- ++n_matches;
- if (n_matches <= 1 || router->is_running)
- best_match = router;
- }
+ ++n_matches;
+ if (n_matches <= 1 || router->is_running)
+ best_match = router;
} else if (maybedigest &&
!memcmp(digest, router->cache_info.identity_digest, DIGEST_LEN)
) {
@@ -991,7 +1080,7 @@ router_get_by_nickname(const char *nickname, int warn_if_unnamed)
char *alternatives = smartlist_join_strings(fps, "; ",0,NULL);
log_warn(LD_CONFIG,
"There are multiple matches for the nickname \"%s\","
- " but none is listed as named by the directory authories. "
+ " but none is listed as named by the directory authorities. "
"Choosing one arbitrarily. If you meant one in particular, "
"you should say %s.", nickname, alternatives);
tor_free(alternatives);
@@ -1006,7 +1095,7 @@ router_get_by_nickname(const char *nickname, int warn_if_unnamed)
base16_encode(fp, sizeof(fp),
best_match->cache_info.identity_digest, DIGEST_LEN);
log_warn(LD_CONFIG, "You specified a server \"%s\" by name, but the "
- "directory authorities do not have a listing for this name. "
+ "directory authorities do not have a binding for this nickname. "
"To make sure you get the same server in the future, refer to "
"it by key, as \"$%s\".", nickname, fp);
rs->name_lookup_warned = 1;
@@ -1090,10 +1179,28 @@ router_get_by_descriptor_digest(const char *digest)
return digestmap_get(routerlist->desc_digest_map, digest);
}
+/* DOCDOC Not always nul-terminated. */
const char *
signed_descriptor_get_body(signed_descriptor_t *desc)
{
- return desc->signed_descriptor_body;
+ const char *r;
+ size_t len = desc->signed_descriptor_len;
+ tor_assert(len > 32);
+ if (desc->saved_location == SAVED_IN_CACHE && routerlist &&
+ routerlist->mmap_descriptors) {
+ tor_assert(desc->saved_offset + len <= routerlist->mmap_descriptors->size);
+ r = routerlist->mmap_descriptors->data + desc->saved_offset;
+ } else {
+ r = desc->signed_descriptor_body;
+ }
+ tor_assert(r);
+ tor_assert(!memcmp("router ", r, 7));
+#if 0
+ tor_assert(!memcmp("\n-----END SIGNATURE-----\n",
+ r + len - 25, 25));
+#endif
+
+ return r;
}
/** Return the current list of all known routers. */
@@ -1167,7 +1274,10 @@ routerlist_free(routerlist_t *rl)
signed_descriptor_free(sd));
smartlist_free(rl->routers);
smartlist_free(rl->old_routers);
+ if (routerlist->mmap_descriptors)
+ tor_munmap_file(routerlist->mmap_descriptors);
tor_free(rl);
+
router_dir_info_changed();
}
@@ -1239,6 +1349,7 @@ routerlist_insert(routerlist_t *rl, routerinfo_t *ri)
digestmap_set(rl->desc_digest_map, ri->cache_info.signed_descriptor_digest,
&(ri->cache_info));
smartlist_add(rl->routers, ri);
+ ri->routerlist_index = smartlist_len(rl->routers) - 1;
router_dir_info_changed();
// routerlist_assert_ok(rl);
}
@@ -1252,6 +1363,7 @@ routerlist_insert_old(routerlist_t *rl, routerinfo_t *ri)
signed_descriptor_t *sd = signed_descriptor_from_routerinfo(ri);
digestmap_set(rl->desc_digest_map, sd->signed_descriptor_digest, sd);
smartlist_add(rl->old_routers, sd);
+ ri->routerlist_index = -1;
} else {
routerinfo_free(ri);
}
@@ -1270,7 +1382,13 @@ routerlist_remove(routerlist_t *rl, routerinfo_t *ri, int idx, int make_old)
idx = _routerlist_find_elt(rl->routers, ri, idx);
if (idx < 0)
return;
+ ri->routerlist_index = -1;
smartlist_del(rl->routers, idx);
+ if (idx < smartlist_len(rl->routers)) {
+ routerinfo_t *r = smartlist_get(rl->routers, idx);
+ r->routerlist_index = idx;
+ }
+
ri_tmp = digestmap_remove(rl->identity_map, ri->cache_info.identity_digest);
router_dir_info_changed();
tor_assert(ri_tmp == ri);
@@ -1319,6 +1437,8 @@ routerlist_replace(routerlist_t *rl, routerinfo_t *ri_old,
router_dir_info_changed();
if (idx >= 0) {
smartlist_set(rl->routers, idx, ri_new);
+ ri_old->routerlist_index = -1;
+ ri_new->routerlist_index = idx;
} else {
log_warn(LD_BUG, "Appending entry from routerlist_replace.");
routerlist_insert(rl, ri_new);
@@ -1502,10 +1622,10 @@ int
router_add_to_routerlist(routerinfo_t *router, const char **msg,
int from_cache, int from_fetch)
{
- int i;
const char *id_digest;
int authdir = get_options()->AuthoritativeDir;
int authdir_believes_valid = 0;
+ routerinfo_t *old_router;
tor_assert(msg);
@@ -1561,68 +1681,91 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg,
rs->need_to_mirror = 0;
});
- /* If we have a router with this name, and the identity key is the same,
- * choose the newer one. If the identity key has changed, and one of the
+ /* If we have a router with the same identity key, choose the newer one. */
+ old_router = digestmap_get(routerlist->identity_map,
+ router->cache_info.identity_digest);
+ if (old_router) {
+ int pos = old_router->routerlist_index;
+ tor_assert(smartlist_get(routerlist->routers, pos) == old_router);
+
+ if (router->cache_info.published_on <=
+ old_router->cache_info.published_on) {
+ /* Same key, but old */
+ log_debug(LD_DIR, "Skipping not-new descriptor for router '%s'",
+ router->nickname);
+ /* Only journal this desc if we'll be serving it. */
+ if (!from_cache && get_options()->DirPort)
+ router_append_to_journal(&router->cache_info);
+ routerlist_insert_old(routerlist, router);
+ *msg = "Router descriptor was not new.";
+ return -1;
+ } else {
+ /* Same key, new. */
+ int unreachable = 0;
+ log_debug(LD_DIR, "Replacing entry for router '%s/%s' [%s]",
+ router->nickname, old_router->nickname,
+ hex_str(id_digest,DIGEST_LEN));
+ if (router->addr == old_router->addr &&
+ router->or_port == old_router->or_port) {
+ /* these carry over when the address and orport are unchanged.*/
+ router->last_reachable = old_router->last_reachable;
+ router->testing_since = old_router->testing_since;
+ router->num_unreachable_notifications =
+ old_router->num_unreachable_notifications;
+ }
+ if (authdir && !from_cache && !from_fetch &&
+ router_have_minimum_dir_info() &&
+ dirserv_thinks_router_is_blatantly_unreachable(router,
+ time(NULL))) {
+ if (router->num_unreachable_notifications >= 3) {
+ unreachable = 1;
+ log_notice(LD_DIR, "Notifying server '%s' that it's unreachable. "
+ "(ContactInfo '%s', platform '%s').",
+ router->nickname,
+ router->contact_info ? router->contact_info : "",
+ router->platform ? router->platform : "");
+ } else {
+ log_info(LD_DIR,"'%s' may be unreachable -- the %d previous "
+ "descriptors were thought to be unreachable.",
+ router->nickname, router->num_unreachable_notifications);
+ router->num_unreachable_notifications++;
+ }
+ }
+ routerlist_replace(routerlist, old_router, router, pos, 1);
+ if (!from_cache) {
+ router_append_to_journal(&router->cache_info);
+ }
+ directory_set_dirty();
+ *msg = unreachable ? "Dirserver believes your ORPort is unreachable" :
+ authdir_believes_valid ? "Valid server updated" :
+ ("Invalid server updated. (This dirserver is marking your "
+ "server as unapproved.)");
+ return unreachable ? 1 : 0;
+ }
+ }
+
+#if 0
+ /* XXXX This block is slow, and could be smarter. All it does is ensure
+ * that if we have a named server called "Foo", we will never have another
+ * server called "Foo." router_get_by_nickname() already knows to prefer
+ * named routers, so the problem only arises when there is a named router
+ * called 'foo', but we don't have it. If, instead, we kept a
+ * name-to-identity-key mapping for each named router in the networkstatus
+ * list, we could eliminate this block.
+ *
+ * Hm. perhaps we should; I don't see how this code is non-broken wrt named
+ * routers. -NM
+ */
+
+ /* If the identity key has changed, and one of the
* routers is named, drop the unnamed ones. (If more than one are named,
* drop the old ones.)
*/
for (i = 0; i < smartlist_len(routerlist->routers); ++i) {
routerinfo_t *old_router = smartlist_get(routerlist->routers, i);
- if (!crypto_pk_cmp_keys(router->identity_pkey,old_router->identity_pkey)) {
- if (router->cache_info.published_on <=
- old_router->cache_info.published_on) {
- /* Same key, but old */
- log_debug(LD_DIR, "Skipping not-new descriptor for router '%s'",
- router->nickname);
- /* Only journal this desc if we'll be serving it. */
- if (!from_cache && get_options()->DirPort)
- router_append_to_journal(&router->cache_info);
- routerlist_insert_old(routerlist, router);
- *msg = "Router descriptor was not new.";
- return -1;
- } else {
- /* Same key, new. */
- int unreachable = 0;
- log_debug(LD_DIR, "Replacing entry for router '%s/%s' [%s]",
- router->nickname, old_router->nickname,
- hex_str(id_digest,DIGEST_LEN));
- if (router->addr == old_router->addr &&
- router->or_port == old_router->or_port) {
- /* these carry over when the address and orport are unchanged.*/
- router->last_reachable = old_router->last_reachable;
- router->testing_since = old_router->testing_since;
- router->num_unreachable_notifications =
- old_router->num_unreachable_notifications;
- }
- if (authdir && !from_cache && !from_fetch &&
- router_have_minimum_dir_info() &&
- dirserv_thinks_router_is_blatantly_unreachable(router,
- time(NULL))) {
- if (router->num_unreachable_notifications >= 3) {
- unreachable = 1;
- log_notice(LD_DIR, "Notifying server '%s' that it's unreachable. "
- "(ContactInfo '%s', platform '%s').",
- router->nickname,
- router->contact_info ? router->contact_info : "",
- router->platform ? router->platform : "");
- } else {
- log_info(LD_DIR,"'%s' may be unreachable -- the %d previous "
- "descriptors were thought to be unreachable.",
- router->nickname, router->num_unreachable_notifications);
- router->num_unreachable_notifications++;
- }
- }
- routerlist_replace(routerlist, old_router, router, i, 1);
- if (!from_cache) {
- router_append_to_journal(&router->cache_info);
- }
- directory_set_dirty();
- *msg = unreachable ? "Dirserver believes your ORPort is unreachable" :
- authdir_believes_valid ? "Valid server updated" :
- ("Invalid server updated. (This dirserver is marking your "
- "server as unapproved.)");
- return unreachable ? 1 : 0;
- }
+ if (!memcmp(router->cache_info.identity_digest,
+ old_router->cache_info.identity_digest, DIGEST_LEN)) {
+
} else if (!strcasecmp(router->nickname, old_router->nickname)) {
/* nicknames match, keys don't. */
if (router->is_named) {
@@ -1633,13 +1776,13 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg,
/* mark-for-close connections using the old key, so we can
* make new ones with the new key.
*/
- connection_t *conn;
+ or_connection_t *conn;
while ((conn = connection_or_get_by_identity_digest(
old_router->cache_info.identity_digest))) {
log_info(LD_DIR,"Closing conn to router '%s'; there is now a named "
"router with that name.",
old_router->nickname);
- connection_mark_for_close(conn);
+ connection_mark_for_close(TO_CONN(conn));
}
routerlist_remove(routerlist, old_router, i--, 0);
} else if (old_router->is_named) {
@@ -1653,6 +1796,8 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg,
}
}
}
+#endif
+
/* We haven't seen a router with this name before. Add it to the end of
* the list. */
routerlist_insert(routerlist, router);
@@ -1790,7 +1935,7 @@ routerlist_remove_old_routers(void)
retain = digestmap_new();
cutoff = now - OLD_ROUTER_DESC_MAX_AGE;
- if (server_mode(options) && options->DirPort) {
+ if (options->DirPort) {
SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
{
SMARTLIST_FOREACH(ns->entries, routerstatus_t *, rs,
@@ -1879,7 +2024,7 @@ router_load_single_router(const char *s, uint8_t purpose, const char **msg)
tor_assert(msg);
*msg = NULL;
- if (!(ri = router_parse_entry_from_string(s, NULL))) {
+ if (!(ri = router_parse_entry_from_string(s, NULL, 1))) {
log_warn(LD_DIR, "Error parsing router descriptor; dropping.");
*msg = "Couldn't parse router descriptor.";
return -1;
@@ -1919,16 +2064,18 @@ router_load_single_router(const char *s, uint8_t purpose, const char **msg)
* uppercased identity fingerprints. Do not update any router whose
* fingerprint is not on the list; after updating a router, remove its
* fingerprint from the list.
+ * DOCDOC saved_location
*/
void
-router_load_routers_from_string(const char *s, int from_cache,
+router_load_routers_from_string(const char *s, saved_location_t saved_location,
smartlist_t *requested_fingerprints)
{
smartlist_t *routers = smartlist_create(), *changed = smartlist_create();
char fp[HEX_DIGEST_LEN+1];
const char *msg;
+ int from_cache = (saved_location != SAVED_NOWHERE);
- router_parse_list_from_string(&s, routers);
+ router_parse_list_from_string(&s, routers, saved_location);
routers_update_status_from_networkstatus(routers, !from_cache);
@@ -2023,12 +2170,13 @@ add_networkstatus_to_cache(const char *s,
/** How far in the future do we allow a network-status to get before removing
* it? (seconds) */
#define NETWORKSTATUS_ALLOW_SKEW (24*60*60)
+
/** Given a string <b>s</b> containing a network status that we received at
* <b>arrived_at</b> from <b>source</b>, try to parse it, see if we want to
* store it, and put it into our cache as necessary.
*
* If <b>source</b> is NS_FROM_DIR or NS_FROM_CACHE, do not replace our
- * own networkstatus_t (if we're a directory server).
+ * own networkstatus_t (if we're an authoritative directory server).
*
* If <b>source</b> is NS_FROM_CACHE, do not write our networkstatus_t to the
* cache.
@@ -2093,7 +2241,8 @@ router_set_networkstatus(const char *s, time_t arrived_at,
if (!networkstatus_list)
networkstatus_list = smartlist_create();
- if (source == NS_FROM_DIR && router_digest_is_me(ns->identity_digest)) {
+ if ( (source == NS_FROM_DIR_BY_FP || source == NS_FROM_DIR_ALL) &&
+ router_digest_is_me(ns->identity_digest)) {
/* Don't replace our own networkstatus when we get it from somebody else.*/
networkstatus_free(ns);
return 0;
@@ -2105,12 +2254,14 @@ router_set_networkstatus(const char *s, time_t arrived_at,
} else {
char *requested =
smartlist_join_strings(requested_fingerprints," ",0,NULL);
- log_warn(LD_DIR,
+ if (source != NS_FROM_DIR_ALL) {
+ log_warn(LD_DIR,
"We received a network status with a fingerprint (%s) that we "
"never requested. (We asked for: %s.) Dropping.",
fp, requested);
- tor_free(requested);
- return 0;
+ tor_free(requested);
+ return 0;
+ }
}
}
@@ -2119,6 +2270,9 @@ router_set_networkstatus(const char *s, time_t arrived_at,
/* We got a non-trusted networkstatus, and we're a directory cache.
* This means that we asked an authority, and it told us about another
* authority we didn't recognize. */
+ log_info(LD_DIR,
+ "We do not recognize authority (%s) but we are willing "
+ "to cache it", fp);
add_networkstatus_to_cache(s, source, ns);
networkstatus_free(ns);
}
@@ -2181,7 +2335,8 @@ router_set_networkstatus(const char *s, time_t arrived_at,
log_info(LD_DIR, "Setting networkstatus %s %s (published %s)",
source == NS_FROM_CACHE?"cached from":
- (source==NS_FROM_DIR?"downloaded from":"generated for"),
+ ((source == NS_FROM_DIR_BY_FP || source == NS_FROM_DIR_ALL) ?
+ "downloaded from":"generated for"),
trusted_dir->description, published);
networkstatus_list_has_changed = 1;
router_dir_info_changed();
@@ -2501,6 +2656,7 @@ update_networkstatus_client_downloads(time_t now)
resource = tor_malloc(resource_len);
memcpy(resource, "fp/", 3);
cp = resource+3;
+ smartlist_sort_digests(missing);
needed = smartlist_len(missing);
SMARTLIST_FOREACH(missing, const char *, d,
{
@@ -2521,10 +2677,10 @@ void
update_networkstatus_downloads(time_t now)
{
or_options_t *options = get_options();
- if (server_mode(options) && options->DirPort)
- update_networkstatus_cache_downloads(time(NULL));
- else
- update_networkstatus_client_downloads(time(NULL));
+ if (options->DirPort)
+ update_networkstatus_cache_downloads(now);
+ else
+ update_networkstatus_client_downloads(now);
}
/** Return 1 if all running sufficiently-stable routers will reject
@@ -2572,7 +2728,7 @@ add_trusted_dir_server(const char *nickname, const char *address,
trusted_dir_servers = smartlist_create();
if (!address) { /* The address is us; we should guess. */
- if (resolve_my_address(get_options(), &a, &hostname) < 0) {
+ if (resolve_my_address(LOG_WARN, get_options(), &a, &hostname) < 0) {
log_warn(LD_CONFIG,
"Couldn't find a suitable address when adding ourself as a "
"trusted directory server.");
@@ -2681,6 +2837,7 @@ compute_recommended_versions(time_t now, int client)
smartlist_t *combined, *recommended;
int n_versioning;
char *result;
+ (void) now; /* right now, we consider *all* ors. */
if (!networkstatus_list)
return tor_strdup("<none>");
@@ -2775,12 +2932,12 @@ routers_update_all_from_networkstatus(void)
++n_named;
});
- if (n_recent && n_listing) {
- if (n_valid <= n_recent/2) {
+ if (n_listing) {
+ if (n_valid <= n_listing/2) {
log_info(LD_GENERAL,
"%d/%d recent statements from directory authorities list us "
"as unapproved. Are you misconfigured?",
- n_recent-n_valid, n_recent);
+ n_listing-n_valid, n_listing);
have_warned_about_invalid_status = 1;
} else if (n_naming && !n_named) {
log_info(LD_GENERAL, "0/%d name-binding directory authorities "
@@ -2981,6 +3138,10 @@ routerstatus_list_update_from_networkstatus(time_t now)
* is a conflict on that nickname, map the lc nickname to conflict.
*/
name_map = strmap_new();
+ /* Clear the global map... */
+ if (named_server_map)
+ strmap_free(named_server_map, _tor_free);
+ named_server_map = strmap_new();
memset(conflict, 0xff, sizeof(conflict));
for (i = 0; i < n_statuses; ++i) {
if (!networkstatus[i]->binds_names)
@@ -2994,11 +3155,14 @@ routerstatus_list_update_from_networkstatus(time_t now)
warned = smartlist_string_isin(warned_conflicts, rs->nickname);
if (!other_digest) {
strmap_set_lc(name_map, rs->nickname, rs->identity_digest);
+ strmap_set_lc(named_server_map, rs->nickname,
+ tor_memdup(rs->identity_digest, DIGEST_LEN));
if (warned)
smartlist_string_remove(warned_conflicts, rs->nickname);
} else if (memcmp(other_digest, rs->identity_digest, DIGEST_LEN) &&
other_digest != conflict) {
if (!warned) {
+ char *d;
int should_warn = options->DirPort && options->AuthoritativeDir;
char fp1[HEX_DIGEST_LEN+1];
char fp2[HEX_DIGEST_LEN+1];
@@ -3009,6 +3173,8 @@ routerstatus_list_update_from_networkstatus(time_t now)
"($%s vs $%s)",
rs->nickname, fp1, fp2);
strmap_set_lc(name_map, rs->nickname, conflict);
+ d = strmap_remove_lc(named_server_map, rs->nickname);
+ tor_free(d);
smartlist_add(warned_conflicts, tor_strdup(rs->nickname));
}
} else {
@@ -3171,6 +3337,7 @@ routerstatus_list_update_from_networkstatus(time_t now)
}
SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, rs,
local_routerstatus_free(rs));
+
smartlist_free(routerstatus_list);
routerstatus_list = result;
@@ -3251,9 +3418,10 @@ list_pending_descriptor_downloads(digestmap_t *result)
if (conn->type == CONN_TYPE_DIR &&
conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC &&
!conn->marked_for_close) {
- if (!strcmpstart(conn->requested_resource, prefix))
- dir_split_resource_into_fingerprints(conn->requested_resource+p_len,
- tmp, NULL, 1);
+ const char *resource = TO_DIR_CONN(conn)->requested_resource;
+ if (!strcmpstart(resource, prefix))
+ dir_split_resource_into_fingerprints(resource + p_len,
+ tmp, NULL, 1, 0);
}
}
SMARTLIST_FOREACH(tmp, char *, d,
@@ -3317,18 +3485,18 @@ initiate_descriptor_downloads(routerstatus_t *source,
/** Return 0 if this routerstatus is obsolete, too new, isn't
* running, or otherwise not a descriptor that we would make any
* use of even if we had it. Else return 1. */
-static int
+static INLINE int
client_would_use_router(routerstatus_t *rs, time_t now, or_options_t *options)
{
- if (rs->published_on + ROUTER_MAX_AGE < now) {
- /* This one is too old to consider. */
- return 0;
- }
if (!rs->is_running && !options->FetchUselessDescriptors) {
/* If we had this router descriptor, we wouldn't even bother using it.
* But, if we want to have a complete list, fetch it anyway. */
return 0;
}
+ if (rs->published_on + ROUTER_MAX_AGE < now) {
+ /* This one is too old to consider. */
+ return 0;
+ }
if (rs->published_on + ESTIMATED_PROPAGATION_TIME > now) {
/* Most caches probably don't have this descriptor yet. */
return 0;
@@ -3360,15 +3528,15 @@ router_list_client_downloadable(void)
SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, rs,
{
routerinfo_t *ri;
- if (!client_would_use_router(&rs->status, now, options)) {
+ if (router_get_by_descriptor_digest(rs->status.descriptor_digest)) {
+ /* We have the 'best' descriptor for this router. */
+ ++n_uptodate;
+ } else if (!client_would_use_router(&rs->status, now, options)) {
/* We wouldn't want this descriptor even if we got it. */
++n_wouldnt_use;
} else if (digestmap_get(downloading, rs->status.descriptor_digest)) {
/* We're downloading this one now. */
++n_in_progress;
- } else if (router_get_by_descriptor_digest(rs->status.descriptor_digest)) {
- /* We have the 'best' descriptor for this router. */
- ++n_uptodate;
} else if ((ri = router_get_by_digest(rs->status.identity_digest)) &&
ri->cache_info.published_on > rs->status.published_on) {
/* Oddly, we have a descriptor more recent than the 'best' one, but it
@@ -3433,15 +3601,19 @@ update_router_descriptor_client_downloads(time_t now)
int should_delay, n_downloadable;
or_options_t *options = get_options();
- if (server_mode(options) && options->DirPort) {
+ if (options->DirPort) {
log_warn(LD_BUG,
- "Called router_descriptor_client_downloads() on a mirror?");
+ "Called router_descriptor_client_downloads() on a dir mirror?");
}
- /* XXX here's another magic 2 that probably should be replaced
- * by <= smartlist_len(trusted_dir_servers)/2
- * or by a function returning same. -- weasel */
- if (networkstatus_list && smartlist_len(networkstatus_list) < 2) {
+ if (rep_hist_circbuilding_dormant(now)) {
+ log_info(LD_CIRC, "Skipping descriptor downloads: we haven't needed "
+ "any circuits lately.");
+ return;
+ }
+
+ if (networkstatus_list && smartlist_len(networkstatus_list) <=
+ smartlist_len(trusted_dir_servers)/2) {
log_info(LD_DIR,
"Not enough networkstatus documents to launch requests.");
}
@@ -3466,8 +3638,8 @@ update_router_descriptor_client_downloads(time_t now)
(int)(now-last_routerdesc_download_attempted));
} else {
log_info(LD_DIR,
- "There are not many downloadable routerdescs, but we've "
- "never downloaded descriptors before. Downloading.");
+ "There are not many downloadable routerdescs, but we haven't "
+ "tried downloading descriptors recently. Downloading.");
}
}
}
@@ -3485,6 +3657,7 @@ update_router_descriptor_client_downloads(time_t now)
(n_downloadable+n_per_request-1)/n_per_request,
n_downloadable>n_per_request?"s":"",
n_downloadable, n_downloadable>1?"s":"", n_per_request);
+ smartlist_sort_digests(downloadable);
for (i=0; i < n_downloadable; i += n_per_request) {
initiate_descriptor_downloads(NULL, downloadable, i, i+n_per_request);
}
@@ -3505,10 +3678,11 @@ update_router_descriptor_cache_downloads(time_t now)
int i, j, n;
int n_download;
or_options_t *options = get_options();
+ (void) now;
- if (!(server_mode(options) && options->DirPort)) {
+ if (!options->DirPort) {
log_warn(LD_BUG, "Called update_router_descriptor_cache_downloads() "
- "on a non-mirror?");
+ "on a non-dir-mirror?");
}
if (!networkstatus_list || !smartlist_len(networkstatus_list))
@@ -3622,7 +3796,7 @@ void
update_router_descriptor_downloads(time_t now)
{
or_options_t *options = get_options();
- if (server_mode(options) && options->DirPort) {
+ if (options->DirPort) {
update_router_descriptor_cache_downloads(now);
} else {
update_router_descriptor_client_downloads(now);
@@ -3659,7 +3833,7 @@ router_have_minimum_dir_info(void)
/** DOCDOC
* Must change when authorities change, networkstatuses change, or list of
- * routerdescs changes.
+ * routerdescs changes, or number of running routers changes.
*/
static void
router_dir_info_changed(void)
@@ -3759,6 +3933,9 @@ router_reset_descriptor_download_failures(void)
* automatically non-cosmetic. */
#define ROUTER_MAX_COSMETIC_TIME_DIFFERENCE (12*60*60)
+/** We allow uptime to vary from how much it ought to be by this much. */
+#define ROUTER_ALLOW_UPTIME_DRIFT (30*60)
+
/** Return true iff the only differences between r1 and r2 are such that
* would not cause a recent (post 0.1.1.6) dirserver to republish.
*/
@@ -3788,6 +3965,7 @@ router_differences_are_cosmetic(routerinfo_t *r1, routerinfo_t *r2)
(r1->contact_info && r2->contact_info &&
strcasecmp(r1->contact_info, r2->contact_info)) ||
r1->is_hibernating != r2->is_hibernating ||
+ r1->has_old_dnsworkers != r2->has_old_dnsworkers ||
cmp_addr_policies(r1->exit_policy, r2->exit_policy))
return 0;
if ((r1->declared_family == NULL) != (r2->declared_family == NULL))
@@ -3818,7 +3996,8 @@ router_differences_are_cosmetic(routerinfo_t *r1, routerinfo_t *r2)
* give or take 30 minutes? */
r1pub = r1->cache_info.published_on;
r2pub = r2->cache_info.published_on;
- if (abs(r2->uptime - (r1->uptime + (r2pub - r1pub))) > 30*60)
+ if (abs(r2->uptime - (r1->uptime + (r2pub - r1pub)))
+ > ROUTER_ALLOW_UPTIME_DRIFT)
return 0;
/* Otherwise, the difference is cosmetic. */
@@ -3840,6 +4019,7 @@ routerlist_assert_ok(routerlist_t *rl)
sd2 = digestmap_get(rl->desc_digest_map,
r->cache_info.signed_descriptor_digest);
tor_assert(&(r->cache_info) == sd2);
+ tor_assert(r->routerlist_index == r_sl_idx);
});
SMARTLIST_FOREACH(rl->old_routers, signed_descriptor_t *, sd,
{
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 10f5512ae3..2f214a1ef4 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -54,6 +54,7 @@ typedef enum {
K_SERVER_VERSIONS,
K_R,
K_S,
+ K_EVENTDNS,
_UNRECOGNIZED,
_ERR,
_EOF,
@@ -145,6 +146,7 @@ static struct {
{ "dir-options", K_DIR_OPTIONS, ARGS, NO_OBJ, NETSTATUS },
{ "client-versions", K_CLIENT_VERSIONS, ARGS, NO_OBJ, NETSTATUS },
{ "server-versions", K_SERVER_VERSIONS, ARGS, NO_OBJ, NETSTATUS },
+ { "eventdns", K_EVENTDNS, ARGS, NO_OBJ, RTR },
{ NULL, -1, NO_ARGS, NO_OBJ, ANY }
};
@@ -540,14 +542,6 @@ find_dir_signing_key(const char *str)
if (tok->key) {
key = tok->key;
tok->key = NULL; /* steal reference. */
- } else if (tok->n_args >= 1) {
- /** XXXX Once all the directories are running 0.1.0.6-rc or later, we
- * can remove this logic. */
- key = crypto_pk_DER64_decode_public_key(tok->args[0]);
- if (!key) {
- log_warn(LD_DIR, "Unparseable dir-signing-key argument");
- return NULL;
- }
} else {
log_warn(LD_DIR, "Dir-signing-key token contained no key");
return NULL;
@@ -643,17 +637,20 @@ check_directory_signature(const char *digest,
* are marked running and valid. Advances *s to a point immediately
* following the last router entry. Ignore any trailing router entries that
* are not complete. Returns 0 on success and -1 on failure.
+ * DOCDOC saved_location
*/
int
-router_parse_list_from_string(const char **s, smartlist_t *dest)
+router_parse_list_from_string(const char **s, smartlist_t *dest,
+ saved_location_t saved_location)
{
routerinfo_t *router;
- const char *end, *cp;
+ const char *end, *cp, *start;
tor_assert(s);
tor_assert(*s);
tor_assert(dest);
+ start = *s;
while (1) {
*s = eat_whitespace(*s);
/* Don't start parsing the rest of *s unless it contains a router. */
@@ -684,13 +681,19 @@ router_parse_list_from_string(const char **s, smartlist_t *dest)
continue;
}
- router = router_parse_entry_from_string(*s, end);
+ router = router_parse_entry_from_string(*s, end,
+ saved_location != SAVED_IN_CACHE);
- *s = end;
if (!router) {
log_warn(LD_DIR, "Error reading router; skipping");
+ *s = end;
continue;
}
+ if (saved_location != SAVED_NOWHERE) {
+ router->cache_info.saved_location = saved_location;
+ router->cache_info.saved_offset = *s - start;
+ }
+ *s = end;
smartlist_add(dest, router);
}
@@ -700,9 +703,11 @@ router_parse_list_from_string(const char **s, smartlist_t *dest)
/** Helper function: reads a single router entry from *<b>s</b> ...
* *<b>end</b>. Mallocs a new router and returns it if all goes well, else
* returns NULL.
+ * DOCDOC cache_copy
*/
routerinfo_t *
-router_parse_entry_from_string(const char *s, const char *end)
+router_parse_entry_from_string(const char *s, const char *end,
+ int cache_copy)
{
routerinfo_t *router = NULL;
char signed_digest[128];
@@ -749,7 +754,9 @@ router_parse_entry_from_string(const char *s, const char *end)
}
router = tor_malloc_zero(sizeof(routerinfo_t));
- router->cache_info.signed_descriptor_body = tor_strndup(s, end-s);
+ router->routerlist_index = -1;
+ if (cache_copy)
+ router->cache_info.signed_descriptor_body = tor_strndup(s, end-s);
router->cache_info.signed_descriptor_len = end-s;
memcpy(router->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
@@ -871,6 +878,13 @@ router_parse_entry_from_string(const char *s, const char *end)
router->contact_info = tor_strdup(tok->args[0]);
}
+ if ((tok = find_first_by_keyword(tokens, K_EVENTDNS))) {
+ router->has_old_dnsworkers = tok->n_args && !strcmp(tok->args[0], "0");
+ } else if (router->platform) {
+ if (! tor_version_as_new_as(router->platform, "0.1.2.2-alpha"))
+ router->has_old_dnsworkers = 1;
+ }
+
exit_policy_tokens = find_all_exitpolicy(tokens);
SMARTLIST_FOREACH(exit_policy_tokens, directory_token_t *, t,
if (router_add_exit_policy(router,t)<0) {
@@ -1071,6 +1085,15 @@ _compare_routerstatus_entries(const void **_a, const void **_b)
return memcmp(a->identity_digest, b->identity_digest, DIGEST_LEN);
}
+static void
+_free_duplicate_routerstatus_entry(void *e)
+{
+ log_warn(LD_DIR,
+ "Network-status has two entries for the same router. "
+ "Dropping one.");
+ routerstatus_free(e);
+}
+
/** Given a versioned (v2 or later) network-status object in <b>s</b>, try to
* parse it and return the result. Return NULL on failure. Check the
* signature of the network status, but do not (yet) check the signing key for
@@ -1213,20 +1236,8 @@ networkstatus_parse_from_string(const char *s)
smartlist_add(ns->entries, rs);
}
smartlist_sort(ns->entries, _compare_routerstatus_entries);
-
- /* Kill duplicate entries. */
- for (i=0; i < smartlist_len(ns->entries)-1; ++i) {
- routerstatus_t *rs1 = smartlist_get(ns->entries, i);
- routerstatus_t *rs2 = smartlist_get(ns->entries, i+1);
- if (!memcmp(rs1->identity_digest,
- rs2->identity_digest, DIGEST_LEN)) {
- log_warn(LD_DIR,
- "Network-status has two entries for the same router. "
- "Dropping one.");
- smartlist_del_keeporder(ns->entries, i--);
- routerstatus_free(rs1);
- }
- }
+ smartlist_uniq(ns->entries, _compare_routerstatus_entries,
+ _free_duplicate_routerstatus_entry);
if (tokenize_string(s, NULL, tokens, NETSTATUS)) {
log_warn(LD_DIR, "Error tokenizing network-status footer.");
@@ -1799,7 +1810,7 @@ tor_version_parse(const char *s, tor_version_t *out)
{
char *eos=NULL, *cp=NULL;
/* Format is:
- * "Tor " ? NUM dot NUM dot NUM [ ( pre | rc | dot ) NUM [ -cvs ] ]
+ * "Tor " ? NUM dot NUM dot NUM [ ( pre | rc | dot ) NUM [ - tag ] ]
*/
tor_assert(s);
tor_assert(out);
@@ -1825,7 +1836,6 @@ tor_version_parse(const char *s, tor_version_t *out)
if (!*eos) {
out->status = VER_RELEASE;
out->patchlevel = 0;
- out->cvs = IS_NOT_CVS;
return 0;
}
cp = eos;
@@ -1849,15 +1859,10 @@ tor_version_parse(const char *s, tor_version_t *out)
if (!eos || eos==cp) return -1;
cp = eos;
- /* Get cvs status and status tag. */
+ /* Get status tag. */
if (*cp == '-' || *cp == '.')
++cp;
strlcpy(out->status_tag, cp, sizeof(out->status_tag));
- if (0==strcmp(cp, "cvs")) {
- out->cvs = IS_CVS;
- } else {
- out->cvs = IS_NOT_CVS;
- }
return 0;
}
@@ -1881,11 +1886,7 @@ tor_version_compare(tor_version_t *a, tor_version_t *b)
else if ((i = a->patchlevel - b->patchlevel))
return i;
- if (a->major > 0 || a->minor > 0) {
- return strcmp(a->status_tag, b->status_tag);
- } else {
- return (a->cvs - b->cvs);
- }
+ return strcmp(a->status_tag, b->status_tag);
}
/** Return true iff versions <b>a</b> and <b>b</b> belong to the same series.
@@ -1928,22 +1929,9 @@ _compare_tor_version_str_ptr(const void **_a, const void **_b)
void
sort_version_list(smartlist_t *versions, int remove_duplicates)
{
- int i;
-
smartlist_sort(versions, _compare_tor_version_str_ptr);
- if (!remove_duplicates)
- return;
-
- for (i = 1; i < smartlist_len(versions); ++i) {
- const void *a, *b;
- a = smartlist_get(versions, i-1);
- b = smartlist_get(versions, i);
- /* use version_cmp so we catch multiple representations of the same
- * version */
- if (_compare_tor_version_str_ptr(&a,&b) == 0) {
- tor_free(smartlist_get(versions, i));
- smartlist_del_keeporder(versions, i--);
- }
- }
+
+ if (remove_duplicates)
+ smartlist_uniq(versions, _compare_tor_version_str_ptr, NULL);
}
diff --git a/src/or/test.c b/src/or/test.c
index 7a413f525b..4f9d79ccf5 100644
--- a/src/or/test.c
+++ b/src/or/test.c
@@ -416,19 +416,6 @@ test_crypto(void)
test_eq(0, crypto_pk_cmp_keys(pk1, pk2));
tor_free(cp);
- /* Check DER encoding */
- i=crypto_pk_DER64_encode_public_key(pk1, &cp);
- test_assert(i>0);
- test_assert(cp);
- test_assert(!strchr(cp, ' '));
- test_assert(!strchr(cp, '\n'));
- test_eq(0, crypto_pk_cmp_keys(pk1, pk1));
- crypto_free_pk_env(pk2);
- pk2 = crypto_pk_DER64_decode_public_key(cp);
- test_assert(pk2);
- test_eq(0, crypto_pk_cmp_keys(pk1, pk2));
- tor_free(cp);
-
test_eq(128, crypto_pk_keysize(pk1));
test_eq(128, crypto_pk_keysize(pk2));
@@ -786,6 +773,16 @@ test_util(void)
test_streq("and", smartlist_bsearch(sl, " AND", _compare_without_first_ch));
test_eq_ptr(NULL, smartlist_bsearch(sl, " ANz", _compare_without_first_ch));
+ /* Test reverse() and pop_last() */
+ smartlist_reverse(sl);
+ cp = smartlist_join_strings(sl, ",", 0, NULL);
+ test_streq(cp,"the,router,onion,nickm,by,arma,and");
+ tor_free(cp);
+ cp = smartlist_pop_last(sl);
+ test_streq(cp, "and");
+ tor_free(cp);
+ test_eq(smartlist_len(sl), 6);
+
/* Test tor_strstrip() */
strcpy(buf, "Testing 1 2 3");
test_eq(0, tor_strstrip(buf, ",!"));
@@ -810,27 +807,28 @@ test_util(void)
/* Test parse_addr_port */
cp = NULL; u32 = 3; u16 = 3;
- test_assert(!parse_addr_port("1.2.3.4", &cp, &u32, &u16));
+ test_assert(!parse_addr_port(LOG_WARN, "1.2.3.4", &cp, &u32, &u16));
test_streq(cp, "1.2.3.4");
test_eq(u32, 0x01020304u);
test_eq(u16, 0);
tor_free(cp);
- test_assert(!parse_addr_port("4.3.2.1:99", &cp, &u32, &u16));
+ test_assert(!parse_addr_port(LOG_WARN, "4.3.2.1:99", &cp, &u32, &u16));
test_streq(cp, "4.3.2.1");
test_eq(u32, 0x04030201u);
test_eq(u16, 99);
tor_free(cp);
- test_assert(!parse_addr_port("nonexistent.address:4040", &cp, NULL, &u16));
+ test_assert(!parse_addr_port(LOG_WARN, "nonexistent.address:4040",
+ &cp, NULL, &u16));
test_streq(cp, "nonexistent.address");
test_eq(u16, 4040);
tor_free(cp);
- test_assert(!parse_addr_port("localhost:9999", &cp, &u32, &u16));
+ test_assert(!parse_addr_port(LOG_WARN, "localhost:9999", &cp, &u32, &u16));
test_streq(cp, "localhost");
test_eq(u32, 0x7f000001u);
test_eq(u16, 9999);
tor_free(cp);
u32 = 3;
- test_assert(!parse_addr_port("localhost", NULL, &u32, &u16));
+ test_assert(!parse_addr_port(LOG_WARN, "localhost", NULL, &u32, &u16));
test_eq(cp, NULL);
test_eq(u32, 0x7f000001u);
test_eq(u16, 0);
@@ -923,11 +921,73 @@ test_util(void)
smartlist_free(sl);
}
+static int
+_compare_strings_for_pqueue(const void *s1, const void *s2)
+{
+ return strcmp((const char*)s1, (const char*)s2);
+}
+
+static void
+test_pqueue(void)
+{
+ smartlist_t *sl;
+ int (*cmp)(const void *, const void*);
+#define OK() smartlist_pqueue_assert_ok(sl, cmp)
+
+ cmp = _compare_strings_for_pqueue;
+
+ sl = smartlist_create();
+ smartlist_pqueue_add(sl, cmp, (char*)"cows");
+ smartlist_pqueue_add(sl, cmp, (char*)"zebras");
+ smartlist_pqueue_add(sl, cmp, (char*)"fish");
+ smartlist_pqueue_add(sl, cmp, (char*)"frogs");
+ smartlist_pqueue_add(sl, cmp, (char*)"apples");
+ smartlist_pqueue_add(sl, cmp, (char*)"squid");
+ smartlist_pqueue_add(sl, cmp, (char*)"daschunds");
+ smartlist_pqueue_add(sl, cmp, (char*)"eggplants");
+ smartlist_pqueue_add(sl, cmp, (char*)"weissbier");
+ smartlist_pqueue_add(sl, cmp, (char*)"lobsters");
+ smartlist_pqueue_add(sl, cmp, (char*)"roquefort");
+
+ OK();
+
+ test_eq(smartlist_len(sl), 11);
+ test_streq(smartlist_get(sl, 0), "apples");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "apples");
+ test_eq(smartlist_len(sl), 10);
+ OK();
+ test_streq(smartlist_pqueue_pop(sl, cmp), "cows");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "daschunds");
+ smartlist_pqueue_add(sl, cmp, (char*)"chinchillas");
+ OK();
+ smartlist_pqueue_add(sl, cmp, (char*)"fireflies");
+ OK();
+ test_streq(smartlist_pqueue_pop(sl, cmp), "chinchillas");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "eggplants");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "fireflies");
+ OK();
+ test_streq(smartlist_pqueue_pop(sl, cmp), "fish");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "frogs");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "lobsters");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "roquefort");
+ OK();
+ test_eq(smartlist_len(sl), 3);
+ test_streq(smartlist_pqueue_pop(sl, cmp), "squid");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "weissbier");
+ test_streq(smartlist_pqueue_pop(sl, cmp), "zebras");
+ test_eq(smartlist_len(sl), 0);
+ OK();
+#undef OK
+ smartlist_free(sl);
+}
+
static void
test_gzip(void)
{
- char *buf1, *buf2=NULL, *buf3=NULL;
+ char *buf1, *buf2=NULL, *buf3=NULL, *cp1, *cp2;
+ const char *ccp2;
size_t len1, len2;
+ tor_zlib_state_t *state;
buf1 = tor_strdup("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ");
test_eq(detect_compression_method(buf1, strlen(buf1)), 0);
@@ -993,6 +1053,35 @@ test_gzip(void)
ZLIB_METHOD, 1, LOG_INFO));
tor_assert(!buf3);
+ /* Now, try streaming compression. */
+ tor_free(buf1);
+ tor_free(buf2);
+ tor_free(buf3);
+ state = tor_zlib_new(1, ZLIB_METHOD);
+ tor_assert(state);
+ cp1 = buf1 = tor_malloc(1024);
+ len1 = 1024;
+ ccp2 = "ABCDEFGHIJABCDEFGHIJ";
+ len2 = 21;
+ test_assert(tor_zlib_process(state, &cp1, &len1, &ccp2, &len2, 0)
+ == TOR_ZLIB_OK);
+ test_eq(len2, 0); /* Make sure we compressed it all. */
+ test_assert(cp1 > buf1);
+
+ len2 = 0;
+ cp2 = cp1;
+ test_assert(tor_zlib_process(state, &cp1, &len1, &ccp2, &len2, 1)
+ == TOR_ZLIB_DONE);
+ test_eq(len2, 0);
+ test_assert(cp1 > cp2); /* Make sure we really added something. */
+
+ tor_assert(!tor_gzip_uncompress(&buf3, &len2, buf1, 1024-len1,
+ ZLIB_METHOD, 1, LOG_WARN));
+ test_streq(buf3, "ABCDEFGHIJABCDEFGHIJ"); /*Make sure it compressed right.*/
+ tor_free(buf3);
+
+ tor_zlib_free(state);
+
tor_free(buf2);
tor_free(buf3);
tor_free(buf1);
@@ -1016,8 +1105,10 @@ test_strmap(void)
test_eq_ptr(strmap_get(map,"K1"), (void*)100);
test_eq_ptr(strmap_get(map,"K2"), (void*)101);
test_eq_ptr(strmap_get(map,"K-not-there"), NULL);
+ strmap_assert_ok(map);
v = strmap_remove(map,"K2");
+ strmap_assert_ok(map);
test_eq_ptr(v, (void*)101);
test_eq_ptr(strmap_get(map,"K2"), NULL);
test_eq_ptr(strmap_remove(map,"K2"), NULL);
@@ -1025,8 +1116,10 @@ test_strmap(void)
strmap_set(map, "K2", (void*)101);
strmap_set(map, "K3", (void*)102);
strmap_set(map, "K4", (void*)103);
+ strmap_assert_ok(map);
strmap_set(map, "K5", (void*)104);
strmap_set(map, "K6", (void*)105);
+ strmap_assert_ok(map);
#if 0
iter = strmap_iter_init(map);
@@ -1053,6 +1146,7 @@ test_strmap(void)
test_eq_ptr(strmap_get(map, "K5"), (void*)10816);
#endif
+ strmap_assert_ok(map);
/* Clean up after ourselves. */
strmap_free(map, NULL);
@@ -1060,9 +1154,11 @@ test_strmap(void)
map = strmap_new();
strmap_set_lc(map,"Ab.C", (void*)1);
test_eq_ptr(strmap_get(map,"ab.c"), (void*)1);
+ strmap_assert_ok(map);
test_eq_ptr(strmap_get_lc(map,"AB.C"), (void*)1);
test_eq_ptr(strmap_get(map,"AB.C"), NULL);
test_eq_ptr(strmap_remove_lc(map,"aB.C"), (void*)1);
+ strmap_assert_ok(map);
test_eq_ptr(strmap_get_lc(map,"AB.C"), NULL);
strmap_free(map,NULL);
}
@@ -1145,6 +1241,8 @@ test_onion_handshake(void)
crypto_free_pk_env(pk);
}
+extern smartlist_t *fingerprint_list;
+
static void
test_dir_format(void)
{
@@ -1259,6 +1357,11 @@ test_dir_format(void)
strcat(buf2, pk1_str);
strcat(buf2, "signing-key\n");
strcat(buf2, pk2_str);
+#ifdef USE_EVENTDNS
+ strcat(buf2, "opt eventdns 1\n");
+#else
+ strcat(buf2, "opt eventdns 0\n");
+#endif
strcat(buf2, bw_lines);
strcat(buf2, "router-signature\n");
buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
@@ -1269,7 +1372,7 @@ test_dir_format(void)
test_assert(router_dump_router_to_string(buf, 2048, &r1, pk2)>0);
cp = buf;
- rp1 = router_parse_entry_from_string((const char*)cp,NULL);
+ rp1 = router_parse_entry_from_string((const char*)cp,NULL,1);
test_assert(rp1);
test_streq(rp1->address, r1.address);
test_eq(rp1->or_port, r1.or_port);
@@ -1292,7 +1395,7 @@ test_dir_format(void)
test_streq(buf, buf2);
cp = buf;
- rp2 = router_parse_entry_from_string(&cp);
+ rp2 = router_parse_entry_from_string(&cp,1);
test_assert(rp2);
test_streq(rp2->address, r2.address);
test_eq(rp2->or_port, r2.or_port);
@@ -1313,7 +1416,6 @@ test_dir_format(void)
/* Okay, now for the directories. */
{
- extern smartlist_t *fingerprint_list;
fingerprint_list = smartlist_create();
crypto_pk_get_fingerprint(pk2, buf, 1);
add_fingerprint_to_dir("Magri", buf, fingerprint_list);
@@ -1333,7 +1435,7 @@ test_dir_format(void)
test_assert(router_dump_router_to_string(buf, 2048, &r2, pk1)>0);
test_eq(dirserv_add_descriptor(buf,&m), 2);
get_options()->Nickname = tor_strdup("DirServer");
- test_assert(!dirserv_dump_directory_to_string(&cp,pk3));
+ test_assert(!dirserv_dump_directory_to_string(&cp,pk3, 0));
crypto_pk_get_digest(pk3, d);
test_assert(!router_parse_directory(cp));
test_eq(2, smartlist_len(dir1->routers));
@@ -1358,35 +1460,30 @@ test_dir_format(void)
test_eq(4, ver1.micro);
test_eq(VER_PRE, ver1.status);
test_eq(2, ver1.patchlevel);
- test_eq(IS_CVS, ver1.cvs);
test_eq(0, tor_version_parse("0.3.4rc1", &ver1));
test_eq(0, ver1.major);
test_eq(3, ver1.minor);
test_eq(4, ver1.micro);
test_eq(VER_RC, ver1.status);
test_eq(1, ver1.patchlevel);
- test_eq(IS_NOT_CVS, ver1.cvs);
test_eq(0, tor_version_parse("1.3.4", &ver1));
test_eq(1, ver1.major);
test_eq(3, ver1.minor);
test_eq(4, ver1.micro);
test_eq(VER_RELEASE, ver1.status);
test_eq(0, ver1.patchlevel);
- test_eq(IS_NOT_CVS, ver1.cvs);
test_eq(0, tor_version_parse("1.3.4.999", &ver1));
test_eq(1, ver1.major);
test_eq(3, ver1.minor);
test_eq(4, ver1.micro);
test_eq(VER_RELEASE, ver1.status);
test_eq(999, ver1.patchlevel);
- test_eq(IS_NOT_CVS, ver1.cvs);
test_eq(0, tor_version_parse("0.1.2.4-alpha", &ver1));
test_eq(0, ver1.major);
test_eq(1, ver1.minor);
test_eq(2, ver1.micro);
test_eq(4, ver1.patchlevel);
test_eq(VER_RELEASE, ver1.status);
- test_eq(IS_NOT_CVS, ver1.cvs);
test_streq("alpha", ver1.status_tag);
test_eq(0, tor_version_parse("0.1.2.4", &ver1));
test_eq(0, ver1.major);
@@ -1394,7 +1491,6 @@ test_dir_format(void)
test_eq(2, ver1.micro);
test_eq(4, ver1.patchlevel);
test_eq(VER_RELEASE, ver1.status);
- test_eq(IS_NOT_CVS, ver1.cvs);
test_streq("", ver1.status_tag);
#define test_eq_vs(vs1, vs2) test_eq_type(version_status_t, "%d", (vs1), (vs2))
@@ -1615,6 +1711,8 @@ main(int c, char**v)
{
or_options_t *options = options_new();
char *errmsg = NULL;
+ (void) c;
+ (void) v;
options->command = CMD_RUN_UNITTESTS;
network_init();
setup_directory();
@@ -1650,6 +1748,7 @@ main(int c, char**v)
test_util();
test_strmap();
test_control_formats();
+ test_pqueue();
puts("\n========================= Onion Skins =====================");
test_onion();
test_onion_handshake();