mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
This commit was manufactured by cvs2svn to create tag 'tor-0_0_6_2'.
svn:r1871
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
|
||||
Main authors:
|
||||
-------------
|
||||
|
||||
Roger Dingledine <arma@freehaven.net> overhauled all of the code, did
|
||||
a bunch of new design work, etc.
|
||||
|
||||
Nick Mathewson <nickm@freehaven.net> wrote lots of stuff too, in
|
||||
particular the router and descriptor parsing, and the crypto and tls
|
||||
wrappers.
|
||||
|
||||
Matej Pfajfar <badbytes@freehaven.net> wrote the first version of the code
|
||||
(called OR) in 2001-2002.
|
||||
|
||||
Contributors:
|
||||
-------------
|
||||
|
||||
John Bashinski <jbash@velvet.com> contributed the initial rpm spec file.
|
||||
|
||||
Christian Grothoff <grothoff@cs.purdue.edu> contributed better daemonizing
|
||||
behavior.
|
||||
|
||||
Steven Hazel <sah@thalassocracy.org> made 'make install' do the right
|
||||
thing.
|
||||
|
||||
Jason Holt <jason@lunkwill.org> contributed patches to the instructions
|
||||
and the man page.
|
||||
|
||||
Peter Palfrader <peter@palfrader.org> maintains everything that's
|
||||
debian-specific.
|
||||
|
||||
Aaron Turner <aturner@netscreen.com> contributed the first version of
|
||||
the tor.sh initscripts shell script.
|
||||
|
||||
@@ -0,0 +1,396 @@
|
||||
Changes in version 0.0.6.1 - 2004-05-06
|
||||
o Fix two bugs in our AES counter-mode implementation (this affected
|
||||
onion-level stream encryption, but not TLS-level). It turns
|
||||
out we were doing something much more akin to a 16-character
|
||||
polyalphabetic cipher. Oops.
|
||||
Thanks to Stefan Kopsell for finding the flaw!
|
||||
o Retire moria3 as a directory server, and add tor26 as a directory
|
||||
server.
|
||||
|
||||
|
||||
Changes in version 0.0.6 - 2004-05-02
|
||||
o Features:
|
||||
- Hidden services and rendezvous points are implemented. Go to
|
||||
http://6sxoyfb3h2nvok2d.onion/ for an index of currently available
|
||||
hidden services. (This only works via a socks4a proxy such as
|
||||
Privoxy, and currently it's quite slow.)
|
||||
- We now rotate link (tls context) keys and onion keys.
|
||||
- CREATE cells now include oaep padding, so you can tell
|
||||
if you decrypted them correctly.
|
||||
- Retry stream correctly when we fail to connect because of
|
||||
exit-policy-reject (should try another) or can't-resolve-address.
|
||||
- When we hup a dirserver and we've *removed* a server from the
|
||||
approved-routers list, now we remove that server from the
|
||||
in-memory directories too.
|
||||
- Add bandwidthburst to server descriptor.
|
||||
- Directories now say which dirserver signed them.
|
||||
- Use a tor_assert macro that logs failed assertions too.
|
||||
- Since we don't support truncateds much, don't bother sending them;
|
||||
just close the circ.
|
||||
- Fetch randomness from /dev/urandom better (not via fopen/fread)
|
||||
- Better debugging for tls errors
|
||||
- Set Content-Type on the directory and hidserv descriptor.
|
||||
- Remove IVs from cipher code, since AES-ctr has none.
|
||||
o Bugfixes:
|
||||
- Fix an assert trigger for exit nodes that's been plaguing us since
|
||||
the days of 0.0.2prexx (thanks weasel!)
|
||||
- Fix a bug where we were closing tls connections intermittently.
|
||||
It turns out openssl keeps its errors around -- so if an error
|
||||
happens, and you don't ask about it, and then another openssl
|
||||
operation happens and succeeds, and you ask if there was an error,
|
||||
it tells you about the first error.
|
||||
- Fix a bug that's been lurking since 27 may 03 (!)
|
||||
When passing back a destroy cell, we would use the wrong circ id.
|
||||
- Don't crash if a conn that sent a begin has suddenly lost its circuit.
|
||||
- Some versions of openssl have an SSL_pending function that erroneously
|
||||
returns bytes when there is a non-application record pending.
|
||||
- Win32 fixes. Tor now compiles on win32 with no warnings/errors.
|
||||
o We were using an array of length zero in a few places.
|
||||
o Win32's gethostbyname can't resolve an IP to an IP.
|
||||
o Win32's close can't close a socket.
|
||||
o Handle windows socket errors correctly.
|
||||
o Portability:
|
||||
- check for <sys/limits.h> so we build on FreeBSD again, and
|
||||
<machine/limits.h> for NetBSD.
|
||||
|
||||
|
||||
Changes in version 0.0.5 - 2004-03-30
|
||||
o Install torrc as torrc.sample -- we no longer clobber your
|
||||
torrc. (Woo!)
|
||||
o Fix mangled-state bug in directory fetching (was causing sigpipes).
|
||||
o Only build circuits after we've fetched the directory: clients were
|
||||
using only the directory servers before they'd fetched a directory.
|
||||
This also means longer startup time; so it goes.
|
||||
o Fix an assert trigger where an OP would fail to handshake, and we'd
|
||||
expect it to have a nickname.
|
||||
o Work around a tsocks bug: do a socks reject when AP connection dies
|
||||
early, else tsocks goes into an infinite loop.
|
||||
o Hold socks connection open until reply is flushed (if possible)
|
||||
o Make exit nodes resolve IPs to IPs immediately, rather than asking
|
||||
the dns farm to do it.
|
||||
o Fix c99 aliasing warnings in rephist.c
|
||||
o Don't include server descriptors that are older than 24 hours in the
|
||||
directory.
|
||||
o Give socks 'reject' replies their whole 15s to attempt to flush,
|
||||
rather than seeing the 60s timeout and assuming the flush had failed.
|
||||
o Clean automake droppings from the cvs repository
|
||||
o Add in a 'notice' log level for things the operator should hear
|
||||
but that aren't warnings
|
||||
|
||||
|
||||
Changes in version 0.0.4 - 2004-03-26
|
||||
o When connecting to a dirserver or OR and the network is down,
|
||||
we would crash.
|
||||
|
||||
|
||||
Changes in version 0.0.3 - 2004-03-26
|
||||
o Warn and fail if server chose a nickname with illegal characters
|
||||
o Port to Solaris and Sparc:
|
||||
- include missing header fcntl.h
|
||||
- have autoconf find -lsocket -lnsl automatically
|
||||
- deal with hardware word alignment
|
||||
- make uname() work (solaris has a different return convention)
|
||||
- switch from using signal() to sigaction()
|
||||
o Preliminary work on reputation system:
|
||||
- Keep statistics on success/fail of connect attempts; they're published
|
||||
by kill -USR1 currently.
|
||||
- Add a RunTesting option to try to learn link state by creating test
|
||||
circuits, even when SocksPort is off.
|
||||
- Remove unused open circuits when there are too many.
|
||||
|
||||
|
||||
Changes in version 0.0.2 - 2004-03-19
|
||||
- Include strlcpy and strlcat for safer string ops
|
||||
- define INADDR_NONE so we compile (but still not run) on solaris
|
||||
|
||||
|
||||
Changes in version 0.0.2pre27 - 2004-03-14
|
||||
o Bugfixes:
|
||||
- Allow internal tor networks (we were rejecting internal IPs,
|
||||
now we allow them if they're set explicitly).
|
||||
- And fix a few endian issues.
|
||||
|
||||
|
||||
Changes in version 0.0.2pre26 - 2004-03-14
|
||||
o New features:
|
||||
- If a stream times out after 15s without a connected cell, don't
|
||||
try that circuit again: try a new one.
|
||||
- Retry streams at most 4 times. Then give up.
|
||||
- When a dirserver gets a descriptor from an unknown router, it
|
||||
logs its fingerprint (so the dirserver operator can choose to
|
||||
accept it even without mail from the server operator).
|
||||
- Inform unapproved servers when we reject their descriptors.
|
||||
- Make tor build on Windows again. It works as a client, who knows
|
||||
about as a server.
|
||||
- Clearer instructions in the torrc for how to set up a server.
|
||||
- Be more efficient about reading fd's when our global token bucket
|
||||
(used for rate limiting) becomes empty.
|
||||
o Bugfixes:
|
||||
- Stop asserting that computers always go forward in time. It's
|
||||
simply not true.
|
||||
- When we sent a cell (e.g. destroy) and then marked an OR connection
|
||||
expired, we might close it before finishing a flush if the other
|
||||
side isn't reading right then.
|
||||
- Don't allow dirservers to start if they haven't defined
|
||||
RecommendedVersions
|
||||
- We were caching transient dns failures. Oops.
|
||||
- Prevent servers from publishing an internal IP as their address.
|
||||
- Address a strcat vulnerability in circuit.c
|
||||
|
||||
|
||||
Changes in version 0.0.2pre25 - 2004-03-04
|
||||
o New features:
|
||||
- Put the OR's IP in its router descriptor, not its fqdn. That way
|
||||
we'll stop being stalled by gethostbyname for nodes with flaky dns,
|
||||
e.g. poblano.
|
||||
o Bugfixes:
|
||||
- If the user typed in an address that didn't resolve, the server
|
||||
crashed.
|
||||
|
||||
|
||||
Changes in version 0.0.2pre24 - 2004-03-03
|
||||
o Bugfixes:
|
||||
- Fix an assertion failure in dns.c, where we were trying to dequeue
|
||||
a pending dns resolve even if it wasn't pending
|
||||
- Fix a spurious socks5 warning about still trying to write after the connection is finished.
|
||||
- Hold certain marked_for_close connections open until they're finished
|
||||
flushing, rather than losing bytes by closing them too early.
|
||||
- Correctly report the reason for ending a stream
|
||||
- Remove some duplicate calls to connection_mark_for_close
|
||||
- Put switch_id and start_daemon earlier in the boot sequence, so it
|
||||
will actually try to chdir() to options.DataDirectory
|
||||
- Make 'make test' exit(1) if a test fails; fix some unit tests
|
||||
- Make tor fail when you use a config option it doesn't know about,
|
||||
rather than warn and continue.
|
||||
- Make --version work
|
||||
- Bugfixes on the rpm spec file and tor.sh, so it's more up to date
|
||||
|
||||
|
||||
Changes in version 0.0.2pre23 - 2004-02-29
|
||||
o New features:
|
||||
- Print a statement when the first circ is finished, so the user
|
||||
knows it's working.
|
||||
- If a relay cell is unrecognized at the end of the circuit,
|
||||
send back a destroy. (So attacks to mutate cells are more
|
||||
clearly thwarted.)
|
||||
- New config option 'excludenodes' to avoid certain nodes for circuits.
|
||||
- When it daemonizes, it chdir's to the DataDirectory rather than "/",
|
||||
so you can collect coredumps there.
|
||||
o Bugfixes:
|
||||
- Fix a bug in tls flushing where sometimes data got wedged and
|
||||
didn't flush until more data got sent. Hopefully this bug was
|
||||
a big factor in the random delays we were seeing.
|
||||
- Make 'connected' cells include the resolved IP, so the client
|
||||
dns cache actually gets populated.
|
||||
- Disallow changing from ORPort=0 to ORPort>0 on hup.
|
||||
- When we time-out on a stream and detach from the circuit, send an
|
||||
end cell down it first.
|
||||
- Only warn about an unknown router (in exitnodes, entrynodes,
|
||||
excludenodes) after we've fetched a directory.
|
||||
|
||||
|
||||
Changes in version 0.0.2pre22 - 2004-02-26
|
||||
o New features:
|
||||
- Servers publish less revealing uname information in descriptors.
|
||||
- More memory tracking and assertions, to crash more usefully when
|
||||
errors happen.
|
||||
- If the default torrc isn't there, just use some default defaults.
|
||||
Plus provide an internal dirservers file if they don't have one.
|
||||
- When the user tries to use Tor as an http proxy, give them an http
|
||||
501 failure explaining that we're a socks proxy.
|
||||
- Dump a new router.desc on hup, to help confused people who change
|
||||
their exit policies and then wonder why router.desc doesn't reflect
|
||||
it.
|
||||
- Clean up the generic tor.sh init script that we ship with.
|
||||
o Bugfixes:
|
||||
- If the exit stream is pending on the resolve, and a destroy arrives,
|
||||
then the stream wasn't getting removed from the pending list. I
|
||||
think this was the one causing recent server crashes.
|
||||
- Use a more robust poll on OSX 10.3, since their poll is flaky.
|
||||
- When it couldn't resolve any dirservers, it was useless from then on.
|
||||
Now it reloads the RouterFile (or default dirservers) if it has no
|
||||
dirservers.
|
||||
- Move the 'tor' binary back to /usr/local/bin/ -- it turns out
|
||||
many users don't even *have* a /usr/local/sbin/.
|
||||
|
||||
|
||||
Changes in version 0.0.2pre21 - 2004-02-18
|
||||
o New features:
|
||||
- There's a ChangeLog file that actually reflects the changelog.
|
||||
- There's a 'torify' wrapper script, with an accompanying
|
||||
tor-tsocks.conf, that simplifies the process of using tsocks for
|
||||
tor. It even has a man page.
|
||||
- The tor binary gets installed to sbin rather than bin now.
|
||||
- Retry streams where the connected cell hasn't arrived in 15 seconds
|
||||
- Clean up exit policy handling -- get the default out of the torrc, so we can update it without forcing each server operator to fix
|
||||
his/her torrc.
|
||||
- Allow imaps and pop3s in default exit policy
|
||||
o Bugfixes:
|
||||
- Prevent picking middleman nodes as the last node in the circuit
|
||||
|
||||
|
||||
Changes in version 0.0.2pre20 - 2004-01-30
|
||||
o New features:
|
||||
- We now have a deb package, and it's in debian unstable. Go to
|
||||
it, apt-getters. :)
|
||||
- I've split the TotalBandwidth option into BandwidthRate (how many
|
||||
bytes per second you want to allow, long-term) and
|
||||
BandwidthBurst (how many bytes you will allow at once before the cap
|
||||
kicks in). This better token bucket approach lets you, say, set
|
||||
BandwidthRate to 10KB/s and BandwidthBurst to 10MB, allowing good
|
||||
performance while not exceeding your monthly bandwidth quota.
|
||||
- Push out a tls record's worth of data once you've got it, rather
|
||||
than waiting until you've read everything waiting to be read. This
|
||||
may improve performance by pipelining better. We'll see.
|
||||
- Add an AP_CONN_STATE_CONNECTING state, to allow streams to detach
|
||||
from failed circuits (if they haven't been connected yet) and attach
|
||||
to new ones.
|
||||
- Expire old streams that haven't managed to connect. Some day we'll
|
||||
have them reattach to new circuits instead.
|
||||
|
||||
o Bugfixes:
|
||||
- Fix several memory leaks that were causing servers to become bloated
|
||||
after a while.
|
||||
- Fix a few very rare assert triggers. A few more remain.
|
||||
- Setuid to User _before_ complaining about running as root.
|
||||
|
||||
|
||||
Changes in version 0.0.2pre19 - 2004-01-07
|
||||
o Bugfixes:
|
||||
- Fix deadlock condition in dns farm. We were telling a child to die by
|
||||
closing the parent's file descriptor to him. But newer children were
|
||||
inheriting the open file descriptor from the parent, and since they
|
||||
weren't closing it, the socket never closed, so the child never read
|
||||
eof, so he never knew to exit. Similarly, dns workers were holding
|
||||
open other sockets, leading to all sorts of chaos.
|
||||
- New cleaner daemon() code for forking and backgrounding.
|
||||
- If you log to a file, it now prints an entry at the top of the
|
||||
logfile so you know it's working.
|
||||
- The onionskin challenge length was 30 bytes longer than necessary.
|
||||
- Started to patch up the spec so it's not quite so out of date.
|
||||
|
||||
|
||||
Changes in version 0.0.2pre18 - 2004-01-02
|
||||
o Bugfixes:
|
||||
- Fix endian issues with the 'integrity' field in the relay header.
|
||||
- Fix a potential bug where connections in state
|
||||
AP_CONN_STATE_CIRCUIT_WAIT might unexpectedly ask to write.
|
||||
|
||||
|
||||
Changes in version 0.0.2pre17 - 2003-12-30
|
||||
o Bugfixes:
|
||||
- Made --debuglogfile (or any second log file, actually) work.
|
||||
- Resolved an edge case in get_unique_circ_id_by_conn where a smart
|
||||
adversary could force us into an infinite loop.
|
||||
|
||||
o Features:
|
||||
- Each onionskin handshake now includes a hash of the computed key,
|
||||
to prove the server's identity and help perfect forward secrecy.
|
||||
- Changed cell size from 256 to 512 bytes (working toward compatibility
|
||||
with MorphMix).
|
||||
- Changed cell length to 2 bytes, and moved it to the relay header.
|
||||
- Implemented end-to-end integrity checking for the payloads of
|
||||
relay cells.
|
||||
- Separated streamid from 'recognized' (otherwise circuits will get
|
||||
messed up when we try to have streams exit from the middle). We
|
||||
use the integrity-checking to confirm that a cell is addressed to
|
||||
this hop.
|
||||
- Randomize the initial circid and streamid values, so an adversary who
|
||||
breaks into a node can't learn how many circuits or streams have
|
||||
been made so far.
|
||||
|
||||
|
||||
Changes in version 0.0.2pre16 - 2003-12-14
|
||||
o Bugfixes:
|
||||
- Fixed a bug that made HUP trigger an assert
|
||||
- Fixed a bug where a circuit that immediately failed wasn't being
|
||||
counted as a failed circuit in counting retries.
|
||||
|
||||
o Features:
|
||||
- Now we close the circuit when we get a truncated cell: otherwise we're
|
||||
open to an anonymity attack where a bad node in the path truncates
|
||||
the circuit and then we open streams at him.
|
||||
- Add port ranges to exit policies
|
||||
- Add a conservative default exit policy
|
||||
- Warn if you're running tor as root
|
||||
- on HUP, retry OR connections and close/rebind listeners
|
||||
- options.EntryNodes: try these nodes first when picking the first node
|
||||
- options.ExitNodes: if your best choices happen to include any of
|
||||
your preferred exit nodes, you choose among just those preferred
|
||||
exit nodes.
|
||||
- options.ExcludedNodes: nodes that are never picked in path building
|
||||
|
||||
|
||||
Changes in version 0.0.2pre15 - 2003-12-03
|
||||
o Robustness and bugfixes:
|
||||
- Sometimes clients would cache incorrect DNS resolves, which would
|
||||
really screw things up.
|
||||
- An OP that goes offline would slowly leak all its sockets and stop
|
||||
working.
|
||||
- A wide variety of bugfixes in exit node selection, exit policy
|
||||
handling, and processing pending streams when a new circuit is
|
||||
established.
|
||||
- Pick nodes for a path only from those the directory says are up
|
||||
- Choose randomly from all running dirservers, not always the first one
|
||||
- Increase allowed http header size for directory fetch.
|
||||
- Stop writing to stderr (if we're daemonized it will be closed).
|
||||
- Enable -g always, so cores will be more useful to me.
|
||||
- Switch "-lcrypto -lssl" to "-lssl -lcrypto" for broken distributions.
|
||||
|
||||
o Documentation:
|
||||
- Wrote a man page. It lists commonly used options.
|
||||
|
||||
o Configuration:
|
||||
- Change default loglevel to warn.
|
||||
- Make PidFile default to null rather than littering in your CWD.
|
||||
- OnionRouter config option is now obsolete. Instead it just checks
|
||||
ORPort>0.
|
||||
- Moved to a single unified torrc file for both clients and servers.
|
||||
|
||||
|
||||
Changes in version 0.0.2pre14 - 2003-11-29
|
||||
o Robustness and bugfixes:
|
||||
- Force the admin to make the DataDirectory himself
|
||||
- to get ownership/permissions right
|
||||
- so clients no longer make a DataDirectory and then never use it
|
||||
- fix bug where a client who was offline for 45 minutes would never
|
||||
pull down a directory again
|
||||
- fix (or at least hide really well) the dns assert bug that was
|
||||
causing server crashes
|
||||
- warnings and improved robustness wrt clockskew for certs
|
||||
- use the native daemon(3) to daemonize, when available
|
||||
- exit if bind() fails
|
||||
- exit if neither socksport nor orport is defined
|
||||
- include our own tor_timegm (Win32 doesn't have its own)
|
||||
- bugfix for win32 with lots of connections
|
||||
- fix minor bias in PRNG
|
||||
- make dirserver more robust to corrupt cached directory
|
||||
|
||||
o Documentation:
|
||||
- Wrote the design document (woo)
|
||||
|
||||
o Circuit building and exit policies:
|
||||
- Circuits no longer try to use nodes that the directory has told them
|
||||
are down.
|
||||
- Exit policies now support bitmasks (18.0.0.0/255.0.0.0) and
|
||||
bitcounts (18.0.0.0/8).
|
||||
- Make AP connections standby for a circuit if no suitable circuit
|
||||
exists, rather than failing
|
||||
- Circuits choose exit node based on addr/port, exit policies, and
|
||||
which AP connections are standing by
|
||||
- Bump min pathlen from 2 to 3
|
||||
- Relay end cells have a payload to describe why the stream ended.
|
||||
- If the stream failed because of exit policy, try again with a new
|
||||
circuit.
|
||||
- Clients have a dns cache to remember resolved addresses.
|
||||
- Notice more quickly when we have no working circuits
|
||||
|
||||
o Configuration:
|
||||
- APPort is now called SocksPort
|
||||
- SocksBindAddress, ORBindAddress, DirBindAddress let you configure
|
||||
where to bind
|
||||
- RecommendedVersions is now a config variable rather than
|
||||
hardcoded (for dirservers)
|
||||
- Reloads config on HUP
|
||||
- Usage info on -h or --help
|
||||
- If you set User and Group config vars, it'll setu/gid to them.
|
||||
@@ -0,0 +1,53 @@
|
||||
Quickstart version for users:
|
||||
|
||||
0) Download the absolute newest version. No, really.
|
||||
http://freehaven.net/tor/dist/
|
||||
1) tar xvf it, and then cd into the directory.
|
||||
2) ./configure
|
||||
3) make
|
||||
4) make install (as root if necessary)
|
||||
5) tor (if it doesn't work, give it the whole path or fix your path)
|
||||
You don't need to run this as root, and you probably shouldn't.
|
||||
(If you're having problems, try running it with "-l info" to get
|
||||
more details.)
|
||||
6) point your browser to socks4 or socks5 proxy at localhost port
|
||||
9050. In mozilla, this is in edit|preferences|advanced|proxies. This
|
||||
allows you to test to make sure tor is installed correctly.
|
||||
(If you have a personal firewall, be sure to allow local connections
|
||||
to port 9050.)
|
||||
(If your firewall blocks outgoing connections, punch a hole so it
|
||||
can connect to TCP *:9001-9004 and *:9031-9033)
|
||||
(If you're using Safari as your browser, keep in mind that OS X before
|
||||
10.3 claims to support socks but does not. You must do step 8.)
|
||||
7) make sure you've set it up correctly: go to
|
||||
http://www.junkbusters.com/cgi-bin/privacy and see what IP it says
|
||||
you're coming from. If it works, you should probably go on to step 8,
|
||||
to get better privacy.
|
||||
|
||||
8) Optionally, install privoxy (www.privoxy.org), and add the line
|
||||
"forward-socks4a / localhost:9050 ." (without the quotes -- don't forget
|
||||
the dot) to its config file. Then change your mozilla to http proxy
|
||||
at localhost port 8118 (and no socks proxy). This step will give you
|
||||
good html scrubbing as well.
|
||||
(See doc/CLIENTS for why direct socks gives you less anonymity.)
|
||||
|
||||
*****If this works for you, you can stop reading here******
|
||||
|
||||
If you got the source from cvs:
|
||||
|
||||
Run "./autogen.sh", which will run the various auto* programs and then
|
||||
run ./configure for you. From there, start at step 3 in the quickstart
|
||||
list above.
|
||||
|
||||
If the quickstart doesn't work for you:
|
||||
|
||||
If you have problems finding libraries, try
|
||||
CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" \
|
||||
./configure
|
||||
rather than simply ./configure.
|
||||
|
||||
Check out the list archives at http://archives.seul.org/or/dev/ and see
|
||||
if somebody else has reported your problem. If not, please subscribe
|
||||
and let us know what you did to fix it, or give us the details and
|
||||
we'll see what we can do.
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
Copyright (c) 2001-2004, Roger Dingledine
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
* Neither the names of the copyright owners nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,21 @@
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
# else it keeps trying to put COPYING back in
|
||||
|
||||
SUBDIRS = src doc contrib
|
||||
|
||||
DIST_SUBDIRS = src doc contrib
|
||||
|
||||
EXTRA_DIST = INSTALL README AUTHORS LICENSE ChangeLog
|
||||
|
||||
#install-data-local:
|
||||
# $(INSTALL) -m 755 -d $(LOCALSTATEDIR)/lib/tor
|
||||
|
||||
dist-rpm: dist
|
||||
rm -rf /tmp/tor-rpm-build
|
||||
mkdir /tmp/tor-rpm-build
|
||||
for subdir in BUILD RPMS SOURCES SPECS SRPMS; do \
|
||||
mkdir /tmp/tor-rpm-build/$$subdir; \
|
||||
done
|
||||
cp tor-$(VERSION).tar.gz /tmp/tor-rpm-build/SOURCES
|
||||
rpmbuild -ba --define '_topdir /tmp/tor-rpm-build' contrib/tor.spec
|
||||
mv /tmp/tor-rpm-build/*RPMS/* .
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
'tor' is an implementation of The Onion Routing system, as
|
||||
described in a bit more detail at http://www.onion-router.net/. You
|
||||
can read list archives, and subscribe to the mailing list, at
|
||||
http://archives.seul.org/or/dev/.
|
||||
|
||||
Is your question in the FAQ? Should it be?
|
||||
|
||||
**************************************************************************
|
||||
See the INSTALL file for a quickstart. That is all you will probably need.
|
||||
**************************************************************************
|
||||
|
||||
**************************************************************************
|
||||
You only need to look beyond this point if the quickstart in the INSTALL
|
||||
doesn't work for you.
|
||||
**************************************************************************
|
||||
|
||||
Do you want to run a tor server?
|
||||
|
||||
First, copy torrc.sample to torrc (by default it's in
|
||||
/usr/local/etc/tor/), and edit the middle part. Create the
|
||||
DataDirectory, and make sure it's owned by whoever will be running
|
||||
tor. Fix your system clock so it's not too far off. Make sure name
|
||||
resolution works.
|
||||
|
||||
Then run tor to generate keys. One of the files generated
|
||||
in your DataDirectory is your 'fingerprint' file. Mail it to
|
||||
arma@mit.edu.
|
||||
|
||||
NOTE: You won't be able to use tor as a client or server
|
||||
in this configuration until you've been added to the directory
|
||||
and can authenticate to the other nodes.
|
||||
|
||||
Do you want to run a hidden service?
|
||||
|
||||
Copy torrc.sample to torrc (by default it's in /usr/local/etc/tor/), and
|
||||
edit the bottom part. Then run Tor. It will create each HiddenServiceDir
|
||||
you have configured, and it will create a 'hostname' file which
|
||||
specifies the url (xyz.onion) for that service. You can tell people
|
||||
the url, and they can connect to it via their Tor proxy.
|
||||
|
||||
Configuring tsocks:
|
||||
|
||||
If you want to use Tor for protocols that can't use Privoxy, or
|
||||
with applications that are not socksified, then download tsocks
|
||||
(tsocks.sourceforge.net) and configure it to talk to localhost:9050
|
||||
as a socks4 server. My /etc/tsocks.conf simply has:
|
||||
server_port = 9050
|
||||
server = 127.0.0.1
|
||||
(I had to "cd /usr/lib; ln -s /lib/libtsocks.so" to get the tsocks
|
||||
library working after install, since my libpath didn't include /lib.)
|
||||
Then you can do "tsocks ssh arma@moria.mit.edu". But note that if
|
||||
ssh is suid root, you either need to do this as root, or cp a local
|
||||
version of ssh that isn't suid.
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
# Microsoft Developer Studio Project File - Name="or" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=or - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "or.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "or.mak" CFG="or - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "or - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "or - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "or - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /MT /W3 /GX /O2 /I "d:\openssl\include ..\win32" /I "..\win32" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib libeay32.lib ssleay32.lib /nologo /subsystem:console /machine:I386 /libpath:"d:\openssl\lib\vc"
|
||||
|
||||
!ELSEIF "$(CFG)" == "or - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\..\src\win32" /I "D:\openssl\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib libeay32.lib ssleay32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/tor.exe" /pdbtype:sept /libpath:"d:\openssl\lib\vc"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "or - Win32 Release"
|
||||
# Name "or - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\common\aes.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\buffers.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\circuit.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\command.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\config.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\connection.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\connection_edge.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\connection_or.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\cpuworker.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\common\crypto.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\directory.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\dirserv.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\dns.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\common\fakepoll.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\common\log.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\main.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\onion.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\rendclient.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\rendcommon.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\rendmid.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\rendservice.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\rephist.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\router.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\routerlist.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\tor_main.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\common\tortls.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\common\util.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\common\aes.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\common\crypto.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\common\fakepoll.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\common\log.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\or.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\win32\orconfig.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\common\test.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\common\torint.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\common\tortls.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\or\tree.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\common\util.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
||||
@@ -0,0 +1,29 @@
|
||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "or"=".\or.dsp" - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "or"="..\or\or.dsp" - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
# Run this to generate all the initial makefiles, etc.
|
||||
aclocal &&
|
||||
autoheader &&
|
||||
autoconf &&
|
||||
automake --add-missing --copy
|
||||
./configure
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
|
||||
AC_INIT
|
||||
AM_INIT_AUTOMAKE(tor, 0.0.6.2)
|
||||
AM_CONFIG_HEADER(orconfig.h)
|
||||
|
||||
CFLAGS="$CFLAGS -Wall -g -O2 -I/usr/kerberos/include"
|
||||
|
||||
AC_ARG_ENABLE(debug,
|
||||
[ --enable-debug compiles with debugging info],
|
||||
[if test x$enableval = xyes; then
|
||||
CFLAGS="$CFLAGS -g"
|
||||
fi])
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_RANLIB
|
||||
|
||||
# The big search for OpenSSL
|
||||
# copied from openssh's configure.ac
|
||||
AC_ARG_WITH(ssl-dir,
|
||||
[ --with-ssl-dir=PATH Specify path to OpenSSL installation ],
|
||||
[
|
||||
if test "x$withval" != "xno" ; then
|
||||
tryssldir=$withval
|
||||
fi
|
||||
]
|
||||
)
|
||||
|
||||
AC_SEARCH_LIBS(socket, [socket])
|
||||
AC_SEARCH_LIBS(gethostbyname, [nsl])
|
||||
|
||||
saved_LIBS="$LIBS"
|
||||
saved_LDFLAGS="$LDFLAGS"
|
||||
saved_CPPFLAGS="$CPPFLAGS"
|
||||
if test "x$prefix" != "xNONE" ; then
|
||||
tryssldir="$tryssldir $prefix"
|
||||
fi
|
||||
AC_CACHE_CHECK([for OpenSSL directory], ac_cv_openssldir, [
|
||||
for ssldir in $tryssldir "" /usr/local/openssl /usr/lib/openssl /usr/local/ssl /usr/lib/ssl /usr/local /usr/pkg /opt /opt/openssl ; do
|
||||
CPPFLAGS="$saved_CPPFLAGS"
|
||||
LDFLAGS="$saved_LDFLAGS"
|
||||
LIBS="$saved_LIBS -lssl -lcrypto"
|
||||
|
||||
# Skip directories if they don't exist
|
||||
if test ! -z "$ssldir" -a ! -d "$ssldir" ; then
|
||||
continue;
|
||||
fi
|
||||
if test ! -z "$ssldir" -a "x$ssldir" != "x/usr"; then
|
||||
# Try to use $ssldir/lib if it exists, otherwise
|
||||
# $ssldir
|
||||
if test -d "$ssldir/lib" ; then
|
||||
LDFLAGS="-L$ssldir/lib $saved_LDFLAGS"
|
||||
if test ! -z "$need_dash_r" ; then
|
||||
LDFLAGS="-R$ssldir/lib $LDFLAGS"
|
||||
fi
|
||||
else
|
||||
LDFLAGS="-L$ssldir $saved_LDFLAGS"
|
||||
if test ! -z "$need_dash_r" ; then
|
||||
LDFLAGS="-R$ssldir $LDFLAGS"
|
||||
fi
|
||||
fi
|
||||
# Try to use $ssldir/include if it exists, otherwise
|
||||
# $ssldir
|
||||
if test -d "$ssldir/include" ; then
|
||||
CPPFLAGS="-I$ssldir/include $saved_CPPFLAGS"
|
||||
else
|
||||
CPPFLAGS="-I$ssldir $saved_CPPFLAGS"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Basic test to check for compatible version and correct linking
|
||||
# *does not* test for RSA - that comes later.
|
||||
AC_TRY_RUN(
|
||||
[
|
||||
#include <string.h>
|
||||
#include <openssl/rand.h>
|
||||
int main(void)
|
||||
{
|
||||
char a[2048];
|
||||
memset(a, 0, sizeof(a));
|
||||
RAND_add(a, sizeof(a), sizeof(a));
|
||||
return(RAND_status() <= 0);
|
||||
}
|
||||
],
|
||||
[
|
||||
found_crypto=1
|
||||
break;
|
||||
], []
|
||||
)
|
||||
|
||||
if test ! -z "$found_crypto" ; then
|
||||
break;
|
||||
fi
|
||||
done
|
||||
|
||||
if test -z "$found_crypto" ; then
|
||||
AC_MSG_ERROR([Could not find working OpenSSL library, please install or check config.log])
|
||||
fi
|
||||
if test -z "$ssldir" ; then
|
||||
ssldir="(system)"
|
||||
fi
|
||||
|
||||
ac_cv_openssldir=$ssldir
|
||||
])
|
||||
if (test ! -z "$ac_cv_openssldir" && test "x$ac_cv_openssldir" != "x(system)") ;
|
||||
then
|
||||
dnl Need to recover ssldir - test above runs in subshell
|
||||
ssldir=$ac_cv_openssldir
|
||||
if test ! -z "$ssldir" -a "x$ssldir" != "x/usr"; then
|
||||
# Try to use $ssldir/lib if it exists, otherwise
|
||||
# $ssldir
|
||||
if test -d "$ssldir/lib" ; then
|
||||
LDFLAGS="-L$ssldir/lib $saved_LDFLAGS"
|
||||
if test ! -z "$need_dash_r" ; then
|
||||
LDFLAGS="-R$ssldir/lib $LDFLAGS"
|
||||
fi
|
||||
else
|
||||
LDFLAGS="-L$ssldir $saved_LDFLAGS"
|
||||
if test ! -z "$need_dash_r" ; then
|
||||
LDFLAGS="-R$ssldir $LDFLAGS"
|
||||
fi
|
||||
fi
|
||||
# Try to use $ssldir/include if it exists, otherwise
|
||||
# $ssldir
|
||||
if test -d "$ssldir/include" ; then
|
||||
CPPFLAGS="-I$ssldir/include $saved_CPPFLAGS"
|
||||
else
|
||||
CPPFLAGS="-I$ssldir $saved_CPPFLAGS"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
LIBS="$saved_LIBS -lssl -lcrypto"
|
||||
|
||||
dnl The warning message here is no longer strictly accurate.
|
||||
|
||||
AC_CHECK_HEADERS(unistd.h string.h signal.h netdb.h ctype.h poll.h sys/stat.h sys/poll.h sys/types.h fcntl.h sys/fcntl.h sys/ioctl.h sys/socket.h sys/time.h netinet/in.h arpa/inet.h errno.h assert.h time.h pwd.h grp.h, , AC_MSG_WARN(some headers were not found, compilation may fail))
|
||||
|
||||
dnl These headers are not essential
|
||||
|
||||
AC_CHECK_HEADERS(stdint.h sys/types.h inttypes.h sys/wait.h sys/limits.h netinet/in.h arpa/inet.h machine/limits.h)
|
||||
|
||||
AC_CHECK_FUNCS(gettimeofday ftime socketpair uname inet_aton strptime)
|
||||
AC_REPLACE_FUNCS(strlcat strlcpy)
|
||||
|
||||
dnl In case we aren't given a working stdint.h, we'll need to grow our own.
|
||||
dnl Watch out.
|
||||
|
||||
AC_CHECK_SIZEOF(int8_t)
|
||||
AC_CHECK_SIZEOF(int16_t)
|
||||
AC_CHECK_SIZEOF(int32_t)
|
||||
AC_CHECK_SIZEOF(int64_t)
|
||||
AC_CHECK_SIZEOF(uint8_t)
|
||||
AC_CHECK_SIZEOF(uint16_t)
|
||||
AC_CHECK_SIZEOF(uint32_t)
|
||||
AC_CHECK_SIZEOF(uint64_t)
|
||||
|
||||
dnl AC_CHECK_TYPES([int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_t])
|
||||
|
||||
AC_CHECK_SIZEOF(char)
|
||||
AC_CHECK_SIZEOF(short)
|
||||
AC_CHECK_SIZEOF(int)
|
||||
AC_CHECK_SIZEOF(long)
|
||||
AC_CHECK_SIZEOF(long long)
|
||||
AC_CHECK_SIZEOF(__int64)
|
||||
|
||||
# Now, let's see about alignment requirements
|
||||
AC_CACHE_CHECK([whether unaligned int access is allowed], tor_cv_unaligned_ok,
|
||||
[AC_RUN_IFELSE([AC_LANG_SOURCE(
|
||||
[[int main () { char s[] = "A\x00\x00\x00\x00\x00\x00\x00";
|
||||
return *(int*)(&s[1]); }]])],
|
||||
[tor_cv_unaligned_ok=yes],
|
||||
[tor_cv_unaligned_ok=no],
|
||||
[tor_cv_unaligned_ok=cross])])
|
||||
if test $tor_cv_unaligned_ok = yes; then
|
||||
AC_DEFINE([UNALIGNED_INT_ACCESS_OK], 1,
|
||||
[Define to 1 iff unaligned int access is allowed])
|
||||
fi
|
||||
|
||||
# $prefix stores the value of the --prefix command line option, or
|
||||
# NONE if the option wasn't set. In the case that it wasn't set, make
|
||||
# it be the default, so that we can use it to expand directories now.
|
||||
if test "x$prefix" = "xNONE"; then
|
||||
prefix=$ac_default_prefix
|
||||
fi
|
||||
|
||||
# and similarly for $exec_prefix
|
||||
if test "x$exec_prefix" = "xNONE"; then
|
||||
exec_prefix=$prefix
|
||||
fi
|
||||
|
||||
CONFDIR=`eval echo $sysconfdir/tor`
|
||||
AC_SUBST(CONFDIR)
|
||||
AC_DEFINE_UNQUOTED(CONFDIR,"$CONFDIR")
|
||||
AC_DEFINE([CONFDIR], [], [tor's configuration directory])
|
||||
|
||||
BINDIR=`eval echo $bindir`
|
||||
AC_SUBST(BINDIR)
|
||||
|
||||
LOCALSTATEDIR=`eval echo $localstatedir`
|
||||
AC_SUBST(LOCALSTATEDIR)
|
||||
|
||||
echo "confdir: $CONFDIR"
|
||||
|
||||
AC_OUTPUT(Makefile contrib/tor.sh contrib/torify contrib/Makefile contrib/tor.spec src/config/torrc.sample doc/tor.1 src/Makefile doc/Makefile src/config/Makefile src/common/Makefile src/or/Makefile)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
tor.sh
|
||||
tor.spec
|
||||
torify
|
||||
@@ -0,0 +1,9 @@
|
||||
confdir = $(sysconfdir)/tor
|
||||
|
||||
EXTRA_DIST = tor-tsocks.conf torify.1 tor.spec
|
||||
|
||||
conf_DATA = tor-tsocks.conf
|
||||
|
||||
bin_SCRIPTS = torify
|
||||
|
||||
man_MANS = torify.1
|
||||
@@ -0,0 +1,7 @@
|
||||
# This is the configuration for libtsocks (transparent socks) for use
|
||||
# with tor, which is providing a socks server on port 9050 by default.
|
||||
#
|
||||
# See tsocks.conf(5) and torify(1) manpages.
|
||||
|
||||
server = 127.0.0.1
|
||||
server_port = 9050
|
||||
@@ -0,0 +1,95 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
#tor The Onion Router
|
||||
#
|
||||
#chkconfig:2345 90 10
|
||||
#description: Onion Router
|
||||
|
||||
TORUSER=
|
||||
TORGROUP=
|
||||
TORBIN=@BINDIR@/tor
|
||||
TORPID=@LOCALSTATEDIR@/run/tor/tor.pid
|
||||
TORLOG=@LOCALSTATEDIR@/log/tor/tor.log
|
||||
TORCONF=@CONFDIR@/torrc
|
||||
# Strictly speaking, we don't need to su if we have --user and --group.
|
||||
# "Belt and suspenders," says jbash.
|
||||
TORARGS="--pidfile $TORPID --logfile $TORLOG --runasdaemon 1"
|
||||
if [ "x$TORUSER" != "x" ]; then
|
||||
TORARGS="$TORARGS --user $TORUSER"
|
||||
fi
|
||||
if [ "x$TORGROUP" != "x" ]; then
|
||||
TORARGS="$TORARGS --group $TORGROUP"
|
||||
fi
|
||||
RETVAL=0
|
||||
|
||||
case "$1" in
|
||||
|
||||
start)
|
||||
if [ -f $TORPID ]; then
|
||||
echo "tor appears to be already running (pid file exists)"
|
||||
echo "Maybe you should run: $0 restart ?"
|
||||
RETVAL=1
|
||||
else
|
||||
echo -n "Starting tor..."
|
||||
if [ "x$TORUSER" = "x" ]; then
|
||||
$TORBIN -f $TORCONF $TORARGS
|
||||
else
|
||||
/bin/su -c "$TORBIN -f $TORCONF $TORARGS" $TORUSER
|
||||
fi
|
||||
RETVAL=$?
|
||||
if [ $RETVAL -eq 0 ]; then
|
||||
echo " ok"
|
||||
else
|
||||
echo " ERROR!"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
stop)
|
||||
if [ -f $TORPID ]; then
|
||||
echo -n "Killing tor..."
|
||||
kill `cat $TORPID`
|
||||
RETVAL=$?
|
||||
if [ $RETVAL -eq 0 ]; then
|
||||
echo " ok"
|
||||
else
|
||||
echo " ERROR!"
|
||||
fi
|
||||
else
|
||||
echo "Unable to kill tor: $TORPID does not exist"
|
||||
RETVAL=1
|
||||
fi
|
||||
;;
|
||||
|
||||
restart)
|
||||
$0 stop
|
||||
if [ -f $TORPID ]; then
|
||||
rm -f $TORPID
|
||||
fi
|
||||
$0 start
|
||||
;;
|
||||
|
||||
status)
|
||||
PID=`cat $TORPID 2>/dev/null`
|
||||
if [ "$PID" != "" ]; then
|
||||
torstat=`ps -p $PID | grep -c "^$PID"`
|
||||
if [ $torstat ]; then
|
||||
echo "tor is running ($PID)"
|
||||
else
|
||||
echo "tor is not running (looks like it crashed, look for core? $PID)"
|
||||
fi
|
||||
else
|
||||
echo "tor is not running (exited gracefully)"
|
||||
fi
|
||||
;;
|
||||
|
||||
log)
|
||||
cat $TORLOG
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Usage: $0 (start|stop|restart|status|log)"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit $RETVAL
|
||||
@@ -0,0 +1,137 @@
|
||||
%define rellevel 2
|
||||
%define relbase std.%{rellevel}
|
||||
%define rhrel %([ -f /etc/redhat-release ] && (sed -e 's/^Red Hat Linux release //' -e 's/ .*$//' -e 's/\\./_/g' -e 's/^.*$/.rh&/' < /etc/redhat-release))
|
||||
%define blddate %(date -u +"%Y%m%d%H%M")
|
||||
%define release %{relbase}%{rhrel}.%{blddate}
|
||||
|
||||
%define initdir /etc/rc.d/init.d
|
||||
|
||||
Summary: tor: anonymizing overlay network for TCP
|
||||
Name: tor
|
||||
Version: @VERSION@
|
||||
Vendor: R. Dingledine <arma@seul.org>
|
||||
Release: %{release}
|
||||
License: BSD-like
|
||||
Group: Applications/Internet
|
||||
URL: http://freehaven.net/tor/
|
||||
|
||||
Source0: http://freehaven.net/tor/dist/tor-%{version}.tar.gz
|
||||
|
||||
Requires(pre): shadow-utils, /usr/bin/id, /bin/date, /bin/sh
|
||||
Requires(pre): %{_sbindir}/useradd, %{_sbindir}/groupadd
|
||||
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{relbase}-root
|
||||
|
||||
%description
|
||||
Tor is a connection-based low-latency anonymous communication system which
|
||||
addresses many flaws in the original onion routing design.
|
||||
|
||||
In brief, Onion Routing is a connection-oriented anonymizing communication
|
||||
service. Users choose a source-routed path through a set of nodes, and
|
||||
negotiate a "virtual circuit" through the network, in which each node
|
||||
knows its predecessor and successor, but no others. Traffic flowing down
|
||||
the circuit is unwrapped by a symmetric key at each node, which reveals
|
||||
the downstream node.
|
||||
|
||||
Basically Tor provides a distributed network of servers ("onion
|
||||
routers"). Users bounce their tcp streams (web traffic, ftp, ssh, etc)
|
||||
around the routers, and recipients, observers, and even the routers
|
||||
themselves have difficulty tracking the source of the stream.
|
||||
|
||||
Note that Tor does no protocol cleaning. That means there is a danger that
|
||||
application protocols and associated programs can be induced to reveal
|
||||
information about the initiator. Tor depends on Privoxy and similar protocol
|
||||
cleaners to solve this problem.
|
||||
|
||||
Client applications can use the Tor network by connecting to the local
|
||||
onion proxy. If the application itself does not come with socks support
|
||||
you can use a socks client such as tsocks. Some web browsers like mozilla
|
||||
and web proxies like privoxy come with socks support, so you don't need an
|
||||
extra socks client if you want to use Tor with them.
|
||||
|
||||
Remember that this is alpha code, and the network is very small -- Tor will
|
||||
not provide anonymity currently.
|
||||
|
||||
This package provides the "tor" program, which serves as both a client
|
||||
and a relay node. Scripts will automatically create a "tor" user and
|
||||
group, set tor up to run as a daemon, and automatically start it at
|
||||
installation time.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
# Patch the startup script to use the right user and group IDs. Force
|
||||
# the use of /bin/sh as the shell for the "tor" account.
|
||||
ed -s contrib/tor.sh.in << '/EOF/' > /dev/null
|
||||
,s/^TORUSER=$/TORUSER=tor/
|
||||
,s/^TORGROUP=$/TORGROUP=tor/
|
||||
,s:/bin/su:/bin/su -s /bin/sh:
|
||||
#
|
||||
# Save and exit ed
|
||||
w
|
||||
q
|
||||
/EOF/
|
||||
|
||||
%build
|
||||
%configure
|
||||
%__make
|
||||
|
||||
%install
|
||||
%makeinstall
|
||||
|
||||
# Install init script.
|
||||
%__mkdir_p ${RPM_BUILD_ROOT}%{initdir}
|
||||
%__install -m 755 contrib/tor.sh ${RPM_BUILD_ROOT}%{initdir}/tor
|
||||
|
||||
# Directories that don't have any preinstalled files
|
||||
%__mkdir_p -m 700 ${RPM_BUILD_ROOT}/var/lib/tor
|
||||
%__mkdir_p -m 755 ${RPM_BUILD_ROOT}/var/run/tor
|
||||
%__mkdir_p -m 755 ${RPM_BUILD_ROOT}/var/log/tor
|
||||
|
||||
%clean
|
||||
[ "${RPM_BUILD_ROOT}" != "/" ] && rm -rf ${RPM_BUILD_ROOT}
|
||||
|
||||
%pre
|
||||
[ -f %{initdir}/tor ] && /sbin/service tor stop
|
||||
if [ ! -n "`/usr/bin/id -g tor 2>/dev/null`" ]; then
|
||||
# One would like to default the GID, but doing that properly would
|
||||
# require thought.
|
||||
%{_sbindir}/groupadd tor 2> /dev/null
|
||||
fi
|
||||
if [ ! -n "`/usr/bin/id -u tor 2>/dev/null`" ]; then
|
||||
# One would also like to default the UID, but doing that properly would
|
||||
# also require thought.
|
||||
if [ -x /sbin/nologin ]; then
|
||||
%{_sbindir}/useradd -r -g tor -d / -s /sbin/nologin tor 2> /dev/null
|
||||
else
|
||||
%{_sbindir}/useradd -r -g tor -d / -s /bin/false tor 2> /dev/null
|
||||
fi
|
||||
fi
|
||||
|
||||
%post
|
||||
/sbin/chkconfig --add tor
|
||||
/sbin/chkconfig tor && /sbin/service tor start
|
||||
|
||||
%preun
|
||||
/sbin/chkconfig tor && /sbin/service tor stop
|
||||
/sbin/chkconfig --del tor
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
%doc AUTHORS INSTALL LICENSE README
|
||||
%{_mandir}/man*/*
|
||||
%{_bindir}/tor
|
||||
%{_bindir}/torify
|
||||
%{initdir}/tor
|
||||
%dir %{_sysconfdir}/tor/
|
||||
%config(noreplace) %{_sysconfdir}/tor/torrc
|
||||
%config(noreplace) %{_sysconfdir}/tor/dirservers
|
||||
%config(noreplace) %{_sysconfdir}/tor/tor-tsocks.conf
|
||||
%attr(-,tor,tor) %dir /var/lib/tor
|
||||
%attr(-,tor,tor) %dir /var/run/tor
|
||||
%attr(-,tor,tor) %dir /var/log/tor
|
||||
|
||||
%changelog
|
||||
* Sat Jan 17 2004 John Bashinski <jbash@velvet.com>
|
||||
- Basic spec file; tested with Red Hat 9.
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
.TH torify 1 "" Feb-2004 ""
|
||||
.\" manual page by Peter Palfrader
|
||||
.SH NAME
|
||||
.LP
|
||||
torify \- wrapper for tsocks and tor
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBtorify\fP\ \fIapplication\fP\ [\fIapplication's\ arguments\fP]
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBtorify\fR is a simple wrapper that calls tsocks with a tor specific
|
||||
configuration file.
|
||||
|
||||
Tsocks itself is wrapper between the tsocks library and the application what
|
||||
you would like to run socksified.
|
||||
|
||||
Please note that since tsocks uses LD_PRELOAD this cannot be applied to suid
|
||||
binaries.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR tor (1),
|
||||
.BR tsocks (1),
|
||||
.BR tsocks.conf (5).
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#! /bin/sh
|
||||
# Wrapper script for use of the tsocks(8) transparent socksification library
|
||||
# See the tsocks(1) and torify(1) manpages.
|
||||
|
||||
TSOCKS_CONF_FILE=@CONFDIR@/tor-tsocks.conf
|
||||
export TSOCKS_CONF_FILE
|
||||
exec tsocks "$@"
|
||||
@@ -0,0 +1,18 @@
|
||||
Tor only provides TCP layer anonymity. It does not do any protocol
|
||||
cleaning, so if you are going to browse the web you still give away a
|
||||
lot of information to servers.
|
||||
|
||||
The privoxy package provides a privacy enhancing HTTP proxy, which
|
||||
is good at filtering headers, cookies, and much more. To view the
|
||||
description of the Debian privoxy package just run "apt-cache show
|
||||
privoxy". Please refer to the privoxy documentation for more details.
|
||||
|
||||
In order to use privoxy over tor, add the following line to your
|
||||
privoxy configuration file:
|
||||
forward-socks4a / localhost:9050 .
|
||||
(the dot is important)
|
||||
|
||||
Then configure your browser to use privoxy as its HTTP proxy.
|
||||
|
||||
--
|
||||
Peter Palfrader <weasel@debian.org>, Tue, 17 Feb 2004 02:15:36 +0100
|
||||
@@ -0,0 +1,9 @@
|
||||
Legend:
|
||||
- Not done
|
||||
* Top priority
|
||||
. Partially done
|
||||
o Done
|
||||
D Deferred
|
||||
X Abandoned
|
||||
|
||||
- strip debugging symbols when tor is more mature
|
||||
@@ -0,0 +1,143 @@
|
||||
tor (0.0.5+0.0.6rc3-1) unstable; urgency=low
|
||||
|
||||
* New upstream release candidate.
|
||||
|
||||
-- Peter Palfrader <weasel@debian.org> Thu, 29 Apr 2004 11:52:07 +0200
|
||||
|
||||
tor (0.0.5+0.0.6rc2-1) unstable; urgency=low
|
||||
|
||||
* New upstream release candidate.
|
||||
* Mention upstream website and mailinglist archives in long
|
||||
description.
|
||||
|
||||
-- Peter Palfrader <weasel@debian.org> Mon, 26 Apr 2004 12:23:20 +0200
|
||||
|
||||
tor (0.0.5-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
* Upstream installs a torrc.sample file now, rather than torrc.
|
||||
Keep using torrc as dpkg handles conffile upgrades.
|
||||
|
||||
-- Peter Palfrader <weasel@debian.org> Tue, 30 Mar 2004 20:54:00 +0200
|
||||
|
||||
tor (0.0.4-1) unstable; urgency=low
|
||||
|
||||
* New upstream release (how the version numbers fly by :).
|
||||
|
||||
-- Peter Palfrader <weasel@debian.org> Fri, 26 Mar 2004 23:46:09 +0100
|
||||
|
||||
tor (0.0.3-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
* Also mention that tree.h is by Niels Provos in debian/copyright.
|
||||
|
||||
-- Peter Palfrader <weasel@debian.org> Fri, 26 Mar 2004 20:36:08 +0100
|
||||
|
||||
tor (0.0.2-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
* Uses strlcpy and strlcat by Todd C. Miller, mention him in
|
||||
debian/copyright.
|
||||
|
||||
-- Peter Palfrader <weasel@debian.org> Fri, 19 Mar 2004 12:37:17 +0100
|
||||
|
||||
tor (0.0.1+0.0.2pre27-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Peter Palfrader <weasel@debian.org> Mon, 15 Mar 2004 05:19:16 +0100
|
||||
|
||||
tor (0.0.1+0.0.2pre26-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
* Mention log and pidfile location in tor.1.
|
||||
|
||||
-- Peter Palfrader <weasel@debian.org> Mon, 15 Mar 2004 02:21:29 +0100
|
||||
|
||||
tor (0.0.1+0.0.2pre25-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Peter Palfrader <weasel@debian.org> Thu, 4 Mar 2004 23:05:38 +0100
|
||||
|
||||
tor (0.0.1+0.0.2pre24-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
* Do not strip binaries for now.
|
||||
* Add "# ulimit -c unlimited" to tor.default
|
||||
* Always enable DataDirectory.
|
||||
* Actually use dpatch now (to modify upstream torrc.in)
|
||||
* Wait for tor to die in init stop. Let the user know if it doesn't.
|
||||
|
||||
-- Peter Palfrader <weasel@debian.org> Wed, 3 Mar 2004 14:10:25 +0100
|
||||
|
||||
tor (0.0.1+0.0.2pre23-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
* The one test that always failed has been fixed: removed comment from
|
||||
rules file.
|
||||
|
||||
-- Peter Palfrader <weasel@debian.org> Sun, 29 Feb 2004 12:36:33 +0100
|
||||
|
||||
tor (0.0.1+0.0.2pre22-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
* Upstream has moved tor back to usr/bin, but we will keep it in
|
||||
usr/sbin. That's the right place and it doesn't break my tab
|
||||
completion there.
|
||||
|
||||
-- Peter Palfrader <weasel@debian.org> Fri, 27 Feb 2004 01:59:09 +0100
|
||||
|
||||
tor (0.0.1+0.0.2pre21-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
* 0.0.2pre20-2 removed the Recommends: on privoxy rather
|
||||
than tsocks (which is now required) by mistake. Fix that.
|
||||
* package description: Mention that the package starts the OP by default and
|
||||
that OR can be enabled in the config.
|
||||
* tor moved to sbin, updating init script.
|
||||
|
||||
-- Peter Palfrader <weasel@debian.org> Wed, 18 Feb 2004 10:08:12 +0100
|
||||
|
||||
tor (0.0.1+0.0.2pre20-2) unstable; urgency=low
|
||||
|
||||
* Add torify script, documentation, and config file. Means we also
|
||||
depend on tsocks now rather than just recommending it. Right now
|
||||
we install it in debian/rules, but upcoming versions might install
|
||||
it in upstream's make install target.
|
||||
* There's an upstream ChangeLog file now. Enjoy!
|
||||
* Add a README.privoxy file that explains how to setup privoxy to
|
||||
go over tor.
|
||||
* As is the case too often, the INSTALL file not only covers
|
||||
installation, but also basic usage and configuration. Therefore
|
||||
include it in the docs dir.
|
||||
* Add a lintian override for the INSTALL file.
|
||||
|
||||
-- Peter Palfrader <weasel@debian.org> Tue, 17 Feb 2004 02:32:00 +0100
|
||||
|
||||
tor (0.0.1+0.0.2pre20-1) unstable; urgency=low
|
||||
|
||||
* New upstream version.
|
||||
- various design paper updates
|
||||
- resolve cygwin warnings
|
||||
- split the token bucket into "rate" and "burst" params
|
||||
- try to resolve discrepency between bytes transmitted over TLS and actual
|
||||
bandwidth use
|
||||
- setuid to user _before_ complaining about running as root
|
||||
- fix several memleaks and double frees
|
||||
- minor logging fixes
|
||||
- add more debugging for logs.
|
||||
- various documentation fixes and improvements
|
||||
- for perforcmance testing, paths are always 3 hops, not "3 or more"
|
||||
(this will go away at a later date again)
|
||||
* Add dependency on adduser which was previously missing.
|
||||
* Change short description to a nicer one.
|
||||
|
||||
-- Peter Palfrader <weasel@debian.org> Sat, 31 Jan 2004 10:10:45 +0100
|
||||
|
||||
tor (0.0.1+0.0.2pre19-1) unstable; urgency=low
|
||||
|
||||
* Initial Release (closes: #216611).
|
||||
|
||||
-- Peter Palfrader <weasel@debian.org> Sat, 10 Jan 2004 11:20:06 +0100
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
4
|
||||
@@ -0,0 +1,48 @@
|
||||
Source: tor
|
||||
Section: comm
|
||||
Priority: optional
|
||||
Maintainer: Peter Palfrader <weasel@debian.org>
|
||||
Build-Depends: debhelper (>= 4.1.65), libssl-dev, dpatch
|
||||
Standards-Version: 3.6.1
|
||||
|
||||
Package: tor
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, adduser, tsocks
|
||||
Recommends: privoxy
|
||||
Suggests: mixmaster, mixminion, anon-proxy
|
||||
Description: anonymizing overlay network for TCP
|
||||
Tor is a connection-based low-latency anonymous communication system which
|
||||
addresses many flaws in the original onion routing design.
|
||||
.
|
||||
In brief, Onion Routing is a connection-oriented anonymizing communication
|
||||
service. Users choose a source-routed path through a set of nodes, and
|
||||
negotiate a "virtual circuit" through the network, in which each node
|
||||
knows its predecessor and successor, but no others. Traffic flowing down
|
||||
the circuit is unwrapped by a symmetric key at each node, which reveals
|
||||
the downstream node.
|
||||
.
|
||||
Basically Tor provides a distributed network of servers ("onion
|
||||
routers"). Users bounce their tcp streams (web traffic, ftp, ssh, etc)
|
||||
around the routers, and recipients, observers, and even the routers
|
||||
themselves have difficulty tracking the source of the stream.
|
||||
.
|
||||
Note that Tor does no protocol cleaning. That means there is a danger that
|
||||
application protocols and associated programs can be induced to reveal
|
||||
information about the initiator. Tor depends on Privoxy and similar protocol
|
||||
cleaners to solve this problem.
|
||||
.
|
||||
Client applications can use the Tor network by connecting to the local
|
||||
onion proxy. If the application itself does not come with socks support
|
||||
you can use a socks client such as tsocks. Some web browsers like mozilla
|
||||
and web proxies like privoxy come with socks support, so you don't need an
|
||||
extra socks client if you want to use Tor with them.
|
||||
.
|
||||
This package enables only the onion proxy by default, but it can be configured
|
||||
as a relay (server) node.
|
||||
.
|
||||
Remember that this is alpha code, and the network is very small -- Tor will
|
||||
not provide anonymity currently.
|
||||
.
|
||||
The latest information can be found at http://freehaven.net/tor/, or on the
|
||||
mailing lists, archived at http://archives.seul.org/or/dev/ or
|
||||
http://archives.seul.org/or/announce/.
|
||||
@@ -0,0 +1,100 @@
|
||||
This package was debianized by Peter Palfrader <weasel@debian.org> on
|
||||
Sat, 10 Jan 2004 11:20:06 +0100.
|
||||
|
||||
It was downloaded from http://freehaven.net/tor/
|
||||
|
||||
Upstream Authors: Roger Dingledine <arma@freehaven.net>
|
||||
Nick Mathewson <nickm@freehaven.net>
|
||||
Matej Pfajfar <badbytes@freehaven.net>
|
||||
|
||||
|
||||
Copyright (c) 2001-2004, Roger Dingledine
|
||||
strlcat, strlcpy: Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
tree.h: Copyright (c) 2002 Niels Provos <provos@citi.umich.edu>
|
||||
Modifications for Debian: Copyright (c) 2004 Peter Palfrader <weasel@debian.org>
|
||||
|
||||
The tor code is under this license:
|
||||
===============================================================================
|
||||
Copyright (c) 2001-2004, Roger Dingledine
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
* Neither the names of the copyright owners nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
===============================================================================
|
||||
tree.h by Niels Provos is licensed as follows:
|
||||
|
||||
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
===============================================================================
|
||||
strlcat and strlcpy by Todd C. Miller are licensed under the following license:
|
||||
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,2 @@
|
||||
01_uncomment_datadirectory.dpatch
|
||||
02_add_debian_files_in_manpage.dpatch
|
||||
@@ -0,0 +1,37 @@
|
||||
#! /bin/sh -e
|
||||
## 01_uncomment_datadirectory.dpatch by <weasel@debian.org>
|
||||
##
|
||||
## All lines beginning with `## DP:' are a description of the patch.
|
||||
## DP: No description.
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts
|
||||
patch_opts="${patch_opts:--f --no-backup-if-mismatch} ${2:+-d $2}"
|
||||
|
||||
case "$1" in
|
||||
-patch) patch -p1 ${patch_opts} < $0;;
|
||||
-unpatch) patch -R -p1 ${patch_opts} < $0;;
|
||||
*)
|
||||
echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
@DPATCH@
|
||||
diff -urNad /home/weasel/projects/tor/cvs/src/config/torrc.sample.in cvs/src/config/torrc.sample.in
|
||||
--- /home/weasel/projects/tor/cvs/src/config/torrc.sample.in 2004-03-01 23:41:26.000000000 +0100
|
||||
+++ cvs/src/config/torrc.sample.in 2004-03-03 13:47:25.000000000 +0100
|
||||
@@ -11,7 +11,7 @@
|
||||
##################### Below is just for servers #####################
|
||||
|
||||
## The directory for keeping all the keys/etc for this server
|
||||
-#DataDirectory @LOCALSTATEDIR@/lib/tor
|
||||
+DataDirectory @LOCALSTATEDIR@/lib/tor
|
||||
|
||||
#Nickname moria # A unique handle for this server
|
||||
#Address moria.seul.org # The fqdn for this server
|
||||
@@ -0,0 +1,41 @@
|
||||
#! /bin/sh -e
|
||||
## 02_add_debian_files_in_manpage.dpatch by <weasel@debian.org>
|
||||
##
|
||||
## All lines beginning with `## DP:' are a description of the patch.
|
||||
## DP: No description.
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts
|
||||
patch_opts="${patch_opts:--f --no-backup-if-mismatch} ${2:+-d $2}"
|
||||
|
||||
case "$1" in
|
||||
-patch) patch -p1 ${patch_opts} < $0;;
|
||||
-unpatch) patch -R -p1 ${patch_opts} < $0;;
|
||||
*)
|
||||
echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
@DPATCH@
|
||||
diff -urNad /home/weasel/projects/tor/cvs/doc/tor.1.in cvs/doc/tor.1.in
|
||||
--- /home/weasel/projects/tor/cvs/doc/tor.1.in 2004-03-01 23:41:25.000000000 +0100
|
||||
+++ cvs/doc/tor.1.in 2004-03-10 16:30:49.000000000 +0100
|
||||
@@ -137,6 +137,12 @@
|
||||
.TP
|
||||
.I @LOCALSTATEDIR@/lib/tor/
|
||||
The tor server stores keys/etc here.
|
||||
+.TP
|
||||
+.I /var/log/tor/log
|
||||
+The tor server logs to this file.
|
||||
+.TP
|
||||
+.I /var/run/tor/tor.pid
|
||||
+The PID of the tor (master) process is stored in this file.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR privoxy (1),
|
||||
Executable
+110
@@ -0,0 +1,110 @@
|
||||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
# Sample debian/rules that uses debhelper.
|
||||
# GNU copyright 1997 to 1999 by Joey Hess.
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
# These are used for cross-compiling and for saving the configure script
|
||||
# from having to guess our platform (since we know it already)
|
||||
DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
|
||||
DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
|
||||
|
||||
CFLAGS = -Wall -g
|
||||
|
||||
export PACKAGE=tor
|
||||
include /usr/share/dpatch/dpatch.make
|
||||
|
||||
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
|
||||
CFLAGS += -O0
|
||||
else
|
||||
CFLAGS += -O2
|
||||
endif
|
||||
#ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
# INSTALL_PROGRAM += -s
|
||||
#endif
|
||||
|
||||
configure: patch-stamp
|
||||
config.status: configure
|
||||
dh_testdir
|
||||
CFLAGS="$(CFLAGS)" ./configure \
|
||||
--host=$(DEB_HOST_GNU_TYPE) \
|
||||
--build=$(DEB_BUILD_GNU_TYPE) \
|
||||
--prefix=/usr \
|
||||
--mandir=\$${prefix}/share/man \
|
||||
--infodir=\$${prefix}/share/info \
|
||||
--localstatedir=/var \
|
||||
--sysconfdir=/etc
|
||||
|
||||
|
||||
build: build-stamp
|
||||
|
||||
build-stamp: config.status
|
||||
dh_testdir
|
||||
|
||||
$(MAKE)
|
||||
@echo
|
||||
@echo
|
||||
src/or/test
|
||||
@echo
|
||||
|
||||
touch build-stamp
|
||||
|
||||
clean: unpatch
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
rm -f build-stamp
|
||||
|
||||
-$(MAKE) distclean
|
||||
|
||||
dh_clean
|
||||
|
||||
install: build
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_clean -k
|
||||
dh_installdirs
|
||||
|
||||
$(MAKE) install DESTDIR=$(CURDIR)/debian/tor
|
||||
# move tor to where it belongs
|
||||
mv $(CURDIR)/debian/tor/etc/tor/torrc.sample $(CURDIR)/debian/tor/etc/tor/torrc
|
||||
mv $(CURDIR)/debian/tor/usr/bin/tor $(CURDIR)/debian/tor/usr/sbin/tor
|
||||
install -m 755 contrib/torify $(CURDIR)/debian/tor/usr/bin
|
||||
install -m 644 contrib/torify.1 $(CURDIR)/debian/tor/usr/share/man/man1
|
||||
install -m 644 contrib/tor-tsocks.conf $(CURDIR)/debian/tor/etc/tor
|
||||
|
||||
install -m 644 debian/tor.lintian-override $(CURDIR)/debian/tor/usr/share/lintian/overrides/tor
|
||||
|
||||
|
||||
# Build architecture-independent files here.
|
||||
binary-indep: build install
|
||||
# We have nothing to do by default.
|
||||
|
||||
# Build architecture-dependent files here.
|
||||
binary-arch: build install
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_installchangelogs ChangeLog
|
||||
dh_installdocs
|
||||
dh_installexamples
|
||||
# dh_install
|
||||
# dh_installdebconf
|
||||
dh_installlogrotate
|
||||
# dh_installemacsen
|
||||
# dh_installmime
|
||||
dh_installinit
|
||||
# dh_installcron
|
||||
dh_installman
|
||||
dh_link
|
||||
#dh_strip
|
||||
dh_compress
|
||||
dh_fixperms
|
||||
dh_installdeb
|
||||
dh_shlibdeps
|
||||
dh_gencontrol
|
||||
dh_md5sums
|
||||
dh_builddeb
|
||||
|
||||
binary: binary-indep binary-arch
|
||||
.PHONY: build clean binary-indep binary-arch binary install
|
||||
@@ -0,0 +1,13 @@
|
||||
# Defaults for tor initscript
|
||||
# sourced by /etc/init.d/tor
|
||||
# installed at /etc/default/tor by the maintainer scripts
|
||||
|
||||
#
|
||||
# This is a POSIX shell fragment
|
||||
#
|
||||
RUN_DAEMON="yes"
|
||||
|
||||
#
|
||||
# Uncomment this if you want to get coredumps
|
||||
#
|
||||
# ulimit -c unlimited
|
||||
@@ -0,0 +1,7 @@
|
||||
etc/tor
|
||||
var/lib/tor
|
||||
var/log/tor
|
||||
var/run/tor
|
||||
usr/share/lintian/overrides
|
||||
usr/bin
|
||||
usr/sbin
|
||||
@@ -0,0 +1,3 @@
|
||||
README
|
||||
INSTALL
|
||||
debian/README.privoxy
|
||||
@@ -0,0 +1,104 @@
|
||||
#! /bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
DAEMON=/usr/sbin/tor
|
||||
NAME=tor
|
||||
DESC="tor daemon"
|
||||
TORLOG=/var/log/tor/log
|
||||
TORPID=/var/run/tor/tor.pid
|
||||
DEFAULTSFILE=/etc/default/$NAME
|
||||
WAITFORDAEMON=10
|
||||
ARGS="--pidfile $TORPID --logfile $TORLOG --runasdaemon 1"
|
||||
|
||||
test -x $DAEMON || exit 0
|
||||
|
||||
# Include tor defaults if available
|
||||
if [ -f $DEFAULTSFILE ] ; then
|
||||
. $DEFAULTSFILE
|
||||
fi
|
||||
|
||||
wait_for_deaddaemon () {
|
||||
pid=$1
|
||||
sleep 1
|
||||
if test -n "$pid"
|
||||
then
|
||||
if kill -0 $pid 2>/dev/null
|
||||
then
|
||||
echo -n "."
|
||||
cnt=0
|
||||
while kill -0 $pid 2>/dev/null
|
||||
do
|
||||
cnt=`expr $cnt + 1`
|
||||
if [ $cnt -gt $WAITFORDAEMON ]
|
||||
then
|
||||
echo " FAILED."
|
||||
return 1
|
||||
fi
|
||||
sleep 1
|
||||
echo -n "."
|
||||
done
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
if [ "$RUN_DAEMON" != "yes" ]; then
|
||||
echo "Not starting $DESC (Disabled in $DEFAULTSFILE)."
|
||||
else
|
||||
echo -n "Starting $DESC: "
|
||||
start-stop-daemon --start --quiet --oknodo \
|
||||
--chuid debian-tor:debian-tor \
|
||||
--pidfile $TORPID \
|
||||
--exec $DAEMON -- $ARGS
|
||||
echo "$NAME."
|
||||
fi
|
||||
;;
|
||||
stop)
|
||||
echo -n "Stopping $DESC: "
|
||||
pid=`cat $TORPID 2>/dev/null` || true
|
||||
if test ! -f $TORPID -o -z "$pid"
|
||||
then
|
||||
echo "not running (there is no $TORPID)."
|
||||
elif start-stop-daemon --stop --quiet --pidfile $TORPID --exec $DAEMON
|
||||
then
|
||||
wait_for_deaddaemon $pid
|
||||
echo "$NAME."
|
||||
elif kill -0 $pid 2>/dev/null
|
||||
then
|
||||
echo "FAILED (Is $pid not $NAME? Is $DAEMON a different binary now?)."
|
||||
else
|
||||
echo "FAILED ($DAEMON died: process $pid not running)."
|
||||
fi
|
||||
;;
|
||||
reload|force-reload)
|
||||
echo -n "Reloading $DESC configuration: "
|
||||
pid=`cat $TORPID 2>/dev/null` || true
|
||||
if test ! -f $TORPID -o -z "$pid"
|
||||
then
|
||||
echo "not running (there is no $TORPID)."
|
||||
elif start-stop-daemon --stop --signal 1 --quiet --pidfile $TORPID --exec $DAEMON
|
||||
then
|
||||
echo "$NAME."
|
||||
elif kill -0 $pid 2>/dev/null
|
||||
then
|
||||
echo "FAILED (Is $pid not $NAME? Is $DAEMON a different binary now?)."
|
||||
else
|
||||
echo "FAILED ($DAEMON died: process $pid not running)."
|
||||
fi
|
||||
;;
|
||||
restart)
|
||||
$0 stop
|
||||
sleep 1
|
||||
$0 start
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|reload|force-reload}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1 @@
|
||||
tor: package-contains-upstream-install-documentation
|
||||
@@ -0,0 +1,11 @@
|
||||
/var/log/tor/log {
|
||||
daily
|
||||
rotate 5
|
||||
compress
|
||||
delaycompress
|
||||
missingok
|
||||
notifempty
|
||||
postrotate
|
||||
/etc/init.d/tor reload > /dev/null
|
||||
endscript
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
# checking debian-tor account
|
||||
|
||||
uid=`getent passwd debian-tor | cut -d ":" -f 3`
|
||||
home=`getent passwd debian-tor | cut -d ":" -f 6`
|
||||
|
||||
# if there is the uid the account is there and we can do
|
||||
# the sanit(ar)y checks otherwise we can safely create it.
|
||||
|
||||
if [ "$uid" ]; then
|
||||
# guess??? the checks!!!
|
||||
if [ $uid -ge 100 ] && [ $uid -le 999 ]; then
|
||||
echo "debian-tor uid check: ok"
|
||||
else
|
||||
echo "ERROR: debian-tor account has a non-system uid!"
|
||||
echo "Please check /usr/share/doc/tor/README.Debian on how to"
|
||||
echo "correct this problem"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$home" = "/var/lib/tor" ]; then
|
||||
echo "debian-tor homedir check: ok"
|
||||
else
|
||||
echo "ERROR: debian-tor account has an invalid home directory!"
|
||||
echo "Please check /usr/share/doc/tor/README.Debian on how to"
|
||||
echo "correct this problem"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# what this might mean?? oh creating a system l^Huser!
|
||||
adduser --quiet \
|
||||
--system \
|
||||
--disabled-password \
|
||||
--home /var/lib/tor \
|
||||
--no-create-home \
|
||||
--shell /bin/bash \
|
||||
--group \
|
||||
debian-tor
|
||||
fi
|
||||
|
||||
# ch{owning,moding} things around
|
||||
# We will do nothing across upgrades.
|
||||
|
||||
if [ "$2" = "" ]; then
|
||||
for i in lib log run; do
|
||||
chown -R debian-tor:debian-tor /var/$i/tor
|
||||
chmod -R 700 /var/$i/tor
|
||||
find /var/$i/tor -type f -exec chmod 600 '{}' ';'
|
||||
done
|
||||
fi
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
if [ "$1" = "purge" ]; then
|
||||
# logs have to be removed according to policy.
|
||||
rm -rf /var/log/tor/
|
||||
rm -rf /var/lib/tor/
|
||||
fi
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,8 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
tor.1
|
||||
*.aux
|
||||
*.dvi
|
||||
*.blg
|
||||
*.bbl
|
||||
*.log
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
Part one: Overview and explanation
|
||||
|
||||
Because tor is an application-level proxy, it needs client-side support
|
||||
from every client program that wants to use it. (This is different from
|
||||
systems like Freedom, which used a single client-side program to capture
|
||||
all packets and redirect them to the Freedom network.) Client applications
|
||||
need two general classes of modifications to be compatible with tor:
|
||||
|
||||
1) Whenever they call connect(), they instead should connect() to the
|
||||
local onion proxy and tell it "address and port". The onion proxy will
|
||||
itself make a connection to "address and port", and then the client
|
||||
application can talk through that socket as if it's directly connected. To
|
||||
support as many applications as possible, tor uses the common "socks"
|
||||
protocol which does exactly the above. So applications with socks support
|
||||
will support tor without needing any modifications.
|
||||
|
||||
2) Applications must not call gethostbyname() to resolve an address
|
||||
they intend to later connect() to via onion routing. gethostbyname()
|
||||
contacts the dns server of the target machine -- thus giving away the
|
||||
fact that you intend to make an anonymous connection to it.
|
||||
|
||||
To clarify, I need to explain more about the socks protocol. Socks
|
||||
comes in three flavors: 4, 4a, and 5. The socks4 protocol basically
|
||||
uses IP and port -- so it is unsuitable because of the gethostbyname()
|
||||
issue above. Socks4a is a slight modification to the socks4 protocol,
|
||||
whereby you can specify an IP of 0.0.0.x to signal the socks server
|
||||
that you will instead be sending a hostname (fqdn). So applications with
|
||||
socks4a support are all set. Socks5, on the other hand, allows the client
|
||||
to specify "address type" and then an address -- so some applications
|
||||
choose to supply an IP and others choose to supply a hostname. If the
|
||||
application uses socks5 you must investigate further to decide whether
|
||||
it's leaking anonymity.
|
||||
|
||||
|
||||
Part two: using tsocks to transparently replace library calls
|
||||
|
||||
tsocks (available from http://tsocks.sourceforge.net/ or from your
|
||||
favorite apt-get equivalent) allows you to run a program as normal,
|
||||
but it replaces the system calls for connect() to connect to the socks
|
||||
server first and then pass it your destination info. In our case the
|
||||
socks server is a tor process (running either locally or elsewhere).
|
||||
In general this works quite well for command-line processes like finger,
|
||||
ssh, etc. But there are a couple of catches: A) tsocks doesn't intercept
|
||||
calls to gethostbyname. So unless you specify an IP rather than hostname,
|
||||
you'll be giving yourself away. B) Programs which are suid don't let you
|
||||
intercept the system calls -- ssh falls into this category. But you can
|
||||
make a local copy of ssh and use that. C) Probably tsocks doesn't behave
|
||||
well for behemoths like Mozilla.
|
||||
|
||||
|
||||
Part three: applications which support tor correctly
|
||||
|
||||
http: Mozilla: set your socks4 proxy to be the onion proxy (but see above)
|
||||
privoxy: set your socks4a proxy to be the onion proxy
|
||||
wget: run privoxy, and then add the line
|
||||
"http_proxy=http://localhost:8118" to your ~/.wgetrc.
|
||||
ssh: tsocks ssh arma@18.244.0.188
|
||||
ftp: tsocks wget ftp://18.244.0.188/quux.tar --passive
|
||||
Mozilla: set your socks4 proxy to be the onion proxy
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
The Onion Routing (TOR) Frequently Asked Questions
|
||||
--------------------------------------------------
|
||||
|
||||
1. General.
|
||||
|
||||
1.1. What is Tor?
|
||||
|
||||
Tor is an implementation of version 2 of Onion Routing.
|
||||
Go read the tor-design.pdf for the details.
|
||||
|
||||
In brief, Onion Routing is a connection-oriented anonymizing communication
|
||||
service. Users choose a source-routed path through a set of nodes, and
|
||||
negotiate a "virtual circuit" through the network, in which each node
|
||||
knows its predecessor and successor, but no others. Traffic flowing down
|
||||
the circuit is unwrapped by a symmetric key at each node, which reveals
|
||||
the downstream node.
|
||||
|
||||
Basically Tor provides a distributed network of servers ("onion
|
||||
routers"). Users bounce their tcp streams (web traffic, ftp, ssh, etc)
|
||||
around the routers, and recipients, observers, and even the routers
|
||||
themselves have difficulty tracking the source of the stream.
|
||||
|
||||
1.2. Why's it called Tor?
|
||||
|
||||
Because Tor is the onion routing system. I kept telling people I was
|
||||
working on onion routing, and they said "Neat. Which one?" Even if onion
|
||||
routing has become a standard household term, this is the actual onion
|
||||
routing project, started out of the Naval Research Lab.
|
||||
|
||||
(Theories about recursive acronyms are ok too. It's also got a fine
|
||||
translation into German.)
|
||||
|
||||
1.3 Is there a backdoor in Tor?
|
||||
|
||||
Not right now, but if this answer changes we probably won't be allowed
|
||||
to tell you. You should always check the source (or at least the diffs
|
||||
since the last release) for suspicious things; and if we don't give you
|
||||
source, that's a sure sign something funny could be going on.
|
||||
|
||||
2. Compiling and installing.
|
||||
|
||||
[Read the README file for now; check back here once we've got packages/etc
|
||||
for you.]
|
||||
|
||||
|
||||
3. Running Tor.
|
||||
|
||||
3.1. What kind of server should I run?
|
||||
|
||||
The same executable functions as both client and server, depending on
|
||||
which ports are specified in the configuration file. You can specify:
|
||||
* SocksPort: client applications (eg privoxy, Mozilla) can speak socks to
|
||||
this port.
|
||||
* ORPort: other onion routers connect to this port
|
||||
* DirPort: onion proxies and onion routers speak http to this port, to
|
||||
pull down a directory of which nodes are currently available.
|
||||
|
||||
3.2. So I can just run a full onion router and join the network?
|
||||
|
||||
No. Users should run just an onion proxy. If you start up a full onion
|
||||
router, the rest of the routers in the system won't recognize you,
|
||||
so they will reject your handshake attempts.
|
||||
|
||||
3.3. How do I join the network then?
|
||||
|
||||
If you just want to use the onion routing network, you can run a proxy
|
||||
and you're all set. If you want to run a router, you must convince
|
||||
the directory server operators (currently arma@mit.edu) that you're a
|
||||
trustworthy and reliable person. From there, the operators add you to
|
||||
the directory, which propagates out to the rest of the network. All
|
||||
nodes will know about you within a half hour.
|
||||
|
||||
3.4. I want to run a directory server too.
|
||||
|
||||
If you run a very reliable node, you plan to be around for a long time,
|
||||
and you want to spend some time ensuring that router operators are
|
||||
people we know and like, we may want you to run a directory server
|
||||
too. We must manually add you to the 'dirservers' file that's part of
|
||||
the distribution; users will only know about you when they upgrade to
|
||||
a new version. Of course, you can always just start up your router as a
|
||||
directory server too --- but users won't know to ask you for directories,
|
||||
and more importantly, you'll never learn from the real directory servers
|
||||
about recently joined routers.
|
||||
|
||||
|
||||
4. Development.
|
||||
|
||||
4.1. Who's doing this?
|
||||
|
||||
4.2. Can I help?
|
||||
|
||||
4.3. I've got a bug.
|
||||
|
||||
|
||||
5. Anonymity.
|
||||
|
||||
5.1. So I'm totally anonymous if I use Tor?
|
||||
|
||||
|
||||
|
||||
5.2. Where can I learn more about anonymity?
|
||||
|
||||
5.3. What attacks remain against onion routing?
|
||||
|
||||
|
||||
|
||||
6. Comparison to related projects.
|
||||
|
||||
6.1. Onion Routing.
|
||||
|
||||
Tor *is* onion routing.
|
||||
|
||||
6.2. Freedom.
|
||||
|
||||
|
||||
7. Protocol and application support.
|
||||
|
||||
7.1. http? ftp? udp? socks? mozilla?
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,534 @@
|
||||
Guide to Hacking Tor
|
||||
|
||||
(As of 8 October 2003, this was all accurate. If you're reading this in
|
||||
the distant future, stuff may have changed.)
|
||||
|
||||
0. Intro and required reading
|
||||
|
||||
Onion Routing is still very much in development stages. This document
|
||||
aims to get you started in the right direction if you want to understand
|
||||
the code, add features, fix bugs, etc.
|
||||
|
||||
Read the README file first, so you can get familiar with the basics of
|
||||
installing and running an onion router.
|
||||
|
||||
Then, skim some of the introductory materials in tor-design.pdf,
|
||||
tor-spec.txt, and the Tor FAQ to learn more about how the Tor protocol
|
||||
is supposed to work. This document will assume you know about Cells,
|
||||
Circuits, Streams, Connections, Onion Routers, and Onion Proxies.
|
||||
|
||||
1. Code organization
|
||||
|
||||
1.1. The modules
|
||||
|
||||
The code is divided into two directories: ./src/common and ./src/or.
|
||||
The "common" directory contains general purpose utility functions not
|
||||
specific to onion routing. The "or" directory implements all
|
||||
onion-routing and onion-proxy specific functionality.
|
||||
|
||||
Files in ./src/common:
|
||||
|
||||
aes.[ch] -- Implements the AES cipher (with 128-bit keys and blocks),
|
||||
and a counter-mode stream cipher on top of AES. This code is
|
||||
taken from the main Rijndael distribution. (We include this
|
||||
because many people are running older versions of OpenSSL without
|
||||
AES support.)
|
||||
|
||||
crypto.[ch] -- Wrapper functions to present a consistent interface to
|
||||
public-key and symmetric cryptography operations from OpenSSL.
|
||||
|
||||
fakepoll.[ch] -- Used on systems that don't have a poll() system call;
|
||||
reimplements() poll using the select() system call.
|
||||
|
||||
log.[ch] -- Tor's logging subsystem.
|
||||
|
||||
test.h -- Macros used by unit tests.
|
||||
|
||||
torint.h -- Provides missing [u]int*_t types for environments that
|
||||
don't have stdint.h.
|
||||
|
||||
tortls.[ch] -- Wrapper functions to present a consistent interface to
|
||||
TLS, SSL, and X.509 functions from OpenSSL.
|
||||
|
||||
util.[ch] -- Miscellaneous portability and convenience functions.
|
||||
|
||||
Files in ./src/or:
|
||||
|
||||
[General-purpose modules]
|
||||
|
||||
or.h -- Common header file: include everything, define everything.
|
||||
|
||||
buffers.c -- Implements a generic buffer interface. Buffers are
|
||||
fairly opaque string holders that can read to or flush from:
|
||||
memory, file descriptors, or TLS connections.
|
||||
|
||||
Also implements parsing functions to read HTTP and SOCKS commands
|
||||
from buffers.
|
||||
|
||||
tree.h -- A splay tree implementation by Niels Provos. Used by
|
||||
dns.c for dns caching at exits, and by connection_edge.c for dns
|
||||
caching at clients.
|
||||
|
||||
config.c -- Code to parse and validate the configuration file.
|
||||
|
||||
[Background processing modules]
|
||||
|
||||
cpuworker.c -- Implements a farm of 'CPU worker' processes to perform
|
||||
CPU-intensive tasks in the background, so as not interrupt the
|
||||
onion router. (OR only)
|
||||
|
||||
dns.c -- Implements a farm of 'DNS worker' 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.] (OR only)
|
||||
|
||||
[Directory-related functionality.]
|
||||
|
||||
directory.c -- Code to send and fetch directories and router
|
||||
descriptors via HTTP. Directories use dirserv.c to generate the
|
||||
results; clients use routers.c to parse them.
|
||||
|
||||
dirserv.c -- Code to manage directory contents and generate
|
||||
directories. [Directory server only]
|
||||
|
||||
routers.c -- Code to parse directories and router descriptors; and to
|
||||
generate a router descriptor corresponding to this OR's
|
||||
capabilities. Also presents some high-level interfaces for
|
||||
managing an OR or OP's view of the directory.
|
||||
|
||||
[Circuit-related modules.]
|
||||
|
||||
circuit.c -- Code to create circuits, manage circuits, and route
|
||||
relay cells along circuits.
|
||||
|
||||
onion.c -- Code to generate and respond to "onion skins".
|
||||
|
||||
[Core protocol implementation.]
|
||||
|
||||
connection.c -- Code used in common by all connection types. See
|
||||
1.2. below for more general information about connections.
|
||||
|
||||
connection_edge.c -- Code used only by edge connections.
|
||||
|
||||
command.c -- Code to handle specific cell types.
|
||||
|
||||
connection_or.c -- Code to implement cell-speaking connections.
|
||||
|
||||
[Toplevel modules.]
|
||||
|
||||
main.c -- Toplevel module. Initializes keys, handles signals,
|
||||
multiplexes between connections, implements main loop, and drives
|
||||
scheduled events.
|
||||
|
||||
tor_main.c -- Stub module containing a main() function. Allows unit
|
||||
test binary to link against main.c
|
||||
|
||||
[Unit tests]
|
||||
|
||||
test.c -- Contains unit tests for many pieces of the lower level Tor
|
||||
modules.
|
||||
|
||||
1.2. All about connections
|
||||
|
||||
All sockets in Tor are handled as different types of nonblocking
|
||||
'connections'. (What the Tor spec calls a "Connection", the code refers
|
||||
to as a "Cell-speaking" or "OR" connection.)
|
||||
|
||||
Connections are implemented by the connection_t struct, defined in or.h.
|
||||
Not every kind of connection uses all the fields in connection_t; see
|
||||
the comments in or.h and the assertions in assert_connection_ok() for
|
||||
more information.
|
||||
|
||||
Every connection has a type and a state. Connections never change their
|
||||
type, but can go through many state changes in their lifetime.
|
||||
|
||||
The connection types break down as follows:
|
||||
|
||||
[Cell-speaking connections]
|
||||
CONN_TYPE_OR -- A bidirectional TLS connection transmitting a
|
||||
sequence of cells. May be from an OR to an OR, or from an OP to
|
||||
an OR.
|
||||
|
||||
[Edge connections]
|
||||
CONN_TYPE_EXIT -- A TCP connection from an onion router to a
|
||||
Stream's destination. [OR only]
|
||||
CONN_TYPE_AP -- A SOCKS proxy connection from the end user
|
||||
application to the onion proxy. [OP only]
|
||||
|
||||
[Listeners]
|
||||
CONN_TYPE_OR_LISTENER [OR only]
|
||||
CONN_TYPE_AP_LISTENER [OP only]
|
||||
CONN_TYPE_DIR_LISTENER [Directory server only]
|
||||
-- Bound network sockets, waiting for incoming connections.
|
||||
|
||||
[Internal]
|
||||
CONN_TYPE_DNSWORKER -- Connection from the main process to a DNS
|
||||
worker process. [OR only]
|
||||
|
||||
CONN_TYPE_CPUWORKER -- Connection from the main process to a CPU
|
||||
worker process. [OR only]
|
||||
|
||||
Connection states are documented in or.h.
|
||||
|
||||
Every connection has two associated input and output buffers.
|
||||
Listeners don't use them. For non-listener connections, incoming
|
||||
data is appended to conn->inbuf, and outgoing data is taken from the
|
||||
front of conn->outbuf. Connections differ primarily in the functions
|
||||
called to fill and drain these buffers.
|
||||
|
||||
1.3. All about circuits.
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
1.4. Asynchronous IO and the main loop.
|
||||
|
||||
Tor uses the poll(2) system call (or it wraps select(2) to act like
|
||||
poll, if poll is not available) to handle nonblocking (asynchronous)
|
||||
IO. If you're not familiar with nonblocking IO, check out the links
|
||||
at the end of this document.
|
||||
|
||||
All asynchronous logic is handled in main.c. The functions
|
||||
'connection_add', 'connection_set_poll_socket', and 'connection_remove'
|
||||
manage an array of connection_t*, and keep in synch with the array of
|
||||
struct pollfd required by poll(2). (This array of connection_t* is
|
||||
accessible via get_connection_array, but users should generally call
|
||||
one of the 'connection_get_by_*' functions in connection.c to look up
|
||||
individual connections.)
|
||||
|
||||
To trap read and write events, connections call the functions
|
||||
'connection_{is|stop|start}_{reading|writing}'. If you want
|
||||
to completely reset the events you're watching for, use
|
||||
'connection_watch_events'.
|
||||
|
||||
Every time poll() finishes, main.c calls conn_read and conn_write on
|
||||
every connection. These functions dispatch events that have something
|
||||
to read to connection_handle_read, and events that have something to
|
||||
write to connection_handle_write, respectively.
|
||||
|
||||
When connections need to be closed, they can respond in two ways. Most
|
||||
simply, they can make connection_handle_* return an error (-1),
|
||||
which will make conn_{read|write} close them. But if it's not
|
||||
convenient to return -1 (for example, processing one connection causes
|
||||
you to realize that a second one should close), then you can also
|
||||
mark a connection to close by setting conn->marked_for_close. Marked
|
||||
connections will be closed at the end of the current iteration of
|
||||
the main loop.
|
||||
|
||||
The main loop handles several other operations: First, it checks
|
||||
whether any signals have been received that require a response (HUP,
|
||||
KILL, USR1, CHLD). Second, it calls prepare_for_poll to handle recurring
|
||||
tasks and compute the necessary poll timeout. These recurring tasks
|
||||
include periodically fetching the directory, timing out unused
|
||||
circuits, incrementing flow control windows and re-enabling connections
|
||||
that were blocking for more bandwidth, and maintaining statistics.
|
||||
|
||||
A word about TLS: Using TLS on OR connections complicates matters in
|
||||
two ways.
|
||||
First, a TLS stream has its own read buffer independent of the
|
||||
connection's read buffer. (TLS needs to read an entire frame from
|
||||
the network before it can decrypt any data. Thus, trying to read 1
|
||||
byte from TLS can require that several KB be read from the network
|
||||
and decrypted. The extra data is stored in TLS's decrypt buffer.)
|
||||
Because the data hasn't been read by tor (it's still inside the TLS),
|
||||
this means that sometimes a connection "has stuff to read" even when
|
||||
poll() didn't return POLLIN. The tor_tls_get_pending_bytes function is
|
||||
used in main.c to detect TLS objects with non-empty internal buffers.
|
||||
Second, the TLS stream's events do not correspond directly to network
|
||||
events: sometimes, before a TLS stream can read, the network must be
|
||||
ready to write -- or vice versa.
|
||||
|
||||
1.5. How data flows (An illustration.)
|
||||
|
||||
Suppose an OR receives 256 bytes along an OR connection. These 256
|
||||
bytes turn out to be a data relay cell, which gets decrypted and
|
||||
delivered to an edge connection. Here we give a possible call sequence
|
||||
for the delivery of this data.
|
||||
|
||||
(This may be outdated quickly.)
|
||||
|
||||
do_main_loop -- Calls poll(2), receives a POLLIN event on a struct
|
||||
pollfd, then calls:
|
||||
conn_read -- Looks up the corresponding connection_t, and calls:
|
||||
connection_handle_read -- Calls:
|
||||
connection_read_to_buf -- Notices that it has an OR connection so:
|
||||
read_to_buf_tls -- Pulls data from the TLS stream onto conn->inbuf.
|
||||
connection_process_inbuf -- Notices that it has an OR connection so:
|
||||
connection_or_process_inbuf -- Checks whether conn is open, and calls:
|
||||
connection_process_cell_from_inbuf -- Notices it has enough data for
|
||||
a cell, then calls:
|
||||
connection_fetch_from_buf -- Pulls the cell from the buffer.
|
||||
cell_unpack -- Decodes the raw cell into a cell_t
|
||||
command_process_cell -- Notices it is a relay cell, so calls:
|
||||
command_process_relay_cell -- Looks up the circuit for the cell,
|
||||
makes sure the circuit is live, then passes the cell to:
|
||||
circuit_deliver_relay_cell -- Passes the cell to each of:
|
||||
relay_crypt -- Strips a layer of encryption from the cell and
|
||||
notices that the cell is for local delivery.
|
||||
connection_edge_process_relay_cell -- extracts the cell's
|
||||
relay command, and makes sure the edge connection is
|
||||
open. Since it has a DATA cell and an open connection,
|
||||
calls:
|
||||
circuit_consider_sending_sendme -- check if the total number
|
||||
of cells received by all streams on this circuit is
|
||||
enough that we should send back an acknowledgement
|
||||
(requesting that more cells be sent to any stream).
|
||||
connection_write_to_buf -- To place the data on the outgoing
|
||||
buffer of the correct edge connection, by calling:
|
||||
connection_start_writing -- To tell the main poll loop about
|
||||
the pending data.
|
||||
write_to_buf -- To actually place the outgoing data on the
|
||||
edge connection.
|
||||
connection_consider_sending_sendme -- if the outbuf waiting
|
||||
to flush to the exit connection is not too full, check
|
||||
if the total number of cells received on this stream
|
||||
is enough that we should send back an acknowledgement
|
||||
(requesting that more cells be sent to this stream).
|
||||
|
||||
In a subsequent iteration, main notices that the edge connection is
|
||||
ready for writing:
|
||||
|
||||
do_main_loop -- Calls poll(2), receives a POLLOUT event on a struct
|
||||
pollfd, then calls:
|
||||
conn_write -- Looks up the corresponding connection_t, and calls:
|
||||
connection_handle_write -- This isn't a TLS connection, so calls:
|
||||
flush_buf -- Delivers data from the edge connection's outbuf to the
|
||||
network.
|
||||
connection_wants_to_flush -- Reports that all data has been flushed.
|
||||
connection_finished_flushing -- Notices the connection is an exit,
|
||||
and calls:
|
||||
connection_edge_finished_flushing -- The connection is open, so it
|
||||
calls:
|
||||
connection_stop_writing -- Tells the main poll loop that this
|
||||
connection has no more data to write.
|
||||
connection_consider_sending_sendme -- now that the outbuf
|
||||
is empty, check again if the total number of cells
|
||||
received on this stream is enough that we should send
|
||||
back an acknowledgement (requesting that more cells be
|
||||
sent to this stream).
|
||||
|
||||
|
||||
1.6. Routers, descriptors, and directories
|
||||
|
||||
All Tor processes need to keep track of a list of onion routers, for
|
||||
several reasons:
|
||||
- OPs need to establish connections and circuits to ORs.
|
||||
- ORs need to establish connections to other ORs.
|
||||
- OPs and ORs need to fetch directories from a directory server.
|
||||
- ORs need to upload their descriptors to directory servers.
|
||||
- Directory servers need to know which ORs are allowed onto the
|
||||
network, what the descriptors are for those ORs, and which of
|
||||
those ORs are currently live.
|
||||
|
||||
Thus, every Tor process keeps track of a list of all the ORs it knows
|
||||
in a static variable 'directory' in the routers.c module. This
|
||||
variable contains a routerinfo_t object for each known OR. On startup,
|
||||
the directory is initialized to a list of known directory servers (via
|
||||
router_get_list_from_file()). Later, the directory is updated via
|
||||
router_get_dir_from_string(). (OPs and ORs retrieve fresh directories
|
||||
from directory servers; directory servers generate their own.)
|
||||
|
||||
Every OR must periodically regenerate a router descriptor for itself.
|
||||
The descriptor and the corresponding routerinfo_t are stored in the
|
||||
'desc_routerinfo' and 'descriptor' static variables in routers.c.
|
||||
|
||||
Additionally, a directory server keeps track of a list of the
|
||||
router descriptors it knows in a separate list in dirserv.c. It
|
||||
uses this list, checking which OR connections are open, to build
|
||||
directories.
|
||||
|
||||
1.7. Data model
|
||||
|
||||
[XXX]
|
||||
|
||||
1.8. Flow control
|
||||
|
||||
[XXX]
|
||||
|
||||
2. Coding conventions
|
||||
|
||||
2.1. Details
|
||||
|
||||
Use tor_malloc, tor_strdup, and tor_gettimeofday instead of their
|
||||
generic equivalents. (They always succeed or exit.)
|
||||
|
||||
Use INLINE instead of 'inline', so that we work properly on windows.
|
||||
|
||||
2.2. Calling and naming conventions
|
||||
|
||||
Whenever possible, functions should return -1 on error and and 0 on
|
||||
success.
|
||||
|
||||
For multi-word identifiers, use lowercase words combined with
|
||||
underscores. (e.g., "multi_word_identifier"). Use ALL_CAPS for macros and
|
||||
constants.
|
||||
|
||||
Typenames should end with "_t".
|
||||
|
||||
Function names should be prefixed with a module name or object name. (In
|
||||
general, code to manipulate an object should be a module with the same
|
||||
name as the object, so it's hard to tell which convention is used.)
|
||||
|
||||
Functions that do things should have imperative-verb names
|
||||
(e.g. buffer_clear, buffer_resize); functions that return booleans should
|
||||
have predicate names (e.g. buffer_is_empty, buffer_needs_resizing).
|
||||
|
||||
2.3. What To Optimize
|
||||
|
||||
Don't optimize anything if it's not in the critical path. Right now,
|
||||
the critical path seems to be AES, logging, and the network itself.
|
||||
Feel free to do your own profiling to determine otherwise.
|
||||
|
||||
2.4. Log conventions
|
||||
|
||||
Log convention: use only these four log severities.
|
||||
|
||||
ERR is if something fatal just happened.
|
||||
WARN if something bad happened, but we're still running. The
|
||||
bad thing is either a bug in the code, an attack or buggy
|
||||
protocol/implementation of the remote peer, etc. The operator should
|
||||
examine the bad thing and try to correct it.
|
||||
NOTICE if it's something the operator will want to know about.
|
||||
(No error or warning messages should be expected during normal OR or OP
|
||||
operation. I expect most people to run on -l notice eventually. If a
|
||||
library function is currently called such that failure always means
|
||||
ERR, then the library function should log WARN and let the caller
|
||||
log ERR.)
|
||||
INFO means something happened (maybe bad, maybe ok), but there's nothing
|
||||
you need to (or can) do about it.
|
||||
DEBUG is for everything louder than INFO.
|
||||
|
||||
[XXX Proposed convention: every messages of severity INFO or higher should
|
||||
either (A) be intelligible to end-users who don't know the Tor source; or
|
||||
(B) somehow inform the end-users that they aren't expected to understand
|
||||
the message (perhaps with a string like "internal error"). Option (A) is
|
||||
to be preferred to option (B). -NM]
|
||||
|
||||
3. References
|
||||
|
||||
About Tor
|
||||
|
||||
See http://freehaven.net/tor/
|
||||
http://freehaven.net/tor/cvs/doc/tor-spec.txt
|
||||
http://freehaven.net/tor/cvs/doc/tor-design.tex
|
||||
http://freehaven.net/tor/cvs/doc/FAQ
|
||||
|
||||
About anonymity
|
||||
|
||||
See http://freehaven.net/anonbib/
|
||||
|
||||
About nonblocking IO
|
||||
|
||||
[XXX insert references]
|
||||
|
||||
|
||||
# ======================================================================
|
||||
# Old HACKING document; merge into the above, move into tor-design.tex,
|
||||
# or delete.
|
||||
# ======================================================================
|
||||
The pieces.
|
||||
|
||||
Routers. Onion routers, as far as the 'tor' program is concerned,
|
||||
are a bunch of data items that are loaded into the router_array when
|
||||
the program starts. Periodically it downloads a new set of routers
|
||||
from a directory server, and updates the router_array. When a new OR
|
||||
connection is started (see below), the relevant information is copied
|
||||
from the router struct to the connection struct.
|
||||
|
||||
Connections. A connection is a long-standing tcp socket between
|
||||
nodes. A connection is named based on what it's connected to -- an "OR
|
||||
connection" has an onion router on the other end, an "OP connection" has
|
||||
an onion proxy on the other end, an "exit connection" has a website or
|
||||
other server on the other end, and an "AP connection" has an application
|
||||
proxy (and thus a user) on the other end.
|
||||
|
||||
Circuits. A circuit is a path over the onion routing
|
||||
network. Applications can connect to one end of the circuit, and can
|
||||
create exit connections at the other end of the circuit. AP and exit
|
||||
connections have only one circuit associated with them (and thus these
|
||||
connection types are closed when the circuit is closed), whereas OP and
|
||||
OR connections multiplex many circuits at once, and stay standing even
|
||||
when there are no circuits running over them.
|
||||
|
||||
Streams. Streams are specific conversations between an AP and an exit.
|
||||
Streams are multiplexed over circuits.
|
||||
|
||||
Cells. Some connections, specifically OR and OP connections, speak
|
||||
"cells". This means that data over that connection is bundled into 256
|
||||
byte packets (8 bytes of header and 248 bytes of payload). Each cell has
|
||||
a type, or "command", which indicates what it's for.
|
||||
|
||||
Robustness features.
|
||||
|
||||
[XXX no longer up to date]
|
||||
Bandwidth throttling. Each cell-speaking connection has a maximum
|
||||
bandwidth it can use, as specified in the routers.or file. Bandwidth
|
||||
throttling can occur on both the sender side and the receiving side. If
|
||||
the LinkPadding option is on, the sending side sends cells at regularly
|
||||
spaced intervals (e.g., a connection with a bandwidth of 25600B/s would
|
||||
queue a cell every 10ms). The receiving side protects against misbehaving
|
||||
servers that send cells more frequently, by using a simple token bucket:
|
||||
|
||||
Each connection has a token bucket with a specified capacity. Tokens are
|
||||
added to the bucket each second (when the bucket is full, new tokens
|
||||
are discarded.) Each token represents permission to receive one byte
|
||||
from the network --- to receive a byte, the connection must remove a
|
||||
token from the bucket. Thus if the bucket is empty, that connection must
|
||||
wait until more tokens arrive. The number of tokens we add enforces a
|
||||
longterm average rate of incoming bytes, yet we still permit short-term
|
||||
bursts above the allowed bandwidth. Currently bucket sizes are set to
|
||||
ten seconds worth of traffic.
|
||||
|
||||
The bandwidth throttling uses TCP to push back when we stop reading.
|
||||
We extend it with token buckets to allow more flexibility for traffic
|
||||
bursts.
|
||||
|
||||
Data congestion control. Even with the above bandwidth throttling,
|
||||
we still need to worry about congestion, either accidental or intentional.
|
||||
If a lot of people make circuits into same node, and they all come out
|
||||
through the same connection, then that connection may become saturated
|
||||
(be unable to send out data cells as quickly as it wants to). An adversary
|
||||
can make a 'put' request through the onion routing network to a webserver
|
||||
he owns, and then refuse to read any of the bytes at the webserver end
|
||||
of the circuit. These bottlenecks can propagate back through the entire
|
||||
network, mucking up everything.
|
||||
|
||||
(See the tor-spec.txt document for details of how congestion control
|
||||
works.)
|
||||
|
||||
In practice, all the nodes in the circuit maintain a receive window
|
||||
close to maximum except the exit node, which stays around 0, periodically
|
||||
receiving a sendme and reading more data cells from the webserver.
|
||||
In this way we can use pretty much all of the available bandwidth for
|
||||
data, but gracefully back off when faced with multiple circuits (a new
|
||||
sendme arrives only after some cells have traversed the entire network),
|
||||
stalled network connections, or attacks.
|
||||
|
||||
We don't need to reimplement full tcp windows, with sequence numbers,
|
||||
the ability to drop cells when we're full etc, because the tcp streams
|
||||
already guarantee in-order delivery of each cell. Rather than trying
|
||||
to build some sort of tcp-on-tcp scheme, we implement this minimal data
|
||||
congestion control; so far it's enough.
|
||||
|
||||
Router twins. In many cases when we ask for a router with a given
|
||||
address and port, we really mean a router who knows a given key. Router
|
||||
twins are two or more routers that share the same private key. We thus
|
||||
give routers extra flexibility in choosing the next hop in the circuit: if
|
||||
some of the twins are down or slow, it can choose the more available ones.
|
||||
|
||||
Currently the code tries for the primary router first, and if it's down,
|
||||
chooses the first available twin.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
EXTRA_DIST = tor-spec.txt CLIENTS FAQ HACKING rendezvous.txt tor-design.tex
|
||||
|
||||
man_MANS = tor.1
|
||||
@@ -0,0 +1,106 @@
|
||||
|
||||
Legend:
|
||||
SPEC!! - Not specified
|
||||
SPEC - Spec not finalized
|
||||
NICK - nick claims
|
||||
ARMA - arma claims
|
||||
- Not done
|
||||
* Top priority
|
||||
. Partially done
|
||||
o Done
|
||||
D Deferred
|
||||
X Abandoned
|
||||
|
||||
|
||||
For September:
|
||||
- Windows port
|
||||
- works as client
|
||||
- deal with pollhup / reached_eof on all platforms
|
||||
- robust as a client
|
||||
- works as server
|
||||
- can be configured
|
||||
- robust as a server
|
||||
- docs for building in win
|
||||
- installer?
|
||||
|
||||
- Docs
|
||||
- FAQ
|
||||
- overview of tor. how does it work, what's it do, pros and
|
||||
cons of using it, why should I use it, etc.
|
||||
- a howto tutorial with examples
|
||||
- tutorial: how to set up your own tor network
|
||||
- (need to not hardcore dirservers file in config.c)
|
||||
- correct, update, polish spec
|
||||
- document the exposed function api?
|
||||
- document what we mean by socks.
|
||||
|
||||
- packages
|
||||
- rpm
|
||||
- find a long-term rpm maintainer
|
||||
|
||||
- code
|
||||
- better warn/info messages
|
||||
- let tor do resolves.
|
||||
- extend socks4 to do resolves?
|
||||
- make script to ask tor for resolves
|
||||
- tsocks
|
||||
- gather patches, submit to maintainer
|
||||
- intercept gethostbyname and others, do resolve via tor
|
||||
- redesign and thorough code revamp, with particular eye toward:
|
||||
- support half-open tcp connections
|
||||
- conn key rotation
|
||||
- other transports -- http, airhook
|
||||
- modular introduction mechanism
|
||||
- allow non-clique topology
|
||||
|
||||
Other details and small and hard things:
|
||||
- rend_services_introduce should check if it's failed a lot
|
||||
recently, and not try for a while if so
|
||||
- check tor version as soon as you get the recommended-versions
|
||||
string, regardless of whether parsing the directory succeeded.
|
||||
- tor should be able to have a pool of outgoing IP addresses
|
||||
that it is able to rotate through. (maybe)
|
||||
- tie into squid
|
||||
- buffer size pool, to let a few buffers grow huge or many buffers
|
||||
grow a bit
|
||||
- hidserv offerers shouldn't need to define a SocksPort
|
||||
- when the client fails to pick an intro point for a hidserv,
|
||||
it should refetch the hidserv desc.
|
||||
. should maybe make clients exit(1) when bad things happen?
|
||||
e.g. clock skew.
|
||||
- should retry exitpolicy end streams even if the end cell didn't
|
||||
resolve the address for you
|
||||
- Add '[...truncated]' or similar to truncated log entries (like the directory
|
||||
in connection_dir_process_inbuf()).
|
||||
. Make logs handle it better when writing to them fails.
|
||||
- Dirserver shouldn't put you in running-routers list if you haven't
|
||||
uploaded a descriptor recently
|
||||
. Refactor: add own routerinfo to routerlist. Right now, only
|
||||
router_get_by_nickname knows about 'this router', as a hack to
|
||||
get circuit_launch_new to do the right thing.
|
||||
|
||||
Rendezvous service:
|
||||
- preemptively build and start rendezvous circs
|
||||
- preemptively build n-1 hops of intro circs?
|
||||
- cannibalize general circs?
|
||||
- fix router_get_by_* functions so they can get ourselves too,
|
||||
and audit everything to make sure rend and intro points are
|
||||
just as likely to be us as not.
|
||||
|
||||
In the distant future:
|
||||
. Scrubbing proxies
|
||||
- Find an smtp proxy?
|
||||
. Get socks4a support into Mozilla
|
||||
- migrate to using IPv6 sizes everywhere
|
||||
- handle half-open tcp conns
|
||||
- Extend by nickname/hostname/something, not by IP.
|
||||
- Need a relay teardown cell, separate from one-way ends.
|
||||
- Make it harder to circumvent bandwidth caps: look at number of bytes
|
||||
sent across sockets, not number sent inside TLS stream.
|
||||
- Look at having smallcells and largecells
|
||||
D Advanced directory servers
|
||||
D Automated reputation management
|
||||
D Figure out how to do threshold directory servers
|
||||
D jurisdiction info in dirserver entries? other info?
|
||||
X On the fly compression of each stream
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
%!PS-Adobe-2.0 EPSF-2.0
|
||||
%%Title: cell-struct.fig
|
||||
%%Creator: fig2dev Version 3.2 Patchlevel 4
|
||||
%%CreationDate: Sat Jan 31 02:13:55 2004
|
||||
%%For: root@last-request (root)
|
||||
%%BoundingBox: 0 0 254 73
|
||||
%%Magnification: 1.0000
|
||||
%%EndComments
|
||||
/$F2psDict 200 dict def
|
||||
$F2psDict begin
|
||||
$F2psDict /mtrx matrix put
|
||||
/col-1 {0 setgray} bind def
|
||||
/col0 {0.000 0.000 0.000 srgb} bind def
|
||||
/col1 {0.000 0.000 1.000 srgb} bind def
|
||||
/col2 {0.000 1.000 0.000 srgb} bind def
|
||||
/col3 {0.000 1.000 1.000 srgb} bind def
|
||||
/col4 {1.000 0.000 0.000 srgb} bind def
|
||||
/col5 {1.000 0.000 1.000 srgb} bind def
|
||||
/col6 {1.000 1.000 0.000 srgb} bind def
|
||||
/col7 {1.000 1.000 1.000 srgb} bind def
|
||||
/col8 {0.000 0.000 0.560 srgb} bind def
|
||||
/col9 {0.000 0.000 0.690 srgb} bind def
|
||||
/col10 {0.000 0.000 0.820 srgb} bind def
|
||||
/col11 {0.530 0.810 1.000 srgb} bind def
|
||||
/col12 {0.000 0.560 0.000 srgb} bind def
|
||||
/col13 {0.000 0.690 0.000 srgb} bind def
|
||||
/col14 {0.000 0.820 0.000 srgb} bind def
|
||||
/col15 {0.000 0.560 0.560 srgb} bind def
|
||||
/col16 {0.000 0.690 0.690 srgb} bind def
|
||||
/col17 {0.000 0.820 0.820 srgb} bind def
|
||||
/col18 {0.560 0.000 0.000 srgb} bind def
|
||||
/col19 {0.690 0.000 0.000 srgb} bind def
|
||||
/col20 {0.820 0.000 0.000 srgb} bind def
|
||||
/col21 {0.560 0.000 0.560 srgb} bind def
|
||||
/col22 {0.690 0.000 0.690 srgb} bind def
|
||||
/col23 {0.820 0.000 0.820 srgb} bind def
|
||||
/col24 {0.500 0.190 0.000 srgb} bind def
|
||||
/col25 {0.630 0.250 0.000 srgb} bind def
|
||||
/col26 {0.750 0.380 0.000 srgb} bind def
|
||||
/col27 {1.000 0.500 0.500 srgb} bind def
|
||||
/col28 {1.000 0.630 0.630 srgb} bind def
|
||||
/col29 {1.000 0.750 0.750 srgb} bind def
|
||||
/col30 {1.000 0.880 0.880 srgb} bind def
|
||||
/col31 {1.000 0.840 0.000 srgb} bind def
|
||||
|
||||
end
|
||||
save
|
||||
newpath 0 73 moveto 0 0 lineto 254 0 lineto 254 73 lineto closepath clip newpath
|
||||
-35.3 77.2 translate
|
||||
1 -1 scale
|
||||
|
||||
/cp {closepath} bind def
|
||||
/ef {eofill} bind def
|
||||
/gr {grestore} bind def
|
||||
/gs {gsave} bind def
|
||||
/sa {save} bind def
|
||||
/rs {restore} bind def
|
||||
/l {lineto} bind def
|
||||
/m {moveto} bind def
|
||||
/rm {rmoveto} bind def
|
||||
/n {newpath} bind def
|
||||
/s {stroke} bind def
|
||||
/sh {show} bind def
|
||||
/slc {setlinecap} bind def
|
||||
/slj {setlinejoin} bind def
|
||||
/slw {setlinewidth} bind def
|
||||
/srgb {setrgbcolor} bind def
|
||||
/rot {rotate} bind def
|
||||
/sc {scale} bind def
|
||||
/sd {setdash} bind def
|
||||
/ff {findfont} bind def
|
||||
/sf {setfont} bind def
|
||||
/scf {scalefont} bind def
|
||||
/sw {stringwidth} bind def
|
||||
/tr {translate} bind def
|
||||
/tnt {dup dup currentrgbcolor
|
||||
4 -2 roll dup 1 exch sub 3 -1 roll mul add
|
||||
4 -2 roll dup 1 exch sub 3 -1 roll mul add
|
||||
4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
|
||||
bind def
|
||||
/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
|
||||
4 -2 roll mul srgb} bind def
|
||||
/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
|
||||
/$F2psEnd {$F2psEnteredState restore end} def
|
||||
|
||||
$F2psBegin
|
||||
10 setmiterlimit
|
||||
0 slj 0 slc
|
||||
0.06000 0.06000 sc
|
||||
%
|
||||
% Fig objects follow
|
||||
%
|
||||
%
|
||||
% here starts figure with depth 50
|
||||
% Polyline
|
||||
7.500 slw
|
||||
n 1200 975 m
|
||||
1200 1275 l gs col0 s gr
|
||||
% Polyline
|
||||
n 1725 975 m
|
||||
1725 1275 l gs col0 s gr
|
||||
% Polyline
|
||||
n 600 975 m 4800 975 l 4800 1275 l 600 1275 l
|
||||
cp gs col0 s gr
|
||||
% Polyline
|
||||
n 1200 300 m
|
||||
1200 600 l gs col0 s gr
|
||||
% Polyline
|
||||
n 1725 300 m
|
||||
1725 600 l gs col0 s gr
|
||||
% Polyline
|
||||
n 600 300 m 4800 300 l 4800 600 l 600 600 l
|
||||
cp gs col0 s gr
|
||||
% Polyline
|
||||
n 2550 975 m
|
||||
2550 1275 l gs col0 s gr
|
||||
% Polyline
|
||||
n 3150 975 m
|
||||
3150 1275 l gs col0 s gr
|
||||
% Polyline
|
||||
n 3450 975 m
|
||||
3450 1275 l gs col0 s gr
|
||||
% Polyline
|
||||
n 3900 975 m
|
||||
3900 1275 l gs col0 s gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
675 1200 m
|
||||
gs 1 -1 sc (CircID) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
900 900 m
|
||||
gs 1 -1 sc (2) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
1425 900 m
|
||||
gs 1 -1 sc (1) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
1275 1200 m
|
||||
gs 1 -1 sc (Relay) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
1800 1200 m
|
||||
gs 1 -1 sc (StreamID) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
2625 1200 m
|
||||
gs 1 -1 sc (Digest) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
3150 1200 m
|
||||
gs 1 -1 sc (Len) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
4200 1200 m
|
||||
gs 1 -1 sc (DATA) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
675 525 m
|
||||
gs 1 -1 sc (CircID) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
1275 525 m
|
||||
gs 1 -1 sc (CMD) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
900 225 m
|
||||
gs 1 -1 sc (2) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
1425 225 m
|
||||
gs 1 -1 sc (1) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
3225 525 m
|
||||
gs 1 -1 sc (DATA) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
2100 900 m
|
||||
gs 1 -1 sc (6) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
2850 900 m
|
||||
gs 1 -1 sc (4) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
3225 900 m
|
||||
gs 1 -1 sc (2) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
3450 1200 m
|
||||
gs 1 -1 sc (CMD) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
3600 900 m
|
||||
gs 1 -1 sc (1) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
4350 900 m
|
||||
gs 1 -1 sc (496) col0 sh gr
|
||||
/Times-Roman ff 180.00 scf sf
|
||||
3300 225 m
|
||||
gs 1 -1 sc (509 bytes) col0 sh gr
|
||||
% here ends figure;
|
||||
$F2psEnd
|
||||
rs
|
||||
showpage
|
||||
@@ -0,0 +1,49 @@
|
||||
#FIG 3.2
|
||||
Landscape
|
||||
Center
|
||||
Inches
|
||||
Letter
|
||||
100.00
|
||||
Single
|
||||
-2
|
||||
1200 2
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
1200 975 1200 1275
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
1725 975 1725 1275
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
600 975 4800 975 4800 1275 600 1275 600 975
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
1200 300 1200 600
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
1725 300 1725 600
|
||||
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||
600 300 4800 300 4800 600 600 600 600 300
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
2550 975 2550 1275
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
3150 975 3150 1275
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
3450 975 3450 1275
|
||||
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
3900 975 3900 1275
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 510 675 1200 CircID\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 90 900 900 2\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 90 1425 900 1\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 435 1275 1200 Relay\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 735 1800 1200 StreamID\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 510 2625 1200 Digest\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 285 3150 1200 Len\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 510 4200 1200 DATA\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 510 675 525 CircID\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 420 1275 525 CMD\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 90 900 225 2\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 90 1425 225 1\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 510 3225 525 DATA\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 90 2100 900 6\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 90 2850 900 4\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 90 3225 900 2\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 420 3450 1200 CMD\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 90 3600 900 1\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 135 270 4350 900 496\001
|
||||
4 0 0 50 -1 0 12 0.0000 4 180 735 3300 225 509 bytes\001
|
||||
Binary file not shown.
@@ -0,0 +1,357 @@
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%deffont "standard" xfont "comic sans ms-medium-r"
|
||||
%%deffont "thick" xfont "arial black-medium-r"
|
||||
%%deffont "typewriter" xfont "courier new-bold-r"
|
||||
%%deffont "type2writer" xfont "arial narrow-bold-r"
|
||||
%%deffont "standard" tfont "standard.ttf", tmfont "kochi-mincho.ttf"
|
||||
%%deffont "thick" tfont "thick.ttf", tmfont "goth.ttf"
|
||||
%%deffont "typewriter" tfont "typewriter.ttf", tmfont "goth.ttf"
|
||||
%deffont "standard" xfont "helvetica-medium-r", tfont "arial.ttf", tmfont "times.ttf"
|
||||
%deffont "thick" xfont "helvetica-bold-r", tfont "arialbd.ttf", tmfont "hoso6.ttf"
|
||||
%deffont "italic" xfont "helvetica-italic-r", tfont "ariali.ttf", tmfont "hoso6.ttf"
|
||||
%deffont "typewriter" xfont "courier-medium-r", tfont "typewriter.ttf", tmfont "hoso6.ttf"
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%
|
||||
%% Default settings per each line numbers.
|
||||
%%
|
||||
%default 1 leftfill, size 8, fore "black", back "white", font "thick", hgap 1
|
||||
%default 2 size 8, vgap 10, prefix " ", ccolor "black"
|
||||
%default 3 size 6, bar "gray70", vgap 0
|
||||
%default 4 size 6, fore "black", vgap 0, prefix " ", font "standard"
|
||||
%%
|
||||
%%default 1 area 90 90, leftfill, size 9, fore "yellow", back "blue", font "thick"
|
||||
%%default 2 size 9, vgap 10, prefix " "
|
||||
%%default 3 size 7, bar "gray70", vgap 10
|
||||
%%default 4 size 7, vgap 30, prefix " ", font "standard"
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%
|
||||
%% Default settings that are applied to TAB-indented lines.
|
||||
%%
|
||||
%tab 1 size 5, vgap 40, prefix " ", icon arc "red" 50
|
||||
%tab 2 size 4, vgap 35, prefix " ", icon delta3 "blue" 40
|
||||
%tab 3 size 3, vgap 35, prefix " ", icon dia "DarkViolet" 40
|
||||
%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
%nodefault
|
||||
%center, size 9, font "thick", back "white", fore "black"
|
||||
|
||||
Tor:
|
||||
%size 8
|
||||
Next-generation Onion Routing
|
||||
|
||||
|
||||
%size 7
|
||||
Roger Dingledine
|
||||
Nick Mathewson
|
||||
Paul Syverson
|
||||
|
||||
The Free Haven Project
|
||||
%font "typewriter", fore "blue"
|
||||
http://freehaven.net/
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Low-latency anonymity system
|
||||
|
||||
%leftfill
|
||||
Deployed: 20 nodes, hundreds (?) of users
|
||||
|
||||
Many improvements on earlier design
|
||||
|
||||
Free software -- modified BSD license
|
||||
|
||||
Design is not covered by earlier onion routing
|
||||
patent
|
||||
|
||||
Uses SOCKS to interface with client apps
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
We have working code
|
||||
|
||||
(14 kloc of C)
|
||||
|
||||
and a design document,
|
||||
and a byte-level specification,
|
||||
and a Debian package (in Unstable)
|
||||
|
||||
Works on Linux, BSD, OSX, Cygwin, ...
|
||||
User-space, doesn't need kernel mods or root
|
||||
|
||||
%size 9
|
||||
http://freehaven.net/tor/
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%page
|
||||
%%
|
||||
%%Talk Overview
|
||||
%%
|
||||
%%A bit about Onion Routing
|
||||
%%
|
||||
%%Improvements we've made
|
||||
%%
|
||||
%%Some related work
|
||||
%%
|
||||
%%Ask me questions
|
||||
%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Anonymity: Who needs it?
|
||||
|
||||
Private citizens
|
||||
advocacy, counseling, whistleblowing, reporting, ...
|
||||
%size 6
|
||||
Higher-level protocols
|
||||
voting, e-cash, auctions
|
||||
%size 6
|
||||
Government applications
|
||||
research, law enforcement
|
||||
%size 6
|
||||
Business applications
|
||||
%size 5
|
||||
(hide relationships and volumes of communication)
|
||||
Who is visiting job sites?
|
||||
Which groups are talking to patent lawyers?
|
||||
Who are your suppliers and customers?
|
||||
Is the CEO talking to a buyout partner?
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Anonymity is a network effect
|
||||
|
||||
Systems need traffic (many low-sensitivity users) to attract the high-sensitivity users
|
||||
Most users do not value anonymity much
|
||||
Weak security (fast system) can mean more users
|
||||
which can mean
|
||||
%cont, font "italic"
|
||||
stronger
|
||||
%cont, font "standard"
|
||||
anonymity
|
||||
High-sensitivity agents have incentive to run nodes
|
||||
so they can be certain first node in their path is good
|
||||
to attract traffic for their messages
|
||||
There can be an optimal level of free-riding
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Onion Routing is...
|
||||
|
||||
An overlay network
|
||||
|
||||
Users build virtual circuits through the network
|
||||
|
||||
One layer of encryption at each hop
|
||||
|
||||
Fixed-size cells
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Tor's goals
|
||||
|
||||
Conservative design
|
||||
minimize new design work needed
|
||||
|
||||
%size 6
|
||||
Support testing of future research
|
||||
|
||||
Design for deployment; deploy for use
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Threat model -- what we aim for
|
||||
|
||||
Protect against somebody watching Alice
|
||||
|
||||
Protect against curious Bob
|
||||
|
||||
Protect against `some' curious nodes in the middle
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Differences / limitations
|
||||
|
||||
|
||||
We're TCP-only, not all IP (but we're user-space and very portable)
|
||||
|
||||
Not as strong as high-latency systems (Mixmaster, Mixminion)
|
||||
|
||||
Not peer-to-peer
|
||||
|
||||
No protocol normalization
|
||||
|
||||
Not unobservable (no steg, etc)
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Perfect forward secrecy
|
||||
|
||||
|
||||
Telescoping circuit
|
||||
|
||||
negotiates keys at each hop
|
||||
no more need for replay detection
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
No mixing, padding, traffic shaping (yet)
|
||||
|
||||
|
||||
Please show us they're worth the usability tradeoff
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%page
|
||||
%%
|
||||
%%Many TCP streams can share one circuit
|
||||
%%
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Many TCP streams share a circuit
|
||||
|
||||
Previous designs built a new circuit for each stream
|
||||
|
||||
lots of public key ops per request
|
||||
plus anonymity dangers from making so many circuits
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Leaky-pipe circuit topology
|
||||
|
||||
Alice can direct cells to any node in her circuit
|
||||
|
||||
So we can support long-range padding,
|
||||
have multiple streams exiting at different places in the circuit
|
||||
etc
|
||||
|
||||
%size 6
|
||||
Unclear whether this is dangerous or useful
|
||||
|
||||
More research needed
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Congestion control
|
||||
|
||||
|
||||
Simple rate limiting
|
||||
|
||||
Plus have to keep internal nodes from overflowing
|
||||
|
||||
(Can't use global state or inter-node control)
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Directory servers
|
||||
|
||||
To solve the `introduction' problem
|
||||
|
||||
Approve new servers
|
||||
|
||||
Tell clients who's up right now
|
||||
|
||||
plus their keys, location, etc
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Variable exit policies
|
||||
|
||||
|
||||
Each server allows different outgoing connections
|
||||
|
||||
E.g. no servers allow outgoing mail currently
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
End-to-end integrity checking
|
||||
|
||||
|
||||
In previous onion routing, an insider could change
|
||||
the text being transmitted:
|
||||
|
||||
"dir" => "rm *"
|
||||
|
||||
Even an external adversary could do this!
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Rendezvous points
|
||||
|
||||
allow hidden services
|
||||
|
||||
don't need (brittle) reply onions
|
||||
|
||||
Access-controlled: Bob can control who he talks to
|
||||
Robust: Bob's service is available even when some Tor nodes go down
|
||||
Smear-resistant: Evil service can't frame a rendezvous router
|
||||
Application-transparent: Don't need to modify Bob's apache
|
||||
|
||||
%size 6
|
||||
(Not implemented yet)
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
How do we compare security?
|
||||
|
||||
Assume adversary owns c of n nodes
|
||||
can choose which
|
||||
%size 6
|
||||
What's the chance for a random Alice and Bob that he wins?
|
||||
|
||||
Freedom, Tor: (c/n)^2
|
||||
Peekabooty, six-four, etc: c/n
|
||||
Jap (if no padding): 1 if c>1
|
||||
Anonymizer: 1 if c>0
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Future work
|
||||
|
||||
Threshold directory agreement
|
||||
|
||||
Scalability: Morphmix/p2p extensions?
|
||||
Restricted-route (non-clique topology)
|
||||
|
||||
Non-TCP transport
|
||||
|
||||
Implement rendezvous points
|
||||
|
||||
Make it work better
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
We have working code
|
||||
|
||||
Plus a design document,
|
||||
and a byte-level specification
|
||||
and a Debian package (in Unstable)
|
||||
|
||||
%size 9
|
||||
http://freehaven.net/tor/
|
||||
|
||||
%size 6
|
||||
Privacy Enhancing Technologies workshop
|
||||
|
||||
%size 9
|
||||
http://petworkshop.org/
|
||||
|
||||
@@ -0,0 +1,463 @@
|
||||
%!PS-Adobe-2.0 EPSF-2.0
|
||||
%%Title: interaction.fig
|
||||
%%Creator: fig2dev Version 3.2 Patchlevel 3d
|
||||
%%CreationDate: Sat Jan 31 05:25:23 2004
|
||||
%%For: nickm@totoro.wangafu.net ()
|
||||
%%BoundingBox: 0 0 449 235
|
||||
%%Magnification: 1.0000
|
||||
%%EndComments
|
||||
/$F2psDict 200 dict def
|
||||
$F2psDict begin
|
||||
$F2psDict /mtrx matrix put
|
||||
/col-1 {0 setgray} bind def
|
||||
/col0 {0.000 0.000 0.000 srgb} bind def
|
||||
/col1 {0.000 0.000 1.000 srgb} bind def
|
||||
/col2 {0.000 1.000 0.000 srgb} bind def
|
||||
/col3 {0.000 1.000 1.000 srgb} bind def
|
||||
/col4 {1.000 0.000 0.000 srgb} bind def
|
||||
/col5 {1.000 0.000 1.000 srgb} bind def
|
||||
/col6 {1.000 1.000 0.000 srgb} bind def
|
||||
/col7 {1.000 1.000 1.000 srgb} bind def
|
||||
/col8 {0.000 0.000 0.560 srgb} bind def
|
||||
/col9 {0.000 0.000 0.690 srgb} bind def
|
||||
/col10 {0.000 0.000 0.820 srgb} bind def
|
||||
/col11 {0.530 0.810 1.000 srgb} bind def
|
||||
/col12 {0.000 0.560 0.000 srgb} bind def
|
||||
/col13 {0.000 0.690 0.000 srgb} bind def
|
||||
/col14 {0.000 0.820 0.000 srgb} bind def
|
||||
/col15 {0.000 0.560 0.560 srgb} bind def
|
||||
/col16 {0.000 0.690 0.690 srgb} bind def
|
||||
/col17 {0.000 0.820 0.820 srgb} bind def
|
||||
/col18 {0.560 0.000 0.000 srgb} bind def
|
||||
/col19 {0.690 0.000 0.000 srgb} bind def
|
||||
/col20 {0.820 0.000 0.000 srgb} bind def
|
||||
/col21 {0.560 0.000 0.560 srgb} bind def
|
||||
/col22 {0.690 0.000 0.690 srgb} bind def
|
||||
/col23 {0.820 0.000 0.820 srgb} bind def
|
||||
/col24 {0.500 0.190 0.000 srgb} bind def
|
||||
/col25 {0.630 0.250 0.000 srgb} bind def
|
||||
/col26 {0.750 0.380 0.000 srgb} bind def
|
||||
/col27 {1.000 0.500 0.500 srgb} bind def
|
||||
/col28 {1.000 0.630 0.630 srgb} bind def
|
||||
/col29 {1.000 0.750 0.750 srgb} bind def
|
||||
/col30 {1.000 0.880 0.880 srgb} bind def
|
||||
/col31 {1.000 0.840 0.000 srgb} bind def
|
||||
|
||||
end
|
||||
save
|
||||
newpath 0 235 moveto 0 0 lineto 449 0 lineto 449 235 lineto closepath clip newpath
|
||||
-62.3 239.8 translate
|
||||
1 -1 scale
|
||||
|
||||
/cp {closepath} bind def
|
||||
/ef {eofill} bind def
|
||||
/gr {grestore} bind def
|
||||
/gs {gsave} bind def
|
||||
/sa {save} bind def
|
||||
/rs {restore} bind def
|
||||
/l {lineto} bind def
|
||||
/m {moveto} bind def
|
||||
/rm {rmoveto} bind def
|
||||
/n {newpath} bind def
|
||||
/s {stroke} bind def
|
||||
/sh {show} bind def
|
||||
/slc {setlinecap} bind def
|
||||
/slj {setlinejoin} bind def
|
||||
/slw {setlinewidth} bind def
|
||||
/srgb {setrgbcolor} bind def
|
||||
/rot {rotate} bind def
|
||||
/sc {scale} bind def
|
||||
/sd {setdash} bind def
|
||||
/ff {findfont} bind def
|
||||
/sf {setfont} bind def
|
||||
/scf {scalefont} bind def
|
||||
/sw {stringwidth} bind def
|
||||
/tr {translate} bind def
|
||||
/tnt {dup dup currentrgbcolor
|
||||
4 -2 roll dup 1 exch sub 3 -1 roll mul add
|
||||
4 -2 roll dup 1 exch sub 3 -1 roll mul add
|
||||
4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
|
||||
bind def
|
||||
/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
|
||||
4 -2 roll mul srgb} bind def
|
||||
/reencdict 12 dict def /ReEncode { reencdict begin
|
||||
/newcodesandnames exch def /newfontname exch def /basefontname exch def
|
||||
/basefontdict basefontname findfont def /newfont basefontdict maxlength dict def
|
||||
basefontdict { exch dup /FID ne { dup /Encoding eq
|
||||
{ exch dup length array copy newfont 3 1 roll put }
|
||||
{ exch newfont 3 1 roll put } ifelse } { pop pop } ifelse } forall
|
||||
newfont /FontName newfontname put newcodesandnames aload pop
|
||||
128 1 255 { newfont /Encoding get exch /.notdef put } for
|
||||
newcodesandnames length 2 idiv { newfont /Encoding get 3 1 roll put } repeat
|
||||
newfontname newfont definefont pop end } def
|
||||
/isovec [
|
||||
8#055 /minus 8#200 /grave 8#201 /acute 8#202 /circumflex 8#203 /tilde
|
||||
8#204 /macron 8#205 /breve 8#206 /dotaccent 8#207 /dieresis
|
||||
8#210 /ring 8#211 /cedilla 8#212 /hungarumlaut 8#213 /ogonek 8#214 /caron
|
||||
8#220 /dotlessi 8#230 /oe 8#231 /OE
|
||||
8#240 /space 8#241 /exclamdown 8#242 /cent 8#243 /sterling
|
||||
8#244 /currency 8#245 /yen 8#246 /brokenbar 8#247 /section 8#250 /dieresis
|
||||
8#251 /copyright 8#252 /ordfeminine 8#253 /guillemotleft 8#254 /logicalnot
|
||||
8#255 /hyphen 8#256 /registered 8#257 /macron 8#260 /degree 8#261 /plusminus
|
||||
8#262 /twosuperior 8#263 /threesuperior 8#264 /acute 8#265 /mu 8#266 /paragraph
|
||||
8#267 /periodcentered 8#270 /cedilla 8#271 /onesuperior 8#272 /ordmasculine
|
||||
8#273 /guillemotright 8#274 /onequarter 8#275 /onehalf
|
||||
8#276 /threequarters 8#277 /questiondown 8#300 /Agrave 8#301 /Aacute
|
||||
8#302 /Acircumflex 8#303 /Atilde 8#304 /Adieresis 8#305 /Aring
|
||||
8#306 /AE 8#307 /Ccedilla 8#310 /Egrave 8#311 /Eacute
|
||||
8#312 /Ecircumflex 8#313 /Edieresis 8#314 /Igrave 8#315 /Iacute
|
||||
8#316 /Icircumflex 8#317 /Idieresis 8#320 /Eth 8#321 /Ntilde 8#322 /Ograve
|
||||
8#323 /Oacute 8#324 /Ocircumflex 8#325 /Otilde 8#326 /Odieresis 8#327 /multiply
|
||||
8#330 /Oslash 8#331 /Ugrave 8#332 /Uacute 8#333 /Ucircumflex
|
||||
8#334 /Udieresis 8#335 /Yacute 8#336 /Thorn 8#337 /germandbls 8#340 /agrave
|
||||
8#341 /aacute 8#342 /acircumflex 8#343 /atilde 8#344 /adieresis 8#345 /aring
|
||||
8#346 /ae 8#347 /ccedilla 8#350 /egrave 8#351 /eacute
|
||||
8#352 /ecircumflex 8#353 /edieresis 8#354 /igrave 8#355 /iacute
|
||||
8#356 /icircumflex 8#357 /idieresis 8#360 /eth 8#361 /ntilde 8#362 /ograve
|
||||
8#363 /oacute 8#364 /ocircumflex 8#365 /otilde 8#366 /odieresis 8#367 /divide
|
||||
8#370 /oslash 8#371 /ugrave 8#372 /uacute 8#373 /ucircumflex
|
||||
8#374 /udieresis 8#375 /yacute 8#376 /thorn 8#377 /ydieresis] def
|
||||
/Times-Bold /Times-Bold-iso isovec ReEncode
|
||||
/Times-Roman /Times-Roman-iso isovec ReEncode
|
||||
/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
|
||||
/$F2psEnd {$F2psEnteredState restore end} def
|
||||
|
||||
$F2psBegin
|
||||
10 setmiterlimit
|
||||
0.06000 0.06000 sc
|
||||
%
|
||||
% Fig objects follow
|
||||
%
|
||||
% Polyline
|
||||
15.000 slw
|
||||
n 6000 300 m
|
||||
6000 3975 l gs col0 s gr
|
||||
% Polyline
|
||||
7.500 slw
|
||||
gs clippath
|
||||
3615 555 m 3615 495 l 3464 495 l 3584 525 l 3464 555 l cp
|
||||
eoclip
|
||||
n 1200 525 m
|
||||
3600 525 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 3464 555 m 3584 525 l 3464 495 l 3464 555 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
1185 795 m 1185 855 l 1336 855 l 1216 825 l 1336 795 l cp
|
||||
eoclip
|
||||
n 3600 825 m
|
||||
1200 825 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 1336 795 m 1216 825 l 1336 855 l 1336 795 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
15.000 slw
|
||||
n 1200 300 m
|
||||
1200 3975 l gs col0 s gr
|
||||
% Polyline
|
||||
7.500 slw
|
||||
gs clippath
|
||||
3615 1155 m 3615 1095 l 3464 1095 l 3584 1125 l 3464 1155 l cp
|
||||
eoclip
|
||||
n 1200 1125 m
|
||||
3600 1125 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 3464 1155 m 3584 1125 l 3464 1095 l 3464 1155 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
15.000 slw
|
||||
n 3600 300 m
|
||||
3600 3975 l gs col0 s gr
|
||||
% Polyline
|
||||
7.500 slw
|
||||
gs clippath
|
||||
6015 1230 m 6015 1170 l 5864 1170 l 5984 1200 l 5864 1230 l cp
|
||||
eoclip
|
||||
n 3600 1200 m
|
||||
6000 1200 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 5864 1230 m 5984 1200 l 5864 1170 l 5864 1230 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
3585 1470 m 3585 1530 l 3736 1530 l 3616 1500 l 3736 1470 l cp
|
||||
eoclip
|
||||
n 6000 1500 m
|
||||
3600 1500 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 3736 1470 m 3616 1500 l 3736 1530 l 3736 1470 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
1185 1545 m 1185 1605 l 1336 1605 l 1216 1575 l 1336 1545 l cp
|
||||
eoclip
|
||||
n 3600 1575 m
|
||||
1200 1575 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 1336 1545 m 1216 1575 l 1336 1605 l 1336 1545 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
[15 45] 45 sd
|
||||
n 1050 1800 m
|
||||
8325 1800 l gs col0 s gr [] 0 sd
|
||||
% Polyline
|
||||
gs clippath
|
||||
3615 2130 m 3615 2070 l 3464 2070 l 3584 2100 l 3464 2130 l cp
|
||||
eoclip
|
||||
n 1200 2100 m
|
||||
3600 2100 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 3464 2130 m 3584 2100 l 3464 2070 l 3464 2130 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
6015 2205 m 6015 2145 l 5864 2145 l 5984 2175 l 5864 2205 l cp
|
||||
eoclip
|
||||
n 3600 2175 m
|
||||
6000 2175 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 5864 2205 m 5984 2175 l 5864 2145 l 5864 2205 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
[60] 0 sd
|
||||
gs clippath
|
||||
8190 2430 m 8190 2370 l 8039 2370 l 8159 2400 l 8039 2430 l cp
|
||||
5985 2370 m 5985 2430 l 6136 2430 l 6016 2400 l 6136 2370 l cp
|
||||
eoclip
|
||||
n 6000 2400 m
|
||||
8175 2400 l gs col0 s gr gr
|
||||
[] 0 sd
|
||||
% arrowhead
|
||||
n 6136 2370 m 6016 2400 l 6136 2430 l 6136 2370 l cp gs 0.00 setgray ef gr col0 s
|
||||
% arrowhead
|
||||
n 8039 2430 m 8159 2400 l 8039 2370 l 8039 2430 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
3585 2520 m 3585 2580 l 3736 2580 l 3616 2550 l 3736 2520 l cp
|
||||
eoclip
|
||||
n 6000 2550 m
|
||||
3600 2550 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 3736 2520 m 3616 2550 l 3736 2580 l 3736 2520 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
1185 2595 m 1185 2655 l 1336 2655 l 1216 2625 l 1336 2595 l cp
|
||||
eoclip
|
||||
n 3600 2625 m
|
||||
1200 2625 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 1336 2595 m 1216 2625 l 1336 2655 l 1336 2595 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
3615 3030 m 3615 2970 l 3464 2970 l 3584 3000 l 3464 3030 l cp
|
||||
eoclip
|
||||
n 1200 3000 m
|
||||
3600 3000 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 3464 3030 m 3584 3000 l 3464 2970 l 3464 3030 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
6015 3105 m 6015 3045 l 5864 3045 l 5984 3075 l 5864 3105 l cp
|
||||
eoclip
|
||||
n 3600 3075 m
|
||||
6000 3075 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 5864 3105 m 5984 3075 l 5864 3045 l 5864 3105 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
8190 3180 m 8190 3120 l 8039 3120 l 8159 3150 l 8039 3180 l cp
|
||||
eoclip
|
||||
n 6000 3150 m
|
||||
8175 3150 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 8039 3180 m 8159 3150 l 8039 3120 l 8039 3180 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
5985 3420 m 5985 3480 l 6136 3480 l 6016 3450 l 6136 3420 l cp
|
||||
eoclip
|
||||
n 8175 3450 m
|
||||
6000 3450 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 6136 3420 m 6016 3450 l 6136 3480 l 6136 3420 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
5985 3495 m 5985 3555 l 6136 3555 l 6016 3525 l 6136 3495 l cp
|
||||
eoclip
|
||||
n 8175 3525 m
|
||||
6000 3525 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 6136 3495 m 6016 3525 l 6136 3555 l 6136 3495 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
5985 3570 m 5985 3630 l 6136 3630 l 6016 3600 l 6136 3570 l cp
|
||||
eoclip
|
||||
n 8175 3600 m
|
||||
6000 3600 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 6136 3570 m 6016 3600 l 6136 3630 l 6136 3570 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
3585 3495 m 3585 3555 l 3736 3555 l 3616 3525 l 3736 3495 l cp
|
||||
eoclip
|
||||
n 6000 3525 m
|
||||
3600 3525 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 3736 3495 m 3616 3525 l 3736 3555 l 3736 3495 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
3585 3645 m 3585 3705 l 3736 3705 l 3616 3675 l 3736 3645 l cp
|
||||
eoclip
|
||||
n 6000 3675 m
|
||||
3600 3675 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 3736 3645 m 3616 3675 l 3736 3705 l 3736 3645 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
3585 3570 m 3585 3630 l 3736 3630 l 3616 3600 l 3736 3570 l cp
|
||||
eoclip
|
||||
n 6000 3600 m
|
||||
3600 3600 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 3736 3570 m 3616 3600 l 3736 3630 l 3736 3570 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
1185 3645 m 1185 3705 l 1336 3705 l 1216 3675 l 1336 3645 l cp
|
||||
eoclip
|
||||
n 3600 3675 m
|
||||
1200 3675 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 1336 3645 m 1216 3675 l 1336 3705 l 1336 3645 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
1185 3720 m 1185 3780 l 1336 3780 l 1216 3750 l 1336 3720 l cp
|
||||
eoclip
|
||||
n 3600 3750 m
|
||||
1200 3750 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 1336 3720 m 1216 3750 l 1336 3780 l 1336 3720 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
gs clippath
|
||||
1185 3795 m 1185 3855 l 1336 3855 l 1216 3825 l 1336 3795 l cp
|
||||
eoclip
|
||||
n 3600 3825 m
|
||||
1200 3825 l gs col0 s gr gr
|
||||
|
||||
% arrowhead
|
||||
n 1336 3795 m 1216 3825 l 1336 3855 l 1336 3795 l cp gs 0.00 setgray ef gr col0 s
|
||||
% Polyline
|
||||
15.000 slw
|
||||
n 8175 300 m
|
||||
8175 3975 l gs col0 s gr
|
||||
% Polyline
|
||||
7.500 slw
|
||||
n 6300 825 m 7950 825 l 7950 1725 l 6300 1725 l
|
||||
cp gs col7 1.00 shd ef gr gs col0 s gr
|
||||
/Times-Bold-iso ff 180.00 scf sf
|
||||
3375 225 m
|
||||
gs 1 -1 sc (OR 1) col0 sh gr
|
||||
/Times-Bold-iso ff 180.00 scf sf
|
||||
1050 225 m
|
||||
gs 1 -1 sc (Alice) col0 sh gr
|
||||
/Times-Bold-iso ff 180.00 scf sf
|
||||
5775 225 m
|
||||
gs 1 -1 sc (OR 2) col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
6075 3075 m
|
||||
gs 1 -1 sc ("HTTP GET...") col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
4800 3975 m
|
||||
gs 1 -1 sc (. . .) dup sw pop 2 div neg 0 rm col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
7125 3975 m
|
||||
gs 1 -1 sc (. . .) dup sw pop 2 div neg 0 rm col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
2400 3975 m
|
||||
gs 1 -1 sc (. . .) dup sw pop 2 div neg 0 rm col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
7125 2325 m
|
||||
gs 1 -1 sc (\(TCP handshake\)) dup sw pop 2 div neg 0 rm col0 sh gr
|
||||
/Times-Bold-iso ff 180.00 scf sf
|
||||
7875 225 m
|
||||
gs 1 -1 sc (website) col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
7125 1425 m
|
||||
gs 1 -1 sc ({X}--AES encryption) dup sw pop 2 div neg 0 rm col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
7125 1200 m
|
||||
gs 1 -1 sc (E\(x\)--RSA encryption) dup sw pop 2 div neg 0 rm col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
7125 975 m
|
||||
gs 1 -1 sc (Legend:) dup sw pop 2 div neg 0 rm col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
2400 225 m
|
||||
gs 1 -1 sc (\(link is TLS-encrypted\)) dup sw pop 2 div neg 0 rm col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
1275 1050 m
|
||||
gs 1 -1 sc (Relay c1{Extend, OR2, E\(g^x2\)}) col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
1275 2025 m
|
||||
gs 1 -1 sc (Relay c1{{Begin <website>:80}}) col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
3525 1500 m
|
||||
gs 1 -1 sc (Relay c1{Extended, g^y2, H\(K2\)}) dup sw pop neg 0 rm col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
3675 2100 m
|
||||
gs 1 -1 sc (Relay c2{Begin <website>:80}) col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
3525 2550 m
|
||||
gs 1 -1 sc (Relay c1{{Connected}}) dup sw pop neg 0 rm col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
5925 2475 m
|
||||
gs 1 -1 sc (Relay c2{Connected}) dup sw pop neg 0 rm col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
1275 2925 m
|
||||
gs 1 -1 sc (Relay c1{{Data, "HTTP GET..."}}) col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
3675 3000 m
|
||||
gs 1 -1 sc (Relay c2{Data, "HTTP GET..."}) col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
4800 225 m
|
||||
gs 1 -1 sc (\(link is TLS-encryped\)) dup sw pop 2 div neg 0 rm col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
7050 225 m
|
||||
gs 1 -1 sc (\(unencrypted\)) dup sw pop 2 div neg 0 rm col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
7125 1650 m
|
||||
gs 1 -1 sc (cN--a circID) dup sw pop 2 div neg 0 rm col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
3525 3600 m
|
||||
gs 1 -1 sc (Relay c1{{Data, \(response\)}}) dup sw pop neg 0 rm col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
8100 3375 m
|
||||
gs 1 -1 sc (\(response\)) dup sw pop neg 0 rm col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
5925 3450 m
|
||||
gs 1 -1 sc (Relay c2{Data, \(response\)}) dup sw pop neg 0 rm col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
5925 1425 m
|
||||
gs 1 -1 sc (Created c2, g^y2, H\(K2\)) dup sw pop neg 0 rm col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
3675 1125 m
|
||||
gs 1 -1 sc (Create c2, E\(g^x2\)) col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
1275 450 m
|
||||
gs 1 -1 sc (Create c1, E\(g^x1\)) col0 sh gr
|
||||
/Times-Roman-iso ff 150.00 scf sf
|
||||
3525 750 m
|
||||
gs 1 -1 sc (Created c1, g^y1, H\(K1\)) dup sw pop neg 0 rm col0 sh gr
|
||||
$F2psEnd
|
||||
rs
|
||||
@@ -0,0 +1,122 @@
|
||||
#FIG 3.2
|
||||
Landscape
|
||||
Center
|
||||
Inches
|
||||
Letter
|
||||
100.00
|
||||
Single
|
||||
-2
|
||||
1200 2
|
||||
2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 2
|
||||
6000 300 6000 3975
|
||||
2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
1200 525 3600 525
|
||||
2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
3600 825 1200 825
|
||||
2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 2
|
||||
1200 300 1200 3975
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
1200 1125 3600 1125
|
||||
2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 2
|
||||
3600 300 3600 3975
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
3600 1200 6000 1200
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
6000 1500 3600 1500
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
3600 1575 1200 1575
|
||||
2 1 2 1 0 7 50 0 -1 3.000 0 0 -1 0 0 2
|
||||
1050 1800 8325 1800
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
1200 2100 3600 2100
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
3600 2175 6000 2175
|
||||
2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2
|
||||
1 1 1.00 60.00 120.00
|
||||
1 1 1.00 60.00 120.00
|
||||
6000 2400 8175 2400
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
6000 2550 3600 2550
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
3600 2625 1200 2625
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
1200 3000 3600 3000
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
3600 3075 6000 3075
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
6000 3150 8175 3150
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
8175 3450 6000 3450
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
8175 3525 6000 3525
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
8175 3600 6000 3600
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
6000 3525 3600 3525
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
6000 3675 3600 3675
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
6000 3600 3600 3600
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
3600 3675 1200 3675
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
3600 3750 1200 3750
|
||||
2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
|
||||
1 1 1.00 60.00 120.00
|
||||
3600 3825 1200 3825
|
||||
2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 2
|
||||
8175 300 8175 3975
|
||||
2 2 0 1 0 7 50 0 20 3.000 0 0 -1 0 0 5
|
||||
6300 825 7950 825 7950 1725 6300 1725 6300 825
|
||||
4 0 0 50 0 2 12 0.0000 4 135 450 3375 225 OR 1\001
|
||||
4 0 0 50 0 2 12 0.0000 4 135 420 1050 225 Alice\001
|
||||
4 0 0 50 0 2 12 0.0000 4 135 450 5775 225 OR 2\001
|
||||
4 0 0 50 0 0 10 0.0000 4 105 960 6075 3075 "HTTP GET..."\001
|
||||
4 1 0 50 0 0 10 0.0000 4 15 135 4800 3975 . . .\001
|
||||
4 1 0 50 0 0 10 0.0000 4 15 135 7125 3975 . . .\001
|
||||
4 1 0 50 0 0 10 0.0000 4 15 135 2400 3975 . . .\001
|
||||
4 1 0 50 0 0 10 0.0000 4 135 1050 7125 2325 (TCP handshake)\001
|
||||
4 0 0 50 0 2 12 0.0000 4 135 630 7875 225 website\001
|
||||
4 1 0 50 0 0 10 0.0000 4 135 1335 7125 1425 {X}--AES encryption\001
|
||||
4 1 0 50 0 0 10 0.0000 4 135 1410 7125 1200 E(x)--RSA encryption\001
|
||||
4 1 0 50 0 0 10 0.0000 4 135 480 7125 975 Legend:\001
|
||||
4 1 0 50 0 0 10 0.0000 4 135 1455 2400 225 (link is TLS-encrypted)\001
|
||||
4 0 0 50 0 0 10 0.0000 4 135 2085 1275 1050 Relay c1{Extend, OR2, E(g^x2)}\001
|
||||
4 0 0 50 0 0 10 0.0000 4 135 1965 1275 2025 Relay c1{{Begin <website>:80}}\001
|
||||
4 2 0 50 0 0 10 0.0000 4 135 2190 3525 1500 Relay c1{Extended, g^y2, H(K2)}\001
|
||||
4 0 0 50 0 0 10 0.0000 4 135 1845 3675 2100 Relay c2{Begin <website>:80}\001
|
||||
4 2 0 50 0 0 10 0.0000 4 135 1410 3525 2550 Relay c1{{Connected}}\001
|
||||
4 2 0 50 0 0 10 0.0000 4 135 1290 5925 2475 Relay c2{Connected}\001
|
||||
4 0 0 50 0 0 10 0.0000 4 135 2085 1275 2925 Relay c1{{Data, "HTTP GET..."}}\001
|
||||
4 0 0 50 0 0 10 0.0000 4 135 1965 3675 3000 Relay c2{Data, "HTTP GET..."}\001
|
||||
4 1 0 50 0 0 10 0.0000 4 135 1365 4800 225 (link is TLS-encryped)\001
|
||||
4 1 0 50 0 0 10 0.0000 4 135 870 7050 225 (unencrypted)\001
|
||||
4 1 0 50 0 0 10 0.0000 4 105 780 7125 1650 cN--a circID\001
|
||||
4 2 0 50 0 0 10 0.0000 4 135 1860 3525 3600 Relay c1{{Data, (response)}}\001
|
||||
4 2 0 50 0 0 10 0.0000 4 135 645 8100 3375 (response)\001
|
||||
4 2 0 50 0 0 10 0.0000 4 135 1650 5925 3450 Relay c2{Data, (response)}\001
|
||||
4 2 0 50 0 0 10 0.0000 4 135 1545 5925 1425 Created c2, g^y2, H(K2)\001
|
||||
4 0 0 50 0 0 10 0.0000 4 135 1170 3675 1125 Create c2, E(g^x2)\001
|
||||
4 0 0 50 0 0 10 0.0000 4 135 1170 1275 450 Create c1, E(g^x1)\001
|
||||
4 2 0 50 0 0 10 0.0000 4 135 1545 3525 750 Created c1, g^y1, H(K1)\001
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,170 @@
|
||||
|
||||
|
||||
% ---------------------------------------------------------------
|
||||
%
|
||||
% $Id$
|
||||
%
|
||||
% by Paolo.Ienne@di.epfl.ch
|
||||
%
|
||||
% ---------------------------------------------------------------
|
||||
%
|
||||
% no guarantee is given that the format corresponds perfectly to
|
||||
% IEEE 8.5" x 11" Proceedings, but most features should be ok.
|
||||
%
|
||||
% ---------------------------------------------------------------
|
||||
% with LaTeX2e:
|
||||
% =============
|
||||
%
|
||||
% use as
|
||||
% \documentclass[times,10pt,twocolumn]{article}
|
||||
% \usepackage{latex8}
|
||||
% \usepackage{times}
|
||||
%
|
||||
% ---------------------------------------------------------------
|
||||
% with LaTeX 2.09:
|
||||
% ================
|
||||
%
|
||||
% use as
|
||||
% \documentstyle[times,art10,twocolumn,latex8]{article}
|
||||
%
|
||||
% ---------------------------------------------------------------
|
||||
% with both versions:
|
||||
% ===================
|
||||
%
|
||||
% specify \pagestyle{empty} to omit page numbers in the final
|
||||
% version
|
||||
%
|
||||
% specify references as
|
||||
% \bibliographystyle{latex8}
|
||||
% \bibliography{...your files...}
|
||||
%
|
||||
% use Section{} and SubSection{} instead of standard section{}
|
||||
% and subsection{} to obtain headings in the form
|
||||
% "1.3. My heading"
|
||||
%
|
||||
% ---------------------------------------------------------------
|
||||
|
||||
\typeout{IEEE 8.5 x 11-Inch Proceedings Style `latex8.sty'.}
|
||||
|
||||
% ten point helvetica bold required for captions
|
||||
% in some sites the name of the helvetica bold font may differ,
|
||||
% change the name here:
|
||||
\font\tenhv = phvb at 10pt
|
||||
%\font\tenhv = phvb7t at 10pt
|
||||
|
||||
% eleven point times bold required for second-order headings
|
||||
% \font\elvbf = cmbx10 scaled 1100
|
||||
\font\elvbf = ptmb scaled 1100
|
||||
|
||||
% set dimensions of columns, gap between columns, and paragraph indent
|
||||
\setlength{\textheight}{8.875in}
|
||||
\setlength{\textwidth}{6.875in}
|
||||
\setlength{\columnsep}{0.3125in}
|
||||
%\setlength{\columnsep}{0.26in}
|
||||
\setlength{\topmargin}{0in}
|
||||
\setlength{\headheight}{0in}
|
||||
\setlength{\headsep}{.5in}
|
||||
\setlength{\parindent}{1pc}
|
||||
\setlength{\oddsidemargin}{-.304in}
|
||||
\setlength{\evensidemargin}{-.304in}
|
||||
|
||||
% memento from size10.clo
|
||||
% \normalsize{\@setfontsize\normalsize\@xpt\@xiipt}
|
||||
% \small{\@setfontsize\small\@ixpt{11}}
|
||||
% \footnotesize{\@setfontsize\footnotesize\@viiipt{9.5}}
|
||||
% \scriptsize{\@setfontsize\scriptsize\@viipt\@viiipt}
|
||||
% \tiny{\@setfontsize\tiny\@vpt\@vipt}
|
||||
% \large{\@setfontsize\large\@xiipt{14}}
|
||||
% \Large{\@setfontsize\Large\@xivpt{18}}
|
||||
% \LARGE{\@setfontsize\LARGE\@xviipt{22}}
|
||||
% \huge{\@setfontsize\huge\@xxpt{25}}
|
||||
% \Huge{\@setfontsize\Huge\@xxvpt{30}}
|
||||
|
||||
\def\@maketitle
|
||||
{
|
||||
\newpage
|
||||
\null
|
||||
\vskip .375in
|
||||
\begin{center}
|
||||
{\Large \bf \@title \par}
|
||||
% additional two empty lines at the end of the title
|
||||
\vspace*{24pt}
|
||||
{
|
||||
\large
|
||||
\lineskip .5em
|
||||
\begin{tabular}[t]{c}
|
||||
\@author
|
||||
\end{tabular}
|
||||
\par
|
||||
}
|
||||
% additional small space at the end of the author name
|
||||
\vskip .5em
|
||||
{
|
||||
\large
|
||||
\begin{tabular}[t]{c}
|
||||
\@affiliation
|
||||
\end{tabular}
|
||||
\par
|
||||
\ifx \@empty \@email
|
||||
\else
|
||||
\begin{tabular}{r@{~}l}
|
||||
E-mail: & {\tt \@email}
|
||||
\end{tabular}
|
||||
\par
|
||||
\fi
|
||||
}
|
||||
% additional empty line at the end of the title block
|
||||
\vspace*{12pt}
|
||||
\end{center}
|
||||
}
|
||||
|
||||
\def\abstract
|
||||
{%
|
||||
\centerline{\large\bf Abstract}%
|
||||
\vspace*{12pt}%
|
||||
\it%
|
||||
}
|
||||
|
||||
\def\endabstract
|
||||
{
|
||||
% additional empty line at the end of the abstract
|
||||
\vspace*{12pt}
|
||||
}
|
||||
|
||||
\def\affiliation#1{\gdef\@affiliation{#1}} \gdef\@affiliation{}
|
||||
|
||||
\def\email#1{\gdef\@email{#1}}
|
||||
\gdef\@email{}
|
||||
|
||||
\newlength{\@ctmp}
|
||||
\newlength{\@figindent}
|
||||
\setlength{\@figindent}{1pc}
|
||||
|
||||
\long\def\@makecaption#1#2{
|
||||
\vskip 10pt
|
||||
\setbox\@tempboxa\hbox{\tenhv\noindent #1.~#2}
|
||||
\setlength{\@ctmp}{\hsize}
|
||||
\addtolength{\@ctmp}{-\@figindent}\addtolength{\@ctmp}{-\@figindent}
|
||||
% IF longer than one indented paragraph line
|
||||
\ifdim \wd\@tempboxa >\@ctmp
|
||||
% THEN set as an indented paragraph
|
||||
\begin{list}{}{\leftmargin\@figindent \rightmargin\leftmargin}
|
||||
\item[]\tenhv #1.~#2\par
|
||||
\end{list}
|
||||
\else
|
||||
% ELSE center
|
||||
\hbox to\hsize{\hfil\box\@tempboxa\hfil}
|
||||
\fi}
|
||||
|
||||
% correct heading spacing and type
|
||||
\def\section{\@startsection {section}{1}{\z@}
|
||||
{14pt plus 2pt minus 2pt}{14pt plus 2pt minus 2pt} {\large\bf}}
|
||||
\def\subsection{\@startsection {subsection}{2}{\z@}
|
||||
{13pt plus 2pt minus 2pt}{13pt plus 2pt minus 2pt} {\elvbf}}
|
||||
|
||||
% add the period after section numbers
|
||||
\newcommand{\Section}[1]{\section{\hskip -1em.~#1}}
|
||||
\newcommand{\SubSection}[1]{\subsection{\hskip -1em.~#1}}
|
||||
|
||||
% end of file latex8.sty
|
||||
% ---------------------------------------------------------------
|
||||
@@ -0,0 +1,333 @@
|
||||
$Id$
|
||||
|
||||
[XXX We need to make nicknames in intro* cells padded to 20
|
||||
bytes, and maybe have a fixed length for nicknames in the
|
||||
descriptor too -RD]
|
||||
|
||||
Tor Rendezvous Spec
|
||||
|
||||
0. Overview and preliminaries
|
||||
|
||||
Rendezvous points provide location-hidden services (server
|
||||
anonymity) for the onion routing network. With rendezvous points,
|
||||
Bob can offer a TCP service (say, a webserver) via the onion
|
||||
routing network, without revealing the IP of that service.
|
||||
|
||||
Bob does this by anonymously advertising a public key for his
|
||||
service, along with a list of onion routers to act as "Introduction
|
||||
Points" for his service. He creates forward OR circuits to those
|
||||
introduction points, and tells them about his public key. To
|
||||
connect to Bob, Alice first builds an OR circuit to an OR to act as
|
||||
her "Rendezvous Point", then connects to one of Bob's chosen
|
||||
introduction points, and asks it to tell him about her Rendezvous
|
||||
Point (RP). If Bob chooses to answer, he builds an OR circuit to her
|
||||
RP, and tells it to connect him to Alice. The RP joints their
|
||||
circuits together, and begins relaying cells. Alice's 'BEGIN'
|
||||
cells are received directly by Bob's OP, which responds by
|
||||
communication with the local server implementing Bob's service.
|
||||
|
||||
Below, we describe a network-level specification of this service,
|
||||
along with interfaces to make this process transparent to Alice
|
||||
(so long as she is using an OP).
|
||||
|
||||
0.1. Notation, conventions and prerequisites
|
||||
|
||||
In the specifications below, we use the same notation as in
|
||||
"tor-spec.txt". The service specified here also requires the existence of
|
||||
an onion routing network as specified in "tor-spec.txt".
|
||||
|
||||
H(x) is a SHA1 digest of x.
|
||||
PKSign(SK,x) is a PKCS.1-padded RSA signature of x with SK.
|
||||
PKEncrypt(SK,x) is a PKCS.1-padded RSA encryption of x with SK.
|
||||
Public keys are all RSA, and encoded in ASN.1.
|
||||
All integers are stored in network (big-endian) order.
|
||||
All symmetric encryption uses AES in counter mode, except where
|
||||
otherwise noted.
|
||||
|
||||
In all discussions, "Alice" will refer to a user connecting to a
|
||||
location-hidden service, and "Bob" will refer to a user running a
|
||||
location-hidden service.
|
||||
|
||||
0.2. Protocol outline
|
||||
|
||||
1. Bob->Bob's OP: "Offer IP:Port as public-key-name:Port". [configuration]
|
||||
(We do not specify this step; it is left to the implementor of
|
||||
Bob's OP.)
|
||||
|
||||
2. Bob's OP generates keypair and rendezvous service descriptor:
|
||||
"Meet public-key X at introduction point A, B, or C." (signed)
|
||||
|
||||
3. Bob's OP->Introduction point via Tor: [introduction setup]
|
||||
"This pk is me."
|
||||
|
||||
4. Bob's OP->directory service via Tor: publishes Bob's service descriptor
|
||||
[advertisement]
|
||||
|
||||
5. Out of band, Alice receives a y.onion:port address. She opens a
|
||||
SOCKS connection to her OP, and requests y.onion:port.
|
||||
|
||||
6. Alice's OP retrieves Bob's descriptor via Tor: [descriptor lookup.]
|
||||
|
||||
7. Alice's OP chooses a rendezvous point, opens a circuit to that
|
||||
rendezvous point, and establishes a rendezvous circuit. [rendezvous
|
||||
setup.]
|
||||
|
||||
8. Alice connects to the Introduction point via Tor, and tells it about
|
||||
her rendezvous point. (Encrypted to Bob.) [Introduction 1]
|
||||
|
||||
9. The Introduction point passes this on to Bob's OP via Tor, along the
|
||||
introduction circuit. [Introduction 2]
|
||||
|
||||
10. Bob's OP decides whether to connect to Alice, and if so, creates a
|
||||
circuit to Alice's RP via Tor. Establishes a shared circuit.
|
||||
[Rendezvous.]
|
||||
|
||||
11. Alice's OP sends begin cells to Bob's OP. [Connection]
|
||||
|
||||
0.3. Constants and new cell types
|
||||
|
||||
Relay cell types
|
||||
32 -- RELAY_ESTABLISH_INTRO
|
||||
33 -- RELAY_ESTABLISH_RENDEZVOUS
|
||||
34 -- RELAY_INTRODUCE1
|
||||
35 -- RELAY_INTRODUCE2
|
||||
36 -- RELAY_RENDEZVOUS1
|
||||
37 -- RELAY_RENDEZVOUS2
|
||||
38 -- RELAY_INTRO_ESTABLISHED
|
||||
39 -- RELAY_RENDEZVOUS_ESTABLISHED
|
||||
40 -- RELAY_COMMAND_INTRODUCE_ACK
|
||||
|
||||
1. The Protocol
|
||||
|
||||
1.1. Bob configures his local OP.
|
||||
|
||||
We do not specify a format for the OP configuration file. However,
|
||||
OPs SHOULD allow Bob to provide more than one advertised service
|
||||
per OP, and MUST allow Bob to specify one or more virtual ports per
|
||||
service. Bob provides a mapping from each of these virtual ports
|
||||
to a local IP:Port pair.
|
||||
|
||||
1.2. Bob's OP generates service descriptors.
|
||||
|
||||
The first time the OP provides an advertised service, it generates
|
||||
a public/private keypair (stored locally). Periodically, the OP
|
||||
generates service descriptor, containing:
|
||||
|
||||
KL Key length [2 octets]
|
||||
PK Bob's public key [KL octets]
|
||||
TS A timestamp [4 octets]
|
||||
NI Number of introduction points [2 octets]
|
||||
Ipt A list of NUL-terminated OR nicknames [variable]
|
||||
SIG Signature of above fields [variable]
|
||||
|
||||
KL is the length of PK, in octets. (Currently, KL must be 128.)
|
||||
TS is the number of seconds elapsed since Jan 1, 1970.
|
||||
|
||||
[It's ok for Bob to advertise 0 introduction points. He might want
|
||||
to do that if he previously advertised some introduction points,
|
||||
and now he doesn't have any. -RD]
|
||||
|
||||
[Shouldn't the nicknames be hostname:port's instead? That way, Alice's
|
||||
directory servers don't need to know Bob's chosen introduction points.
|
||||
Not important now, but essential if we ever have a non-total-knowledge
|
||||
design. -NM]
|
||||
|
||||
1.3. Bob's OP establishes his introduction points.
|
||||
|
||||
The OP establishes a new introduction circuit to each introduction
|
||||
point. These circuits MUST NOT be used for anything but rendezvous
|
||||
introduction. To establish the introduction, Bob sends a
|
||||
RELAY_ESTABLISH_INTRO cell, containing:
|
||||
|
||||
KL Key length [2 octets]
|
||||
PK Bob's public key [KL octets]
|
||||
HS Hash of session info [20 octets]
|
||||
SIG Signature of above information [variable]
|
||||
|
||||
To prevent replay attacks, the HS field contains a SHA-1 hash based on the
|
||||
shared secret KH between Bob's OP and the introduction point, as
|
||||
follows:
|
||||
HS = H(KH | "INTRODUCE")
|
||||
That is:
|
||||
HS = H(KH | [49 4E 54 52 4F 44 55 43 45])
|
||||
(KH, as specified in tor-spec.txt, is H(g^xy | [00]) .)
|
||||
|
||||
Upon receiving such a cell, the OR first checks that the signature is
|
||||
correct with the included public key. If so, it checks whether HS is
|
||||
correct given the shared state between Bob's OP and the OR. If either
|
||||
check fails, the OP discards the cell; otherwise, it associates the
|
||||
circuit with Bob's public key, and dissociates any other circuits
|
||||
currently associated with PK. On success, the OR sends Bob a
|
||||
RELAY_INTRO_ESTABLISHED cell with an empty payload.
|
||||
|
||||
1.4. Bob's OP advertises his server descriptor
|
||||
|
||||
Bob's OP opens a stream to each directory server's directory port via Tor.
|
||||
(He may re-use old circuits for this.)
|
||||
Over this stream, Bob's OP makes an HTTP 'POST' request, to the URL
|
||||
'/rendezvous/publish' (relative to the directory server's root),
|
||||
containing as its body Bob's service descriptor. Upon receiving a
|
||||
descriptor, the directory server checks the signature, and discards the
|
||||
descriptor if the signature does not match the enclosed public key. Next,
|
||||
the directory server checks the timestamp. If the timestamp is more than
|
||||
24 hours in the past or more than 1 hour in the future, or the directory
|
||||
server already has a newer descriptor with the same public key, the server
|
||||
discards the descriptor. Otherwise, the server discards any older
|
||||
descriptors with the same public key, and associates the new descriptor
|
||||
with the public key. The directory server remembers this descriptor for
|
||||
at least 24 hours after its timestamp. At least every 24 hours, Bob's OP
|
||||
uploads a fresh descriptor.
|
||||
|
||||
1.5. Alice receives a y.onion address
|
||||
|
||||
When Alice receives a pointer to a location-hidden service, it is as a
|
||||
hostname of the form "y.onion", where y is a base-32 encoding of a
|
||||
10-octet hash of Bob's service's public key, computed as follows:
|
||||
|
||||
1. Let H = H(PK).
|
||||
2. Let H' = the first 80 bits of H, considering each octet from
|
||||
most significant bit to least significant bit.
|
||||
2. Generate a 16-character encoding of H', using base32 as defined
|
||||
in RFC 3548.
|
||||
|
||||
(We only use 80 bits instead of the 160 bits from SHA1 because we don't
|
||||
need to worry about man-in-the-middle attacks, and because it will make
|
||||
handling the url's more convenient.)
|
||||
|
||||
[Yes, numbers are allowed at the beginning. See RFC1123. -NM]
|
||||
|
||||
1.6. Alice's OP retrieves a service descriptor
|
||||
|
||||
Alice opens a stream to a directory server via Tor, and makes an HTTP GET
|
||||
request for the document '/rendezvous/<y>', where '<y> is replaced with the
|
||||
encoding of Bob's public key as described above. (She may re-use old
|
||||
circuits for this.) The directory replies with a 404 HTTP response if
|
||||
it does not recognize <y>, and otherwise returns Bob's most recently
|
||||
uploaded service descriptor.
|
||||
|
||||
If Alice's OP receives a 404 response, it tries the other directory
|
||||
servers, and only fails the lookup if none recognizes the public key hash.
|
||||
|
||||
Upon receiving a service descriptor, Alice verifies with the same process
|
||||
as the directory server uses, described above in section 1.4.
|
||||
|
||||
The directory server gives a 400 response if it cannot understand Alice's
|
||||
request.
|
||||
|
||||
Alice should cache the descriptor locally, but should not use
|
||||
descriptors that are more than 24 hours older than their timestamp.
|
||||
[Caching may make her partitionable, but she fetched it anonymously,
|
||||
and we can't very well *not* cache it. -RD]
|
||||
|
||||
1.7. Alice's OP establishes a rendezvous point.
|
||||
|
||||
When Alice requests a connection to a given location-hidden service,
|
||||
and Alice's OP does not have an established circuit to that service,
|
||||
the OP builds a rendezvous circuit. It does this by establishing
|
||||
a circuit to a randomly chosen OR, and sending a
|
||||
RELAY_ESTABLISH_RENDEZVOUS cell to that OR. The body of that cell
|
||||
contains:
|
||||
|
||||
RC Rendezvous cookie [20 octets]
|
||||
|
||||
The rendezvous cookie is an arbitrary 20-byte value, chosen randomly by
|
||||
Alice's OP.
|
||||
|
||||
Upon receiving a RELAY_ESTABLISH_RENDEZVOUS cell, the OR associates the
|
||||
RC with the circuit that sent it. It replies to Alice with an empty
|
||||
RELAY_RENDEZVOUS_ESTABLISHED cell to indicate success.
|
||||
|
||||
Alice's OP MUST NOT use the circuit which sent the cell for any purpose
|
||||
other than rendezvous with the given location-hidden service.
|
||||
|
||||
1.8. Introduction: from Alice's OP to Introduction Point
|
||||
|
||||
Alice builds a separate circuit to one of Bob's chosen introduction
|
||||
points, and sends it a RELAY_INTRODUCE1 cell containing:
|
||||
|
||||
Cleartext
|
||||
PK_ID Identifier for Bob's PK [20 octets]
|
||||
|
||||
Encrypted to Bob's PK:
|
||||
RP Rendezvous point's nickname [20 octets]
|
||||
RC Rendezvous cookie [20 octets]
|
||||
g^x Diffie-Hellman data, part 1 [128 octetes]
|
||||
|
||||
PK_ID is the hash of Bob's public key. RP is NUL-padded.
|
||||
|
||||
The hybrid encryption to Bob's PK works just like the hybrid
|
||||
encryption in CREATE cells (see main spec). Thus the payload of the
|
||||
RELAY_INTRODUCE1 cell on the wire will contain 20+42+16+20+20+128=246
|
||||
bytes.
|
||||
|
||||
1.9. Introduction: From the Introduction Point to Bob's OP
|
||||
|
||||
If the Introduction Point recognizes PK_ID as a public key which has
|
||||
established a circuit for introductions as in 1.3 above, it sends the body
|
||||
of the cell in a new RELAY_INTRODUCE2 cell down the corresponding circuit.
|
||||
(If the PK_ID is unrecognized, the RELAY_INTRODUCE1 cell is discarded.)
|
||||
|
||||
After sending the RELAY_INTRODUCE2 cell, the OR replies to Alice with an
|
||||
empty RELAY_COMMAND_INTRODUCE_ACK cell. If no RELAY_INTRODUCE2 cell can
|
||||
be sent, the OR replies to Alice with a non-empty cell to indicate an
|
||||
error. (The semantics of the cell body may be determined later; the
|
||||
current implementation sends a single '1' byte on failure.)
|
||||
|
||||
When Bob's OP receives the RELAY_INTRODUCE2 cell, it decrypts it with
|
||||
the private key for the corresponding hidden service, and extracts the
|
||||
rendezvous point's nickname, the rendezvous cookie, and the value of g^x
|
||||
chosen by Alice.
|
||||
|
||||
1.10. Rendezvous
|
||||
|
||||
Bob's OP build a new Tor circuit ending at Alice's chosen rendezvous
|
||||
point, and sends a RELAY_RENDEZVOUS1 cell along this circuit, containing:
|
||||
RC Rendezvous cookie [20 octets]
|
||||
g^y Diffie-Hellman [128 octets]
|
||||
KH Handshake digest [20 octets]
|
||||
|
||||
(Bob's OP MUST NOT use this circuit for any other purpose.)
|
||||
|
||||
If the RP recognizes RC, it relays the rest of the cell down the
|
||||
corresponding circuit in a RELAY_RENDEZVOUS2 cell, containing:
|
||||
|
||||
g^y Diffie-Hellman [128 octets]
|
||||
KH Handshake digest [20 octets]
|
||||
|
||||
(If the RP does not recognize the RC, it discards the cell and
|
||||
tears down the circuit.)
|
||||
|
||||
When Alice's OP receives a RELAY_RENDEZVOUS2 cell on a circuit which
|
||||
has sent a RELAY_ESTABLISH_RENDEZVOUS cell but which has not yet received
|
||||
a reply, it uses g^y and H(g^xy) to complete the handshake as in the Tor
|
||||
circuit extend process: they establish a 60-octet string as
|
||||
K = SHA1(g^xy | [00]) | SHA1(g^xy | [01]) | SHA1(g^xy | [02])
|
||||
and generate
|
||||
KH = K[0..15]
|
||||
Kf = K[16..31]
|
||||
Kb = K[32..47]
|
||||
|
||||
Subsequently, the rendezvous point passes relay cells, unchanged, from
|
||||
each of the two circuits to the other. When Alice's OP sends
|
||||
RELAY cells along the circuit, it first encrypts them with the
|
||||
Kf, then with all of the keys for the ORs in Alice's side of the circuit;
|
||||
and when Alice's OP receives RELAY cells from the circuit, it decrypts
|
||||
them with the keys for the ORs in Alice's side of the circuit, then
|
||||
decrypts them with Kb. Bob's OP does the same, with Kf and Kb
|
||||
interchanged.
|
||||
|
||||
1.11. Creating streams
|
||||
|
||||
To open TCP connections to Bob's location-hidden service, Alice's OP sends
|
||||
a RELAY_BEGIN cell along the established circuit, using the special
|
||||
address "", and a chosen port. Bob's OP chooses a destination IP and
|
||||
port, based on the configuration of the service connected to the circuit,
|
||||
and opens a TCP stream. From then on, Bob's OP treats the stream as an
|
||||
ordinary exit connection.
|
||||
[ Except he doesn't include addr in the connected cell or the end
|
||||
cell. -RD]
|
||||
|
||||
Alice MAY send multiple RELAY_BEGIN cells along the circuit, to open
|
||||
multiple streams to Bob. Alice SHOULD NOT send RELAY_BEGIN cells for any
|
||||
other address along her circuit to Bob; if she does, Bob MUST reject them.
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
How to make rendezvous points work
|
||||
|
||||
0. Overview
|
||||
|
||||
Rendezvous points are an implementation of location-hidden services
|
||||
(server anonymity) in the onion routing network. Location-hidden
|
||||
services means Bob can offer a tcp service (say, a webserver) via the
|
||||
onion routing network, without revealing the IP of that service.
|
||||
|
||||
The basic idea is to provide censorship resistance for Bob by allowing
|
||||
him to advertise a variety of onion routers as his public location
|
||||
(nodes known as his Introduction Points, see Section 1). Alice,
|
||||
the client, chooses a node known as a Meeting Point (see Section
|
||||
2). This extra level of indirection is needed so Bob doesn't serve
|
||||
files directly from his public locations (so these nodes don't open
|
||||
themselves up to abuse, eg from serving Nazi propaganda in France). The
|
||||
extra level of indirection also allows Bob to choose which requests
|
||||
to respond to, and which to ignore.
|
||||
|
||||
We provide the necessary glue code so that Alice can view webpages
|
||||
on a location-hidden webserver, and Bob can run a location-hidden
|
||||
server, with minimal invasive changes (see Section 3). Both Alice
|
||||
and Bob must run local onion proxies (OPs) -- software that knows
|
||||
how to talk to the onion routing network.
|
||||
|
||||
The big picture follows. We direct the reader to the rest of the
|
||||
document for more details and explanation.
|
||||
|
||||
1) Bob chooses some Introduction Points, and advertises them on a
|
||||
Distributed Hash Table (DHT).
|
||||
2) Bob establishes onion routing connections to each of his
|
||||
Introduction Points, and waits.
|
||||
3) Alice learns about Bob's service out of band (perhaps Bob gave her
|
||||
a pointer, or she found it on a website). She looks up the details
|
||||
of Bob's service from the DHT.
|
||||
4) Alice chooses and establishes a Meeting Point for this transaction.
|
||||
5) Alice goes to one of Bob's Introduction Points, and gives it a blob
|
||||
(encrypted for Bob) which tells him about herself and the Meeting
|
||||
Point she chose. The Introduction Point sends the blob to Bob.
|
||||
6) Bob chooses whether to ignore the blob, or to onion route to MP.
|
||||
Let's assume the latter.
|
||||
7) MP plugs together Alice and Bob. Note that MP doesn't know (or care)
|
||||
who Alice is, or who Bob is; and it can't read anything they
|
||||
transmit either, because they share a session key.
|
||||
8) Alice sends a 'begin' cell along the circuit. It makes its way
|
||||
to Bob's onion proxy. Bob's onion proxy connects to Bob's webserver.
|
||||
9) Data goes back and forth as usual.
|
||||
|
||||
1. Introduction service
|
||||
|
||||
Bob wants to learn about client requests for communication, but
|
||||
wants to avoid responding unnecessarily to unauthorized clients.
|
||||
Bob's proxy opens a circuit, and tells some onion router on that
|
||||
circuit to expect incoming connections, and notify Bob of them.
|
||||
|
||||
When establishing such an introduction point, Bob provides the onion
|
||||
router with a public "introduction" key. The hash of this public
|
||||
key identifies a unique Bob, and (since Bob is required to sign his
|
||||
messages) prevents anybody else from usurping Bob's introduction
|
||||
point in the future. Additionally, Bob can use the same public key
|
||||
to establish an introduction point on another onion router (OR),
|
||||
and Alice can still be confident that Bob is the same server.
|
||||
|
||||
(The set-up-an-introduction-point command should come via a
|
||||
RELAY_BIND_INTRODUCTION cell. This cell creates a new stream on the
|
||||
circuit from Bob to the introduction point.)
|
||||
|
||||
ORs that support introduction run an introduction service on a
|
||||
separate port. When Alice wants to notify Bob of a meeting point,
|
||||
she connects (directly or via Tor) to the introduction port, and
|
||||
sends the following:
|
||||
|
||||
MEETING REQUEST
|
||||
RSA-OAEP encrypted with server's public key:
|
||||
[20 bytes] Hash of Bob's public key (identifies which Bob to notify)
|
||||
[ 0 bytes] Initial authentication [optional]
|
||||
RSA encrypted with Bob's public key:
|
||||
[16 bytes] Symmetric key for encrypting blob past RSA
|
||||
[ 6 bytes] Meeting point (IP/port)
|
||||
[ 8 bytes] Meeting cookie
|
||||
[ 0 bytes] End-to-end authentication [optional]
|
||||
[98 bytes] g^x part 1 (inside the RSA)
|
||||
[30 bytes] g^x part 2 (symmetrically encrypted)
|
||||
|
||||
The meeting point and meeting cookie allow Bob to contact Alice and
|
||||
prove his identity; the end-to-end authentication enables Bob to
|
||||
decide whether to talk to Alice; the initial authentication enables
|
||||
the introduction point to pre-screen introduction requests before
|
||||
sending them to Bob. (See Section 2 for a discussion of meeting
|
||||
points; see Section 1.1 for an example authentication mechanism.)
|
||||
|
||||
The authentication steps are the appropriate places for the
|
||||
introduction server or Bob to do replay prevention, if desired.
|
||||
|
||||
When the introduction point receives a valid meeting request, it
|
||||
sends the portion intended for Bob along the stream
|
||||
created by Bob's RELAY_BIND_INTRODUCTION. Bob then, at his
|
||||
discretion, connects to Alice's meeting point.
|
||||
|
||||
1.1. An example authentication scheme for introduction services
|
||||
|
||||
Bob makes two short-term secrets SB and SN, and tells the
|
||||
introduction point about SN. Bob gives Alice a cookie consisting
|
||||
of A,B,C such that H(A|SB)=B and H(A|SN)=C. Alice's initial
|
||||
authentication is <A,C>; Alice's end-to-end authentication is <A,B>.
|
||||
|
||||
[Maybe] Bob keeps a replay cache of A values, and doesn't allow any
|
||||
value to be used twice. Over time, Bob rotates SB and SN.
|
||||
|
||||
[Maybe] Each 'A' has an expiration time built in to it.
|
||||
|
||||
In reality, we'll want to pick a scheme that (a) wasn't invented from
|
||||
scratch in an evening, and (b) doesn't require Alice to remember this
|
||||
many bits (see section 3.2).
|
||||
|
||||
2. Meeting points
|
||||
|
||||
For Bob to actually reply to Alice, Alice first establishes a
|
||||
circuit to an onion router R, and sends a RELAY_BIND_MEETING cell
|
||||
to that onion router. The RELAY_BIND_MEETING cell contains a
|
||||
'Meeting cookie' (MC) that Bob can use to authenticate to R. R
|
||||
remembers the cookie and associates it with Alice.
|
||||
|
||||
Later, Bob also routes to R and sends R a RELAY_JOIN_MEETING cell with
|
||||
the meeting cookie MC. After this point, R routes all traffic from
|
||||
Bob's circuit or Alice's circuit as if the two circuits were joined:
|
||||
any RELAY cells that are not for a recognized topic are passed down
|
||||
Alice or Bob's circuit. Bob's first cell to Alice contains g^y.
|
||||
|
||||
To prevent R from reading their traffic, Alice and Bob derive two
|
||||
end-to-end keys from g^{xy}, and they each treat R as just another
|
||||
hop on the circuit. (These keys are used in addition to the series
|
||||
of encryption keys already in use on Alice and Bob's circuits.)
|
||||
|
||||
Bob's OP accepts RELAY_BEGIN, RELAY_DATA, RELAY_END, and
|
||||
RELAY_SENDME cells from Alice. Alice's OP accepts RELAY_DATA,
|
||||
RELAY_END, and RELAY_SENDME cells from Bob. All RELAY_BEGIN cells
|
||||
to Bob must have target IP and port of zero; Bob's OP will redirect
|
||||
them to the actual target IP and port of Bob's server.
|
||||
|
||||
Alice and Bob's OPs disallow CREATE or RELAY_EXTEND cells as usual.
|
||||
|
||||
3. Application interface
|
||||
|
||||
3.1. Application interface: server side
|
||||
|
||||
Bob has a service that he wants to offer to the world but keep its
|
||||
location hidden. He configures his local OP to know about this
|
||||
service, including the following data:
|
||||
|
||||
Local IP and port of the service
|
||||
Strategy for choosing introduction points
|
||||
(for now, just randomly pick among the ORs offering it)
|
||||
Strategy for user authentication
|
||||
(for now, just accept all users)
|
||||
Public (RSA) key (one for each service Bob offers)
|
||||
|
||||
Bob chooses a set of N Introduction servers on which to advertise
|
||||
his service.
|
||||
|
||||
We assume the existence of a robust decentralized efficient lookup
|
||||
system (call it "DHT" for distributed hash table -- note that the
|
||||
onion routers can run nodes). Bob publishes
|
||||
* Bob's Public Key for that service
|
||||
* Expiration date ("don't use after")
|
||||
* Introduction server 0 ... Introduction server N
|
||||
(All signed by Bob's Public Key)
|
||||
into DHT, indexed by the hash of Bob's Public Key. Bob should
|
||||
periodically republish his introduction information with a new
|
||||
expiration date (and possibly with new/different introduction servers
|
||||
if he wants), so Alice can trust that DHT is giving her an up-to-date
|
||||
version. The Chord CFS paper describes a sample DHT that allows
|
||||
authenticated updating.
|
||||
|
||||
3.2. Application interface: client side
|
||||
|
||||
We require that the client interface remain a SOCKS proxy, and we
|
||||
require that Alice shouldn't have to modify her applications. Thus
|
||||
we encode all of the necessary information into the hostname (more
|
||||
correctly, fqdn) that Alice uses, eg when clicking on a url in her
|
||||
browser.
|
||||
|
||||
To establish a connection to Bob, Alice needs to know an Introduction
|
||||
point, Bob's PK, and some authentication cookie. Because encoding this
|
||||
information into the hostname will be too long for a typical hostname,
|
||||
we instead use a layer of indirection. We encode a hash of Bob's PK
|
||||
(10 bytes is sufficient since we're not worrying about collisions),
|
||||
and also the authentication token (empty for now). Location-hidden
|
||||
services use the special top level domain called '.onion': thus
|
||||
hostnames take the form x.y.onion where x is the hash of PK, and y
|
||||
is the authentication cookie. If no cookie is required, the hostname
|
||||
can simply be of the form x.onion. Assuming only case insensitive
|
||||
alphanumeric and hyphen, we get a bit more than 6 bits encoded
|
||||
per character, meaning the x part of the hostname will be about
|
||||
13 characters.
|
||||
|
||||
Alice's onion proxy examines hostnames and recognizes when they're
|
||||
destined for a hidden server. If so, it decodes the PK and performs
|
||||
the steps in Section 0 above.
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%deffont "standard" xfont "comic sans ms-medium-r"
|
||||
%%deffont "thick" xfont "arial black-medium-r"
|
||||
%%deffont "typewriter" xfont "courier new-bold-r"
|
||||
%%deffont "type2writer" xfont "arial narrow-bold-r"
|
||||
%%deffont "standard" tfont "standard.ttf", tmfont "kochi-mincho.ttf"
|
||||
%%deffont "thick" tfont "thick.ttf", tmfont "goth.ttf"
|
||||
%%deffont "typewriter" tfont "typewriter.ttf", tmfont "goth.ttf"
|
||||
%deffont "standard" xfont "helvetica-medium-r", tfont "arial.ttf", tmfont "times.ttf"
|
||||
%deffont "thick" xfont "helvetica-bold-r", tfont "arialbd.ttf", tmfont "hoso6.ttf"
|
||||
%deffont "italic" xfont "helvetica-italic-r", tfont "ariali.ttf", tmfont "hoso6.ttf"
|
||||
%deffont "typewriter" xfont "courier-medium-r", tfont "typewriter.ttf", tmfont "hoso6.ttf"
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%
|
||||
%% Default settings per each line numbers.
|
||||
%%
|
||||
%default 1 leftfill, size 8, fore "black", back "white", font "thick", hgap 1
|
||||
%default 2 size 8, vgap 10, prefix " ", ccolor "black"
|
||||
%default 3 size 6, bar "gray70", vgap 0
|
||||
%default 4 size 6, fore "black", vgap 0, prefix " ", font "standard"
|
||||
%%
|
||||
%%default 1 area 90 90, leftfill, size 9, fore "yellow", back "blue", font "thick"
|
||||
%%default 2 size 9, vgap 10, prefix " "
|
||||
%%default 3 size 7, bar "gray70", vgap 10
|
||||
%%default 4 size 7, vgap 30, prefix " ", font "standard"
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%
|
||||
%% Default settings that are applied to TAB-indented lines.
|
||||
%%
|
||||
%tab 1 size 5, vgap 40, prefix " ", icon arc "red" 50
|
||||
%tab 2 size 4, vgap 35, prefix " ", icon delta3 "blue" 40
|
||||
%tab 3 size 3, vgap 35, prefix " ", icon dia "DarkViolet" 40
|
||||
%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
%nodefault
|
||||
%center, size 9, font "thick", back "white", fore "black"
|
||||
|
||||
|
||||
|
||||
Tor:
|
||||
%size 8
|
||||
Next-generation Onion Routing
|
||||
|
||||
|
||||
%size 7
|
||||
Roger Dingledine
|
||||
Nick Mathewson
|
||||
Paul Syverson
|
||||
|
||||
%%The Free Haven Project
|
||||
%%%font "typewriter", fore "blue"
|
||||
%%http://freehaven.net/
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Low-latency anonymity system
|
||||
|
||||
%leftfill
|
||||
Deployed: 19 nodes, hundreds of users (?)
|
||||
|
||||
Many improvements on earlier design
|
||||
|
||||
Free software -- available source code
|
||||
|
||||
Design is not covered by earlier onion routing
|
||||
patent
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Perfect forward secrecy
|
||||
|
||||
|
||||
Telescoping circuit
|
||||
|
||||
negotiates keys at each hop
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%page
|
||||
%%
|
||||
%%Separation from "protocol cleaning"
|
||||
%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
No mixing, padding, traffic shaping (yet)
|
||||
|
||||
|
||||
Please show us they're worth the usability tradeoff
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%page
|
||||
%%
|
||||
%%Many TCP streams can share one circuit
|
||||
%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Congestion control
|
||||
|
||||
|
||||
Simple rate limiting
|
||||
|
||||
Plus have to keep internal nodes from overflowing
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Directory servers
|
||||
|
||||
|
||||
Approve new servers
|
||||
|
||||
Tell clients who's up right now
|
||||
|
||||
plus their keys, location, etc
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Variable exit policies
|
||||
|
||||
|
||||
Each server allows different outgoing connections
|
||||
|
||||
E.g. no servers allow outgoing mail currently
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
End-to-end integrity checking
|
||||
|
||||
|
||||
In previous onion routing, an insider could change
|
||||
the text being transmitted:
|
||||
|
||||
"dir" => "rm *"
|
||||
|
||||
Even an external adversary could do this!
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Rendezvous points
|
||||
|
||||
|
||||
allow hidden services
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
Differences / limitations
|
||||
|
||||
|
||||
We're TCP-only, not all IP (but we're user-space and very portable)
|
||||
|
||||
Not peer-to-peer
|
||||
|
||||
No protocol normalization
|
||||
|
||||
%%Not unobservable
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%page
|
||||
|
||||
We have working code
|
||||
|
||||
|
||||
Plus a design document,
|
||||
and a byte-level specification
|
||||
|
||||
%size 9
|
||||
http://freehaven.net/tor/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,616 @@
|
||||
sw$Id$
|
||||
|
||||
Tor Spec
|
||||
|
||||
Note: This is an attempt to specify Tor as it exists as implemented in
|
||||
early March, 2004. It is not recommended that others implement this
|
||||
design as it stands; future versions of Tor will implement improved
|
||||
protocols.
|
||||
|
||||
This is not a design document; most design criteria are not examined. For
|
||||
more information on why Tor acts as it does, see tor-design.pdf.
|
||||
|
||||
TODO: (very soon)
|
||||
- EXTEND cells should have hostnames or nicknames, so that OPs never
|
||||
resolve OR hostnames. Else DNS servers can give different answers to
|
||||
different OPs, and compromise their anonymity.
|
||||
- Alternatively, directories should include IPs.
|
||||
- REASON_CONNECTFAILED should include an IP.
|
||||
- Copy prose from tor-design to make everything more readable.
|
||||
|
||||
|
||||
0. Notation:
|
||||
|
||||
PK -- a public key.
|
||||
SK -- a private key
|
||||
K -- a key for a symmetric cypher
|
||||
|
||||
a|b -- concatenation of 'a' and 'b'.
|
||||
|
||||
[A0 B1 C2] -- a three-byte sequence, containing the bytes with
|
||||
hexadecimal values A0, B1, and C2, in that order.
|
||||
|
||||
All numeric values are encoded in network (big-endian) order.
|
||||
|
||||
Unless otherwise specified, all symmetric ciphers are AES in counter
|
||||
mode, with an IV of all 0 bytes. Asymmetric ciphers are either RSA
|
||||
with 1024-bit keys and exponents of 65537, or DH with the safe prime
|
||||
from rfc2409, section 6.2, whose hex representation is:
|
||||
|
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
|
||||
"8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
|
||||
"302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
|
||||
"A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
|
||||
"49286651ECE65381FFFFFFFFFFFFFFFF"
|
||||
|
||||
1. System overview
|
||||
|
||||
Onion Routing is a distributed overlay network designed to anonymize
|
||||
low-latency TCP-based applications such as web browsing, secure shell,
|
||||
and instant messaging. Clients choose a path through the network and
|
||||
build a ``circuit'', in which each node (or ``onion router'' or ``OR'')
|
||||
in the path knows its predecessor and successor, but no other nodes in
|
||||
the circuit. Traffic flowing down the circuit is sent in fixed-size
|
||||
``cells'', which are unwrapped by a symmetric key at each node (like
|
||||
the layers of an onion) and relayed downstream.
|
||||
|
||||
2. Connections
|
||||
|
||||
There are two ways to connect to an onion router (OR). The first is
|
||||
as an onion proxy (OP), which allows the OP to authenticate the OR
|
||||
without authenticating itself. The second is as another OR, which
|
||||
allows mutual authentication.
|
||||
|
||||
Tor uses TLS for link encryption. All implementations MUST support
|
||||
the TLS ciphersuite "TLS_EDH_RSA_WITH_DES_192_CBC3_SHA", and SHOULD
|
||||
support "TLS_DHE_RSA_WITH_AES_128_CBC_SHA" if it is available.
|
||||
Implementations MAY support other ciphersuites, but MUST NOT
|
||||
support any suite without ephemeral keys, symmetric keys of at
|
||||
least 128 bits, and digests of at least 160 bits.
|
||||
|
||||
An OR always sends a self-signed X.509 certificate whose commonName
|
||||
is the server's nickname, and whose public key is in the server
|
||||
directory.
|
||||
|
||||
All parties receiving certificates must confirm that the public
|
||||
key is as it appears in the server directory, and close the
|
||||
connection if it is not.
|
||||
|
||||
Once a TLS connection is established, the two sides send cells
|
||||
(specified below) to one another. Cells are sent serially. All
|
||||
cells are 512 bytes long. Cells may be sent embedded in TLS
|
||||
records of any size or divided across TLS records, but the framing
|
||||
of TLS records MUST NOT leak information about the type or contents
|
||||
of the cells.
|
||||
|
||||
OR-to-OR connections are never deliberately closed. When an OR
|
||||
starts or receives a new directory, it tries to open new
|
||||
connections to any OR it is not already connected to.
|
||||
|
||||
OR-to-OP connections are not permanent. An OP should close a
|
||||
connection to an OR if there are no circuits running over the
|
||||
connection, and an amount of time (KeepalivePeriod, defaults to 5
|
||||
minutes) has passed.
|
||||
|
||||
3. Cell Packet format
|
||||
|
||||
The basic unit of communication for onion routers and onion
|
||||
proxies is a fixed-width "cell". Each cell contains the following
|
||||
fields:
|
||||
|
||||
CircID [2 bytes]
|
||||
Command [1 byte]
|
||||
Payload (padded with 0 bytes) [509 bytes]
|
||||
[Total size: 512 bytes]
|
||||
|
||||
The CircID field determines which circuit, if any, the cell is
|
||||
associated with.
|
||||
|
||||
The 'Command' field holds one of the following values:
|
||||
0 -- PADDING (Padding) (See Sec 6.2)
|
||||
1 -- CREATE (Create a circuit) (See Sec 4)
|
||||
2 -- CREATED (Acknowledge create) (See Sec 4)
|
||||
3 -- RELAY (End-to-end data) (See Sec 5)
|
||||
4 -- DESTROY (Stop using a circuit) (See Sec 4)
|
||||
|
||||
The interpretation of 'Payload' depends on the type of the cell.
|
||||
PADDING: Payload is unused.
|
||||
CREATE: Payload contains the handshake challenge.
|
||||
CREATED: Payload contains the handshake response.
|
||||
RELAY: Payload contains the relay header and relay body.
|
||||
DESTROY: Payload is unused.
|
||||
Upon receiving any other value for the command field, an OR must
|
||||
drop the cell.
|
||||
|
||||
The payload is padded with 0 bytes.
|
||||
|
||||
PADDING cells are currently used to implement connection keepalive.
|
||||
ORs and OPs send one another a PADDING cell every few minutes.
|
||||
|
||||
CREATE, CREATED, and DESTROY cells are used to manage circuits;
|
||||
see section 4 below.
|
||||
|
||||
RELAY cells are used to send commands and data along a circuit; see
|
||||
section 5 below.
|
||||
|
||||
4. Circuit management
|
||||
|
||||
4.1. CREATE and CREATED cells
|
||||
|
||||
Users set up circuits incrementally, one hop at a time. To create a
|
||||
new circuit, OPs send a CREATE cell to the first node, with the
|
||||
first half of the DH handshake; that node responds with a CREATED
|
||||
cell with the second half of the DH handshake plus the first 20 bytes
|
||||
of derivative key data (see section 4.2). To extend a circuit past
|
||||
the first hop, the OP sends an EXTEND relay cell (see section 5)
|
||||
which instructs the last node in the circuit to send a CREATE cell
|
||||
to extend the circuit.
|
||||
|
||||
The payload for a CREATE cell is an 'onion skin', which consists
|
||||
of the first step of the DH handshake data (also known as g^x).
|
||||
|
||||
The data is encrypted to Bob's PK as follows: Suppose Bob's PK is
|
||||
L octets long. If the data to be encrypted is shorter than L-42,
|
||||
then it is encrypted directly (with OAEP padding). If the data is at
|
||||
least as long as L-42, then a randomly generated 16-byte symmetric
|
||||
key is prepended to the data, after which the first L-16-42 bytes
|
||||
of the data are encrypted with Bob's PK; and the rest of the data is
|
||||
encrypted with the symmetric key.
|
||||
|
||||
So in this case, the onion skin on the wire looks like:
|
||||
RSA-encrypted:
|
||||
OAEP padding [42 bytes]
|
||||
Symmetric key [16 bytes]
|
||||
First part of g^x [70 bytes]
|
||||
Symmetrically encrypted:
|
||||
Second part of g^x [58 bytes]
|
||||
|
||||
The relay payload for an EXTEND relay cell consists of:
|
||||
Address [4 bytes]
|
||||
Port [2 bytes]
|
||||
Onion skin [186 bytes]
|
||||
|
||||
The port and address field denote the IPV4 address and port of the
|
||||
next onion router in the circuit.
|
||||
|
||||
The payload for a CREATED cell, or the relay payload for an
|
||||
EXTENDED cell, contains:
|
||||
DH data (g^y) [128 bytes]
|
||||
Derivative key data (KH) [20 bytes] <see 4.2 below>
|
||||
|
||||
The CircID for a CREATE cell is an arbitrarily chosen 2-byte
|
||||
integer, selected by the node (OP or OR) that sends the CREATE
|
||||
cell. To prevent CircID collisions, when one OR sends a CREATE
|
||||
cell to another, it chooses from only one half of the possible
|
||||
values based on the ORs' nicknames: if the sending OR has a
|
||||
lexicographically earlier nickname, it chooses a CircID with a high
|
||||
bit of 0; otherwise, it chooses a CircID with a high bit of 1.
|
||||
|
||||
4.2. Setting circuit keys
|
||||
|
||||
Once the handshake between the OP and an OR is completed, both
|
||||
servers can now calculate g^xy with ordinary DH. From the base key
|
||||
material g^xy, they compute derivative key material as follows.
|
||||
First, the server represents g^xy as a big-endian unsigned integer.
|
||||
Next, the server computes 60 bytes of key data as K = SHA1(g^xy |
|
||||
[00]) | SHA1(g^xy | [01]) | SHA1(g^xy | [02]) where "00" is a single
|
||||
octet whose value is zero, [01] is a single octet whose value is
|
||||
one, etc. The first 20 bytes of K form KH, the next 16 bytes of K
|
||||
form Kf, and the next 16 bytes of K form Kb.
|
||||
|
||||
KH is used in the handshake response to demonstrate knowledge of the
|
||||
computed shared key. Kf is used to encrypt the stream of data going
|
||||
from the OP to the OR, and Kb is used to encrypt the stream of data
|
||||
going from the OR to the OP.
|
||||
|
||||
4.3. Creating circuits
|
||||
|
||||
When creating a circuit through the network, the circuit creator
|
||||
(OP) performs the following steps:
|
||||
|
||||
1. Choose an onion router as an exit node (R_N), such that the onion
|
||||
router's exit policy does not exclude all pending streams
|
||||
that need a circuit.
|
||||
|
||||
2. Choose a chain of (N-1) chain of N onion routers
|
||||
(R_1...R_N-1) to constitute the path, such that no router
|
||||
appears in the path twice.
|
||||
|
||||
3. If not already connected to the first router in the chain,
|
||||
open a new connection to that router.
|
||||
|
||||
4. Choose a circID not already in use on the connection with the
|
||||
first router in the chain; send a CREATE cell along the
|
||||
connection, to be received by the first onion router.
|
||||
|
||||
5. Wait until a CREATED cell is received; finish the handshake
|
||||
and extract the forward key Kf_1 and the backward key Kb_1.
|
||||
|
||||
6. For each subsequent onion router R (R_2 through R_N), extend
|
||||
the circuit to R.
|
||||
|
||||
To extend the circuit by a single onion router R_M, the OP performs
|
||||
these steps:
|
||||
|
||||
1. Create an onion skin, encrypting the RSA-encrypted part with
|
||||
R's public key.
|
||||
|
||||
2. Encrypt and send the onion skin in a relay EXTEND cell along
|
||||
the circuit (see section 5).
|
||||
|
||||
3. When a relay EXTENDED cell is received, verify KH, and
|
||||
calculate the shared keys. The circuit is now extended.
|
||||
|
||||
When an onion router receives an EXTEND relay cell, it sends a CREATE
|
||||
cell to the next onion router, with the enclosed onion skin as its
|
||||
payload. The initiating onion router chooses some circID not yet
|
||||
used on the connection between the two onion routers. (But see
|
||||
section 4.1. above, concerning choosing circIDs based on
|
||||
lexicographic order of nicknames.)
|
||||
|
||||
As an extension (called router twins), if the desired next onion
|
||||
router R in the circuit is down, and some other onion router R'
|
||||
has the same public keys as R, then it's ok to extend to R' rather than R.
|
||||
|
||||
When an onion router receives a CREATE cell, if it already has a
|
||||
circuit on the given connection with the given circID, it drops the
|
||||
cell. Otherwise, after receiving the CREATE cell, it completes the
|
||||
DH handshake, and replies with a CREATED cell. Upon receiving a
|
||||
CREATED cell, an onion router packs it payload into an EXTENDED relay
|
||||
cell (see section 5), and sends that cell up the circuit. Upon
|
||||
receiving the EXTENDED relay cell, the OP can retrieve g^y.
|
||||
|
||||
(As an optimization, OR implementations may delay processing onions
|
||||
until a break in traffic allows time to do so without harming
|
||||
network latency too greatly.)
|
||||
|
||||
4.4. Tearing down circuits
|
||||
|
||||
Circuits are torn down when an unrecoverable error occurs along
|
||||
the circuit, or when all streams on a circuit are closed and the
|
||||
circuit's intended lifetime is over. Circuits may be torn down
|
||||
either completely or hop-by-hop.
|
||||
|
||||
To tear down a circuit completely, an OR or OP sends a DESTROY
|
||||
cell to the adjacent nodes on that circuit, using the appropriate
|
||||
direction's circID.
|
||||
|
||||
Upon receiving an outgoing DESTROY cell, an OR frees resources
|
||||
associated with the corresponding circuit. If it's not the end of
|
||||
the circuit, it sends a DESTROY cell for that circuit to the next OR
|
||||
in the circuit. If the node is the end of the circuit, then it tears
|
||||
down any associated edge connections (see section 5.1).
|
||||
|
||||
After a DESTROY cell has been processed, an OR ignores all data or
|
||||
destroy cells for the corresponding circuit.
|
||||
|
||||
(The rest of this section is not currently used; on errors, circuits
|
||||
are destroyed, not truncated.)
|
||||
|
||||
To tear down part of a circuit, the OP may send a RELAY_TRUNCATE cell
|
||||
signaling a given OR (Stream ID zero). That OR sends a DESTROY
|
||||
cell to the next node in the circuit, and replies to the OP with a
|
||||
RELAY_TRUNCATED cell.
|
||||
|
||||
When an unrecoverable error occurs along one connection in a
|
||||
circuit, the nodes on either side of the connection should, if they
|
||||
are able, act as follows: the node closer to the OP should send a
|
||||
RELAY_TRUNCATED cell towards the OP; the node farther from the OP
|
||||
should send a DESTROY cell down the circuit.
|
||||
|
||||
4.5. Routing relay cells
|
||||
|
||||
When an OR receives a RELAY cell, it checks the cell's circID and
|
||||
determines whether it has a corresponding circuit along that
|
||||
connection. If not, the OR drops the RELAY cell.
|
||||
|
||||
Otherwise, if the OR is not at the OP edge of the circuit (that is,
|
||||
either an 'exit node' or a non-edge node), it de/encrypts the payload
|
||||
with AES/CTR, as follows:
|
||||
'Forward' relay cell (same direction as CREATE):
|
||||
Use Kf as key; encrypt.
|
||||
'Back' relay cell (opposite direction from CREATE):
|
||||
Use Kb as key; decrypt.
|
||||
|
||||
The OR then decides whether it recognizes the relay cell, by
|
||||
inspecting the payload as described in section 5.1 below. If the OR
|
||||
recognizes the cell, it processes the contents of the relay cell.
|
||||
Otherwise, it passes the decrypted relay cell along the circuit if
|
||||
the circuit continues. If the OR at the end of the circuit
|
||||
encounters an unrecognized relay cell, an error has occurred: the OR
|
||||
sends a DESTROY cell to tear down the circuit.
|
||||
|
||||
When a relay cell arrives at an OP, it the OP encrypts the length and
|
||||
payload fields with AES/CTR as follows:
|
||||
OP receives data cell:
|
||||
For I=N...1,
|
||||
Encrypt with Kb_I. If the payload is recognized (see
|
||||
section 5.1), then stop and process the payload.
|
||||
|
||||
For more information, see section 5 below.
|
||||
|
||||
5. Application connections and stream management
|
||||
|
||||
5.1. Relay cells
|
||||
|
||||
Within a circuit, the OP and the exit node use the contents of
|
||||
RELAY packets to tunnel end-to-end commands and TCP connections
|
||||
("Streams") across circuits. End-to-end commands can be initiated
|
||||
by either edge; streams are initiated by the OP.
|
||||
|
||||
The payload of each unencrypted RELAY cell consists of:
|
||||
Relay command [1 byte]
|
||||
'Recognized' [2 bytes]
|
||||
StreamID [2 bytes]
|
||||
Digest [4 bytes]
|
||||
Length [2 bytes]
|
||||
Data [498 bytes]
|
||||
|
||||
The relay commands are:
|
||||
1 -- RELAY_BEGIN
|
||||
2 -- RELAY_DATA
|
||||
3 -- RELAY_END
|
||||
4 -- RELAY_CONNECTED
|
||||
5 -- RELAY_SENDME
|
||||
6 -- RELAY_EXTEND
|
||||
7 -- RELAY_EXTENDED
|
||||
8 -- RELAY_TRUNCATE
|
||||
9 -- RELAY_TRUNCATED
|
||||
10 -- RELAY_DROP
|
||||
|
||||
The 'Recognized' field in any unencrypted relay payload is always set
|
||||
to zero; the 'digest' field is computed as the first four bytes of a
|
||||
SHA-1 digest of the rest of the RELAY cell's payload, taken with the
|
||||
digest field set to zero.
|
||||
|
||||
When the 'recognized' field of a RELAY cell is zero, and the digest
|
||||
is correct, the cell is considered "recognized" for the purposes of
|
||||
decryption (see section 4.5 above).
|
||||
|
||||
All RELAY cells pertaining to the same tunneled stream have the
|
||||
same stream ID. StreamIDs are chosen randomly by the OP. RELAY
|
||||
cells that affect the entire circuit rather than a particular
|
||||
stream use a StreamID of zero.
|
||||
|
||||
The 'Length' field of a relay cell contains the number of bytes in
|
||||
the relay payload which contain real payload data. The remainder of
|
||||
the payload is padded with random bytes.
|
||||
|
||||
5.2. Opening streams and transferring data
|
||||
|
||||
To open a new anonymized TCP connection, the OP chooses an open
|
||||
circuit to an exit that may be able to connect to the destination
|
||||
address, selects an arbitrary StreamID not yet used on that circuit,
|
||||
and constructs a RELAY_BEGIN cell with a payload encoding the address
|
||||
and port of the destination host. The payload format is:
|
||||
|
||||
ADDRESS | ':' | PORT | [00]
|
||||
|
||||
where ADDRESS is be a DNS hostname, or an IPv4 address in
|
||||
dotted-quad format; and where PORT is encoded in decimal.
|
||||
|
||||
[What is the [00] for? -NM]
|
||||
|
||||
Upon receiving this cell, the exit node resolves the address as
|
||||
necessary, and opens a new TCP connection to the target port. If the
|
||||
address cannot be resolved, or a connection can't be established, the
|
||||
exit node replies with a RELAY_END cell. (See 5.4 below.)
|
||||
Otherwise, the exit node replies with a RELAY_CONNECTED cell, whose
|
||||
payload is the 4-byte IP address to which the connection was made.
|
||||
|
||||
The OP waits for a RELAY_CONNECTED cell before sending any data.
|
||||
Once a connection has been established, the OP and exit node
|
||||
package stream data in RELAY_DATA cells, and upon receiving such
|
||||
cells, echo their contents to the corresponding TCP stream.
|
||||
RELAY_DATA cells sent to unrecognized streams are dropped.
|
||||
|
||||
Relay RELAY_DROP cells are long-range dummies; upon receiving such
|
||||
a cell, the OR or OP must drop it.
|
||||
|
||||
5.3. Closing streams
|
||||
|
||||
When an anonymized TCP connection is closed, or an edge node
|
||||
encounters error on any stream, it sends a 'RELAY_END' cell along the
|
||||
circuit (if possible) and closes the TCP connection immediately. If
|
||||
an edge node receives a 'RELAY_END' cell for any stream, it closes
|
||||
the TCP connection completely, and sends nothing more along the
|
||||
circuit for that stream.
|
||||
|
||||
The payload of a RELAY_END cell begins with a single 'reason' byte to
|
||||
describe why the stream is closing, plus optional data (depending on
|
||||
the reason.) The values are:
|
||||
|
||||
1 -- REASON_MISC (catch-all for unlisted reasons)
|
||||
2 -- REASON_RESOLVEFAILED (couldn't look up hostname)
|
||||
3 -- REASON_CONNECTFAILED (couldn't connect to host/port)
|
||||
4 -- REASON_EXITPOLICY (OR refuses to connect to host or port)
|
||||
5 -- REASON_DESTROY (circuit is being destroyed [???-NM])
|
||||
6 -- REASON_DONE (anonymized TCP connection was closed)
|
||||
7 -- REASON_TIMEOUT (OR timed out while connecting [???-NM])
|
||||
|
||||
(With REASON_EXITPOLICY, the 4-byte IP address forms the optional
|
||||
data; no other reason currently has extra data.)
|
||||
|
||||
|
||||
*** [The rest of this section describes unimplemented functionality.]
|
||||
|
||||
Because TCP connections can be half-open, we follow an equivalent
|
||||
to TCP's FIN/FIN-ACK/ACK protocol to close streams.
|
||||
|
||||
An exit connection can have a TCP stream in one of three states:
|
||||
'OPEN', 'DONE_PACKAGING', and 'DONE_DELIVERING'. For the purposes
|
||||
of modeling transitions, we treat 'CLOSED' as a fourth state,
|
||||
although connections in this state are not, in fact, tracked by the
|
||||
onion router.
|
||||
|
||||
A stream begins in the 'OPEN' state. Upon receiving a 'FIN' from
|
||||
the corresponding TCP connection, the edge node sends a 'RELAY_FIN'
|
||||
cell along the circuit and changes its state to 'DONE_PACKAGING'.
|
||||
Upon receiving a 'RELAY_FIN' cell, an edge node sends a 'FIN' to
|
||||
the corresponding TCP connection (e.g., by calling
|
||||
shutdown(SHUT_WR)) and changing its state to 'DONE_DELIVERING'.
|
||||
|
||||
When a stream in already in 'DONE_DELIVERING' receives a 'FIN', it
|
||||
also sends a 'RELAY_FIN' along the circuit, and changes its state
|
||||
to 'CLOSED'. When a stream already in 'DONE_PACKAGING' receives a
|
||||
'RELAY_FIN' cell, it sends a 'FIN' and changes its state to
|
||||
'CLOSED'.
|
||||
|
||||
If an edge node encounters an error on any stream, it sends a
|
||||
'RELAY_END' cell (if possible) and closes the stream immediately.
|
||||
|
||||
|
||||
6. Flow control
|
||||
|
||||
6.1. Link throttling
|
||||
|
||||
Each node should do appropriate bandwidth throttling to keep its
|
||||
user happy.
|
||||
|
||||
Communicants rely on TCP's default flow control to push back when they
|
||||
stop reading.
|
||||
|
||||
6.2. Link padding
|
||||
|
||||
Currently nodes are not required to do any sort of link padding or
|
||||
dummy traffic. Because strong attacks exist even with link padding,
|
||||
and because link padding greatly increases the bandwidth requirements
|
||||
for running a node, we plan to leave out link padding until this
|
||||
tradeoff is better understood.
|
||||
|
||||
6.3. Circuit-level flow control
|
||||
|
||||
To control a circuit's bandwidth usage, each OR keeps track of
|
||||
two 'windows', consisting of how many RELAY_DATA cells it is
|
||||
allowed to package for transmission, and how many RELAY_DATA cells
|
||||
it is willing to deliver to streams outside the network.
|
||||
Each 'window' value is initially set to 1000 data cells
|
||||
in each direction (cells that are not data cells do not affect
|
||||
the window). When an OR is willing to deliver more cells, it sends a
|
||||
RELAY_SENDME cell towards the OP, with Stream ID zero. When an OR
|
||||
receives a RELAY_SENDME cell with stream ID zero, it increments its
|
||||
packaging window.
|
||||
|
||||
Each of these cells increments the corresponding window by 100.
|
||||
|
||||
The OP behaves identically, except that it must track a packaging
|
||||
window and a delivery window for every OR in the circuit.
|
||||
|
||||
An OR or OP sends cells to increment its delivery window when the
|
||||
corresponding window value falls under some threshold (900).
|
||||
|
||||
If a packaging window reaches 0, the OR or OP stops reading from
|
||||
TCP connections for all streams on the corresponding circuit, and
|
||||
sends no more RELAY_DATA cells until receiving a RELAY_SENDME cell.
|
||||
[this stuff is badly worded; copy in the tor-design section -RD]
|
||||
|
||||
6.4. Stream-level flow control
|
||||
|
||||
Edge nodes use RELAY_SENDME cells to implement end-to-end flow
|
||||
control for individual connections across circuits. Similarly to
|
||||
circuit-level flow control, edge nodes begin with a window of cells
|
||||
(500) per stream, and increment the window by a fixed value (50)
|
||||
upon receiving a RELAY_SENDME cell. Edge nodes initiate RELAY_SENDME
|
||||
cells when both a) the window is <= 450, and b) there are less than
|
||||
ten cell payloads remaining to be flushed at that edge.
|
||||
|
||||
|
||||
7. Directories and routers
|
||||
|
||||
7.1. Extensible information format
|
||||
|
||||
Router descriptors and directories both obey the following lightweight
|
||||
extensible information format.
|
||||
|
||||
The highest level object is a Document, which consists of one or more Items.
|
||||
Every Item begins with a KeywordLine, followed by one or more Objects. A
|
||||
KeywordLine begins with a Keyword, optionally followed by a space and more
|
||||
non-newline characters, and ends with a newline. A Keyword is a sequence of
|
||||
one or more characters in the set [A-Za-z0-9-]. An Object is a block of
|
||||
encoded data in pseudo-Open-PGP-style armor. (cf. RFC 2440)
|
||||
|
||||
More formally:
|
||||
|
||||
Document ::= (Item | NL)+
|
||||
Item ::= KeywordLine Object*
|
||||
KeywordLine ::= Keyword NL | Keyword SP ArgumentsChar+ NL
|
||||
Keyword = KeywordChar+
|
||||
KeywordChar ::= 'A' ... 'Z' | 'a' ... 'z' | '0' ... '9' | '-'
|
||||
ArgumentChar ::= any printing ASCII character except NL.
|
||||
Object ::= BeginLine Base-64-encoded-data EndLine
|
||||
BeginLine ::= "-----BEGIN " Keyword "-----" NL
|
||||
EndLine ::= "-----END " Keyword "-----" NL
|
||||
|
||||
The BeginLine and EndLine of an Object must use the same keyword.
|
||||
|
||||
When interpreting a Document, software MUST reject any document containing a
|
||||
KeywordLine that starts with a keyword it doesn't recognize.
|
||||
|
||||
7.1. Router descriptor format.
|
||||
|
||||
Every router descriptor MUST start with a "router" Item; MUST end with a
|
||||
"router-signature" Item and an extra NL; and MUST contain exactly one
|
||||
instance of each of the following Items: "published" "onion-key" "link-key"
|
||||
"signing-key". Additionally, a router descriptor MAY contain any number of
|
||||
"accept", "reject", and "opt" Items.
|
||||
|
||||
The items' formats are as follows:
|
||||
"router" nickname address (ORPort SocksPort DirPort bandwidth)?
|
||||
"ports" ORPort SocksPort DirPort
|
||||
"bandwidth" bandwidth
|
||||
"platform" string
|
||||
"published" YYYY-MM-DD HH:MM:SS
|
||||
"onion-key" NL a public key in PEM format
|
||||
"link-key" NL a public key in PEM format
|
||||
"signing-key" NL a public key in PEM format
|
||||
"accept" string
|
||||
"reject" string
|
||||
"router-signature" NL "-----BEGIN SIGNATURE-----" NL Signature NL
|
||||
"-----END SIGNATURE-----"
|
||||
"opt" SP keyword string? NL,Object?
|
||||
|
||||
ORport ::= port where the router listens for routers/proxies (speaking cells)
|
||||
SocksPort ::= where the router listens for applications (speaking socks)
|
||||
DirPort ::= where the router listens for directory download requests
|
||||
bandwidth ::= maximum bandwidth, in bytes/s
|
||||
nickname ::= between 1 and 19 alphanumeric characters, case-insensitive.
|
||||
|
||||
Bandwidth and ports are required; if they are not included in the router
|
||||
line, they must appear in "bandwidth" and "ports" lines.
|
||||
|
||||
"opt" is reserved for non-critical future extensions.
|
||||
|
||||
7.2. Directory format
|
||||
|
||||
A Directory begins with a "signed-directory" item, followed by one each of
|
||||
the following, in any order: "recommended-software". It may include any
|
||||
number of "opt" items. After these items, a directory includes any number
|
||||
of router descriptors, and a singer "directory-signature" item.
|
||||
|
||||
"signed-directory"
|
||||
"recommended-software" comma-separated-version-list
|
||||
"directory-signature" NL Signature
|
||||
|
||||
Note: The router descriptor for the directory server must appear first.
|
||||
The signature is computed by computing the SHA-1 hash of the
|
||||
directory, from the characters "signed-directory", through the newline
|
||||
after "directory-signature". This digest is then padded with PKCS.1,
|
||||
and signed with the directory server's signing key.
|
||||
|
||||
If software encounters an unrecognized keyword in a single router descriptor,
|
||||
it should reject only that router descriptor, and continue using the
|
||||
others. If it encounters an unrecognized keyword in the directory header,
|
||||
it should reject the entire directory.
|
||||
|
||||
7.3. Behavior of a directory server
|
||||
|
||||
lists nodes that are connected currently
|
||||
speaks http on a socket, spits out directory on request
|
||||
|
||||
-----------
|
||||
(for emacs)
|
||||
Local Variables:
|
||||
mode:text
|
||||
indent-tabs-mode:nil
|
||||
fill-column:77
|
||||
End:
|
||||
@@ -0,0 +1,182 @@
|
||||
.TH TOR 1 "November 2003" "TOR"
|
||||
.SH NAME
|
||||
tor \- The second-generation onion router
|
||||
.SH SYNOPSIS
|
||||
.B tor
|
||||
[\fIOPTION value\fR]...
|
||||
.SH DESCRIPTION
|
||||
.I tor
|
||||
is a connection-oriented anonymizing communication
|
||||
service. Users choose a source-routed path through a set of nodes, and
|
||||
negotiate a "virtual circuit" through the network, in which each node
|
||||
knows its predecessor and successor, but no others. Traffic flowing down
|
||||
the circuit is unwrapped by a symmetric key at each node, which reveals
|
||||
the downstream node.
|
||||
.PP
|
||||
Basically \fItor\fR provides a distributed network of servers ("onion
|
||||
routers"). Users bounce their tcp streams -- web traffic, ftp, ssh, etc --
|
||||
around the routers, and recipients, observers, and even the routers
|
||||
themselves have difficulty tracking the source of the stream.
|
||||
.SH OPTIONS
|
||||
\fB-h, -help\fP
|
||||
Display a short help message and exit.
|
||||
.TP
|
||||
\fB-f \fR\fIFILE\fP
|
||||
FILE contains further "option value" pairs. (Default: @CONFDIR@/torrc)
|
||||
.TP
|
||||
Other options can be specified either on the commandline (\fI--option value\fR), or in the configuration file (\fIoption value\fR).
|
||||
.TP
|
||||
\fBloglevel debug|info|warn|err\fP
|
||||
Set the verboseness level of the primary log. (Default: warn)
|
||||
.TP
|
||||
\fBlogfile \fR\fIFILE\fP
|
||||
Rather than logging to stdout, log to FILE.
|
||||
.TP
|
||||
\fBbandwidthrate \fR\fINUM\fP
|
||||
A token bucket limits the average incoming bandwidth on this node to NUM bytes per second. (Default: 800000)
|
||||
.TP
|
||||
\fBbandwidthburst \fR\fINUM\fP
|
||||
Limit the maximum token bucket size (also known as the burst) to NUM bytes. (Default: 10000000)
|
||||
.TP
|
||||
\fBdebuglogfile \fR\fIFILE\fP
|
||||
In addition to other logging, we will log to FILE at log-level debug.
|
||||
.TP
|
||||
\fBgroup \fR\fIGID\fP
|
||||
On startup, setgid to this user.
|
||||
.TP
|
||||
\fBkeepaliveperiod \fR\fINUM\fP
|
||||
To keep firewalls from expiring connections, send a padding keepalive cell on open connections every NUM seconds. (Default: 300)
|
||||
.TP
|
||||
\fBpidfile \fR\fIFILE\fP
|
||||
On startup, write our PID to FILE. On clean shutdown, remove FILE.
|
||||
.TP
|
||||
\fBrouterfile \fR\fIFILE\fP
|
||||
FILE contains a list of directory servers, to bootstrap into the network. (Default: @CONFDIR@/dirservers)
|
||||
.TP
|
||||
\fBrunasdaemon \fR\fI0|1\fP
|
||||
If 1, Tor forks and daemonizes to the background. (Default: 0)
|
||||
.TP
|
||||
\fBuser \fR\fIUID\fP
|
||||
On startup, setuid to this user.
|
||||
|
||||
.SH CLIENT OPTIONS
|
||||
.PP
|
||||
The following options are useful only for clients (that is, if \fBsocksport\fP is non-zero):
|
||||
.TP
|
||||
\fBentrynodes \fR\fInickname,nickname,...\fP
|
||||
A list of preferred nodes to use for the first hop in the circuit, if possible.
|
||||
.TP
|
||||
\fBexitnodes \fR\fInickname,nickname,...\fP
|
||||
A list of preferred nodes to use for the last hop in the circuit, if possible.
|
||||
.TP
|
||||
\fBexcludenodes \fR\iInickname,nickname,...\fP
|
||||
A list of nodes to never use when building a circuit.
|
||||
.TP
|
||||
\fBnewcircuitperiod \fR\fINUM\fP
|
||||
Every NUM seconds consider whether to build a new circuit. (Default: 60)
|
||||
.TP
|
||||
\fBpathlencoinweight \fR\fI0.0-1.0\fP
|
||||
Paths are 3 hops plus a geometric distribution centered around this coinweight. Must be >=0.0 and <1.0. (Default: 0.3)
|
||||
.TP
|
||||
\fBsocksport \fR\fIPORT\fP
|
||||
Bind to this port to listen for connections from socks-speaking applications.
|
||||
.TP
|
||||
\fBsocksbindaddress \fR\fIIP\fP
|
||||
Bind to this address to listen for connections from socks-speaking applications. (Default: 127.0.0.1)
|
||||
|
||||
.SH SERVER OPTIONS
|
||||
.PP
|
||||
The following options are useful only for servers (that is, if \fBorport\fP is non-zero):
|
||||
.TP
|
||||
\fBaddress address\fP
|
||||
The fqdn of this server (e.g. moria.mit.edu).
|
||||
.TP
|
||||
\fBdatadirectory \fR\fIDIR\fP
|
||||
Store working data in DIR (Default: @LOCALSTATEDIR@/lib/tor)
|
||||
.TP
|
||||
\fBexitpolicy \fR\fIpolicy,policy,...\fP
|
||||
Set an exit policy for this server. Each policy is of the form
|
||||
"\fBreject\fP \fIADDR\fP\fB/\fP\fIMASK\fP\fB:\fP\fIPORT\fP".
|
||||
If \fB/\fP\fIMASK\fP is ommitted then this policy just applies to the host
|
||||
given. Instead of giving a host or network you can also use "\fB*\fP" to
|
||||
denote the universe (0.0.0.0/0). \fIPORT\fP can either be a single port number
|
||||
or an interval of ports: "\fIFROM_PORT\fP\fB-\fP\fITO_PORT\fP".
|
||||
|
||||
For example, "reject 127.0.0.1:*,reject 192.168.1.0/24:*,accept *:*" would
|
||||
reject any traffic destined for localhost and any 192.168.1.* address, but
|
||||
accept anything else.
|
||||
.TP
|
||||
\fBmaxonionspending \fR\fINUM\fP
|
||||
If you have more than this number of onionskins queued for decrypt, reject new ones. (Default: 100)
|
||||
.TP
|
||||
\fBnickname \fR\fIname\fP
|
||||
Set the server's nickname to 'name'.
|
||||
.TP
|
||||
\fBnumcpus \fR\fInum\fP
|
||||
How many processes to use at once for decrypting onionskins. (Default: 1)
|
||||
.TP
|
||||
\fBorport \fR\fIPORT\fP
|
||||
Bind to this port to listen for connections from Tor clients and servers.
|
||||
.TP
|
||||
\fBorbindaddress \fR\fIIP\fP
|
||||
Bind to this address to listen for connections from Tor clients and servers. (Default: 0.0.0.0)
|
||||
|
||||
.SH DIRECTORY SERVER OPTIONS
|
||||
.PP
|
||||
The following options are useful only for directory servers (that is, if \fBdirport\fP is non-zero):
|
||||
.TP
|
||||
\fBdirport \fR\fIPORT\fP
|
||||
Bind the directory service to this port.
|
||||
.TP
|
||||
\fBdirbindaddress \fR\fIIP\fP
|
||||
Bind the directory service to this address. (Default: 0.0.0.0)
|
||||
.TP
|
||||
\fBrecommendedversions \fR\fISTRING\fP
|
||||
STRING is a command-separated list of Tor versions currently believed to be safe. The list is included in each directory, and nodes which pull down the directory learn whether they need to upgrade.
|
||||
|
||||
.SH HIDDEN SERVER OPTIONS
|
||||
.PP
|
||||
The following options are used to configure a hidden service.
|
||||
.TP
|
||||
\fBhiddenservicedir \fR\fIDIRECTORY\fP
|
||||
Store data files for a hidden service in DIRECTORY. Every hidden
|
||||
service must have a separate directory. You may use this option multiple
|
||||
times to specify multiple services.
|
||||
.TP
|
||||
\fBhiddenserviceport \fR\fIVIRTPORT \fR[\fITARGET\fR]\fP
|
||||
Configure a virtual port VIRTPORT for a hidden service. You may use this
|
||||
option multiple times; each time applies to the service using the most recent
|
||||
hiddenservicedir. By default, this option maps the virtual port to the
|
||||
same port on 127.0.0.1. You may override the target port, address, or both
|
||||
by specifying a target of addr, port, or addr:port.
|
||||
.TP
|
||||
\fBhiddenservicenodes \fR\fInickname,nicknamme,...\fP
|
||||
If possible, use the specified nodes as introduction points for the hidden
|
||||
service.
|
||||
.TP
|
||||
\fBhiddenserviceexcludenodes \fR\fInickname,nicknamme,...\fP
|
||||
Do not use the specified nodes as introduction points for the hidden
|
||||
service.
|
||||
|
||||
.SH FILES
|
||||
.TP
|
||||
.I @CONFDIR@/torrc
|
||||
The configuration file, which contains "option value" pairs.
|
||||
.TP
|
||||
.I @CONFDIR@/dirservers
|
||||
A list of directory servers, to bootstrap into the network.
|
||||
.TP
|
||||
.I @LOCALSTATEDIR@/lib/tor/
|
||||
The tor server stores keys/etc here.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR privoxy (1),
|
||||
.BR tsocks (1)
|
||||
|
||||
.BR http://freehaven.net/tor/
|
||||
|
||||
.SH BUGS
|
||||
Plenty, probably. It's still in alpha. Please report them.
|
||||
.SH AUTHORS
|
||||
Roger Dingledine <arma@mit.edu>.
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
% usenix-2e.sty - to be used with latex2e (the new one) for USENIX.
|
||||
% To use this style file, do this:
|
||||
%
|
||||
% \documentclass[twocolumn]{article}
|
||||
% \usepackage{usenix-2e}
|
||||
% and put {\rm ....} around the author names.
|
||||
%
|
||||
% $Id$
|
||||
%
|
||||
% The following definitions are modifications of standard article.sty
|
||||
% definitions, arranged to do a better job of matching the USENIX
|
||||
% guidelines.
|
||||
% It will automatically select two-column mode and the Times-Roman
|
||||
% font.
|
||||
|
||||
%
|
||||
% USENIX papers are two-column.
|
||||
% Times-Roman font is nice if you can get it (requires NFSS,
|
||||
% which is in latex2e.
|
||||
|
||||
\if@twocolumn\else\input twocolumn.sty\fi
|
||||
\usepackage{times}
|
||||
|
||||
%
|
||||
% USENIX wants margins of: 7/8" side, 1" bottom, and 3/4" top.
|
||||
% 0.25" gutter between columns.
|
||||
% Gives active areas of 6.75" x 9.25"
|
||||
%
|
||||
\setlength{\textheight}{9.0in}
|
||||
\setlength{\columnsep}{0.25in}
|
||||
%%\setlength{\textwidth}{6.75in}
|
||||
\setlength{\textwidth}{7.00in}
|
||||
%\setlength{\footheight}{0.0in}
|
||||
\setlength{\topmargin}{-0.25in}
|
||||
\setlength{\headheight}{0.0in}
|
||||
\setlength{\headsep}{0.0in}
|
||||
\setlength{\evensidemargin}{-0.125in}
|
||||
\setlength{\oddsidemargin}{-0.125in}
|
||||
|
||||
%
|
||||
% Usenix wants no page numbers for submitted papers, so that they can
|
||||
% number them themselves.
|
||||
%
|
||||
\pagestyle{empty}
|
||||
|
||||
%
|
||||
% Usenix titles are in 14-point bold type, with no date, and with no
|
||||
% change in the empty page headers. The whol author section is 12 point
|
||||
% italic--- you must use {\rm } around the actual author names to get
|
||||
% them in roman.
|
||||
%
|
||||
\def\maketitle{\par
|
||||
\begingroup
|
||||
\renewcommand\thefootnote{\fnsymbol{footnote}}%
|
||||
\def\@makefnmark{\hbox to\z@{$\m@th^{\@thefnmark}$\hss}}%
|
||||
\long\def\@makefntext##1{\parindent 1em\noindent
|
||||
\hbox to1.8em{\hss$\m@th^{\@thefnmark}$}##1}%
|
||||
\if@twocolumn
|
||||
\twocolumn[\@maketitle]%
|
||||
\else \newpage
|
||||
\global\@topnum\z@
|
||||
\@maketitle \fi\@thanks
|
||||
\endgroup
|
||||
\setcounter{footnote}{0}%
|
||||
\let\maketitle\relax
|
||||
\let\@maketitle\relax
|
||||
\gdef\@thanks{}\gdef\@author{}\gdef\@title{}\let\thanks\relax}
|
||||
|
||||
\def\@maketitle{\newpage
|
||||
\vbox to 2.5in{
|
||||
\vspace*{\fill}
|
||||
\vskip 2em
|
||||
\begin{center}%
|
||||
{\Large\bf \@title \par}%
|
||||
\vskip 0.375in minus 0.300in
|
||||
{\large\it
|
||||
\lineskip .5em
|
||||
\begin{tabular}[t]{c}\@author
|
||||
\end{tabular}\par}%
|
||||
\end{center}%
|
||||
\par
|
||||
\vspace*{\fill}
|
||||
% \vskip 1.5em
|
||||
}
|
||||
}
|
||||
|
||||
%
|
||||
% The abstract is preceded by a 12-pt bold centered heading
|
||||
\def\abstract{\begin{center}%
|
||||
{\large\bf \abstractname\vspace{-.5em}\vspace{\z@}}%
|
||||
\end{center}}
|
||||
\def\endabstract{}
|
||||
|
||||
%
|
||||
% Main section titles are 12-pt bold. Others can be same or smaller.
|
||||
%
|
||||
\def\section{\@startsection {section}{1}{\z@}{-3.5ex plus-1ex minus
|
||||
-.2ex}{2.3ex plus.2ex}{\reset@font\large\bf}}
|
||||
@@ -0,0 +1,2 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
# leave in dependency order, since common must be built first
|
||||
|
||||
SUBDIRS = common or config
|
||||
DIST_SUBDIRS = common or config
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
.deps
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
noinst_LIBRARIES = libor.a
|
||||
|
||||
#CFLAGS = -Wall -Wpointer-arith -O2
|
||||
|
||||
libor_a_SOURCES = log.c crypto.c fakepoll.c util.c aes.c tortls.c
|
||||
|
||||
noinst_HEADERS = log.h crypto.h fakepoll.h test.h util.h aes.h torint.h tortls.h strlcpy.c strlcat.c
|
||||
@@ -0,0 +1,798 @@
|
||||
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
/* Implementation of a simple AES counter mode. We include AES because
|
||||
* 1) it didn't come with any versions of OpenSSL before 0.9.7.
|
||||
* We include counter mode because OpenSSL doesn't do it right.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "orconfig.h"
|
||||
#include "aes.h"
|
||||
#include "util.h"
|
||||
|
||||
/*======================================================================*/
|
||||
/* From rijndael-alg-fst.h */
|
||||
|
||||
typedef uint64_t u64;
|
||||
typedef uint32_t u32;
|
||||
typedef uint8_t u8;
|
||||
|
||||
#define MAXKC (256/32)
|
||||
#define MAXKB (256/8)
|
||||
#define MAXNR 14
|
||||
|
||||
static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
|
||||
static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]);
|
||||
|
||||
/*======================================================================*/
|
||||
/* Interface to AES code, and counter implementation */
|
||||
|
||||
struct aes_cnt_cipher {
|
||||
u32 rk[4*(MAXNR+1)];
|
||||
int nr;
|
||||
u32 counter1;
|
||||
u32 counter0;
|
||||
u8 buf[16];
|
||||
u8 pos;
|
||||
};
|
||||
|
||||
static void
|
||||
_aes_fill_buf(aes_cnt_cipher_t *cipher)
|
||||
{
|
||||
u32 counter0 = cipher->counter0;
|
||||
u32 counter1 = cipher->counter1;
|
||||
u8 buf[16];
|
||||
memset(buf, 0, 8);
|
||||
buf[15] = (counter0 >> 0) & 0xff;
|
||||
buf[14] = (counter0 >> 8) & 0xff;
|
||||
buf[13] = (counter0 >> 16) & 0xff;
|
||||
buf[12] = (counter0 >> 24) & 0xff;
|
||||
buf[11] = (counter1 >> 0) & 0xff;
|
||||
buf[10] = (counter1 >> 8) & 0xff;
|
||||
buf[ 9] = (counter1 >> 16) & 0xff;
|
||||
buf[ 8] = (counter1 >> 24) & 0xff;
|
||||
|
||||
rijndaelEncrypt(cipher->rk, cipher->nr, buf, cipher->buf);
|
||||
}
|
||||
|
||||
aes_cnt_cipher_t*
|
||||
aes_new_cipher()
|
||||
{
|
||||
aes_cnt_cipher_t* result = tor_malloc(sizeof(aes_cnt_cipher_t));
|
||||
memset(result->rk, 0, 4*(MAXNR+1));
|
||||
memset(result->buf, 0, 16);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
aes_set_key(aes_cnt_cipher_t *cipher, const unsigned char *key, int key_bits)
|
||||
{
|
||||
cipher->nr = rijndaelKeySetupEnc(cipher->rk, key, key_bits);
|
||||
cipher->counter0 = 0;
|
||||
cipher->counter1 = 0;
|
||||
cipher->pos = 0;
|
||||
_aes_fill_buf(cipher);
|
||||
}
|
||||
|
||||
void
|
||||
aes_free_cipher(aes_cnt_cipher_t *cipher)
|
||||
{
|
||||
assert(cipher);
|
||||
memset(cipher, 0, sizeof(cipher));
|
||||
free(cipher);
|
||||
}
|
||||
|
||||
void
|
||||
aes_crypt(aes_cnt_cipher_t *cipher, const char *input, int len, char *output)
|
||||
{
|
||||
int c = cipher->pos;
|
||||
if (!len) return;
|
||||
|
||||
while (1) {
|
||||
do {
|
||||
if (len-- == 0) { cipher->pos = c; return; }
|
||||
*(output++) = *(input++) ^ cipher->buf[c];
|
||||
} while (++c != 16);
|
||||
cipher->pos = c = 0;
|
||||
if (! ++cipher->counter0)
|
||||
++cipher->counter1;
|
||||
_aes_fill_buf(cipher);
|
||||
}
|
||||
}
|
||||
|
||||
u64
|
||||
aes_get_counter(aes_cnt_cipher_t *cipher)
|
||||
{
|
||||
u64 counter = cipher->pos;
|
||||
counter |= ((u64)cipher->counter0) << 4;
|
||||
counter |= ((u64)cipher->counter1) << 36;
|
||||
return counter;
|
||||
}
|
||||
|
||||
void
|
||||
aes_set_counter(aes_cnt_cipher_t *cipher, u64 counter)
|
||||
{
|
||||
cipher->pos = (u8)(counter & 0x0f);
|
||||
cipher->counter0 = (u32) ((counter >> 4) & 0xffffffff);
|
||||
cipher->counter1 = (u32) (counter >> 36);
|
||||
_aes_fill_buf(cipher);
|
||||
}
|
||||
|
||||
void
|
||||
aes_adjust_counter(aes_cnt_cipher_t *cipher, long delta)
|
||||
{
|
||||
u64 counter = aes_get_counter(cipher);
|
||||
counter += delta;
|
||||
aes_set_counter(cipher, counter);
|
||||
}
|
||||
|
||||
/*======================================================================*/
|
||||
/* From rijndael-alg-fst.c */
|
||||
|
||||
/**
|
||||
* rijndael-alg-fst.c
|
||||
*
|
||||
* @version 3.0 (December 2000)
|
||||
*
|
||||
* Optimised ANSI C code for the Rijndael cipher (now AES)
|
||||
*
|
||||
* @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
|
||||
* @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
|
||||
* @author Paulo Barreto <paulo.barreto@terra.com.br>
|
||||
*
|
||||
* This code is hereby placed in the public domain.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
Te0[x] = S [x].[02, 01, 01, 03];
|
||||
Te1[x] = S [x].[03, 02, 01, 01];
|
||||
Te2[x] = S [x].[01, 03, 02, 01];
|
||||
Te3[x] = S [x].[01, 01, 03, 02];
|
||||
Te4[x] = S [x].[01, 01, 01, 01];
|
||||
|
||||
Td0[x] = Si[x].[0e, 09, 0d, 0b];
|
||||
Td1[x] = Si[x].[0b, 0e, 09, 0d];
|
||||
Td2[x] = Si[x].[0d, 0b, 0e, 09];
|
||||
Td3[x] = Si[x].[09, 0d, 0b, 0e];
|
||||
Td4[x] = Si[x].[01, 01, 01, 01];
|
||||
*/
|
||||
|
||||
static const u32 Te0[256] = {
|
||||
0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
|
||||
0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
|
||||
0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
|
||||
0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
|
||||
0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
|
||||
0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
|
||||
0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
|
||||
0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
|
||||
0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
|
||||
0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
|
||||
0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
|
||||
0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
|
||||
0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
|
||||
0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
|
||||
0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
|
||||
0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
|
||||
0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
|
||||
0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
|
||||
0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
|
||||
0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
|
||||
0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
|
||||
0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
|
||||
0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
|
||||
0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
|
||||
0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
|
||||
0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
|
||||
0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
|
||||
0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
|
||||
0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
|
||||
0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
|
||||
0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
|
||||
0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
|
||||
0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
|
||||
0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
|
||||
0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
|
||||
0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
|
||||
0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
|
||||
0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
|
||||
0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
|
||||
0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
|
||||
0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
|
||||
0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
|
||||
0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
|
||||
0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
|
||||
0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
|
||||
0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
|
||||
0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
|
||||
0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
|
||||
0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
|
||||
0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
|
||||
0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
|
||||
0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
|
||||
0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
|
||||
0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
|
||||
0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
|
||||
0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
|
||||
0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
|
||||
0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
|
||||
0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
|
||||
0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
|
||||
0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
|
||||
0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
|
||||
0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
|
||||
0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
|
||||
};
|
||||
static const u32 Te1[256] = {
|
||||
0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
|
||||
0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
|
||||
0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
|
||||
0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
|
||||
0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
|
||||
0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
|
||||
0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
|
||||
0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
|
||||
0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
|
||||
0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
|
||||
0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
|
||||
0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
|
||||
0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
|
||||
0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
|
||||
0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
|
||||
0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
|
||||
0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
|
||||
0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
|
||||
0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
|
||||
0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
|
||||
0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
|
||||
0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
|
||||
0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
|
||||
0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
|
||||
0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
|
||||
0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
|
||||
0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
|
||||
0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
|
||||
0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
|
||||
0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
|
||||
0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
|
||||
0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
|
||||
0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
|
||||
0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
|
||||
0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
|
||||
0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
|
||||
0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
|
||||
0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
|
||||
0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
|
||||
0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
|
||||
0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
|
||||
0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
|
||||
0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
|
||||
0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
|
||||
0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
|
||||
0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
|
||||
0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
|
||||
0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
|
||||
0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
|
||||
0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
|
||||
0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
|
||||
0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
|
||||
0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
|
||||
0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
|
||||
0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
|
||||
0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
|
||||
0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
|
||||
0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
|
||||
0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
|
||||
0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
|
||||
0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
|
||||
0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
|
||||
0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
|
||||
0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
|
||||
};
|
||||
static const u32 Te2[256] = {
|
||||
0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
|
||||
0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
|
||||
0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
|
||||
0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
|
||||
0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
|
||||
0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
|
||||
0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
|
||||
0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
|
||||
0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
|
||||
0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
|
||||
0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
|
||||
0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
|
||||
0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
|
||||
0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
|
||||
0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
|
||||
0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
|
||||
0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
|
||||
0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
|
||||
0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
|
||||
0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
|
||||
0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
|
||||
0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
|
||||
0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
|
||||
0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
|
||||
0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
|
||||
0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
|
||||
0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
|
||||
0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
|
||||
0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
|
||||
0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
|
||||
0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
|
||||
0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
|
||||
0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
|
||||
0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
|
||||
0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
|
||||
0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
|
||||
0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
|
||||
0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
|
||||
0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
|
||||
0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
|
||||
0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
|
||||
0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
|
||||
0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
|
||||
0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
|
||||
0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
|
||||
0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
|
||||
0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
|
||||
0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
|
||||
0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
|
||||
0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
|
||||
0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
|
||||
0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
|
||||
0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
|
||||
0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
|
||||
0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
|
||||
0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
|
||||
0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
|
||||
0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
|
||||
0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
|
||||
0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
|
||||
0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
|
||||
0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
|
||||
0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
|
||||
0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
|
||||
};
|
||||
static const u32 Te3[256] = {
|
||||
|
||||
0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
|
||||
0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
|
||||
0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
|
||||
0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
|
||||
0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
|
||||
0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
|
||||
0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
|
||||
0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
|
||||
0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
|
||||
0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
|
||||
0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
|
||||
0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
|
||||
0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
|
||||
0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
|
||||
0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
|
||||
0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
|
||||
0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
|
||||
0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
|
||||
0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
|
||||
0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
|
||||
0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
|
||||
0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
|
||||
0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
|
||||
0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
|
||||
0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
|
||||
0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
|
||||
0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
|
||||
0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
|
||||
0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
|
||||
0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
|
||||
0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
|
||||
0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
|
||||
0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
|
||||
0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
|
||||
0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
|
||||
0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
|
||||
0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
|
||||
0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
|
||||
0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
|
||||
0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
|
||||
0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
|
||||
0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
|
||||
0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
|
||||
0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
|
||||
0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
|
||||
0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
|
||||
0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
|
||||
0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
|
||||
0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
|
||||
0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
|
||||
0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
|
||||
0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
|
||||
0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
|
||||
0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
|
||||
0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
|
||||
0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
|
||||
0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
|
||||
0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
|
||||
0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
|
||||
0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
|
||||
0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
|
||||
0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
|
||||
0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
|
||||
0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
|
||||
};
|
||||
static const u32 Te4[256] = {
|
||||
0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
|
||||
0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
|
||||
0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
|
||||
0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
|
||||
0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
|
||||
0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
|
||||
0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
|
||||
0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
|
||||
0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
|
||||
0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
|
||||
0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
|
||||
0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
|
||||
0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
|
||||
0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
|
||||
0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
|
||||
0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
|
||||
0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
|
||||
0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
|
||||
0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
|
||||
0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
|
||||
0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
|
||||
0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
|
||||
0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
|
||||
0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
|
||||
0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
|
||||
0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
|
||||
0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
|
||||
0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
|
||||
0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
|
||||
0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
|
||||
0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
|
||||
0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
|
||||
0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
|
||||
0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
|
||||
0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
|
||||
0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
|
||||
0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
|
||||
0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
|
||||
0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
|
||||
0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
|
||||
0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
|
||||
0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
|
||||
0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
|
||||
0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
|
||||
0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
|
||||
0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
|
||||
0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
|
||||
0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
|
||||
0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
|
||||
0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
|
||||
0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
|
||||
0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
|
||||
0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
|
||||
0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
|
||||
0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
|
||||
0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
|
||||
0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
|
||||
0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
|
||||
0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
|
||||
0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
|
||||
0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
|
||||
0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
|
||||
0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
|
||||
0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
|
||||
};
|
||||
|
||||
static const u32 rcon[] = {
|
||||
0x01000000, 0x02000000, 0x04000000, 0x08000000,
|
||||
0x10000000, 0x20000000, 0x40000000, 0x80000000,
|
||||
0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
|
||||
};
|
||||
|
||||
#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define GETU32(p) SWAP(*((u32 *)(p)))
|
||||
#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
|
||||
#else
|
||||
#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
|
||||
#define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Expand the cipher key into the encryption key schedule.
|
||||
*
|
||||
* @return the number of rounds for the given cipher key size.
|
||||
*/
|
||||
int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) {
|
||||
int i = 0;
|
||||
u32 temp;
|
||||
|
||||
rk[0] = GETU32(cipherKey );
|
||||
rk[1] = GETU32(cipherKey + 4);
|
||||
rk[2] = GETU32(cipherKey + 8);
|
||||
rk[3] = GETU32(cipherKey + 12);
|
||||
if (keyBits == 128) {
|
||||
for (;;) {
|
||||
temp = rk[3];
|
||||
rk[4] = rk[0] ^
|
||||
(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
|
||||
(Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
|
||||
(Te4[(temp ) & 0xff] & 0x0000ff00) ^
|
||||
(Te4[(temp >> 24) ] & 0x000000ff) ^
|
||||
rcon[i];
|
||||
rk[5] = rk[1] ^ rk[4];
|
||||
rk[6] = rk[2] ^ rk[5];
|
||||
rk[7] = rk[3] ^ rk[6];
|
||||
if (++i == 10) {
|
||||
return 10;
|
||||
}
|
||||
rk += 4;
|
||||
}
|
||||
}
|
||||
rk[4] = GETU32(cipherKey + 16);
|
||||
rk[5] = GETU32(cipherKey + 20);
|
||||
if (keyBits == 192) {
|
||||
for (;;) {
|
||||
temp = rk[ 5];
|
||||
rk[ 6] = rk[ 0] ^
|
||||
(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
|
||||
(Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
|
||||
(Te4[(temp ) & 0xff] & 0x0000ff00) ^
|
||||
(Te4[(temp >> 24) ] & 0x000000ff) ^
|
||||
rcon[i];
|
||||
rk[ 7] = rk[ 1] ^ rk[ 6];
|
||||
rk[ 8] = rk[ 2] ^ rk[ 7];
|
||||
rk[ 9] = rk[ 3] ^ rk[ 8];
|
||||
if (++i == 8) {
|
||||
return 12;
|
||||
}
|
||||
rk[10] = rk[ 4] ^ rk[ 9];
|
||||
rk[11] = rk[ 5] ^ rk[10];
|
||||
rk += 6;
|
||||
}
|
||||
}
|
||||
rk[6] = GETU32(cipherKey + 24);
|
||||
rk[7] = GETU32(cipherKey + 28);
|
||||
if (keyBits == 256) {
|
||||
for (;;) {
|
||||
temp = rk[ 7];
|
||||
rk[ 8] = rk[ 0] ^
|
||||
(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
|
||||
(Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
|
||||
(Te4[(temp ) & 0xff] & 0x0000ff00) ^
|
||||
(Te4[(temp >> 24) ] & 0x000000ff) ^
|
||||
rcon[i];
|
||||
rk[ 9] = rk[ 1] ^ rk[ 8];
|
||||
rk[10] = rk[ 2] ^ rk[ 9];
|
||||
rk[11] = rk[ 3] ^ rk[10];
|
||||
if (++i == 7) {
|
||||
return 14;
|
||||
}
|
||||
temp = rk[11];
|
||||
rk[12] = rk[ 4] ^
|
||||
(Te4[(temp >> 24) ] & 0xff000000) ^
|
||||
(Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
|
||||
(Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^
|
||||
(Te4[(temp ) & 0xff] & 0x000000ff);
|
||||
rk[13] = rk[ 5] ^ rk[12];
|
||||
rk[14] = rk[ 6] ^ rk[13];
|
||||
rk[15] = rk[ 7] ^ rk[14];
|
||||
|
||||
rk += 8;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) {
|
||||
u32 s0, s1, s2, s3, t0, t1, t2, t3;
|
||||
#ifndef FULL_UNROLL
|
||||
int r;
|
||||
#endif /* ?FULL_UNROLL */
|
||||
|
||||
/*
|
||||
* map byte array block to cipher state
|
||||
* and add initial round key:
|
||||
*/
|
||||
s0 = GETU32(pt ) ^ rk[0];
|
||||
s1 = GETU32(pt + 4) ^ rk[1];
|
||||
s2 = GETU32(pt + 8) ^ rk[2];
|
||||
s3 = GETU32(pt + 12) ^ rk[3];
|
||||
#ifdef FULL_UNROLL
|
||||
/* round 1: */
|
||||
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
|
||||
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
|
||||
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
|
||||
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
|
||||
/* round 2: */
|
||||
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
|
||||
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
|
||||
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
|
||||
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
|
||||
/* round 3: */
|
||||
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
|
||||
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
|
||||
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
|
||||
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
|
||||
/* round 4: */
|
||||
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
|
||||
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
|
||||
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
|
||||
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
|
||||
/* round 5: */
|
||||
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
|
||||
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
|
||||
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
|
||||
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
|
||||
/* round 6: */
|
||||
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
|
||||
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
|
||||
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
|
||||
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
|
||||
/* round 7: */
|
||||
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
|
||||
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
|
||||
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
|
||||
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
|
||||
/* round 8: */
|
||||
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
|
||||
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
|
||||
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
|
||||
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
|
||||
/* round 9: */
|
||||
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
|
||||
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
|
||||
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
|
||||
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
|
||||
if (Nr > 10) {
|
||||
/* round 10: */
|
||||
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40];
|
||||
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41];
|
||||
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42];
|
||||
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43];
|
||||
/* round 11: */
|
||||
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44];
|
||||
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45];
|
||||
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46];
|
||||
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47];
|
||||
if (Nr > 12) {
|
||||
/* round 12: */
|
||||
s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48];
|
||||
s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49];
|
||||
s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50];
|
||||
s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51];
|
||||
/* round 13: */
|
||||
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52];
|
||||
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53];
|
||||
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54];
|
||||
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55];
|
||||
}
|
||||
}
|
||||
rk += Nr << 2;
|
||||
#else /* !FULL_UNROLL */
|
||||
/*
|
||||
* Nr - 1 full rounds:
|
||||
*/
|
||||
r = Nr >> 1;
|
||||
for (;;) {
|
||||
t0 =
|
||||
Te0[(s0 >> 24) ] ^
|
||||
Te1[(s1 >> 16) & 0xff] ^
|
||||
Te2[(s2 >> 8) & 0xff] ^
|
||||
Te3[(s3 ) & 0xff] ^
|
||||
rk[4];
|
||||
t1 =
|
||||
Te0[(s1 >> 24) ] ^
|
||||
Te1[(s2 >> 16) & 0xff] ^
|
||||
Te2[(s3 >> 8) & 0xff] ^
|
||||
Te3[(s0 ) & 0xff] ^
|
||||
rk[5];
|
||||
t2 =
|
||||
Te0[(s2 >> 24) ] ^
|
||||
Te1[(s3 >> 16) & 0xff] ^
|
||||
Te2[(s0 >> 8) & 0xff] ^
|
||||
Te3[(s1 ) & 0xff] ^
|
||||
rk[6];
|
||||
t3 =
|
||||
Te0[(s3 >> 24) ] ^
|
||||
Te1[(s0 >> 16) & 0xff] ^
|
||||
Te2[(s1 >> 8) & 0xff] ^
|
||||
Te3[(s2 ) & 0xff] ^
|
||||
rk[7];
|
||||
|
||||
rk += 8;
|
||||
if (--r == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
s0 =
|
||||
Te0[(t0 >> 24) ] ^
|
||||
Te1[(t1 >> 16) & 0xff] ^
|
||||
Te2[(t2 >> 8) & 0xff] ^
|
||||
Te3[(t3 ) & 0xff] ^
|
||||
rk[0];
|
||||
s1 =
|
||||
Te0[(t1 >> 24) ] ^
|
||||
Te1[(t2 >> 16) & 0xff] ^
|
||||
Te2[(t3 >> 8) & 0xff] ^
|
||||
Te3[(t0 ) & 0xff] ^
|
||||
rk[1];
|
||||
s2 =
|
||||
Te0[(t2 >> 24) ] ^
|
||||
Te1[(t3 >> 16) & 0xff] ^
|
||||
Te2[(t0 >> 8) & 0xff] ^
|
||||
Te3[(t1 ) & 0xff] ^
|
||||
rk[2];
|
||||
s3 =
|
||||
Te0[(t3 >> 24) ] ^
|
||||
Te1[(t0 >> 16) & 0xff] ^
|
||||
Te2[(t1 >> 8) & 0xff] ^
|
||||
Te3[(t2 ) & 0xff] ^
|
||||
rk[3];
|
||||
}
|
||||
#endif /* ?FULL_UNROLL */
|
||||
/*
|
||||
* apply last round and
|
||||
* map cipher state to byte array block:
|
||||
*/
|
||||
s0 =
|
||||
(Te4[(t0 >> 24) ] & 0xff000000) ^
|
||||
(Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
|
||||
(Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
|
||||
(Te4[(t3 ) & 0xff] & 0x000000ff) ^
|
||||
rk[0];
|
||||
PUTU32(ct , s0);
|
||||
s1 =
|
||||
(Te4[(t1 >> 24) ] & 0xff000000) ^
|
||||
(Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
|
||||
(Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
|
||||
(Te4[(t0 ) & 0xff] & 0x000000ff) ^
|
||||
rk[1];
|
||||
PUTU32(ct + 4, s1);
|
||||
s2 =
|
||||
(Te4[(t2 >> 24) ] & 0xff000000) ^
|
||||
(Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
|
||||
(Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
|
||||
(Te4[(t1 ) & 0xff] & 0x000000ff) ^
|
||||
rk[2];
|
||||
PUTU32(ct + 8, s2);
|
||||
s3 =
|
||||
(Te4[(t3 >> 24) ] & 0xff000000) ^
|
||||
(Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
|
||||
(Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
|
||||
(Te4[(t2 ) & 0xff] & 0x000000ff) ^
|
||||
rk[3];
|
||||
PUTU32(ct + 12, s3);
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
@@ -0,0 +1,31 @@
|
||||
/* Copyright 2003 Roger Dingledine */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
/* Implements a minimal interface to counter-mode AES. */
|
||||
|
||||
#ifndef __AES_H
|
||||
#define __AES_H
|
||||
|
||||
#include "../common/torint.h"
|
||||
|
||||
struct aes_cnt_cipher;
|
||||
typedef struct aes_cnt_cipher aes_cnt_cipher_t;
|
||||
|
||||
aes_cnt_cipher_t* aes_new_cipher();
|
||||
void aes_free_cipher(aes_cnt_cipher_t *cipher);
|
||||
void aes_set_key(aes_cnt_cipher_t *cipher, const unsigned char *key, int key_bits);
|
||||
void aes_crypt(aes_cnt_cipher_t *cipher, const char *input, int len, char *output);
|
||||
uint64_t aes_get_counter(aes_cnt_cipher_t *cipher);
|
||||
void aes_set_counter(aes_cnt_cipher_t *cipher, uint64_t counter);
|
||||
void aes_adjust_counter(aes_cnt_cipher_t *cipher, long delta);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,141 @@
|
||||
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef __CRYPTO_H
|
||||
#define __CRYPTO_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Length of the output of our message digest. */
|
||||
#define DIGEST_LEN 20
|
||||
/* Length of our symmetric cipher's keys. */
|
||||
#define CIPHER_KEY_LEN 16
|
||||
/* Length of our public keys. */
|
||||
#define PK_BYTES (1024/8)
|
||||
/* Length of our DH keys. */
|
||||
#define DH_BYTES (1024/8)
|
||||
|
||||
/* Constants used to indicate desired public-key padding functions. */
|
||||
#define PK_NO_PADDING 60000
|
||||
#define PK_PKCS1_PADDING 60001
|
||||
#define PK_PKCS1_OAEP_PADDING 60002
|
||||
|
||||
/* Bytes added for PKCS1 padding. */
|
||||
#define PKCS1_PADDING_OVERHEAD 11
|
||||
/* Bytes added for PKCS1-OAEP padding. */
|
||||
#define PKCS1_OAEP_PADDING_OVERHEAD 42
|
||||
|
||||
/* Length of encoded public key fingerprints, including space; but not
|
||||
* including terminating NUL. */
|
||||
#define FINGERPRINT_LEN 49
|
||||
|
||||
|
||||
typedef struct crypto_pk_env_t crypto_pk_env_t;
|
||||
typedef struct crypto_cipher_env_t crypto_cipher_env_t;
|
||||
typedef struct crypto_digest_env_t crypto_digest_env_t;
|
||||
typedef struct crypto_dh_env_t crypto_dh_env_t;
|
||||
|
||||
/* global state */
|
||||
int crypto_global_init();
|
||||
int crypto_global_cleanup();
|
||||
|
||||
/* environment setup */
|
||||
crypto_pk_env_t *crypto_new_pk_env(void);
|
||||
void crypto_free_pk_env(crypto_pk_env_t *env);
|
||||
|
||||
crypto_cipher_env_t *crypto_new_cipher_env(void);
|
||||
void crypto_free_cipher_env(crypto_cipher_env_t *env);
|
||||
|
||||
/* public key crypto */
|
||||
int crypto_pk_generate_key(crypto_pk_env_t *env);
|
||||
|
||||
int crypto_pk_write_public_key_to_string(crypto_pk_env_t *env, char **dest, int *len);
|
||||
int crypto_pk_read_public_key_from_string(crypto_pk_env_t *env, const char *src, int len);
|
||||
int crypto_pk_write_private_key_to_filename(crypto_pk_env_t *env, const char *fname);
|
||||
int crypto_pk_check_key(crypto_pk_env_t *env);
|
||||
int crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env, const char *keyfile);
|
||||
|
||||
int crypto_pk_cmp_keys(crypto_pk_env_t *a, crypto_pk_env_t *b);
|
||||
crypto_pk_env_t *crypto_pk_dup_key(crypto_pk_env_t *orig);
|
||||
int crypto_pk_keysize(crypto_pk_env_t *env);
|
||||
|
||||
int crypto_pk_public_encrypt(crypto_pk_env_t *env, const unsigned char *from, int fromlen, unsigned char *to, int padding);
|
||||
int crypto_pk_private_decrypt(crypto_pk_env_t *env, const unsigned char *from, int fromlen, unsigned char *to, int padding);
|
||||
int crypto_pk_private_sign(crypto_pk_env_t *env, const unsigned char *from, int fromlen, unsigned char *to);
|
||||
int crypto_pk_private_sign_digest(crypto_pk_env_t *env, const unsigned char *from, int fromlen, unsigned char *to);
|
||||
int crypto_pk_public_checksig(crypto_pk_env_t *env, const unsigned char *from, int fromlen, unsigned char *to);
|
||||
int crypto_pk_public_checksig_digest(crypto_pk_env_t *env, const unsigned char *data, int datalen, const unsigned char *sig, int siglen);
|
||||
int crypto_pk_public_hybrid_encrypt(crypto_pk_env_t *env,
|
||||
const unsigned char *from, int fromlen,
|
||||
unsigned char *to, int padding, int force);
|
||||
int crypto_pk_private_hybrid_decrypt(crypto_pk_env_t *env,
|
||||
const unsigned char *from, int fromlen,
|
||||
unsigned char *to,int padding);
|
||||
|
||||
int crypto_pk_asn1_encode(crypto_pk_env_t *pk, char *dest, int dest_len);
|
||||
crypto_pk_env_t *crypto_pk_asn1_decode(const char *str, int len);
|
||||
int crypto_pk_get_digest(crypto_pk_env_t *pk, char *digest_out);
|
||||
int crypto_pk_get_fingerprint(crypto_pk_env_t *pk, char *fp_out);
|
||||
int crypto_pk_check_fingerprint_syntax(const char *s);
|
||||
|
||||
int base64_encode(char *dest, int destlen, const char *src, int srclen);
|
||||
int base64_decode(char *dest, int destlen, const char *src, int srclen);
|
||||
#define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567"
|
||||
int base32_encode(char *dest, int destlen, const char *src, int srclen);
|
||||
|
||||
/* Key negotiation */
|
||||
crypto_dh_env_t *crypto_dh_new();
|
||||
int crypto_dh_get_bytes(crypto_dh_env_t *dh);
|
||||
int crypto_dh_generate_public(crypto_dh_env_t *dh);
|
||||
int crypto_dh_get_public(crypto_dh_env_t *dh, char *pubkey_out,
|
||||
int pubkey_out_len);
|
||||
int crypto_dh_compute_secret(crypto_dh_env_t *dh,
|
||||
const char *pubkey, int pubkey_len,
|
||||
char *secret_out, int secret_out_len);
|
||||
void crypto_dh_free(crypto_dh_env_t *dh);
|
||||
|
||||
/* symmetric crypto */
|
||||
int crypto_cipher_generate_key(crypto_cipher_env_t *env);
|
||||
int crypto_cipher_set_key(crypto_cipher_env_t *env, const unsigned char *key);
|
||||
int crypto_cipher_encrypt_init_cipher(crypto_cipher_env_t *env);
|
||||
int crypto_cipher_decrypt_init_cipher(crypto_cipher_env_t *env);
|
||||
const unsigned char *crypto_cipher_get_key(crypto_cipher_env_t *env);
|
||||
|
||||
int crypto_cipher_encrypt(crypto_cipher_env_t *env, const unsigned char *from, unsigned int fromlen, unsigned char *to);
|
||||
int crypto_cipher_decrypt(crypto_cipher_env_t *env, const unsigned char *from, unsigned int fromlen, unsigned char *to);
|
||||
|
||||
/* only implemented for CRYPTO_CIPHER_AES_CTR */
|
||||
int crypto_cipher_rewind(crypto_cipher_env_t *env, long delta);
|
||||
int crypto_cipher_advance(crypto_cipher_env_t *env, long delta);
|
||||
|
||||
/* convenience function: wraps crypto_create_crypto_env, set_key, and init. */
|
||||
crypto_cipher_env_t *crypto_create_init_cipher(const char *key, int encrypt_mode);
|
||||
|
||||
/* SHA-1 */
|
||||
int crypto_digest(const unsigned char *m, int len, unsigned char *digest);
|
||||
crypto_digest_env_t *crypto_new_digest_env();
|
||||
void crypto_free_digest_env(crypto_digest_env_t *digest);
|
||||
void crypto_digest_add_bytes(crypto_digest_env_t *digest, const char *data,
|
||||
size_t len);
|
||||
void crypto_digest_get_digest(crypto_digest_env_t *digest,
|
||||
char *out, size_t out_len);
|
||||
crypto_digest_env_t *crypto_digest_dup(const crypto_digest_env_t *digest);
|
||||
void crypto_digest_assign(crypto_digest_env_t *into,
|
||||
const crypto_digest_env_t *from);
|
||||
|
||||
/* random numbers */
|
||||
int crypto_seed_rng();
|
||||
int crypto_rand(unsigned int n, unsigned char *to);
|
||||
void crypto_pseudo_rand(unsigned int n, unsigned char *to);
|
||||
int crypto_pseudo_rand_int(unsigned int max);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
@@ -0,0 +1,107 @@
|
||||
/* Copyright 2002,2003 Nick Mathewson, Roger Dingledine */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
/*****
|
||||
* fakepoll.c: On systems where 'poll' doesn't exist, fake it with 'select'.
|
||||
*****/
|
||||
|
||||
#include "orconfig.h"
|
||||
#include "fakepoll.h"
|
||||
|
||||
#ifdef USE_FAKE_POLL
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#if _MSC_VER > 1300
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#elif defined(_MSC_VER)
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
|
||||
/* by default, windows handles only 64 fd's */
|
||||
#if defined(MS_WINDOWS) && !defined(FD_SETSIZE)
|
||||
#define FD_SETSIZE MAXCONNECTIONS
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
|
||||
int
|
||||
tor_poll(struct pollfd *ufds, unsigned int nfds, int timeout)
|
||||
{
|
||||
unsigned int idx;
|
||||
int maxfd, fd;
|
||||
int r;
|
||||
#ifdef MS_WINDOWS
|
||||
int any_fds_set = 0;
|
||||
#endif
|
||||
fd_set readfds, writefds, exceptfds;
|
||||
#ifdef USING_FAKE_TIMEVAL
|
||||
#undef timeval
|
||||
#undef tv_sec
|
||||
#undef tv_usec
|
||||
#endif
|
||||
struct timeval _timeout;
|
||||
_timeout.tv_sec = timeout/1000;
|
||||
_timeout.tv_usec = (timeout%1000)*1000;
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
FD_ZERO(&exceptfds);
|
||||
|
||||
maxfd = -1;
|
||||
for (idx = 0; idx < nfds; ++idx) {
|
||||
ufds[idx].revents = 0;
|
||||
fd = ufds[idx].fd;
|
||||
if (fd > maxfd) {
|
||||
maxfd = fd;
|
||||
#ifdef MS_WINDOWS
|
||||
any_fds_set = 1;
|
||||
#endif
|
||||
}
|
||||
if (ufds[idx].events & POLLIN)
|
||||
FD_SET(fd, &readfds);
|
||||
if (ufds[idx].events & POLLOUT)
|
||||
FD_SET(fd, &writefds);
|
||||
FD_SET(fd, &exceptfds);
|
||||
}
|
||||
#ifdef MS_WINDOWS
|
||||
if (!any_fds_set) {
|
||||
Sleep(timeout);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
r = select(maxfd+1, &readfds, &writefds, &exceptfds,
|
||||
timeout == -1 ? NULL : &_timeout);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
r = 0;
|
||||
for (idx = 0; idx < nfds; ++idx) {
|
||||
fd = ufds[idx].fd;
|
||||
if (FD_ISSET(fd, &readfds))
|
||||
ufds[idx].revents |= POLLIN;
|
||||
if (FD_ISSET(fd, &writefds))
|
||||
ufds[idx].revents |= POLLOUT;
|
||||
if (FD_ISSET(fd, &exceptfds))
|
||||
ufds[idx].revents |= POLLERR;
|
||||
if (ufds[idx].revents)
|
||||
++r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
@@ -0,0 +1,56 @@
|
||||
/* Copyright 2002,2003 Nick Mathewson, Roger Dingledine. */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef __FAKEPOLL_H
|
||||
#define __FAKEPOLL_H
|
||||
|
||||
#include "orconfig.h"
|
||||
|
||||
#define POLL_NO_WARN
|
||||
|
||||
#if defined(HAVE_POLL_H)
|
||||
#include <poll.h>
|
||||
#elif defined(HAVE_SYS_POLL_H)
|
||||
#include <sys/poll.h>
|
||||
#endif
|
||||
|
||||
/* If _POLL_EMUL_H_ is defined, then poll is just a just a thin wrapper around
|
||||
* select. On Mac OS 10.3, this wrapper is kinda flaky, and we should
|
||||
* use our own.
|
||||
*/
|
||||
#if (defined(HAVE_POLL_H)||defined(HAVE_SYS_POLL_H)) && !defined(_POLL_EMUL_H_)
|
||||
#define tor_poll poll
|
||||
#else
|
||||
#define USE_FAKE_POLL
|
||||
#endif
|
||||
|
||||
#ifdef USE_FAKE_POLL
|
||||
|
||||
#ifndef _POLL_EMUL_H_
|
||||
struct pollfd {
|
||||
int fd;
|
||||
short events;
|
||||
short revents;
|
||||
};
|
||||
|
||||
#define POLLIN 0x0001
|
||||
#define POLLPRI 0x0002
|
||||
#define POLLOUT 0x0004
|
||||
#define POLLERR 0x0008
|
||||
#define POLLHUP 0x0010
|
||||
#define POLLNVAL 0x0020
|
||||
#endif
|
||||
|
||||
int tor_poll(struct pollfd *ufds, unsigned int nfds, int timeout);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
@@ -0,0 +1,180 @@
|
||||
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include "orconfig.h"
|
||||
#include "./util.h"
|
||||
#include "./log.h"
|
||||
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
#define vsnprintf _vsnprintf
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
struct logfile_t;
|
||||
typedef struct logfile_t {
|
||||
struct logfile_t *next;
|
||||
const char *filename;
|
||||
FILE *file;
|
||||
int needs_close;
|
||||
int loglevel;
|
||||
int max_loglevel;
|
||||
} logfile_t;
|
||||
|
||||
static INLINE const char *sev_to_string(int severity) {
|
||||
switch(severity) {
|
||||
case LOG_DEBUG: return "debug";
|
||||
case LOG_INFO: return "info";
|
||||
case LOG_NOTICE: return "notice";
|
||||
case LOG_WARN: return "warn";
|
||||
case LOG_ERR: return "err";
|
||||
default: assert(0); return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static logfile_t *logfiles = NULL;
|
||||
|
||||
/* Format a log message into a fixed-sized buffer. (This is factored out
|
||||
* of 'logv' so that we never format a message more than once.
|
||||
*/
|
||||
static INLINE void format_msg(char *buf, size_t buf_len,
|
||||
int severity, const char *funcname,
|
||||
const char *format, va_list ap)
|
||||
{
|
||||
time_t t;
|
||||
struct timeval now;
|
||||
size_t n;
|
||||
|
||||
buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */
|
||||
|
||||
tor_gettimeofday(&now);
|
||||
t = (time_t)now.tv_sec;
|
||||
|
||||
n = strftime(buf, buf_len, "%b %d %H:%M:%S", localtime(&t));
|
||||
n += snprintf(buf+n, buf_len-n,
|
||||
".%.3ld [%s] ",
|
||||
(long)now.tv_usec / 1000, sev_to_string(severity));
|
||||
if(n > buf_len)
|
||||
n = buf_len-1; /* the *nprintf funcs return how many bytes they
|
||||
* _would_ print, if the output is truncated.
|
||||
* Subtract one because the count doesn't include the \0 */
|
||||
|
||||
if (funcname) {
|
||||
n += snprintf(buf+n, buf_len-n, "%s(): ", funcname);
|
||||
if(n > buf_len)
|
||||
n = buf_len-1;
|
||||
}
|
||||
|
||||
n += vsnprintf(buf+n,buf_len-n,format,ap);
|
||||
if(n > buf_len)
|
||||
n = buf_len-1;
|
||||
buf[n]='\n';
|
||||
buf[n+1]='\0';
|
||||
}
|
||||
|
||||
static void
|
||||
logv(int severity, const char *funcname, const char *format, va_list ap)
|
||||
{
|
||||
char buf[10024];
|
||||
int formatted = 0;
|
||||
logfile_t *lf;
|
||||
|
||||
assert(format);
|
||||
for (lf = logfiles; lf; lf = lf->next) {
|
||||
if (severity < lf->loglevel || severity > lf->max_loglevel)
|
||||
continue;
|
||||
if (!lf->file)
|
||||
continue;
|
||||
|
||||
if (!formatted) {
|
||||
format_msg(buf, 10024, severity, funcname, format, ap);
|
||||
formatted = 1;
|
||||
}
|
||||
if(fputs(buf, lf->file) == EOF) { /* error */
|
||||
assert(0); /* XXX */
|
||||
}
|
||||
if(fflush(lf->file) == EOF) { /* error */
|
||||
/* don't log the error! */
|
||||
assert(0); /* XXX fail for now. what's better to do? */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Outputs a message to stdout */
|
||||
void _log(int severity, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap,format);
|
||||
logv(severity, NULL, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void _log_fn(int severity, const char *fn, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap,format);
|
||||
logv(severity, fn, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void close_logs()
|
||||
{
|
||||
logfile_t *victim;
|
||||
while(logfiles) {
|
||||
victim = logfiles;
|
||||
logfiles = logfiles->next;
|
||||
if (victim->needs_close)
|
||||
fclose(victim->file);
|
||||
free(victim);
|
||||
}
|
||||
}
|
||||
|
||||
void reset_logs()
|
||||
{
|
||||
logfile_t *lf;
|
||||
for (lf = logfiles; lf; lf = lf->next) {
|
||||
if (lf->needs_close) {
|
||||
fclose(lf->file);
|
||||
lf->file = fopen(lf->filename, "a");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_stream_log(int loglevel, const char *name, FILE *stream)
|
||||
{
|
||||
logfile_t *lf;
|
||||
lf = tor_malloc(sizeof(logfile_t));
|
||||
lf->filename = name;
|
||||
lf->needs_close = 0;
|
||||
lf->loglevel = loglevel;
|
||||
lf->max_loglevel = LOG_ERR;
|
||||
lf->file = stream;
|
||||
lf->next = logfiles;
|
||||
logfiles = lf;
|
||||
}
|
||||
|
||||
/*
|
||||
* If opening the logfile fails, -1 is returned and
|
||||
* errno is set appropriately (by fopen)
|
||||
*/
|
||||
int add_file_log(int loglevel, const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
f = fopen(filename, "a");
|
||||
if (!f) return -1;
|
||||
add_stream_log(loglevel, filename, f);
|
||||
logfiles->needs_close = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
@@ -0,0 +1,53 @@
|
||||
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef __LOG_H
|
||||
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
#include <syslog.h>
|
||||
#define LOG_WARN LOG_WARNING
|
||||
#else
|
||||
#define LOG_DEBUG 0
|
||||
#define LOG_INFO 1
|
||||
#define LOG_NOTICE 2
|
||||
#define LOG_WARN 3
|
||||
#define LOG_ERR 4
|
||||
#endif
|
||||
|
||||
/* magic to make GCC check for proper format strings. */
|
||||
#ifdef __GNUC__
|
||||
#define CHECK_PRINTF(formatIdx, firstArg) \
|
||||
__attribute__ ((format (printf, formatIdx, firstArg)))
|
||||
#else
|
||||
#define CHECK_PRINTF(formatIdx, firstArg)
|
||||
#endif
|
||||
|
||||
void add_stream_log(int loglevel, const char *name, FILE *stream);
|
||||
int add_file_log(int severity, const char *filename);
|
||||
void close_logs();
|
||||
void reset_logs();
|
||||
|
||||
/* Outputs a message to stdout */
|
||||
void _log(int severity, const char *format, ...) CHECK_PRINTF(2,3);
|
||||
|
||||
#ifdef __GNUC__
|
||||
void _log_fn(int severity, const char *funcname, const char *format, ...)
|
||||
CHECK_PRINTF(3,4);
|
||||
#define log_fn(severity, args...) \
|
||||
_log_fn(severity, __PRETTY_FUNCTION__, args)
|
||||
#else
|
||||
#define log_fn _log
|
||||
#endif
|
||||
#define log _log /* hack it so we don't conflict with log() as much */
|
||||
|
||||
# define __LOG_H
|
||||
#endif
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
@@ -0,0 +1,73 @@
|
||||
/* $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char *rcsid = "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Appends src to string dst of size siz (unlike strncat, siz is the
|
||||
* full size of dst, not space left). At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
|
||||
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
|
||||
* If retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcat(dst, src, siz)
|
||||
char *dst;
|
||||
const char *src;
|
||||
size_t siz;
|
||||
{
|
||||
register char *d = dst;
|
||||
register const char *s = src;
|
||||
register size_t n = siz;
|
||||
size_t dlen;
|
||||
|
||||
/* Find the end of dst and adjust bytes left but don't go past end */
|
||||
while (n-- != 0 && *d != '\0')
|
||||
d++;
|
||||
dlen = d - dst;
|
||||
n = siz - dlen;
|
||||
|
||||
if (n == 0)
|
||||
return(dlen + strlen(s));
|
||||
while (*s != '\0') {
|
||||
if (n != 1) {
|
||||
*d++ = *s;
|
||||
n--;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
*d = '\0';
|
||||
|
||||
return(dlen + (s - src)); /* count does not include NUL */
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/* $Id$ */
|
||||
/* $OpenBSD: strlcpy.c,v 1.2 1998/11/06 04:33:16 wvdputte Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char *rcsid = "$OpenBSD: strlcpy.c,v 1.2 1998/11/06 04:33:16 wvdputte Exp $";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Copy src to string dst of size siz. At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz == 0).
|
||||
* Returns strlen(src); if retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t strlcpy(dst, src, siz)
|
||||
char *dst;
|
||||
const char *src;
|
||||
size_t siz;
|
||||
{
|
||||
register char *d = dst;
|
||||
register const char *s = src;
|
||||
register size_t n = siz;
|
||||
|
||||
if (n == 0)
|
||||
return(strlen(s));
|
||||
while (*s != '\0') {
|
||||
if (n != 1) {
|
||||
*d++ = *s;
|
||||
n--;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
*d = '\0';
|
||||
|
||||
return(s - src); /* count does not include NUL */
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/* Copyright 2001,2002,2003 Roger Dingledine. */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef __TEST_H
|
||||
#define __TEST_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define STMT_BEGIN do {
|
||||
#define STMT_END } while (0)
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||
#else
|
||||
#define PRETTY_FUNCTION ""
|
||||
#endif
|
||||
|
||||
extern int have_failed;
|
||||
|
||||
#define test_fail() \
|
||||
STMT_BEGIN \
|
||||
have_failed = 1; \
|
||||
printf("\nFile %s: line %d (%s): assertion failed.", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
PRETTY_FUNCTION); \
|
||||
return; \
|
||||
STMT_END
|
||||
|
||||
#define test_assert(expr) \
|
||||
STMT_BEGIN \
|
||||
if(expr) { printf("."); fflush(stdout); } else { \
|
||||
have_failed = 1; \
|
||||
printf("\nFile %s: line %d (%s): assertion failed: (%s)\n", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
PRETTY_FUNCTION, \
|
||||
#expr); \
|
||||
return; \
|
||||
} STMT_END
|
||||
|
||||
#define test_eq(expr1, expr2) \
|
||||
STMT_BEGIN \
|
||||
long v1=(long)(expr1), v2=(long)(expr2); \
|
||||
if(v1==v2) { printf("."); fflush(stdout); } else { \
|
||||
have_failed = 1; \
|
||||
printf("\nFile %s: line %d (%s): Assertion failed: (%s==%s)\n"\
|
||||
" (%ld != %ld)\n", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
PRETTY_FUNCTION, \
|
||||
#expr1, #expr2, \
|
||||
v1, v2); \
|
||||
return; \
|
||||
} STMT_END
|
||||
|
||||
#define test_neq(expr1, expr2) \
|
||||
STMT_BEGIN \
|
||||
long v1=(long)(expr1), v2=(long)(expr2); \
|
||||
if(v1!=v2) { printf("."); fflush(stdout); } else { \
|
||||
have_failed = 1; \
|
||||
printf("\nFile %s: line %d (%s): Assertion failed: (%s!=%s)\n"\
|
||||
" (%ld == %ld)\n", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
PRETTY_FUNCTION, \
|
||||
#expr1, #expr2, \
|
||||
v1, v2); \
|
||||
return; \
|
||||
} STMT_END
|
||||
|
||||
#define test_streq(expr1, expr2) \
|
||||
STMT_BEGIN \
|
||||
const char *v1=(expr1), *v2=(expr2); \
|
||||
if(!strcmp(v1,v2)) { printf("."); fflush(stdout); } else { \
|
||||
have_failed = 1; \
|
||||
printf("\nFile %s: line %d (%s): Assertion failed: (%s==%s)\n"\
|
||||
" (\"%s\" != \"%s\")\n", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
PRETTY_FUNCTION, \
|
||||
#expr1, #expr2, \
|
||||
v1, v2); \
|
||||
return; \
|
||||
} STMT_END
|
||||
|
||||
#define test_strneq(expr1, expr2) \
|
||||
STMT_BEGIN \
|
||||
const char *v1=(expr1), *v2=(expr2); \
|
||||
if(strcmp(v1,v2)) { printf("."); fflush(stdout); } else { \
|
||||
have_failed = 1; \
|
||||
printf("\nFile %s: line %d (%s): Assertion failed: (%s!=%s)\n"\
|
||||
" (\"%s\" == \"%s\")\n", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
PRETTY_FUNCTION, \
|
||||
#expr1, #expr2, \
|
||||
v1, v2); \
|
||||
return; \
|
||||
} STMT_END
|
||||
|
||||
#define test_memeq(expr1, expr2, len) \
|
||||
STMT_BEGIN \
|
||||
void *v1=(expr1), *v2=(expr2); \
|
||||
if(!memcmp(v1,v2,(len))) { printf("."); fflush(stdout); } else { \
|
||||
have_failed = 1; \
|
||||
printf("\nFile %s: line %d (%s): Assertion failed: (%s==%s)\n", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
PRETTY_FUNCTION, \
|
||||
#expr1, #expr2); \
|
||||
return; \
|
||||
} STMT_END
|
||||
|
||||
#define test_memneq(expr1, expr2, len) \
|
||||
STMT_BEGIN \
|
||||
void *v1=(expr1), *v2=(expr2); \
|
||||
if(memcmp(v1,v2,(len))) { printf("."); fflush(stdout); } else { \
|
||||
have_failed = 1; \
|
||||
printf("\nFile %s: line %d (%s): Assertion failed: (%s!=%s)\n", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
PRETTY_FUNCTION, \
|
||||
#expr1, #expr2); \
|
||||
return; \
|
||||
} STMT_END
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
@@ -0,0 +1,168 @@
|
||||
/* Copyright 2003 Roger Dingledine */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
/*****
|
||||
* torint.h: Header file to define uint32_t and friends.
|
||||
*****/
|
||||
|
||||
#ifndef __TORINT_H
|
||||
#define __TORINT_H
|
||||
|
||||
#include "orconfig.h"
|
||||
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
|
||||
#if (SIZEOF_INT8_T != 0)
|
||||
#define HAVE_INT8_T
|
||||
#endif
|
||||
#if (SIZEOF_INT16_T != 0)
|
||||
#define HAVE_INT16_T
|
||||
#endif
|
||||
#if (SIZEOF_INT32_T != 0)
|
||||
#define HAVE_INT32_T
|
||||
#endif
|
||||
#if (SIZEOF_INT64_T != 0)
|
||||
#define HAVE_INT64_T
|
||||
#endif
|
||||
#if (SIZEOF_UINT8_T != 0)
|
||||
#define HAVE_UINT8_T
|
||||
#endif
|
||||
#if (SIZEOF_UINT16_T != 0)
|
||||
#define HAVE_UINT16_T
|
||||
#endif
|
||||
#if (SIZEOF_UINT32_T != 0)
|
||||
#define HAVE_UINT32_T
|
||||
#endif
|
||||
#if (SIZEOF_UINT64_T != 0)
|
||||
#define HAVE_UINT64_T
|
||||
#endif
|
||||
|
||||
#if (SIZEOF_CHAR == 1)
|
||||
#ifndef HAVE_INT8_T
|
||||
typedef signed char int8_t;
|
||||
#define HAVE_INT8_T
|
||||
#endif
|
||||
#ifndef HAVE_UINT8_T
|
||||
typedef unsigned char uint8_t;
|
||||
#define HAVE_UINT8_T
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (SIZEOF_SHORT == 2)
|
||||
#ifndef HAVE_INT16_T
|
||||
typedef signed short int16_t;
|
||||
#define HAVE_INT16_T
|
||||
#endif
|
||||
#ifndef HAVE_UINT16_T
|
||||
typedef unsigned short uint16_t;
|
||||
#define HAVE_UINT16_T
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if (SIZEOF_INT == 2)
|
||||
#ifndef HAVE_INT16_T
|
||||
typedef signed int int16_t;
|
||||
#define HAVE_INT16_T
|
||||
#endif
|
||||
#ifndef HAVE_UINT16_T
|
||||
typedef unsigned int uint16_t;
|
||||
#define HAVE_UINT16_T
|
||||
#endif
|
||||
#elif (SIZEOF_INT == 4)
|
||||
#ifndef HAVE_INT32_T
|
||||
typedef signed int int32_t;
|
||||
#define HAVE_INT32_T
|
||||
#endif
|
||||
#ifndef HAVE_UINT32_T
|
||||
typedef unsigned int uint32_t;
|
||||
#define HAVE_UINT32_T
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if (SIZEOF_LONG == 4)
|
||||
#ifndef HAVE_INT32_T
|
||||
typedef signed long int32_t;
|
||||
#define HAVE_INT32_T
|
||||
#endif
|
||||
#ifndef HAVE_UINT32_T
|
||||
typedef unsigned long uint32_t;
|
||||
#define HAVE_UINT32_T
|
||||
#endif
|
||||
#elif (SIZEOF_LONG == 8)
|
||||
#ifndef HAVE_INT64_T
|
||||
typedef signed long int64_t;
|
||||
#define HAVE_INT64_T
|
||||
#endif
|
||||
#ifndef HAVE_UINT32_T
|
||||
typedef unsigned long uint64_t;
|
||||
#define HAVE_UINT32_T
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (SIZEOF_LONG_LONG == 8)
|
||||
#ifndef HAVE_INT64_T
|
||||
typedef signed long long int64_t;
|
||||
#define HAVE_INT64_T
|
||||
#endif
|
||||
#ifndef HAVE_UINT64_T
|
||||
typedef unsigned long long uint64_t;
|
||||
#define HAVE_UINT64_T
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (SIZEOF___INT64 == 8)
|
||||
#ifndef HAVE_INT64_T
|
||||
typedef signed __int64 int64_t;
|
||||
#define HAVE_INT64_T
|
||||
#endif
|
||||
#ifndef HAVE_UINT64_T
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#define HAVE_UINT64_T
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HAVE_INT8_T
|
||||
#error "Missing type int8_t"
|
||||
#endif
|
||||
#ifndef HAVE_UINT8_T
|
||||
#error "Missing type uint8_t"
|
||||
#endif
|
||||
#ifndef HAVE_INT16_T
|
||||
#error "Missing type int16_t"
|
||||
#endif
|
||||
#ifndef HAVE_UINT16_T
|
||||
#error "Missing type uint16_t"
|
||||
#endif
|
||||
#ifndef HAVE_INT32_T
|
||||
#error "Missing type int32_t"
|
||||
#endif
|
||||
#ifndef HAVE_UINT32_T
|
||||
#error "Missing type uint32_t"
|
||||
#endif
|
||||
#ifndef HAVE_INT64_T
|
||||
#error "Missing type int64_t"
|
||||
#endif
|
||||
#ifndef HAVE_UINT64_T
|
||||
#error "Missing type uint64_t"
|
||||
#endif
|
||||
|
||||
#endif /* __TORINT_H */
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
@@ -0,0 +1,690 @@
|
||||
/* Copyright 2003 Roger Dingledine. */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
/*****
|
||||
* tortls.c: TLS wrappers for Tor. (Unlike other tor functions, these
|
||||
* are prefixed with tor_ in order to avoid conflicting with OpenSSL
|
||||
* functions and variables.)
|
||||
*****/
|
||||
|
||||
#include "./crypto.h"
|
||||
#include "./tortls.h"
|
||||
#include "./util.h"
|
||||
#include "./log.h"
|
||||
#include <string.h>
|
||||
|
||||
/* Copied from or.h */
|
||||
#define LEGAL_NICKNAME_CHARACTERS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
|
||||
#include <assert.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/tls1.h>
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/bio.h>
|
||||
|
||||
/* How long do identity certificates live? (sec) */
|
||||
#define IDENTITY_CERT_LIFETIME (365*24*60*60)
|
||||
/* How much clock skew do we tolerate when checking certificates? (sec) */
|
||||
#define CERT_ALLOW_SKEW (90*60)
|
||||
|
||||
typedef struct tor_tls_context_st {
|
||||
SSL_CTX *ctx;
|
||||
} tor_tls_context;
|
||||
|
||||
/* Holds a SSL object and its associated data.
|
||||
*/
|
||||
struct tor_tls_st {
|
||||
SSL *ssl;
|
||||
int socket; /* The underlying fd. */
|
||||
enum {
|
||||
TOR_TLS_ST_HANDSHAKE, TOR_TLS_ST_OPEN, TOR_TLS_ST_GOTCLOSE,
|
||||
TOR_TLS_ST_SENTCLOSE, TOR_TLS_ST_CLOSED
|
||||
} state; /* The current SSL state, depending on which operations have
|
||||
* completed successfully. */
|
||||
int isServer;
|
||||
int wantwrite_n; /* 0 normally, >0 if we returned wantwrite last time */
|
||||
};
|
||||
|
||||
static X509* tor_tls_create_certificate(crypto_pk_env_t *rsa,
|
||||
crypto_pk_env_t *rsa_sign,
|
||||
const char *cname,
|
||||
const char *cname_sign,
|
||||
unsigned int lifetime);
|
||||
|
||||
/* Global tls context. We keep it here because nobody else needs to touch it */
|
||||
static tor_tls_context *global_tls_context = NULL;
|
||||
/* True iff tor_tls_init() has been called. */
|
||||
static int tls_library_is_initialized = 0;
|
||||
|
||||
/* Module-internal error codes. */
|
||||
#define _TOR_TLS_SYSCALL -6
|
||||
#define _TOR_TLS_ZERORETURN -5
|
||||
|
||||
/* These functions are declared in crypto.c but not exported. */
|
||||
EVP_PKEY *_crypto_pk_env_get_evp_pkey(crypto_pk_env_t *env, int private);
|
||||
crypto_pk_env_t *_crypto_new_pk_env_rsa(RSA *rsa);
|
||||
DH *_crypto_dh_env_get_dh(crypto_dh_env_t *dh);
|
||||
|
||||
/* Log all pending tls errors at level 'severity'. Use 'doing' to describe
|
||||
* our current activities.
|
||||
*/
|
||||
static void
|
||||
tls_log_errors(int severity, const char *doing)
|
||||
{
|
||||
int err;
|
||||
const char *msg, *lib, *func;
|
||||
while ((err = ERR_get_error()) != 0) {
|
||||
msg = (const char*)ERR_reason_error_string(err);
|
||||
lib = (const char*)ERR_lib_error_string(err);
|
||||
func = (const char*)ERR_func_error_string(err);
|
||||
if (!msg) msg = "(null)";
|
||||
if (doing) {
|
||||
log(severity, "TLS error while %s: %s (in %s:%s)", doing, msg, lib,func);
|
||||
} else {
|
||||
log(severity, "TLS error: %s (in %s:%s)", msg, lib, func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define CATCH_SYSCALL 1
|
||||
#define CATCH_ZERO 2
|
||||
|
||||
/* Given a TLS object and the result of an SSL_* call, use
|
||||
* SSL_get_error to determine whether an error has occurred, and if so
|
||||
* which one. Return one of TOR_TLS_{DONE|WANTREAD|WANTWRITE|ERROR}.
|
||||
* If extra&CATCH_SYSCALL is true, return _TOR_TLS_SYSCALL instead of
|
||||
* reporting syscall errors. If extra&CATCH_ZERO is true, return
|
||||
* _TOR_TLS_ZERORETURN instead of reporting zero-return errors.
|
||||
*
|
||||
* If an error has occurred, log it at level 'severity' and describe the
|
||||
* current action as 'doing'.
|
||||
*/
|
||||
static int
|
||||
tor_tls_get_error(tor_tls *tls, int r, int extra,
|
||||
const char *doing, int severity)
|
||||
{
|
||||
int err = SSL_get_error(tls->ssl, r);
|
||||
switch (err) {
|
||||
case SSL_ERROR_NONE:
|
||||
return TOR_TLS_DONE;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
return TOR_TLS_WANTREAD;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
return TOR_TLS_WANTWRITE;
|
||||
case SSL_ERROR_SYSCALL:
|
||||
if (extra&CATCH_SYSCALL)
|
||||
return _TOR_TLS_SYSCALL;
|
||||
if (r == 0)
|
||||
log(severity, "TLS error: unexpected close while %s", doing);
|
||||
else {
|
||||
int e = tor_socket_errno(tls->socket);
|
||||
log(severity, "TLS error: <syscall error while %s> (errno=%d: %s)",
|
||||
doing, e, strerror(e));
|
||||
}
|
||||
tls_log_errors(severity, doing);
|
||||
return TOR_TLS_ERROR;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
if (extra&CATCH_ZERO)
|
||||
return _TOR_TLS_ZERORETURN;
|
||||
log(severity, "TLS error: Zero return");
|
||||
tls_log_errors(severity, doing);
|
||||
return TOR_TLS_ERROR;
|
||||
default:
|
||||
tls_log_errors(severity, doing);
|
||||
return TOR_TLS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize OpenSSL, unless it has already been initialized.
|
||||
*/
|
||||
static void
|
||||
tor_tls_init() {
|
||||
if (!tls_library_is_initialized) {
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
crypto_global_init();
|
||||
OpenSSL_add_all_algorithms();
|
||||
tls_library_is_initialized = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* We need to give OpenSSL a callback to verify certificates. This is
|
||||
* it: We always accept peer certs and complete the handshake. We
|
||||
* don't validate them until later.
|
||||
*/
|
||||
static int always_accept_verify_cb(int preverify_ok,
|
||||
X509_STORE_CTX *x509_ctx)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generate and sign an X509 certificate with the public key 'rsa',
|
||||
* signed by the private key 'rsa_sign'. The commonName of the
|
||||
* certificate will be 'cname'; the commonName of the issuer will be
|
||||
* cname_sign. The cert will be valid for cert_lifetime seconds
|
||||
* starting from now. Return a certificate on success, NULL on
|
||||
* failure.
|
||||
*/
|
||||
static X509 *
|
||||
tor_tls_create_certificate(crypto_pk_env_t *rsa,
|
||||
crypto_pk_env_t *rsa_sign,
|
||||
const char *cname,
|
||||
const char *cname_sign,
|
||||
unsigned int cert_lifetime)
|
||||
{
|
||||
time_t start_time, end_time;
|
||||
EVP_PKEY *sign_pkey = NULL, *pkey=NULL;
|
||||
X509 *x509 = NULL;
|
||||
X509_NAME *name = NULL, *name_issuer=NULL;
|
||||
int nid;
|
||||
|
||||
tor_tls_init();
|
||||
|
||||
start_time = time(NULL);
|
||||
|
||||
tor_assert(rsa && cname && rsa_sign && cname_sign);
|
||||
if (!(sign_pkey = _crypto_pk_env_get_evp_pkey(rsa_sign,1)))
|
||||
goto error;
|
||||
if (!(pkey = _crypto_pk_env_get_evp_pkey(rsa,0)))
|
||||
goto error;
|
||||
if (!(x509 = X509_new()))
|
||||
goto error;
|
||||
if (!(X509_set_version(x509, 2)))
|
||||
goto error;
|
||||
if (!(ASN1_INTEGER_set(X509_get_serialNumber(x509), (long)start_time)))
|
||||
goto error;
|
||||
|
||||
if (!(name = X509_NAME_new()))
|
||||
goto error;
|
||||
if ((nid = OBJ_txt2nid("organizationName")) == NID_undef) goto error;
|
||||
if (!(X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC,
|
||||
"TOR", -1, -1, 0))) goto error;
|
||||
if ((nid = OBJ_txt2nid("commonName")) == NID_undef) goto error;
|
||||
if (!(X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC,
|
||||
(char*)cname, -1, -1, 0))) goto error;
|
||||
if (!(X509_set_subject_name(x509, name)))
|
||||
goto error;
|
||||
|
||||
if (!(name_issuer = X509_NAME_new()))
|
||||
goto error;
|
||||
if ((nid = OBJ_txt2nid("organizationName")) == NID_undef) goto error;
|
||||
if (!(X509_NAME_add_entry_by_NID(name_issuer, nid, MBSTRING_ASC,
|
||||
"TOR", -1, -1, 0))) goto error;
|
||||
if ((nid = OBJ_txt2nid("commonName")) == NID_undef) goto error;
|
||||
if (!(X509_NAME_add_entry_by_NID(name_issuer, nid, MBSTRING_ASC,
|
||||
(char*)cname_sign, -1, -1, 0))) goto error;
|
||||
if (!(X509_set_issuer_name(x509, name_issuer)))
|
||||
goto error;
|
||||
|
||||
if (!X509_time_adj(X509_get_notBefore(x509),0,&start_time))
|
||||
goto error;
|
||||
end_time = start_time + cert_lifetime;
|
||||
if (!X509_time_adj(X509_get_notAfter(x509),0,&end_time))
|
||||
goto error;
|
||||
if (!X509_set_pubkey(x509, pkey))
|
||||
goto error;
|
||||
if (!X509_sign(x509, sign_pkey, EVP_sha1()))
|
||||
goto error;
|
||||
|
||||
goto done;
|
||||
error:
|
||||
tls_log_errors(LOG_WARN, "generating certificate");
|
||||
if (x509) {
|
||||
X509_free(x509);
|
||||
x509 = NULL;
|
||||
}
|
||||
done:
|
||||
if (sign_pkey)
|
||||
EVP_PKEY_free(sign_pkey);
|
||||
if (pkey)
|
||||
EVP_PKEY_free(pkey);
|
||||
if (name)
|
||||
X509_NAME_free(name);
|
||||
if (name_issuer)
|
||||
X509_NAME_free(name_issuer);
|
||||
return x509;
|
||||
}
|
||||
|
||||
|
||||
#ifdef EVERYONE_HAS_AES
|
||||
/* Everybody is running OpenSSL 0.9.7 or later, so no backward compatibility
|
||||
* is needed. */
|
||||
#define CIPHER_LIST TLS1_TXT_DHE_RSA_WITH_AES_128_SHA
|
||||
#elif defined(TLS1_TXT_DHE_RSA_WITH_AES_128_SHA)
|
||||
/* Some people are running OpenSSL before 0.9.7, but we aren't.
|
||||
* We can support AES and 3DES.
|
||||
*/
|
||||
#define CIPHER_LIST (TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":" \
|
||||
SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA)
|
||||
#else
|
||||
/* We're running OpenSSL before 0.9.7. We only support 3DES. */
|
||||
#define CIPHER_LIST SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA
|
||||
#endif
|
||||
|
||||
/* Create a new TLS context. If we are going to be using it as a
|
||||
* server, it must have isServer set to true, 'identity' set to the
|
||||
* identity key used to sign that certificate, and 'nickname' set to
|
||||
* the server's nickname. If we're only going to be a client,
|
||||
* isServer should be false, identity should be NULL, and nickname
|
||||
* should be NULL. Return -1 if failure, else 0.
|
||||
*
|
||||
* You can call this function multiple times. Each time you call it,
|
||||
* it generates new certificates; all new connections will be begin
|
||||
* with the new SSL context.
|
||||
*/
|
||||
int
|
||||
tor_tls_context_new(crypto_pk_env_t *identity,
|
||||
int isServer, const char *nickname,
|
||||
unsigned int key_lifetime)
|
||||
{
|
||||
crypto_pk_env_t *rsa = NULL;
|
||||
crypto_dh_env_t *dh = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
tor_tls_context *result = NULL;
|
||||
X509 *cert = NULL, *idcert = NULL;
|
||||
char nn2[1024];
|
||||
sprintf(nn2, "%s <identity>", nickname);
|
||||
|
||||
tor_tls_init();
|
||||
|
||||
if (isServer) {
|
||||
/* Generate short-term RSA key. */
|
||||
if (!(rsa = crypto_new_pk_env()))
|
||||
goto error;
|
||||
if (crypto_pk_generate_key(rsa)<0)
|
||||
goto error;
|
||||
/* Create certificate signed by identity key. */
|
||||
cert = tor_tls_create_certificate(rsa, identity, nickname, nn2,
|
||||
key_lifetime);
|
||||
/* Create self-signed certificate for identity key. */
|
||||
idcert = tor_tls_create_certificate(identity, identity, nn2, nn2,
|
||||
IDENTITY_CERT_LIFETIME);
|
||||
if (!cert || !idcert) {
|
||||
log(LOG_WARN, "Error creating certificate");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
result = tor_malloc(sizeof(tor_tls_context));
|
||||
result->ctx = NULL;
|
||||
#ifdef EVERYONE_HAS_AES
|
||||
/* Tell OpenSSL to only use TLS1 */
|
||||
if (!(result->ctx = SSL_CTX_new(TLSv1_method())))
|
||||
goto error;
|
||||
#else
|
||||
/* Tell OpenSSL to use SSL3 or TLS1 but not SSL2. */
|
||||
if (!(result->ctx = SSL_CTX_new(SSLv23_method())))
|
||||
goto error;
|
||||
SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv2);
|
||||
#endif
|
||||
if (!SSL_CTX_set_cipher_list(result->ctx, CIPHER_LIST))
|
||||
goto error;
|
||||
if (cert && !SSL_CTX_use_certificate(result->ctx,cert))
|
||||
goto error;
|
||||
if (idcert && !SSL_CTX_add_extra_chain_cert(result->ctx,idcert))
|
||||
goto error;
|
||||
SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF);
|
||||
if (isServer) {
|
||||
tor_assert(rsa);
|
||||
if (!(pkey = _crypto_pk_env_get_evp_pkey(rsa,1)))
|
||||
goto error;
|
||||
if (!SSL_CTX_use_PrivateKey(result->ctx, pkey))
|
||||
goto error;
|
||||
EVP_PKEY_free(pkey);
|
||||
pkey = NULL;
|
||||
if (cert) {
|
||||
if (!SSL_CTX_check_private_key(result->ctx))
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
dh = crypto_dh_new();
|
||||
SSL_CTX_set_tmp_dh(result->ctx, _crypto_dh_env_get_dh(dh));
|
||||
crypto_dh_free(dh);
|
||||
SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER,
|
||||
always_accept_verify_cb);
|
||||
/* let us realloc bufs that we're writing from */
|
||||
SSL_CTX_set_mode(result->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
|
||||
/* Free the old context if one exists. */
|
||||
if (global_tls_context) {
|
||||
/* This is safe even if there are open connections: OpenSSL does
|
||||
* reference counting with SSL and SSL_CTX objects. */
|
||||
SSL_CTX_free(global_tls_context->ctx);
|
||||
free(global_tls_context);
|
||||
}
|
||||
global_tls_context = result;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
tls_log_errors(LOG_WARN, "creating TLS context");
|
||||
if (pkey)
|
||||
EVP_PKEY_free(pkey);
|
||||
if (rsa)
|
||||
crypto_free_pk_env(rsa);
|
||||
if (dh)
|
||||
crypto_dh_free(dh);
|
||||
if (result && result->ctx)
|
||||
SSL_CTX_free(result->ctx);
|
||||
if (result)
|
||||
free(result);
|
||||
/* leak certs XXXX ? */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a new TLS object from a TLS context, a file descriptor, and
|
||||
* a flag to determine whether it is functioning as a server.
|
||||
*/
|
||||
tor_tls *
|
||||
tor_tls_new(int sock, int isServer)
|
||||
{
|
||||
tor_tls *result = tor_malloc(sizeof(tor_tls));
|
||||
tor_assert(global_tls_context); /* make sure somebody made it first */
|
||||
if (!(result->ssl = SSL_new(global_tls_context->ctx)))
|
||||
return NULL;
|
||||
result->socket = sock;
|
||||
SSL_set_fd(result->ssl, sock);
|
||||
result->state = TOR_TLS_ST_HANDSHAKE;
|
||||
result->isServer = isServer;
|
||||
result->wantwrite_n = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Release resources associated with a TLS object. Does not close the
|
||||
* underlying file descriptor.
|
||||
*/
|
||||
void
|
||||
tor_tls_free(tor_tls *tls)
|
||||
{
|
||||
SSL_free(tls->ssl);
|
||||
free(tls);
|
||||
}
|
||||
|
||||
/* Underlying function for TLS reading. Reads up to 'len' characters
|
||||
* from 'tls' into 'cp'. On success, returns the number of characters
|
||||
* read. On failure, returns TOR_TLS_ERROR, TOR_TLS_CLOSE,
|
||||
* TOR_TLS_WANTREAD, or TOR_TLS_WANTWRITE.
|
||||
*/
|
||||
int
|
||||
tor_tls_read(tor_tls *tls, char *cp, int len)
|
||||
{
|
||||
int r, err;
|
||||
tor_assert(tls && tls->ssl);
|
||||
tor_assert(tls->state == TOR_TLS_ST_OPEN);
|
||||
r = SSL_read(tls->ssl, cp, len);
|
||||
if (r > 0)
|
||||
return r;
|
||||
err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_INFO);
|
||||
log_fn(LOG_DEBUG,"returned r=%d, err=%d",r,err);
|
||||
if (err == _TOR_TLS_ZERORETURN) {
|
||||
tls->state = TOR_TLS_ST_CLOSED;
|
||||
return TOR_TLS_CLOSE;
|
||||
} else {
|
||||
tor_assert(err != TOR_TLS_DONE);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Underlying function for TLS writing. Write up to 'n' characters
|
||||
* from 'cp' onto 'tls'. On success, returns the number of characters
|
||||
* written. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD,
|
||||
* or TOR_TLS_WANTWRITE.
|
||||
*/
|
||||
int
|
||||
tor_tls_write(tor_tls *tls, char *cp, int n)
|
||||
{
|
||||
int r, err;
|
||||
tor_assert(tls && tls->ssl);
|
||||
tor_assert(tls->state == TOR_TLS_ST_OPEN);
|
||||
if (n == 0)
|
||||
return 0;
|
||||
if(tls->wantwrite_n) {
|
||||
/* if WANTWRITE last time, we must use the _same_ n as before */
|
||||
tor_assert(n >= tls->wantwrite_n);
|
||||
log_fn(LOG_DEBUG,"resuming pending-write, (%d to flush, reusing %d)",
|
||||
n, tls->wantwrite_n);
|
||||
n = tls->wantwrite_n;
|
||||
tls->wantwrite_n = 0;
|
||||
}
|
||||
r = SSL_write(tls->ssl, cp, n);
|
||||
err = tor_tls_get_error(tls, r, 0, "writing", LOG_INFO);
|
||||
if (err == TOR_TLS_DONE) {
|
||||
return r;
|
||||
}
|
||||
if (err == TOR_TLS_WANTWRITE || err == TOR_TLS_WANTREAD) {
|
||||
// log_fn(LOG_INFO,"wantwrite or wantread. remembering the number %d.",n);
|
||||
tls->wantwrite_n = n;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Perform initial handshake on 'tls'. When finished, returns
|
||||
* TOR_TLS_DONE. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD,
|
||||
* or TOR_TLS_WANTWRITE.
|
||||
*/
|
||||
int
|
||||
tor_tls_handshake(tor_tls *tls)
|
||||
{
|
||||
int r;
|
||||
tor_assert(tls && tls->ssl);
|
||||
tor_assert(tls->state == TOR_TLS_ST_HANDSHAKE);
|
||||
if (tls->isServer) {
|
||||
r = SSL_accept(tls->ssl);
|
||||
} else {
|
||||
r = SSL_connect(tls->ssl);
|
||||
}
|
||||
r = tor_tls_get_error(tls,r,0, "handshaking", LOG_INFO);
|
||||
if (r == TOR_TLS_DONE) {
|
||||
tls->state = TOR_TLS_ST_OPEN;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Shut down an open tls connection 'tls'. When finished, returns
|
||||
* TOR_TLS_DONE. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD,
|
||||
* or TOR_TLS_WANTWRITE.
|
||||
*/
|
||||
int
|
||||
tor_tls_shutdown(tor_tls *tls)
|
||||
{
|
||||
int r, err;
|
||||
char buf[128];
|
||||
tor_assert(tls && tls->ssl);
|
||||
|
||||
while (1) {
|
||||
if (tls->state == TOR_TLS_ST_SENTCLOSE) {
|
||||
/* If we've already called shutdown once to send a close message,
|
||||
* we read until the other side has closed too.
|
||||
*/
|
||||
do {
|
||||
r = SSL_read(tls->ssl, buf, 128);
|
||||
} while (r>0);
|
||||
err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading to shut down",
|
||||
LOG_INFO);
|
||||
if (err == _TOR_TLS_ZERORETURN) {
|
||||
tls->state = TOR_TLS_ST_GOTCLOSE;
|
||||
/* fall through... */
|
||||
} else {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
r = SSL_shutdown(tls->ssl);
|
||||
if (r == 1) {
|
||||
/* If shutdown returns 1, the connection is entirely closed. */
|
||||
tls->state = TOR_TLS_ST_CLOSED;
|
||||
return TOR_TLS_DONE;
|
||||
}
|
||||
err = tor_tls_get_error(tls, r, CATCH_SYSCALL|CATCH_ZERO, "shutting down",
|
||||
LOG_INFO);
|
||||
if (err == _TOR_TLS_SYSCALL) {
|
||||
/* The underlying TCP connection closed while we were shutting down. */
|
||||
tls->state = TOR_TLS_ST_CLOSED;
|
||||
return TOR_TLS_DONE;
|
||||
} else if (err == _TOR_TLS_ZERORETURN) {
|
||||
/* The TLS connection says that it sent a shutdown record, but
|
||||
* isn't done shutting down yet. Make sure that this hasn't
|
||||
* happened before, then go back to the start of the function
|
||||
* and try to read.
|
||||
*/
|
||||
if (tls->state == TOR_TLS_ST_GOTCLOSE ||
|
||||
tls->state == TOR_TLS_ST_SENTCLOSE) {
|
||||
log(LOG_WARN,
|
||||
"TLS returned \"half-closed\" value while already half-closed");
|
||||
return TOR_TLS_ERROR;
|
||||
}
|
||||
tls->state = TOR_TLS_ST_SENTCLOSE;
|
||||
/* fall through ... */
|
||||
} else {
|
||||
return err;
|
||||
}
|
||||
} /* end loop */
|
||||
}
|
||||
|
||||
/* Return true iff this TLS connection is authenticated.
|
||||
*/
|
||||
int
|
||||
tor_tls_peer_has_cert(tor_tls *tls)
|
||||
{
|
||||
X509 *cert;
|
||||
if (!(cert = SSL_get_peer_certificate(tls->ssl)))
|
||||
return 0;
|
||||
X509_free(cert);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return the nickname (if any) that the peer connected on 'tls'
|
||||
* claims to have.
|
||||
*/
|
||||
int
|
||||
tor_tls_get_peer_cert_nickname(tor_tls *tls, char *buf, int buflen)
|
||||
{
|
||||
X509 *cert = NULL;
|
||||
X509_NAME *name = NULL;
|
||||
int nid;
|
||||
int lenout;
|
||||
|
||||
if (!(cert = SSL_get_peer_certificate(tls->ssl))) {
|
||||
log_fn(LOG_WARN, "Peer has no certificate");
|
||||
goto error;
|
||||
}
|
||||
if (!(name = X509_get_subject_name(cert))) {
|
||||
log_fn(LOG_WARN, "Peer certificate has no subject name");
|
||||
goto error;
|
||||
}
|
||||
if ((nid = OBJ_txt2nid("commonName")) == NID_undef)
|
||||
goto error;
|
||||
|
||||
lenout = X509_NAME_get_text_by_NID(name, nid, buf, buflen);
|
||||
if (lenout == -1)
|
||||
goto error;
|
||||
if (((int)strspn(buf, LEGAL_NICKNAME_CHARACTERS)) < lenout) {
|
||||
log_fn(LOG_WARN, "Peer certificate nickname has illegal characters.");
|
||||
goto error;
|
||||
}
|
||||
return 0;
|
||||
error:
|
||||
if (cert)
|
||||
X509_free(cert);
|
||||
if (name)
|
||||
X509_NAME_free(name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If the provided tls connection is authenticated and has a
|
||||
* certificate that is currently valid and is correctly signed by
|
||||
* identity_key, return 0. Else, return -1.
|
||||
*/
|
||||
int
|
||||
tor_tls_verify(tor_tls *tls, crypto_pk_env_t *identity_key)
|
||||
{
|
||||
X509 *cert = NULL;
|
||||
EVP_PKEY *id_pkey = NULL;
|
||||
time_t now, t;
|
||||
int r = -1;
|
||||
|
||||
if (!(cert = SSL_get_peer_certificate(tls->ssl)))
|
||||
return -1;
|
||||
|
||||
now = time(NULL);
|
||||
t = now + CERT_ALLOW_SKEW;
|
||||
if (X509_cmp_time(X509_get_notBefore(cert), &t) > 0) {
|
||||
log_fn(LOG_WARN,"Certificate becomes valid in the future: possible clock skew.");
|
||||
goto done;
|
||||
}
|
||||
t = now - CERT_ALLOW_SKEW;
|
||||
if (X509_cmp_time(X509_get_notAfter(cert), &t) < 0) {
|
||||
log_fn(LOG_WARN,"Certificate already expired; possible clock skew.");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Get the public key. */
|
||||
if (!(id_pkey = _crypto_pk_env_get_evp_pkey(identity_key,0)) ||
|
||||
X509_verify(cert, id_pkey) <= 0) {
|
||||
log_fn(LOG_WARN,"X509_verify on cert and pkey returned <= 0");
|
||||
tls_log_errors(LOG_WARN,"verifying certificate");
|
||||
goto done;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
done:
|
||||
if (cert)
|
||||
X509_free(cert);
|
||||
if (id_pkey)
|
||||
EVP_PKEY_free(id_pkey);
|
||||
|
||||
/* XXXX This should never get invoked, but let's make sure for now. */
|
||||
tls_log_errors(LOG_WARN, "finishing tor_tls_verify");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
tor_tls_get_pending_bytes(tor_tls *tls)
|
||||
{
|
||||
tor_assert(tls);
|
||||
#if OPENSSL_VERSION_NUMBER < 0x0090700fl
|
||||
if (tls->ssl->rstate == SSL_ST_READ_BODY)
|
||||
return 0;
|
||||
if (tls->ssl->s3->rrec.type != SSL3_RT_APPLICATION_DATA)
|
||||
return 0;
|
||||
#endif
|
||||
return SSL_pending(tls->ssl);
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of bytes read across the underlying socket. */
|
||||
unsigned long tor_tls_get_n_bytes_read(tor_tls *tls)
|
||||
{
|
||||
tor_assert(tls);
|
||||
return BIO_number_read(SSL_get_rbio(tls->ssl));
|
||||
}
|
||||
/* Return the number of bytes written across the underlying socket. */
|
||||
unsigned long tor_tls_get_n_bytes_written(tor_tls *tls)
|
||||
{
|
||||
tor_assert(tls);
|
||||
return BIO_number_written(SSL_get_wbio(tls->ssl));
|
||||
}
|
||||
|
||||
/* Implement assert_no_tls_errors: If there are any pending OpenSSL
|
||||
* errors, log an error message and assert(0). */
|
||||
void _assert_no_tls_errors(const char *fname, int line)
|
||||
{
|
||||
if (ERR_peek_error() == 0)
|
||||
return;
|
||||
log_fn(LOG_ERR, "Unhandled OpenSSL errors found at %s:%d: ",
|
||||
fname, line);
|
||||
tls_log_errors(LOG_ERR, NULL);
|
||||
|
||||
tor_assert(0);
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
@@ -0,0 +1,50 @@
|
||||
/* Copyright 2003 Roger Dingledine */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef _TORTLS_H
|
||||
#define _TORTLS_H
|
||||
|
||||
#include "../common/crypto.h"
|
||||
|
||||
/* Opaque structure to hold a TLS connection. */
|
||||
typedef struct tor_tls_st tor_tls;
|
||||
|
||||
/* Possible return values for most tor_tls_* functions. */
|
||||
#define TOR_TLS_ERROR -4
|
||||
#define TOR_TLS_CLOSE -3
|
||||
#define TOR_TLS_WANTREAD -2
|
||||
#define TOR_TLS_WANTWRITE -1
|
||||
#define TOR_TLS_DONE 0
|
||||
|
||||
int tor_tls_context_new(crypto_pk_env_t *rsa, int isServer,
|
||||
const char *nickname, unsigned int key_lifetime);
|
||||
tor_tls *tor_tls_new(int sock, int isServer);
|
||||
void tor_tls_free(tor_tls *tls);
|
||||
int tor_tls_peer_has_cert(tor_tls *tls);
|
||||
int tor_tls_get_peer_cert_nickname(tor_tls *tls, char *buf, int buflen);
|
||||
int tor_tls_verify(tor_tls *tls, crypto_pk_env_t *identity);
|
||||
int tor_tls_read(tor_tls *tls, char *cp, int len);
|
||||
int tor_tls_write(tor_tls *tls, char *cp, int n);
|
||||
int tor_tls_handshake(tor_tls *tls);
|
||||
int tor_tls_shutdown(tor_tls *tls);
|
||||
int tor_tls_get_pending_bytes(tor_tls *tls);
|
||||
|
||||
unsigned long tor_tls_get_n_bytes_read(tor_tls *tls);
|
||||
unsigned long tor_tls_get_n_bytes_written(tor_tls *tls);
|
||||
|
||||
/* Log and abort if there are unhandled TLS errors in OpenSSL's error stack.
|
||||
*/
|
||||
#define assert_no_tls_errors() _assert_no_tls_errors(__FILE__,__LINE__)
|
||||
|
||||
void _assert_no_tls_errors(const char *fname, int line);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,268 @@
|
||||
/* Copyright 2003 Roger Dingledine */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef __UTIL_H
|
||||
#define __UTIL_H
|
||||
|
||||
#include "orconfig.h"
|
||||
#include "torint.h"
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if _MSC_VER > 1300
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#elif defined(_MSC_VER)
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
#ifndef HAVE_GETTIMEOFDAY
|
||||
#ifdef HAVE_FTIME
|
||||
#define USING_FAKE_TIMEVAL
|
||||
#include <sys/timeb.h>
|
||||
#define timeval timeb
|
||||
#define tv_sec time
|
||||
#define tv_usec millitm
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
/* Windows names string functions differently from most other platforms. */
|
||||
#define strncasecmp strnicmp
|
||||
#define strcasecmp stricmp
|
||||
/* "inline" is __inline on windows. " */
|
||||
#define INLINE __inline
|
||||
/* Windows compilers before VC7 don't have __FUNCTION__. */
|
||||
#if _MSC_VER < 1300
|
||||
#define __FUNCTION__ "???"
|
||||
#endif
|
||||
#else
|
||||
#define INLINE inline
|
||||
#endif
|
||||
|
||||
/* Replace assert() with a variant that sends failures to the log before
|
||||
* calling assert() normally.
|
||||
*/
|
||||
#ifdef NDEBUG
|
||||
#define tor_assert(expr) do {} while(0)
|
||||
#else
|
||||
#define tor_assert(expr) do { \
|
||||
if (!(expr)) { \
|
||||
log(LOG_ERR, "%s:%d: %s: Assertion %s failed; aborting.", \
|
||||
__FILE__, __LINE__, __FUNCTION__, #expr); \
|
||||
assert(expr); /* write to console too. */ \
|
||||
abort(); /* unreached */ \
|
||||
} } while (0)
|
||||
#endif
|
||||
|
||||
/* On windows, you have to call close() on fds returned by open(), and
|
||||
* closesocket() on fds returned by socket(). On Unix, everything
|
||||
* gets close()'d. We abstract this difference by always using the
|
||||
* following macro to close sockets, and always using close() on
|
||||
* files.
|
||||
*/
|
||||
#ifdef MS_WINDOWS
|
||||
#define tor_close_socket(s) closesocket(s)
|
||||
#else
|
||||
#define tor_close_socket(s) close(s)
|
||||
#endif
|
||||
|
||||
/* legal characters in a filename */
|
||||
/* XXXX This isn't so on windows. */
|
||||
#define CONFIG_LEGAL_FILENAME_CHARACTERS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_/"
|
||||
|
||||
size_t strlcat(char *dst, const char *src, size_t siz);
|
||||
size_t strlcpy(char *dst, const char *src, size_t siz);
|
||||
|
||||
void *tor_malloc(size_t size);
|
||||
void *tor_malloc_zero(size_t size);
|
||||
void *tor_realloc(void *ptr, size_t size);
|
||||
char *tor_strdup(const char *s);
|
||||
char *tor_strndup(const char *s, size_t n);
|
||||
#define tor_free(p) do {if(p) {free(p); (p)=NULL;}} while(0)
|
||||
void tor_strlower(char *s);
|
||||
|
||||
/* Some platforms segfault when you try to access a multi-byte type
|
||||
* that isn't aligned to a word boundary. The macros and/or functions
|
||||
* below can be used to access unaligned data on any platform.
|
||||
*/
|
||||
#ifdef UNALIGNED_INT_ACCESS_OK
|
||||
#define get_uint16(cp) (*(uint16_t*)(cp))
|
||||
#define get_uint32(cp) (*(uint32_t*)(cp))
|
||||
#define set_uint16(cp,v) do { *(uint16_t*)(cp) = (v); } while (0)
|
||||
#define set_uint32(cp,v) do { *(uint32_t*)(cp) = (v); } while (0)
|
||||
#else
|
||||
#if 1
|
||||
uint16_t get_uint16(const char *cp);
|
||||
uint32_t get_uint32(const char *cp);
|
||||
void set_uint16(char *cp, uint16_t v);
|
||||
void set_uint32(char *cp, uint32_t v);
|
||||
#else
|
||||
#define get_uint16(cp) \
|
||||
( ((*(((uint8_t*)(cp))+0))<<8) + \
|
||||
((*(((uint8_t*)(cp))+1)) ) )
|
||||
#define get_uint32(cp) \
|
||||
( ((*(((uint8_t*)(cp))+0))<<24) + \
|
||||
((*(((uint8_t*)(cp))+1))<<16) + \
|
||||
((*(((uint8_t*)(cp))+2))<<8 ) + \
|
||||
((*(((uint8_t*)(cp))+3)) ) )
|
||||
#define set_uint16(cp,v) \
|
||||
do { \
|
||||
uint16_t u16v = (v); \
|
||||
*(((uint8_t*)(cp))+0) = (v >> 8)&0xff; \
|
||||
*(((uint8_t*)(cp))+1) = (v >> 0)&0xff; \
|
||||
} while (0)
|
||||
#define set_uint32(cp,val) \
|
||||
do { \
|
||||
uint32_t u32v = (v); \
|
||||
*(((uint8_t*)(cp))+0) = s32 >> 24)&0xff; \
|
||||
*(((uint8_t*)(cp))+1) = s32 >> 16)&0xff; \
|
||||
*(((uint8_t*)(cp))+2) = s32 >> 8)&0xff; \
|
||||
*(((uint8_t*)(cp))+3) = s32 >> 0)&0xff; \
|
||||
} while (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void hex_encode(const char *from, int fromlen, char *to);
|
||||
const char *hex_str(const char *from, int fromlen);
|
||||
|
||||
/* Resizeable array. */
|
||||
typedef struct smartlist_t smartlist_t;
|
||||
|
||||
smartlist_t *smartlist_create();
|
||||
void smartlist_free(smartlist_t *sl);
|
||||
void smartlist_set_capacity(smartlist_t *sl, int n);
|
||||
void smartlist_clear(smartlist_t *sl);
|
||||
void smartlist_truncate(smartlist_t *sl, int n);
|
||||
void smartlist_add(smartlist_t *sl, void *element);
|
||||
void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2);
|
||||
void smartlist_remove(smartlist_t *sl, void *element);
|
||||
int smartlist_isin(const smartlist_t *sl, void *element);
|
||||
int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2);
|
||||
void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2);
|
||||
void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2);
|
||||
void *smartlist_choose(const smartlist_t *sl);
|
||||
void *smartlist_get(const smartlist_t *sl, int idx);
|
||||
void *smartlist_set(smartlist_t *sl, int idx, void *val);
|
||||
void *smartlist_del(smartlist_t *sl, int idx);
|
||||
void *smartlist_del_keeporder(smartlist_t *sl, int idx);
|
||||
void smartlist_insert(smartlist_t *sl, int idx, void *val);
|
||||
int smartlist_len(const smartlist_t *sl);
|
||||
#define SMARTLIST_FOREACH(sl, type, var, cmd) \
|
||||
do { \
|
||||
int sl_idx, sl_len=smartlist_len(sl); \
|
||||
type var; \
|
||||
for(sl_idx = 0; sl_idx < sl_len; ++sl_idx) { \
|
||||
var = smartlist_get((sl),sl_idx); \
|
||||
do {cmd;} while(0); \
|
||||
} } while (0)
|
||||
|
||||
/* Map from const char * to void*. Implemented with a splay tree. */
|
||||
typedef struct strmap_t strmap_t;
|
||||
typedef struct strmap_entry_t strmap_entry_t;
|
||||
typedef struct strmap_entry_t strmap_iter_t;
|
||||
strmap_t* strmap_new(void);
|
||||
void* strmap_set(strmap_t *map, const char *key, void *val);
|
||||
void* strmap_get(strmap_t *map, const char *key);
|
||||
void* strmap_remove(strmap_t *map, const char *key);
|
||||
void* strmap_set_lc(strmap_t *map, const char *key, void *val);
|
||||
void* strmap_get_lc(strmap_t *map, const char *key);
|
||||
void* strmap_remove_lc(strmap_t *map, const char *key);
|
||||
typedef void* (*strmap_foreach_fn)(const char *key, void *val, void *data);
|
||||
void strmap_foreach(strmap_t *map, strmap_foreach_fn fn, void *data);
|
||||
void strmap_free(strmap_t *map, void (*free_val)(void*));
|
||||
|
||||
strmap_iter_t *strmap_iter_init(strmap_t *map);
|
||||
strmap_iter_t *strmap_iter_next(strmap_t *map, strmap_iter_t *iter);
|
||||
strmap_iter_t *strmap_iter_next_rmv(strmap_t *map, strmap_iter_t *iter);
|
||||
void strmap_iter_get(strmap_iter_t *iter, const char **keyp, void **valp);
|
||||
|
||||
int strmap_iter_done(strmap_iter_t *iter);
|
||||
|
||||
/* String manipulation */
|
||||
const char *eat_whitespace(const char *s);
|
||||
const char *eat_whitespace_no_nl(const char *s);
|
||||
const char *find_whitespace(const char *s);
|
||||
|
||||
/* Time helpers */
|
||||
void tor_gettimeofday(struct timeval *timeval);
|
||||
long tv_udiff(struct timeval *start, struct timeval *end);
|
||||
void tv_addms(struct timeval *a, long ms);
|
||||
void tv_add(struct timeval *a, struct timeval *b);
|
||||
int tv_cmp(struct timeval *a, struct timeval *b);
|
||||
time_t tor_timegm(struct tm *tm);
|
||||
|
||||
int write_all(int fd, const char *buf, size_t count, int isSocket);
|
||||
int read_all(int fd, char *buf, size_t count, int isSocket);
|
||||
|
||||
void set_socket_nonblocking(int socket);
|
||||
|
||||
typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR} file_status_t;
|
||||
|
||||
file_status_t file_status(const char *filename);
|
||||
int check_private_dir(const char *dirname, int create);
|
||||
int write_str_to_file(const char *fname, const char *str);
|
||||
char *read_file_to_str(const char *filename);
|
||||
int parse_line_from_file(char *line, int maxlen, FILE *f, char **key_out, char **value_out);
|
||||
|
||||
int spawn_func(int (*func)(void *), void *data);
|
||||
void spawn_exit();
|
||||
|
||||
int tor_socketpair(int family, int type, int protocol, int fd[2]);
|
||||
|
||||
int is_internal_IP(uint32_t ip);
|
||||
|
||||
const char *get_uname(void);
|
||||
|
||||
/* Start putting the process into daemon mode: fork and drop all resources
|
||||
* except standard fds. The parent process never returns, but stays around
|
||||
* until finish_daemon is called. (Note: it's safe to call this more
|
||||
* than once: calls after the first are ignored.)
|
||||
*/
|
||||
void start_daemon(char *desired_cwd);
|
||||
/* Finish putting the process into daemon mode: drop standard fds, and tell
|
||||
* the parent process to exit. (Note: it's safe to call this more than once:
|
||||
* calls after the first are ignored. Calls start_daemon first if it hasn't
|
||||
* been called already.)
|
||||
*/
|
||||
void finish_daemon(void);
|
||||
|
||||
void write_pidfile(char *filename);
|
||||
int switch_id(char *user, char *group);
|
||||
|
||||
struct in_addr;
|
||||
int tor_inet_aton(const char *cp, struct in_addr *addr);
|
||||
int tor_lookup_hostname(const char *name, uint32_t *addr);
|
||||
|
||||
/* For stupid historical reasons, windows sockets have an independent
|
||||
* set of errnos, and an independent way to get them. Also, you can't
|
||||
* always believe WSAEWOULDBLOCK. Use the macros below to compare
|
||||
* errnos against expected values, and use tor_socket_errno to find
|
||||
* the actual errno after a socket operation fails.
|
||||
*/
|
||||
#ifdef MS_WINDOWS
|
||||
#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == WSAEWOULDBLOCK)
|
||||
#define ERRNO_IS_EINPROGRESS(e) ((e) == WSAEINPROGRESS)
|
||||
#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == WSAEINPROGRESS || (e)== WSAEINVAL)
|
||||
int tor_socket_errno(int sock);
|
||||
#else
|
||||
#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN)
|
||||
#define ERRNO_IS_EINPROGRESS(e) ((e) == EINPROGRESS)
|
||||
#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS)
|
||||
#define tor_socket_errno(sock) (errno)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
@@ -0,0 +1,5 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
sample-server-torrc
|
||||
torrc
|
||||
torrc.sample
|
||||
@@ -0,0 +1,5 @@
|
||||
confdir = $(sysconfdir)/tor
|
||||
|
||||
EXTRA_DIST = dirservers
|
||||
|
||||
conf_DATA = dirservers torrc.sample
|
||||
@@ -0,0 +1,110 @@
|
||||
# This is no longer a manually-editable file. It's just a
|
||||
# concatenation of a bunch of signed router descriptors.
|
||||
|
||||
router moria1 18.244.0.188 9001 9021 9031
|
||||
platform Tor 0.0.6rc1 on Linux moria.mit.edu i686
|
||||
published 2004-04-25 21:54:28
|
||||
bandwidth 800000 10000000
|
||||
onion-key
|
||||
-----BEGIN RSA PUBLIC KEY-----
|
||||
MIGJAoGBANoIvHieyHUTzIacbnWOnyTyzGrLOdXqbcjz2GGMxyHEd5K1bO1ZBNHP
|
||||
9i5qLQpN5viFk2K2rEGuG8tFgDEzSWZEtBqv3NVfUdiumdERWMBwlaQ0MVK4C+jf
|
||||
y5gZ8KI3o9ZictgPS1AQF+Kk932/vIHTuRIUKb4ILTnQilNvID0NAgMBAAE=
|
||||
-----END RSA PUBLIC KEY-----
|
||||
signing-key
|
||||
-----BEGIN RSA PUBLIC KEY-----
|
||||
MIGJAoGBAMHa0ZC/jo2Q2DrwKYF/6ZbmZ27PFYG91u4gUzzmZ/VXLpZ8wNzEV3oW
|
||||
nt+I61048fBiC1frT1/DZ351n2bLSk9zJbB6jyGZJn0380FPRX3+cXyXS0Gq8Ril
|
||||
xkhMQf5XuNFUb8UmYPSOH4WErjvYjKvU+gfjbK/82Jo9SuHpYz+BAgMBAAE=
|
||||
-----END RSA PUBLIC KEY-----
|
||||
reject 0.0.0.0/255.0.0.0:*
|
||||
reject 169.254.0.0/255.255.0.0:*
|
||||
reject 127.0.0.0/255.0.0.0:*
|
||||
reject 192.168.0.0/255.255.0.0:*
|
||||
reject 10.0.0.0/255.0.0.0:*
|
||||
reject 172.16.0.0/255.240.0.0:*
|
||||
accept *:20-22
|
||||
accept *:53
|
||||
accept *:79-80
|
||||
accept *:110
|
||||
accept *:143
|
||||
accept *:443
|
||||
accept *:873
|
||||
accept *:993
|
||||
accept *:995
|
||||
accept *:1024-65535
|
||||
reject *:*
|
||||
router-signature
|
||||
-----BEGIN SIGNATURE-----
|
||||
o1eAoRHDAEAXsnh5wN++vIwrupd+DbAJ2p3wxHDrmqxTpygzxxCnyQyhMfX03ua2
|
||||
4iplyNlwyFwzWcw0sk31otlO2HBYXT1V9G0YxGtKMOeOBMHjfGbUjGvEALHzWi4z
|
||||
8DXGJp13zgnUyP4ZA6xaGROwcT6oB5e7UlztvvpGxTg=
|
||||
-----END SIGNATURE-----
|
||||
|
||||
router moria2 18.244.0.188 9002 9022 9032
|
||||
platform Tor 0.0.6rc1 on Linux moria.mit.edu i686
|
||||
published 2004-04-25 21:54:30
|
||||
bandwidth 800000 10000000
|
||||
onion-key
|
||||
-----BEGIN RSA PUBLIC KEY-----
|
||||
MIGJAoGBAM4Cc/npgYC54XrYLC+grVxJp7PDmNO2DRRJOxKttBBtvLpnR1UaueTi
|
||||
kyknT5kmlx+ihgZF/jmye//2dDUp2+kK/kSkpRV4xnDLXZmed+sNSQxqmm9TtZQ9
|
||||
/hjpxhp5J9HmUTYhntBs+4E4CUKokmrI6oRLoln4SA39AX9QLPcnAgMBAAE=
|
||||
-----END RSA PUBLIC KEY-----
|
||||
signing-key
|
||||
-----BEGIN RSA PUBLIC KEY-----
|
||||
MIGJAoGBAOcrht/y5rkaahfX7sMe2qnpqoPibsjTSJaDvsUtaNP/Bq0MgNDGOR48
|
||||
rtwfqTRff275Edkp/UYw3G3vSgKCJr76/bqOHCmkiZrnPV1zxNfrK18gNw2Cxre0
|
||||
nTA+fD8JQqpPtb8b0SnG9kwy75eS//sRu7TErie2PzGMxrf9LH0LAgMBAAE=
|
||||
-----END RSA PUBLIC KEY-----
|
||||
reject 0.0.0.0/255.0.0.0:*
|
||||
reject 169.254.0.0/255.255.0.0:*
|
||||
reject 127.0.0.0/255.0.0.0:*
|
||||
reject 192.168.0.0/255.255.0.0:*
|
||||
reject 10.0.0.0/255.0.0.0:*
|
||||
reject 172.16.0.0/255.240.0.0:*
|
||||
accept *:20-22
|
||||
accept *:53
|
||||
accept *:79-80
|
||||
accept *:110
|
||||
accept *:143
|
||||
accept *:443
|
||||
accept *:873
|
||||
accept *:993
|
||||
accept *:995
|
||||
accept *:1024-65535
|
||||
reject *:*
|
||||
router-signature
|
||||
-----BEGIN SIGNATURE-----
|
||||
RKROLwP1ExjTZeg6wuN0pzYqed9IJUd5lAe9hp4ritbnmJAgS6qfww6jgx61CfUR
|
||||
6SElhOLE7Q77jAdoL45Ji5pn/Y+Q+E+5lJm1E/ed9ha+YsOPaOc7z6GQ7E4mihCL
|
||||
gI1vsw92+P1Ty4RHj6fyD9DhbV19nh2Qs+pvGJOS2FY=
|
||||
-----END SIGNATURE-----
|
||||
|
||||
router tor26 62.116.124.106 9001 9050 9030
|
||||
platform Tor 0.0.6 on Linux seppia i686
|
||||
published 2004-05-06 21:33:23
|
||||
bandwidth 500000 10000000
|
||||
onion-key
|
||||
-----BEGIN RSA PUBLIC KEY-----
|
||||
MIGJAoGBAMEHdDnpj3ik1AF1xe/VqjoguH2DbANifYqXXfempu0fS+tU9FGo6dU/
|
||||
fnVHAZwL9Ek9k2rMzumShi1RduK9p035R/Gk+PBBcLfvwYJ/Nat+ZO/L8jn/3bZe
|
||||
ieQd9CKj2LjNGKpRNry37vkwMGIOIlegwK+2us8aXJ7sIvlNts0TAgMBAAE=
|
||||
-----END RSA PUBLIC KEY-----
|
||||
signing-key
|
||||
-----BEGIN RSA PUBLIC KEY-----
|
||||
MIGJAoGBAMQgV2gXLbXgesWgeAsj8P1Uvm/zibrFXqwDq27lLKNgWGYGX2ax3LyT
|
||||
3nzI1Y5oLs4kPKTsMM5ft9aokwf417lKoCRlZc9ptfRbgxDx90c9GtWVmkrmDvCK
|
||||
ae59TMoXIiGfZiwWT6KKq5Zm9/Fu2Il3B2vHGkKJYKixmiBJRKp/AgMBAAE=
|
||||
-----END RSA PUBLIC KEY-----
|
||||
accept 62.245.184.24:25
|
||||
accept 62.116.124.106:6666-6670
|
||||
accept *:48099
|
||||
reject *:*
|
||||
router-signature
|
||||
-----BEGIN SIGNATURE-----
|
||||
qh/xRoqfLNFzPaB8VdpbdMAwRyuk5qjx4LeLVQ2pDwTZ55PqmG99+VKUNte2WTTD
|
||||
7dZEA7um2rueohGe4nYmvbhJWr20/I0ZxmWDRDvFy0b5nwzDMGvLvDw95Zu/XJQ2
|
||||
md32NE3y9VZCfbCN+GlvETX3fdR3Svzcm8Kzesg2/s4=
|
||||
-----END SIGNATURE-----
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
DataDirectory moria1
|
||||
Nickname moria1
|
||||
|
||||
ORPort 9001
|
||||
DirPort 9031
|
||||
|
||||
# List of routers
|
||||
RouterFile ../config/dirservers
|
||||
|
||||
ExitPolicy reject 0.0.0.0/8,reject 127.0.0.0/8,reject 192.168.0.0/16,reject 10.0.0.0/8,reject 172.16.0.0/12,accept *:20-22,accept *:53,accept *:79-80,accept *:110,accept *:143,accept *:443,accept *:873,accept *:1024-65535,reject *:*
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
DataDirectory moria2
|
||||
Nickname moria2
|
||||
|
||||
ORPort 9002
|
||||
DirPort 9032
|
||||
|
||||
# List of routers
|
||||
RouterFile ../config/dirservers
|
||||
|
||||
ExitPolicy reject 0.0.0.0/8,reject 127.0.0.0/8,reject 192.168.0.0/16,reject 10.0.0.0/8,reject 172.16.0.0/12,accept *:20-22,accept *:53,accept *:79-80,accept *:110,accept *:143,accept *:443,accept *:873,accept *:1024-65535,reject *:*
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
DataDirectory moria3
|
||||
Nickname moria3
|
||||
|
||||
ORPort 9003
|
||||
DirPort 9033
|
||||
|
||||
# List of routers
|
||||
RouterFile ../config/dirservers
|
||||
|
||||
ExitPolicy reject 0.0.0.0/8,reject 127.0.0.0/8,reject 192.168.0.0/16,reject 10.0.0.0/8,reject 172.16.0.0/12,accept *:20-22,accept *:53,accept *:79-80,accept *:110,accept *:143,accept *:443,accept *:873,accept *:1024-65535,reject *:*
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Configuration file for a typical tor user
|
||||
|
||||
# List of routers. Tor nodes start out knowing about the directory
|
||||
# servers, and from them they get a list of currently up nodes.
|
||||
RouterFile @CONFDIR@/dirservers
|
||||
|
||||
# Comment out if you don't want to allow applications to connect.
|
||||
SocksPort 9050
|
||||
SocksBindAddress 127.0.0.1 # accept connections only from localhost
|
||||
|
||||
##################### Below is just for servers #####################
|
||||
|
||||
## NOTE: If you enable these, you won't be able to use tor as a client
|
||||
## or server until you've been added to the directory and can
|
||||
## authenticate to the other nodes. See the README for details.
|
||||
|
||||
## The directory for keeping all the keys/etc for this server
|
||||
#DataDirectory @LOCALSTATEDIR@/lib/tor
|
||||
|
||||
#Nickname moria # A unique handle for this server
|
||||
#Address moria.seul.org # The fqdn for this server
|
||||
|
||||
#ORPort 9001 # where to listen for tor connections
|
||||
#ORBindAddress 0.0.0.0 # accept connections from anywhere
|
||||
|
||||
## A comma-separated list of exit policies. If you want to *replace*
|
||||
## the default exit policy, end this with either a reject *:* or an
|
||||
## accept *:*. Otherwise, you're *augmenting* (prepending to) the
|
||||
## default exit policy. Leave commented to just use the default.
|
||||
#ExitPolicy accept 18.244.0.188:25,accept 18.244.0.114:25
|
||||
#ExitPolicy reject *:*
|
||||
|
||||
##################### Below is just for location-hidden services ###
|
||||
|
||||
## This stuff is so bleeding-edge that my teeth hurt just thinking
|
||||
## about it.
|
||||
|
||||
#HiddenServiceDir /tmp/hidden_service/
|
||||
#HiddenServicePort 80 127.0.0.1:80
|
||||
|
||||
#HiddenServiceDir /tmp/other_hidden_service/
|
||||
#HiddenServicePort 80 127.0.0.1:80
|
||||
#HiddenServicePort 22 127.0.0.1:22
|
||||
#HiddenServiceNodes moria1,moria2
|
||||
#HiddenServiceExcludeNodes bad,otherbad
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
tor
|
||||
test
|
||||
.deps
|
||||
@@ -0,0 +1,27 @@
|
||||
TESTS = test
|
||||
|
||||
noinst_PROGRAMS = test
|
||||
|
||||
bin_PROGRAMS = tor
|
||||
|
||||
tor_SOURCES = buffers.c circuit.c command.c config.c \
|
||||
connection.c connection_edge.c connection_or.c \
|
||||
cpuworker.c directory.c dirserv.c dns.c main.c \
|
||||
onion.c rendcommon.c rendclient.c rendmid.c \
|
||||
rendservice.c rephist.c router.c routerlist.c \
|
||||
tor_main.c
|
||||
|
||||
tor_LDADD = ../common/libor.a
|
||||
|
||||
test_SOURCES = buffers.c circuit.c command.c config.c \
|
||||
connection.c connection_edge.c connection_or.c \
|
||||
cpuworker.c directory.c dirserv.c dns.c main.c \
|
||||
onion.c rendcommon.c rendclient.c rendmid.c \
|
||||
rendservice.c rephist.c router.c routerlist.c \
|
||||
test.c
|
||||
|
||||
test_LDADD = ../common/libor.a
|
||||
|
||||
noinst_HEADERS = or.h tree.h
|
||||
|
||||
|
||||
@@ -0,0 +1,630 @@
|
||||
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
/*****
|
||||
* buffers.c: Abstractions for buffered IO.
|
||||
*****/
|
||||
|
||||
#include "or.h"
|
||||
|
||||
#define BUFFER_MAGIC 0xB0FFF312u
|
||||
struct buf_t {
|
||||
uint32_t magic; /* Magic cookie for debugging: Must be set to BUFFER_MAGIC */
|
||||
char *mem; /* Storage for data in the buffer */
|
||||
size_t len; /* Maximum amount of data that 'mem' can hold. */
|
||||
size_t datalen; /* Number of bytes currently in 'mem'. */
|
||||
};
|
||||
|
||||
/* Size, in bytes, for newly allocated buffers. Should be a power of 2. */
|
||||
#define INITIAL_BUF_SIZE (4*1024)
|
||||
/* Maximum size, in bytes, for resized buffers. */
|
||||
#define MAX_BUF_SIZE (1024*1024*10)
|
||||
/* Size, in bytes, for minimum 'shrink' size for buffers. Buffers may start
|
||||
* out smaller than this, but they will never autoshrink to less
|
||||
* than this size. */
|
||||
#define MIN_BUF_SHRINK_SIZE (16*1024)
|
||||
|
||||
/* Change a buffer's capacity. new_capacity must be <= buf->datalen. */
|
||||
static INLINE void buf_resize(buf_t *buf, size_t new_capacity)
|
||||
{
|
||||
tor_assert(buf->datalen <= new_capacity);
|
||||
tor_assert(new_capacity);
|
||||
buf->mem = tor_realloc(buf->mem, new_capacity);
|
||||
buf->len = new_capacity;
|
||||
}
|
||||
|
||||
/* If the buffer is not large enough to hold "capacity" bytes, resize
|
||||
* it so that it can. (The new size will be a power of 2 times the old
|
||||
* size.)
|
||||
*/
|
||||
static INLINE int buf_ensure_capacity(buf_t *buf, size_t capacity)
|
||||
{
|
||||
size_t new_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.
|
||||
*/
|
||||
new_len = buf->len*2;
|
||||
while (new_len < capacity)
|
||||
new_len *= 2;
|
||||
/* Resize the buffer. */
|
||||
log_fn(LOG_DEBUG,"Growing buffer from %d to %d bytes.",
|
||||
(int)buf->len, (int)new_len);
|
||||
buf_resize(buf,new_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the buffer is at least 2*MIN_BUF_SHRINK_SIZE bytes in capacity,
|
||||
* and if the buffer is less than 1/4 full, shrink the buffer until
|
||||
* one of the above no longer holds. (We shrink the buffer by
|
||||
* dividing by powers of 2.)
|
||||
*/
|
||||
static INLINE void buf_shrink_if_underfull(buf_t *buf) {
|
||||
size_t new_len;
|
||||
/* If the buffer is at least .25 full, or if shrinking the buffer would
|
||||
* put it onder MIN_BUF_SHRINK_SIZE, don't do it. */
|
||||
if (buf->datalen >= buf->len/4 || buf->len < 2*MIN_BUF_SHRINK_SIZE)
|
||||
return;
|
||||
/* Shrink new_len by powers of 2 until: datalen is at least 1/4 of
|
||||
* new_len, OR shrinking new_len more would put it under
|
||||
* MIN_BUF_SHRINK_SIZE.
|
||||
*/
|
||||
new_len = buf->len / 2;
|
||||
while (buf->datalen < new_len/4 && new_len/2 > MIN_BUF_SHRINK_SIZE)
|
||||
new_len /= 2;
|
||||
log_fn(LOG_DEBUG,"Shrinking buffer from %d to %d bytes.",
|
||||
(int)buf->len, (int)new_len);
|
||||
buf_resize(buf, new_len);
|
||||
}
|
||||
|
||||
/* Remove the first 'n' bytes from buf.
|
||||
*/
|
||||
static INLINE void buf_remove_from_front(buf_t *buf, size_t n) {
|
||||
tor_assert(buf->datalen >= n);
|
||||
buf->datalen -= n;
|
||||
memmove(buf->mem, buf->mem+n, buf->datalen);
|
||||
buf_shrink_if_underfull(buf);
|
||||
}
|
||||
|
||||
/* Find the first instance of the str_len byte string 'sr' on the
|
||||
* buf_len byte string 'bufstr'. Strings are not necessary
|
||||
* NUL-terminated. If none exists, return -1. Otherwise, return index
|
||||
* of the first character in bufstr _after_ the first instance of str.
|
||||
*/
|
||||
/* XXXX The way this function is used, we could always get away with
|
||||
* XXXX assuming that str is NUL terminated, and use strstr instead. */
|
||||
static int find_mem_in_mem(const char *str, int str_len,
|
||||
const char *bufstr, int buf_len)
|
||||
{
|
||||
const char *location;
|
||||
const char *last_possible = bufstr + buf_len - str_len;
|
||||
|
||||
tor_assert(str && str_len > 0 && bufstr);
|
||||
|
||||
if(buf_len < str_len)
|
||||
return -1;
|
||||
|
||||
for(location = bufstr; location <= last_possible; location++)
|
||||
if((*location == *str) && !memcmp(location+1, str+1, str_len-1))
|
||||
return location-bufstr+str_len;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create and return a new buf with capacity 'size'.
|
||||
*/
|
||||
buf_t *buf_new_with_capacity(size_t size) {
|
||||
buf_t *buf;
|
||||
buf = tor_malloc(sizeof(buf_t));
|
||||
buf->magic = BUFFER_MAGIC;
|
||||
buf->mem = tor_malloc(size);
|
||||
buf->len = size;
|
||||
buf->datalen = 0;
|
||||
// memset(buf->mem,0,size);
|
||||
|
||||
assert_buf_ok(buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Allocate and return a new buffer with default capacity. */
|
||||
buf_t *buf_new()
|
||||
{
|
||||
return buf_new_with_capacity(INITIAL_BUF_SIZE);
|
||||
}
|
||||
|
||||
/* Remove all data from 'buf' */
|
||||
void buf_clear(buf_t *buf)
|
||||
{
|
||||
buf->datalen = 0;
|
||||
}
|
||||
|
||||
/* Return the number of bytes stored in 'buf' */
|
||||
size_t buf_datalen(const buf_t *buf)
|
||||
{
|
||||
return buf->datalen;
|
||||
}
|
||||
|
||||
/* Return the maximum bytes that can be stored in 'buf' before buf
|
||||
* needs to resize. */
|
||||
size_t buf_capacity(const buf_t *buf)
|
||||
{
|
||||
return buf->len;
|
||||
}
|
||||
|
||||
/* For testing only: Return a pointer to the raw memory stored in 'buf'.
|
||||
*/
|
||||
const char *_buf_peek_raw_buffer(const buf_t *buf)
|
||||
{
|
||||
return buf->mem;
|
||||
}
|
||||
|
||||
/* Release storage held by 'buf'.
|
||||
*/
|
||||
void buf_free(buf_t *buf) {
|
||||
assert_buf_ok(buf);
|
||||
buf->magic = 0xDEADBEEF;
|
||||
tor_free(buf->mem);
|
||||
tor_free(buf);
|
||||
}
|
||||
|
||||
/* Read from socket s, writing onto end of buf. Read at most
|
||||
* 'at_most' bytes, resizing the buffer as necessary. If read()
|
||||
* returns 0, set *reached_eof to 1 and return 0. Return -1 on error;
|
||||
* else return the number of bytes read. Return 0 if read() would
|
||||
* block.
|
||||
*/
|
||||
int read_to_buf(int s, size_t at_most, buf_t *buf, int *reached_eof) {
|
||||
|
||||
int read_result;
|
||||
|
||||
assert_buf_ok(buf);
|
||||
tor_assert(reached_eof && (s>=0));
|
||||
|
||||
if (buf_ensure_capacity(buf,buf->datalen+at_most))
|
||||
return -1;
|
||||
|
||||
if(at_most + buf->datalen > buf->len)
|
||||
at_most = buf->len - buf->datalen; /* take the min of the two */
|
||||
|
||||
if(at_most == 0)
|
||||
return 0; /* we shouldn't read anything */
|
||||
|
||||
// log_fn(LOG_DEBUG,"reading at most %d bytes.",at_most);
|
||||
read_result = recv(s, buf->mem+buf->datalen, at_most, 0);
|
||||
if (read_result < 0) {
|
||||
if(!ERRNO_IS_EAGAIN(tor_socket_errno(s))) { /* it's a real error */
|
||||
return -1;
|
||||
}
|
||||
return 0; /* would block. */
|
||||
} else if (read_result == 0) {
|
||||
log_fn(LOG_DEBUG,"Encountered eof");
|
||||
*reached_eof = 1;
|
||||
return 0;
|
||||
} else { /* we read some bytes */
|
||||
buf->datalen += read_result;
|
||||
log_fn(LOG_DEBUG,"Read %d bytes. %d on inbuf.",read_result,
|
||||
(int)buf->datalen);
|
||||
return read_result;
|
||||
}
|
||||
}
|
||||
|
||||
/* As read_to_buf, but reads from a TLS connection.
|
||||
*/
|
||||
int read_to_buf_tls(tor_tls *tls, size_t at_most, buf_t *buf) {
|
||||
int r;
|
||||
tor_assert(tls);
|
||||
assert_buf_ok(buf);
|
||||
|
||||
log_fn(LOG_DEBUG,"start: %d on buf, %d pending, at_most %d.",(int)buf_datalen(buf),
|
||||
tor_tls_get_pending_bytes(tls), at_most);
|
||||
|
||||
if (buf_ensure_capacity(buf, at_most+buf->datalen))
|
||||
return TOR_TLS_ERROR;
|
||||
|
||||
if (at_most + buf->datalen > buf->len)
|
||||
at_most = buf->len - buf->datalen;
|
||||
|
||||
if (at_most == 0)
|
||||
return 0;
|
||||
|
||||
log_fn(LOG_DEBUG,"before: %d on buf, %d pending, at_most %d.",(int)buf_datalen(buf),
|
||||
tor_tls_get_pending_bytes(tls), at_most);
|
||||
|
||||
assert_no_tls_errors();
|
||||
r = tor_tls_read(tls, buf->mem+buf->datalen, at_most);
|
||||
if (r<0)
|
||||
return r;
|
||||
buf->datalen += r;
|
||||
log_fn(LOG_DEBUG,"Read %d bytes. %d on inbuf; %d pending",r,
|
||||
(int)buf->datalen,(int)tor_tls_get_pending_bytes(tls));
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Write data from 'buf' to the socket 's'. Write at most
|
||||
* *buf_flushlen bytes, and decrement *buf_flushlen by the number of
|
||||
* bytes actually written. Return the number of bytes written on
|
||||
* success, -1 on failure. Return 0 if write() would block.
|
||||
*/
|
||||
int flush_buf(int s, buf_t *buf, int *buf_flushlen)
|
||||
{
|
||||
/* push from buf onto s
|
||||
* then memmove to front of buf
|
||||
* return -1 or how many bytes you just flushed */
|
||||
|
||||
int write_result;
|
||||
|
||||
assert_buf_ok(buf);
|
||||
tor_assert(buf_flushlen && (s>=0) && ((unsigned)*buf_flushlen <= buf->datalen));
|
||||
|
||||
if(*buf_flushlen == 0) /* nothing to flush */
|
||||
return 0;
|
||||
|
||||
write_result = send(s, buf->mem, *buf_flushlen, 0);
|
||||
if (write_result < 0) {
|
||||
if(!ERRNO_IS_EAGAIN(tor_socket_errno(s))) { /* it's a real error */
|
||||
/* get a stack trace to find epipe bugs */
|
||||
tor_assert(tor_socket_errno(s) != EPIPE);
|
||||
return -1;
|
||||
}
|
||||
log_fn(LOG_DEBUG,"write() would block, returning.");
|
||||
return 0;
|
||||
} else {
|
||||
*buf_flushlen -= write_result;
|
||||
buf_remove_from_front(buf, write_result);
|
||||
log_fn(LOG_DEBUG,"%d: flushed %d bytes, %d ready to flush, %d remain.",
|
||||
s,write_result,*buf_flushlen,(int)buf->datalen);
|
||||
|
||||
return write_result;
|
||||
}
|
||||
}
|
||||
|
||||
/* As flush_buf, but writes data to a TLS connection.
|
||||
*/
|
||||
int flush_buf_tls(tor_tls *tls, buf_t *buf, int *buf_flushlen)
|
||||
{
|
||||
int r;
|
||||
assert_buf_ok(buf);
|
||||
tor_assert(tls && buf_flushlen);
|
||||
|
||||
/* we want to let tls write even if flushlen is zero, because it might
|
||||
* have a partial record pending */
|
||||
r = tor_tls_write(tls, buf->mem, *buf_flushlen);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
*buf_flushlen -= r;
|
||||
buf_remove_from_front(buf, r);
|
||||
log_fn(LOG_DEBUG,"flushed %d bytes, %d ready to flush, %d remain.",
|
||||
r,*buf_flushlen,(int)buf->datalen);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Append string_len bytes from 'string' to the end of 'buf'.
|
||||
* Return the new length of the buffer on success, -1 on failure.
|
||||
*/
|
||||
int write_to_buf(const char *string, int string_len, buf_t *buf) {
|
||||
|
||||
/* append string to buf (growing as needed, return -1 if "too big")
|
||||
* return total number of bytes on the buf
|
||||
*/
|
||||
|
||||
tor_assert(string);
|
||||
assert_buf_ok(buf);
|
||||
|
||||
if (buf_ensure_capacity(buf, buf->datalen+string_len)) {
|
||||
log_fn(LOG_WARN, "buflen too small, can't hold %d bytes.", (int)buf->datalen+string_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(buf->mem+buf->datalen, string, string_len);
|
||||
buf->datalen += string_len;
|
||||
log_fn(LOG_DEBUG,"added %d bytes to buf (now %d total).",string_len, (int)buf->datalen);
|
||||
return buf->datalen;
|
||||
}
|
||||
|
||||
|
||||
/* Remove string_len bytes from the front of 'buf', and store them
|
||||
* into 'string'. Return the new buffer size. string_len must be <=
|
||||
* the number of bytes on the buffer.
|
||||
*/
|
||||
int fetch_from_buf(char *string, size_t string_len, buf_t *buf) {
|
||||
|
||||
/* There must be string_len bytes in buf; write them onto string,
|
||||
* then memmove buf back (that is, remove them from buf).
|
||||
*
|
||||
* Return the number of bytes still on the buffer. */
|
||||
|
||||
tor_assert(string);
|
||||
tor_assert(string_len <= buf->datalen); /* make sure we don't ask for too much */
|
||||
assert_buf_ok(buf);
|
||||
|
||||
memcpy(string,buf->mem,string_len);
|
||||
buf_remove_from_front(buf, string_len);
|
||||
return buf->datalen;
|
||||
}
|
||||
|
||||
/* There is a (possibly incomplete) http statement on *buf, of the
|
||||
* form "%s\r\n\r\n%s", headers, body. (body may contain nuls.)
|
||||
* If a) the headers include a Content-Length field and all bytes in
|
||||
* the body are present, or b) there's no Content-Length field and
|
||||
* all headers are present, then:
|
||||
* strdup headers into *headers_out, and nul-terminate it.
|
||||
* memdup body into *body_out, and nul-terminate it.
|
||||
* Then remove them from buf, and return 1.
|
||||
*
|
||||
* If headers or body is NULL, discard that part of the buf.
|
||||
* If a headers or body doesn't fit in the arg, return -1.
|
||||
*
|
||||
* Else, change nothing and return 0.
|
||||
*/
|
||||
int fetch_from_buf_http(buf_t *buf,
|
||||
char **headers_out, int max_headerlen,
|
||||
char **body_out, int *body_used, int max_bodylen) {
|
||||
char *headers, *body;
|
||||
int i;
|
||||
int headerlen, bodylen, contentlen;
|
||||
|
||||
assert_buf_ok(buf);
|
||||
|
||||
headers = buf->mem;
|
||||
i = find_mem_in_mem("\r\n\r\n", 4, buf->mem, buf->datalen);
|
||||
if(i < 0) {
|
||||
log_fn(LOG_DEBUG,"headers not all here yet.");
|
||||
return 0;
|
||||
}
|
||||
body = buf->mem+i;
|
||||
headerlen = body-headers; /* includes the CRLFCRLF */
|
||||
bodylen = buf->datalen - headerlen;
|
||||
log_fn(LOG_DEBUG,"headerlen %d, bodylen %d.", headerlen, bodylen);
|
||||
|
||||
if(headers_out && max_headerlen <= headerlen) {
|
||||
log_fn(LOG_WARN,"headerlen %d larger than %d. Failing.", headerlen, max_headerlen-1);
|
||||
return -1;
|
||||
}
|
||||
if(body_out && max_bodylen <= bodylen) {
|
||||
log_fn(LOG_WARN,"bodylen %d larger than %d. Failing.", bodylen, max_bodylen-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define CONTENT_LENGTH "\r\nContent-Length: "
|
||||
i = find_mem_in_mem(CONTENT_LENGTH, strlen(CONTENT_LENGTH),
|
||||
headers, headerlen);
|
||||
if(i > 0) {
|
||||
contentlen = atoi(headers+i);
|
||||
/* if content-length is malformed, then our body length is 0. fine. */
|
||||
log_fn(LOG_DEBUG,"Got a contentlen of %d.",contentlen);
|
||||
if(bodylen < contentlen) {
|
||||
log_fn(LOG_DEBUG,"body not all here yet.");
|
||||
return 0; /* not all there yet */
|
||||
}
|
||||
if(bodylen > contentlen) {
|
||||
bodylen = contentlen;
|
||||
log_fn(LOG_DEBUG,"bodylen reduced to %d.",bodylen);
|
||||
}
|
||||
}
|
||||
/* all happy. copy into the appropriate places, and return 1 */
|
||||
if(headers_out) {
|
||||
*headers_out = tor_malloc(headerlen+1);
|
||||
memcpy(*headers_out,buf->mem,headerlen);
|
||||
(*headers_out)[headerlen] = 0; /* null terminate it */
|
||||
}
|
||||
if(body_out) {
|
||||
tor_assert(body_used);
|
||||
*body_used = bodylen;
|
||||
*body_out = tor_malloc(bodylen+1);
|
||||
memcpy(*body_out,buf->mem+headerlen,bodylen);
|
||||
(*body_out)[bodylen] = 0; /* null terminate it */
|
||||
}
|
||||
buf_remove_from_front(buf, headerlen+bodylen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* There is a (possibly incomplete) socks handshake on buf, of one
|
||||
* of the forms
|
||||
* socks4: "socksheader username\0"
|
||||
* socks4a: "socksheader username\0 destaddr\0"
|
||||
* socks5 phase one: "version #methods methods"
|
||||
* socks5 phase two: "version command 0 addresstype..."
|
||||
* If it's a complete and valid handshake, and destaddr fits in
|
||||
* MAX_SOCKS_ADDR_LEN bytes, then pull the handshake off the buf,
|
||||
* assign to req, and return 1.
|
||||
* If it's invalid or too big, return -1.
|
||||
* Else it's not all there yet, leave buf alone and return 0.
|
||||
* If you want to specify the socks reply, write it into req->reply
|
||||
* and set req->replylen, else leave req->replylen alone.
|
||||
* If returning 0 or -1, req->address and req->port are undefined.
|
||||
*/
|
||||
int fetch_from_buf_socks(buf_t *buf, socks_request_t *req) {
|
||||
unsigned char len;
|
||||
char *tmpbuf=NULL;
|
||||
uint32_t destip;
|
||||
enum {socks4, socks4a} socks4_prot = socks4a;
|
||||
char *next, *startaddr;
|
||||
struct in_addr in;
|
||||
|
||||
if(buf->datalen < 2) /* version and another byte */
|
||||
return 0;
|
||||
switch(*(buf->mem)) { /* which version of socks? */
|
||||
|
||||
case 5: /* socks5 */
|
||||
|
||||
if(req->socks_version != 5) { /* we need to negotiate a method */
|
||||
unsigned char nummethods = (unsigned char)*(buf->mem+1);
|
||||
tor_assert(!req->socks_version);
|
||||
if(buf->datalen < 2u+nummethods)
|
||||
return 0;
|
||||
if(!nummethods || !memchr(buf->mem+2, 0, nummethods)) {
|
||||
log_fn(LOG_WARN,"socks5: offered methods don't include 'no auth'. Rejecting.");
|
||||
req->replylen = 2; /* 2 bytes of response */
|
||||
req->reply[0] = 5; /* socks5 reply */
|
||||
req->reply[1] = '\xFF'; /* reject all methods */
|
||||
return -1;
|
||||
}
|
||||
buf_remove_from_front(buf,2+nummethods);/* remove packet from buf */
|
||||
|
||||
req->replylen = 2; /* 2 bytes of response */
|
||||
req->reply[0] = 5; /* socks5 reply */
|
||||
req->reply[1] = 0; /* choose the 'no auth' method */
|
||||
req->socks_version = 5; /* remember that we've already negotiated auth */
|
||||
log_fn(LOG_DEBUG,"socks5: accepted method 0");
|
||||
return 0;
|
||||
}
|
||||
/* we know the method; read in the request */
|
||||
log_fn(LOG_DEBUG,"socks5: checking request");
|
||||
if(buf->datalen < 8) /* basic info plus >=2 for addr plus 2 for port */
|
||||
return 0; /* not yet */
|
||||
if(*(buf->mem+1) != 1) { /* not a connect? we don't support it. */
|
||||
log_fn(LOG_WARN,"socks5: command %d not '1'. Rejecting.",*(buf->mem+1));
|
||||
return -1;
|
||||
}
|
||||
switch(*(buf->mem+3)) { /* address type */
|
||||
case 1: /* IPv4 address */
|
||||
log_fn(LOG_DEBUG,"socks5: ipv4 address type");
|
||||
if(buf->datalen < 10) /* ip/port there? */
|
||||
return 0; /* not yet */
|
||||
destip = ntohl(*(uint32_t*)(buf->mem+4));
|
||||
in.s_addr = htonl(destip);
|
||||
tmpbuf = inet_ntoa(in);
|
||||
if(strlen(tmpbuf)+1 > MAX_SOCKS_ADDR_LEN) {
|
||||
log_fn(LOG_WARN,"socks5 IP takes %d bytes, which doesn't fit in %d. Rejecting.",
|
||||
(int)strlen(tmpbuf)+1,(int)MAX_SOCKS_ADDR_LEN);
|
||||
return -1;
|
||||
}
|
||||
strcpy(req->address,tmpbuf);
|
||||
req->port = ntohs(*(uint16_t*)(buf->mem+8));
|
||||
buf_remove_from_front(buf, 10);
|
||||
return 1;
|
||||
case 3: /* fqdn */
|
||||
log_fn(LOG_DEBUG,"socks5: fqdn address type");
|
||||
len = (unsigned char)*(buf->mem+4);
|
||||
if(buf->datalen < 7u+len) /* addr/port there? */
|
||||
return 0; /* not yet */
|
||||
if(len+1 > MAX_SOCKS_ADDR_LEN) {
|
||||
log_fn(LOG_WARN,"socks5 hostname is %d bytes, which doesn't fit in %d. Rejecting.",
|
||||
len+1,MAX_SOCKS_ADDR_LEN);
|
||||
return -1;
|
||||
}
|
||||
memcpy(req->address,buf->mem+5,len);
|
||||
req->address[len] = 0;
|
||||
req->port = ntohs(get_uint16(buf->mem+5+len));
|
||||
buf_remove_from_front(buf, 5+len+2);
|
||||
return 1;
|
||||
default: /* unsupported */
|
||||
log_fn(LOG_WARN,"socks5: unsupported address type %d. Rejecting.",*(buf->mem+3));
|
||||
return -1;
|
||||
}
|
||||
tor_assert(0);
|
||||
case 4: /* socks4 */
|
||||
/* http://archive.socks.permeo.com/protocol/socks4.protocol */
|
||||
/* http://archive.socks.permeo.com/protocol/socks4a.protocol */
|
||||
|
||||
req->socks_version = 4;
|
||||
if(buf->datalen < SOCKS4_NETWORK_LEN) /* basic info available? */
|
||||
return 0; /* not yet */
|
||||
|
||||
if(*(buf->mem+1) != 1) { /* not a connect? we don't support it. */
|
||||
log_fn(LOG_WARN,"socks4: command %d not '1'. Rejecting.",*(buf->mem+1));
|
||||
return -1;
|
||||
}
|
||||
|
||||
req->port = ntohs(*(uint16_t*)(buf->mem+2));
|
||||
destip = ntohl(*(uint32_t*)(buf->mem+4));
|
||||
if(!req->port || !destip) {
|
||||
log_fn(LOG_WARN,"socks4: Port or DestIP is zero. Rejecting.");
|
||||
return -1;
|
||||
}
|
||||
if(destip >> 8) {
|
||||
log_fn(LOG_DEBUG,"socks4: destip not in form 0.0.0.x.");
|
||||
in.s_addr = htonl(destip);
|
||||
tmpbuf = inet_ntoa(in);
|
||||
if(strlen(tmpbuf)+1 > MAX_SOCKS_ADDR_LEN) {
|
||||
log_fn(LOG_WARN,"socks4 addr (%d bytes) too long. Rejecting.",
|
||||
(int)strlen(tmpbuf));
|
||||
return -1;
|
||||
}
|
||||
log_fn(LOG_DEBUG,"socks4: successfully read destip (%s)", tmpbuf);
|
||||
socks4_prot = socks4;
|
||||
}
|
||||
|
||||
next = memchr(buf->mem+SOCKS4_NETWORK_LEN, 0, buf->datalen);
|
||||
if(!next) {
|
||||
log_fn(LOG_DEBUG,"socks4: Username not here yet.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
startaddr = next+1;
|
||||
if(socks4_prot == socks4a) {
|
||||
next = memchr(startaddr, 0, buf->mem+buf->datalen-startaddr);
|
||||
if(!next) {
|
||||
log_fn(LOG_DEBUG,"socks4: Destaddr not here yet.");
|
||||
return 0;
|
||||
}
|
||||
if(MAX_SOCKS_ADDR_LEN <= next-startaddr) {
|
||||
log_fn(LOG_WARN,"socks4: Destaddr too long. Rejecting.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
log_fn(LOG_DEBUG,"socks4: Everything is here. Success.");
|
||||
strcpy(req->address, socks4_prot == socks4 ? tmpbuf : startaddr);
|
||||
/* XXX on very old netscapes (socks4) the next line triggers an
|
||||
* assert, because next-buf->mem+1 is greater than buf->datalen.
|
||||
*/
|
||||
buf_remove_from_front(buf, next-buf->mem+1); /* next points to the final \0 on inbuf */
|
||||
return 1;
|
||||
|
||||
case 'G': /* get */
|
||||
case 'H': /* head */
|
||||
case 'P': /* put/post */
|
||||
case 'C': /* connect */
|
||||
strcpy(req->reply,
|
||||
"HTTP/1.0 501 Tor is not an HTTP Proxy\r\n"
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n\r\n"
|
||||
"<html>\n"
|
||||
"<head>\n"
|
||||
"<title>Tor is not an HTTP Proxy</title>\n"
|
||||
"</head>\n"
|
||||
"<body>\n"
|
||||
"<h1>Tor is not an HTTP Proxy</h1>\n"
|
||||
"<p>\n"
|
||||
"It appears you have configured your web browser to use Tor as an HTTP Proxy.\n"
|
||||
"This is not correct: Tor provides a SOCKS proxy. Please configure your\n"
|
||||
"client accordingly.\n"
|
||||
"</p>\n"
|
||||
"<p>\n"
|
||||
"See <a href=\"http://freehaven.net/tor/cvs/INSTALL\">http://freehaven.net/tor/cvs/INSTALL</a> for more information.\n"
|
||||
"<!-- Plus this comment, to make the body response more than 512 bytes, so IE will be willing to display it. Comment comment comment comment comment comment comment comment comment comment comment comment.-->\n"
|
||||
"</p>\n"
|
||||
"</body>\n"
|
||||
"</html>\n"
|
||||
);
|
||||
req->replylen = strlen(req->reply)+1;
|
||||
/* fall through */
|
||||
default: /* version is not socks4 or socks5 */
|
||||
log_fn(LOG_WARN,"Socks version %d not recognized. (Tor is not an http proxy.)",
|
||||
*(buf->mem));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Log an error and exit if 'buf' is corrupted.
|
||||
*/
|
||||
void assert_buf_ok(buf_t *buf)
|
||||
{
|
||||
tor_assert(buf);
|
||||
tor_assert(buf->magic == BUFFER_MAGIC);
|
||||
tor_assert(buf->mem);
|
||||
tor_assert(buf->datalen <= buf->len);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,226 @@
|
||||
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
#include "or.h"
|
||||
|
||||
extern or_options_t options; /* command-line and config-file options */
|
||||
|
||||
unsigned long stats_n_padding_cells_processed = 0;
|
||||
unsigned long stats_n_create_cells_processed = 0;
|
||||
unsigned long stats_n_created_cells_processed = 0;
|
||||
unsigned long stats_n_relay_cells_processed = 0;
|
||||
unsigned long stats_n_destroy_cells_processed = 0;
|
||||
|
||||
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_time_process_cell(cell_t *cell, connection_t *conn,
|
||||
int *num, int *time,
|
||||
void (*func)(cell_t *, connection_t *)) {
|
||||
struct timeval start, end;
|
||||
long time_passed;
|
||||
|
||||
*num += 1;
|
||||
|
||||
tor_gettimeofday(&start);
|
||||
|
||||
(*func)(cell, conn);
|
||||
|
||||
tor_gettimeofday(&end);
|
||||
time_passed = tv_udiff(&start, &end) ;
|
||||
|
||||
if (time_passed > 10000) { /* more than 10ms */
|
||||
log_fn(LOG_INFO,"That call just took %ld ms.",time_passed/1000);
|
||||
}
|
||||
*time += time_passed;
|
||||
}
|
||||
|
||||
void command_process_cell(cell_t *cell, connection_t *conn) {
|
||||
static int num_create=0, num_created=0, num_relay=0, num_destroy=0;
|
||||
static int create_time=0, created_time=0, relay_time=0, destroy_time=0;
|
||||
static time_t current_second = 0; /* from previous calls to time */
|
||||
time_t now = time(NULL);
|
||||
|
||||
if(now > current_second) { /* the second has rolled over */
|
||||
/* print stats */
|
||||
log(LOG_INFO,"At end of second: %d creates (%d ms), %d createds (%d ms), %d relays (%d ms), %d destroys (%d ms)",
|
||||
num_create, create_time/1000,
|
||||
num_created, created_time/1000,
|
||||
num_relay, relay_time/1000,
|
||||
num_destroy, destroy_time/1000);
|
||||
|
||||
/* zero out stats */
|
||||
num_create = num_created = num_relay = num_destroy = 0;
|
||||
create_time = created_time = relay_time = destroy_time = 0;
|
||||
|
||||
/* remember which second it is, for next time */
|
||||
current_second = now;
|
||||
}
|
||||
|
||||
switch(cell->command) {
|
||||
case CELL_PADDING:
|
||||
++stats_n_padding_cells_processed;
|
||||
/* do nothing */
|
||||
break;
|
||||
case CELL_CREATE:
|
||||
++stats_n_create_cells_processed;
|
||||
command_time_process_cell(cell, conn, &num_create, &create_time,
|
||||
command_process_create_cell);
|
||||
break;
|
||||
case CELL_CREATED:
|
||||
++stats_n_created_cells_processed;
|
||||
command_time_process_cell(cell, conn, &num_created, &created_time,
|
||||
command_process_created_cell);
|
||||
break;
|
||||
case CELL_RELAY:
|
||||
++stats_n_relay_cells_processed;
|
||||
command_time_process_cell(cell, conn, &num_relay, &relay_time,
|
||||
command_process_relay_cell);
|
||||
break;
|
||||
case CELL_DESTROY:
|
||||
++stats_n_destroy_cells_processed;
|
||||
command_time_process_cell(cell, conn, &num_destroy, &destroy_time,
|
||||
command_process_destroy_cell);
|
||||
break;
|
||||
default:
|
||||
log_fn(LOG_WARN,"Cell of unknown type (%d) received. Dropping.", cell->command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void command_process_create_cell(cell_t *cell, connection_t *conn) {
|
||||
circuit_t *circ;
|
||||
|
||||
circ = circuit_get_by_circ_id_conn(cell->circ_id, conn);
|
||||
|
||||
if(circ) {
|
||||
log_fn(LOG_WARN,"received CREATE cell (circID %d) for known circ. Dropping.", cell->circ_id);
|
||||
return;
|
||||
}
|
||||
|
||||
circ = circuit_new(cell->circ_id, conn);
|
||||
circ->state = CIRCUIT_STATE_ONIONSKIN_PENDING;
|
||||
circ->purpose = CIRCUIT_PURPOSE_OR;
|
||||
|
||||
memcpy(circ->onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN);
|
||||
|
||||
/* hand it off to the cpuworkers, and then return */
|
||||
if(assign_to_cpuworker(NULL, CPUWORKER_TASK_ONION, circ) < 0) {
|
||||
log_fn(LOG_WARN,"Failed to hand off onionskin. Closing.");
|
||||
circuit_mark_for_close(circ);
|
||||
return;
|
||||
}
|
||||
log_fn(LOG_DEBUG,"success: handed off onionskin.");
|
||||
}
|
||||
|
||||
static void command_process_created_cell(cell_t *cell, connection_t *conn) {
|
||||
circuit_t *circ;
|
||||
|
||||
circ = circuit_get_by_circ_id_conn(cell->circ_id, conn);
|
||||
|
||||
if(!circ) {
|
||||
log_fn(LOG_INFO,"(circID %d) unknown circ (probably got a destroy earlier). Dropping.", cell->circ_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if(circ->n_circ_id != cell->circ_id) {
|
||||
log_fn(LOG_WARN,"got created cell from OPward? Closing.");
|
||||
circuit_mark_for_close(circ);
|
||||
return;
|
||||
}
|
||||
|
||||
if(CIRCUIT_IS_ORIGIN(circ)) { /* we're the OP. Handshake this. */
|
||||
log_fn(LOG_DEBUG,"at OP. Finishing handshake.");
|
||||
if(circuit_finish_handshake(circ, cell->payload) < 0) {
|
||||
log_fn(LOG_WARN,"circuit_finish_handshake failed.");
|
||||
circuit_mark_for_close(circ);
|
||||
return;
|
||||
}
|
||||
log_fn(LOG_DEBUG,"Moving to next skin.");
|
||||
if(circuit_send_next_onion_skin(circ) < 0) {
|
||||
log_fn(LOG_INFO,"circuit_send_next_onion_skin failed.");
|
||||
circuit_mark_for_close(circ); /* XXX push this circuit_close lower */
|
||||
return;
|
||||
}
|
||||
} else { /* pack it into an extended relay cell, and send it. */
|
||||
log_fn(LOG_DEBUG,"Converting created cell to extended relay cell, sending.");
|
||||
connection_edge_send_command(NULL, circ, RELAY_COMMAND_EXTENDED,
|
||||
cell->payload, ONIONSKIN_REPLY_LEN, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void command_process_relay_cell(cell_t *cell, connection_t *conn) {
|
||||
circuit_t *circ;
|
||||
|
||||
circ = circuit_get_by_circ_id_conn(cell->circ_id, conn);
|
||||
|
||||
if(!circ) {
|
||||
log_fn(LOG_INFO,"unknown circuit %d on connection to %s:%d. Dropping.",
|
||||
cell->circ_id, conn->address, conn->port);
|
||||
return;
|
||||
}
|
||||
|
||||
if(circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
|
||||
log_fn(LOG_WARN,"circuit in create_wait. Closing.");
|
||||
circuit_mark_for_close(circ);
|
||||
return;
|
||||
}
|
||||
|
||||
if(cell->circ_id == circ->p_circ_id) { /* it's an outgoing cell */
|
||||
if(circuit_receive_relay_cell(cell, circ, CELL_DIRECTION_OUT) < 0) {
|
||||
log_fn(LOG_WARN,"circuit_receive_relay_cell (forward) failed. Closing.");
|
||||
circuit_mark_for_close(circ);
|
||||
return;
|
||||
}
|
||||
} else { /* it's an ingoing cell */
|
||||
if(circuit_receive_relay_cell(cell, circ, CELL_DIRECTION_IN) < 0) {
|
||||
log_fn(LOG_WARN,"circuit_receive_relay_cell (backward) failed. Closing.");
|
||||
circuit_mark_for_close(circ);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void command_process_destroy_cell(cell_t *cell, connection_t *conn) {
|
||||
circuit_t *circ;
|
||||
|
||||
circ = circuit_get_by_circ_id_conn(cell->circ_id, conn);
|
||||
|
||||
if(!circ) {
|
||||
log_fn(LOG_INFO,"unknown circuit %d on connection to %s:%d. Dropping.",
|
||||
cell->circ_id, conn->address, conn->port);
|
||||
return;
|
||||
}
|
||||
|
||||
log_fn(LOG_INFO,"Received for circID %d.",cell->circ_id);
|
||||
if(circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
|
||||
onion_pending_remove(circ);
|
||||
}
|
||||
|
||||
if(cell->circ_id == circ->p_circ_id) {
|
||||
/* the destroy came from behind */
|
||||
circ->p_conn = NULL;
|
||||
circuit_mark_for_close(circ);
|
||||
} else { /* the destroy came from ahead */
|
||||
circ->n_conn = NULL;
|
||||
#if 0
|
||||
if(!CIRCUIT_IS_ORIGIN(circ)) {
|
||||
log_fn(LOG_DEBUG, "Delivering 'truncated' back.");
|
||||
connection_edge_send_command(NULL, circ, RELAY_COMMAND_TRUNCATED,
|
||||
NULL, 0, NULL);
|
||||
}
|
||||
#endif
|
||||
circuit_mark_for_close(circ);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
@@ -0,0 +1,708 @@
|
||||
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
#include "or.h"
|
||||
|
||||
/* enumeration of types which option values can take */
|
||||
#define CONFIG_TYPE_STRING 0
|
||||
#define CONFIG_TYPE_CHAR 1
|
||||
#define CONFIG_TYPE_INT 2
|
||||
#define CONFIG_TYPE_LONG 3
|
||||
#define CONFIG_TYPE_DOUBLE 4
|
||||
#define CONFIG_TYPE_BOOL 5
|
||||
#define CONFIG_TYPE_LINELIST 6
|
||||
|
||||
#define CONFIG_LINE_T_MAXLEN 4096
|
||||
|
||||
static FILE *config_open(const unsigned char *filename);
|
||||
static int config_close(FILE *f);
|
||||
static struct config_line_t *config_get_commandlines(int argc, char **argv);
|
||||
static struct config_line_t *config_get_lines(FILE *f);
|
||||
static void config_free_lines(struct config_line_t *front);
|
||||
static int config_compare(struct config_line_t *c, char *key, int type, void *arg);
|
||||
static int config_assign(or_options_t *options, struct config_line_t *list);
|
||||
|
||||
/* open configuration file for reading */
|
||||
static FILE *config_open(const unsigned char *filename) {
|
||||
tor_assert(filename);
|
||||
if (strspn(filename,CONFIG_LEGAL_FILENAME_CHARACTERS) != strlen(filename)) {
|
||||
/* filename has illegal letters */
|
||||
return NULL;
|
||||
}
|
||||
return fopen(filename, "r");
|
||||
}
|
||||
|
||||
/* close configuration file */
|
||||
static int config_close(FILE *f) {
|
||||
tor_assert(f);
|
||||
return fclose(f);
|
||||
}
|
||||
|
||||
static struct config_line_t *config_get_commandlines(int argc, char **argv) {
|
||||
struct config_line_t *new;
|
||||
struct config_line_t *front = NULL;
|
||||
char *s;
|
||||
int i = 1;
|
||||
|
||||
while(i < argc-1) {
|
||||
if(!strcmp(argv[i],"-f")) {
|
||||
// log(LOG_DEBUG,"Commandline: skipping over -f.");
|
||||
i+=2; /* this is the config file option. ignore it. */
|
||||
continue;
|
||||
}
|
||||
|
||||
new = tor_malloc(sizeof(struct config_line_t));
|
||||
s = argv[i];
|
||||
while(*s == '-')
|
||||
s++;
|
||||
new->key = tor_strdup(s);
|
||||
new->value = tor_strdup(argv[i+1]);
|
||||
|
||||
log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
|
||||
new->key, new->value);
|
||||
new->next = front;
|
||||
front = new;
|
||||
i += 2;
|
||||
}
|
||||
return front;
|
||||
}
|
||||
|
||||
static struct config_line_t *
|
||||
config_line_prepend(struct config_line_t *front,
|
||||
const char *key,
|
||||
const char *val)
|
||||
{
|
||||
struct config_line_t *newline;
|
||||
newline = tor_malloc(sizeof(struct config_line_t));
|
||||
newline->key = tor_strdup(key);
|
||||
newline->value = tor_strdup(val);
|
||||
newline->next = front;
|
||||
return newline;
|
||||
}
|
||||
|
||||
/* parse the config file and strdup into key/value strings. Return list,
|
||||
* or NULL if parsing the file failed.
|
||||
* Warn and ignore mangled lines. */
|
||||
static struct config_line_t *config_get_lines(FILE *f) {
|
||||
|
||||
struct config_line_t *front = NULL;
|
||||
char line[CONFIG_LINE_T_MAXLEN];
|
||||
int result;
|
||||
char *key, *value;
|
||||
|
||||
while( (result=parse_line_from_file(line,sizeof(line),f,&key,&value)) > 0) {
|
||||
front = config_line_prepend(front, key, value);
|
||||
}
|
||||
if(result < 0)
|
||||
return NULL;
|
||||
return front;
|
||||
}
|
||||
|
||||
static void config_free_lines(struct config_line_t *front) {
|
||||
struct config_line_t *tmp;
|
||||
|
||||
while(front) {
|
||||
tmp = front;
|
||||
front = tmp->next;
|
||||
|
||||
free(tmp->key);
|
||||
free(tmp->value);
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static int config_compare(struct config_line_t *c, char *key, int type, void *arg) {
|
||||
int i;
|
||||
|
||||
if(strncasecmp(c->key,key,strlen(c->key)))
|
||||
return 0;
|
||||
|
||||
/* it's a match. cast and assign. */
|
||||
log_fn(LOG_DEBUG,"Recognized keyword '%s' as %s, using value '%s'.",c->key,key,c->value);
|
||||
|
||||
switch(type) {
|
||||
case CONFIG_TYPE_INT:
|
||||
*(int *)arg = atoi(c->value);
|
||||
break;
|
||||
case CONFIG_TYPE_BOOL:
|
||||
i = atoi(c->value);
|
||||
if (i != 0 && i != 1) {
|
||||
log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1", c->key);
|
||||
return 0;
|
||||
}
|
||||
*(int *)arg = i;
|
||||
break;
|
||||
case CONFIG_TYPE_STRING:
|
||||
tor_free(*(char **)arg);
|
||||
*(char **)arg = tor_strdup(c->value);
|
||||
break;
|
||||
case CONFIG_TYPE_DOUBLE:
|
||||
*(double *)arg = atof(c->value);
|
||||
break;
|
||||
case CONFIG_TYPE_LINELIST:
|
||||
/* Note: this reverses the order that the lines appear in. That's
|
||||
* just fine, since we build up the list of lines reversed in the
|
||||
* first place. */
|
||||
*(struct config_line_t**)arg =
|
||||
config_line_prepend(*(struct config_line_t**)arg, c->key, c->value);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Iterate through list.
|
||||
* For each item, convert as appropriate and assign to 'options'.
|
||||
* If an item is unrecognized, return -1 immediately,
|
||||
* else return 0 for success. */
|
||||
static int config_assign(or_options_t *options, struct config_line_t *list) {
|
||||
|
||||
while(list) {
|
||||
if(
|
||||
|
||||
/* order matters here! abbreviated arguments use the first match. */
|
||||
|
||||
/* string options */
|
||||
config_compare(list, "Address", CONFIG_TYPE_STRING, &options->Address) ||
|
||||
|
||||
config_compare(list, "BandwidthRate", CONFIG_TYPE_INT, &options->BandwidthRate) ||
|
||||
config_compare(list, "BandwidthBurst", CONFIG_TYPE_INT, &options->BandwidthBurst) ||
|
||||
|
||||
config_compare(list, "DebugLogFile", CONFIG_TYPE_STRING, &options->DebugLogFile) ||
|
||||
config_compare(list, "DataDirectory", CONFIG_TYPE_STRING, &options->DataDirectory) ||
|
||||
config_compare(list, "DirPort", CONFIG_TYPE_INT, &options->DirPort) ||
|
||||
config_compare(list, "DirBindAddress", CONFIG_TYPE_STRING, &options->DirBindAddress) ||
|
||||
config_compare(list, "DirFetchPostPeriod",CONFIG_TYPE_INT, &options->DirFetchPostPeriod) ||
|
||||
|
||||
config_compare(list, "ExitNodes", CONFIG_TYPE_STRING, &options->ExitNodes) ||
|
||||
config_compare(list, "EntryNodes", CONFIG_TYPE_STRING, &options->EntryNodes) ||
|
||||
config_compare(list, "ExitPolicy", CONFIG_TYPE_STRING, &options->ExitPolicy) ||
|
||||
config_compare(list, "ExcludeNodes", CONFIG_TYPE_STRING, &options->ExcludeNodes) ||
|
||||
|
||||
config_compare(list, "Group", CONFIG_TYPE_STRING, &options->Group) ||
|
||||
|
||||
config_compare(list, "IgnoreVersion", CONFIG_TYPE_BOOL, &options->IgnoreVersion) ||
|
||||
|
||||
config_compare(list, "KeepalivePeriod",CONFIG_TYPE_INT, &options->KeepalivePeriod) ||
|
||||
|
||||
config_compare(list, "LogLevel", CONFIG_TYPE_STRING, &options->LogLevel) ||
|
||||
config_compare(list, "LogFile", CONFIG_TYPE_STRING, &options->LogFile) ||
|
||||
config_compare(list, "LinkPadding", CONFIG_TYPE_BOOL, &options->LinkPadding) ||
|
||||
|
||||
config_compare(list, "MaxConn", CONFIG_TYPE_INT, &options->MaxConn) ||
|
||||
config_compare(list, "MaxOnionsPending",CONFIG_TYPE_INT, &options->MaxOnionsPending) ||
|
||||
|
||||
config_compare(list, "Nickname", CONFIG_TYPE_STRING, &options->Nickname) ||
|
||||
config_compare(list, "NewCircuitPeriod",CONFIG_TYPE_INT, &options->NewCircuitPeriod) ||
|
||||
config_compare(list, "NumCpus", CONFIG_TYPE_INT, &options->NumCpus) ||
|
||||
|
||||
config_compare(list, "ORPort", CONFIG_TYPE_INT, &options->ORPort) ||
|
||||
config_compare(list, "ORBindAddress", CONFIG_TYPE_STRING, &options->ORBindAddress) ||
|
||||
|
||||
config_compare(list, "PidFile", CONFIG_TYPE_STRING, &options->PidFile) ||
|
||||
config_compare(list, "PathlenCoinWeight",CONFIG_TYPE_DOUBLE, &options->PathlenCoinWeight) ||
|
||||
|
||||
config_compare(list, "RouterFile", CONFIG_TYPE_STRING, &options->RouterFile) ||
|
||||
config_compare(list, "RunAsDaemon", CONFIG_TYPE_BOOL, &options->RunAsDaemon) ||
|
||||
config_compare(list, "RecommendedVersions",CONFIG_TYPE_STRING, &options->RecommendedVersions) ||
|
||||
config_compare(list, "RendNodes", CONFIG_TYPE_STRING, &options->RendNodes) ||
|
||||
config_compare(list, "RendExcludeNodes",CONFIG_TYPE_STRING, &options->RendExcludeNodes) ||
|
||||
|
||||
config_compare(list, "SocksPort", CONFIG_TYPE_INT, &options->SocksPort) ||
|
||||
config_compare(list, "SocksBindAddress",CONFIG_TYPE_STRING,&options->SocksBindAddress) ||
|
||||
|
||||
config_compare(list, "TrafficShaping", CONFIG_TYPE_BOOL, &options->TrafficShaping) ||
|
||||
|
||||
config_compare(list, "User", CONFIG_TYPE_STRING, &options->User) ||
|
||||
config_compare(list, "RunTesting", CONFIG_TYPE_BOOL, &options->RunTesting) ||
|
||||
config_compare(list, "HiddenServiceDir", CONFIG_TYPE_LINELIST, &options->RendConfigLines)||
|
||||
config_compare(list, "HiddenServicePort", CONFIG_TYPE_LINELIST, &options->RendConfigLines)||
|
||||
config_compare(list, "HiddenServiceNodes", CONFIG_TYPE_LINELIST, &options->RendConfigLines)||
|
||||
config_compare(list, "HiddenServiceExcludeNodes", CONFIG_TYPE_LINELIST, &options->RendConfigLines)
|
||||
) {
|
||||
/* then we're ok. it matched something. */
|
||||
} else {
|
||||
log_fn(LOG_WARN,"Unknown keyword '%s'. Failing.",list->key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX are there any other specifiers we want to give so making
|
||||
* a several-thousand-byte string is less painful? */
|
||||
const char default_dirservers_string[] =
|
||||
"router moria1 18.244.0.188 9001 9021 9031\n"
|
||||
"platform Tor 0.0.6rc1 on Linux moria.mit.edu i686\n"
|
||||
"published 2004-04-25 21:54:28\n"
|
||||
"bandwidth 800000 10000000\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBANoIvHieyHUTzIacbnWOnyTyzGrLOdXqbcjz2GGMxyHEd5K1bO1ZBNHP\n"
|
||||
"9i5qLQpN5viFk2K2rEGuG8tFgDEzSWZEtBqv3NVfUdiumdERWMBwlaQ0MVK4C+jf\n"
|
||||
"y5gZ8KI3o9ZictgPS1AQF+Kk932/vIHTuRIUKb4ILTnQilNvID0NAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAMHa0ZC/jo2Q2DrwKYF/6ZbmZ27PFYG91u4gUzzmZ/VXLpZ8wNzEV3oW\n"
|
||||
"nt+I61048fBiC1frT1/DZ351n2bLSk9zJbB6jyGZJn0380FPRX3+cXyXS0Gq8Ril\n"
|
||||
"xkhMQf5XuNFUb8UmYPSOH4WErjvYjKvU+gfjbK/82Jo9SuHpYz+BAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"reject 0.0.0.0/255.0.0.0:*\n"
|
||||
"reject 169.254.0.0/255.255.0.0:*\n"
|
||||
"reject 127.0.0.0/255.0.0.0:*\n"
|
||||
"reject 192.168.0.0/255.255.0.0:*\n"
|
||||
"reject 10.0.0.0/255.0.0.0:*\n"
|
||||
"reject 172.16.0.0/255.240.0.0:*\n"
|
||||
"accept *:20-22\n"
|
||||
"accept *:53\n"
|
||||
"accept *:79-80\n"
|
||||
"accept *:110\n"
|
||||
"accept *:143\n"
|
||||
"accept *:443\n"
|
||||
"accept *:873\n"
|
||||
"accept *:993\n"
|
||||
"accept *:995\n"
|
||||
"accept *:1024-65535\n"
|
||||
"reject *:*\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"o1eAoRHDAEAXsnh5wN++vIwrupd+DbAJ2p3wxHDrmqxTpygzxxCnyQyhMfX03ua2\n"
|
||||
"4iplyNlwyFwzWcw0sk31otlO2HBYXT1V9G0YxGtKMOeOBMHjfGbUjGvEALHzWi4z\n"
|
||||
"8DXGJp13zgnUyP4ZA6xaGROwcT6oB5e7UlztvvpGxTg=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
"router moria2 18.244.0.188 9002 9022 9032\n"
|
||||
"platform Tor 0.0.6rc1 on Linux moria.mit.edu i686\n"
|
||||
"published 2004-04-25 21:54:30\n"
|
||||
"bandwidth 800000 10000000\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAM4Cc/npgYC54XrYLC+grVxJp7PDmNO2DRRJOxKttBBtvLpnR1UaueTi\n"
|
||||
"kyknT5kmlx+ihgZF/jmye//2dDUp2+kK/kSkpRV4xnDLXZmed+sNSQxqmm9TtZQ9\n"
|
||||
"/hjpxhp5J9HmUTYhntBs+4E4CUKokmrI6oRLoln4SA39AX9QLPcnAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAOcrht/y5rkaahfX7sMe2qnpqoPibsjTSJaDvsUtaNP/Bq0MgNDGOR48\n"
|
||||
"rtwfqTRff275Edkp/UYw3G3vSgKCJr76/bqOHCmkiZrnPV1zxNfrK18gNw2Cxre0\n"
|
||||
"nTA+fD8JQqpPtb8b0SnG9kwy75eS//sRu7TErie2PzGMxrf9LH0LAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"reject 0.0.0.0/255.0.0.0:*\n"
|
||||
"reject 169.254.0.0/255.255.0.0:*\n"
|
||||
"reject 127.0.0.0/255.0.0.0:*\n"
|
||||
"reject 192.168.0.0/255.255.0.0:*\n"
|
||||
"reject 10.0.0.0/255.0.0.0:*\n"
|
||||
"reject 172.16.0.0/255.240.0.0:*\n"
|
||||
"accept *:20-22\n"
|
||||
"accept *:53\n"
|
||||
"accept *:79-80\n"
|
||||
"accept *:110\n"
|
||||
"accept *:143\n"
|
||||
"accept *:443\n"
|
||||
"accept *:873\n"
|
||||
"accept *:993\n"
|
||||
"accept *:995\n"
|
||||
"accept *:1024-65535\n"
|
||||
"reject *:*\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"RKROLwP1ExjTZeg6wuN0pzYqed9IJUd5lAe9hp4ritbnmJAgS6qfww6jgx61CfUR\n"
|
||||
"6SElhOLE7Q77jAdoL45Ji5pn/Y+Q+E+5lJm1E/ed9ha+YsOPaOc7z6GQ7E4mihCL\n"
|
||||
"gI1vsw92+P1Ty4RHj6fyD9DhbV19nh2Qs+pvGJOS2FY=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
"router tor26 62.116.124.106 9001 9050 9030\n"
|
||||
"platform Tor 0.0.6 on Linux seppia i686\n"
|
||||
"published 2004-05-06 21:33:23\n"
|
||||
"bandwidth 500000 10000000\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAMEHdDnpj3ik1AF1xe/VqjoguH2DbANifYqXXfempu0fS+tU9FGo6dU/\n"
|
||||
"fnVHAZwL9Ek9k2rMzumShi1RduK9p035R/Gk+PBBcLfvwYJ/Nat+ZO/L8jn/3bZe\n"
|
||||
"ieQd9CKj2LjNGKpRNry37vkwMGIOIlegwK+2us8aXJ7sIvlNts0TAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAMQgV2gXLbXgesWgeAsj8P1Uvm/zibrFXqwDq27lLKNgWGYGX2ax3LyT\n"
|
||||
"3nzI1Y5oLs4kPKTsMM5ft9aokwf417lKoCRlZc9ptfRbgxDx90c9GtWVmkrmDvCK\n"
|
||||
"ae59TMoXIiGfZiwWT6KKq5Zm9/Fu2Il3B2vHGkKJYKixmiBJRKp/AgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"accept 62.245.184.24:25\n"
|
||||
"accept 62.116.124.106:6666-6670\n"
|
||||
"accept *:48099\n"
|
||||
"reject *:*\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"qh/xRoqfLNFzPaB8VdpbdMAwRyuk5qjx4LeLVQ2pDwTZ55PqmG99+VKUNte2WTTD\n"
|
||||
"7dZEA7um2rueohGe4nYmvbhJWr20/I0ZxmWDRDvFy0b5nwzDMGvLvDw95Zu/XJQ2\n"
|
||||
"md32NE3y9VZCfbCN+GlvETX3fdR3Svzcm8Kzesg2/s4=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
;
|
||||
|
||||
int config_assign_default_dirservers(void) {
|
||||
if(router_set_routerlist_from_string(default_dirservers_string) < 0) {
|
||||
log_fn(LOG_WARN,"Bug: the default dirservers internal string is corrupt.");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Call this function when they're using the default torrc but
|
||||
* we can't find it. For now, just hard-code what comes in the
|
||||
* default torrc.
|
||||
*/
|
||||
static int config_assign_default(or_options_t *options) {
|
||||
|
||||
/* set them up as a client only */
|
||||
options->SocksPort = 9050;
|
||||
|
||||
/* plus give them a dirservers file */
|
||||
if(config_assign_default_dirservers() < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* prints the usage of tor. */
|
||||
static void print_usage(void) {
|
||||
printf("tor -f <torrc> [args]\n"
|
||||
"See man page for more options. This -h is probably obsolete.\n\n"
|
||||
"-b <bandwidth>\t\tbytes/second rate limiting\n"
|
||||
"-d <file>\t\tDebug file\n"
|
||||
// "-m <max>\t\tMax number of connections\n"
|
||||
"-l <level>\t\tLog level\n"
|
||||
"-r <file>\t\tList of known routers\n");
|
||||
printf("\nClient options:\n"
|
||||
"-e \"nick1 nick2 ...\"\t\tExit nodes\n"
|
||||
"-s <IP>\t\t\tPort to bind to for Socks\n"
|
||||
);
|
||||
printf("\nServer options:\n"
|
||||
"-n <nick>\t\tNickname of router\n"
|
||||
"-o <port>\t\tOR port to bind to\n"
|
||||
"-p <file>\t\tPID file\n"
|
||||
);
|
||||
}
|
||||
|
||||
static int resolve_my_address(or_options_t *options) {
|
||||
struct in_addr in;
|
||||
struct hostent *rent;
|
||||
char localhostname[256];
|
||||
int explicit_ip=1;
|
||||
|
||||
if(!options->Address) { /* then we need to guess our address */
|
||||
explicit_ip = 0; /* it's implicit */
|
||||
|
||||
if(gethostname(localhostname,sizeof(localhostname)) < 0) {
|
||||
log_fn(LOG_WARN,"Error obtaining local hostname");
|
||||
return -1;
|
||||
}
|
||||
#if 0 /* don't worry about complaining, as long as it resolves */
|
||||
if(!strchr(localhostname,'.')) {
|
||||
log_fn(LOG_WARN,"fqdn '%s' has only one element. Misconfigured machine?",address);
|
||||
log_fn(LOG_WARN,"Try setting the Address line in your config file.");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
options->Address = tor_strdup(localhostname);
|
||||
log_fn(LOG_DEBUG,"Guessed local host name as '%s'",options->Address);
|
||||
}
|
||||
|
||||
/* now we know options->Address is set. resolve it and keep only the IP */
|
||||
|
||||
if(tor_inet_aton(options->Address, &in) == 0) {
|
||||
/* then we have to resolve it */
|
||||
explicit_ip = 0;
|
||||
rent = (struct hostent *)gethostbyname(options->Address);
|
||||
if (!rent) {
|
||||
log_fn(LOG_WARN,"Could not resolve Address %s. Failing.", options->Address);
|
||||
return -1;
|
||||
}
|
||||
tor_assert(rent->h_length == 4);
|
||||
memcpy(&in.s_addr, rent->h_addr,rent->h_length);
|
||||
}
|
||||
if(!explicit_ip && is_internal_IP(htonl(in.s_addr))) {
|
||||
log_fn(LOG_WARN,"Address '%s' resolves to private IP '%s'. "
|
||||
"Please set the Address config option to be the IP you want to use.",
|
||||
options->Address, inet_ntoa(in));
|
||||
return -1;
|
||||
}
|
||||
tor_free(options->Address);
|
||||
options->Address = tor_strdup(inet_ntoa(in));
|
||||
log_fn(LOG_DEBUG,"Resolved Address to %s.", options->Address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_options(or_options_t *options) {
|
||||
tor_free(options->LogLevel);
|
||||
tor_free(options->LogFile);
|
||||
tor_free(options->DebugLogFile);
|
||||
tor_free(options->DataDirectory);
|
||||
tor_free(options->RouterFile);
|
||||
tor_free(options->Nickname);
|
||||
tor_free(options->Address);
|
||||
tor_free(options->PidFile);
|
||||
tor_free(options->ExitNodes);
|
||||
tor_free(options->EntryNodes);
|
||||
tor_free(options->ExcludeNodes);
|
||||
tor_free(options->RendNodes);
|
||||
tor_free(options->RendExcludeNodes);
|
||||
tor_free(options->ExitPolicy);
|
||||
tor_free(options->SocksBindAddress);
|
||||
tor_free(options->ORBindAddress);
|
||||
tor_free(options->DirBindAddress);
|
||||
tor_free(options->RecommendedVersions);
|
||||
tor_free(options->User);
|
||||
tor_free(options->Group);
|
||||
config_free_lines(options->RendConfigLines);
|
||||
}
|
||||
|
||||
static void init_options(or_options_t *options) {
|
||||
/* give reasonable values for each option. Defaults to zero. */
|
||||
memset(options,0,sizeof(or_options_t));
|
||||
options->LogLevel = tor_strdup("notice");
|
||||
options->ExitNodes = tor_strdup("");
|
||||
options->EntryNodes = tor_strdup("");
|
||||
options->ExcludeNodes = tor_strdup("");
|
||||
options->RendNodes = tor_strdup("");
|
||||
options->RendExcludeNodes = tor_strdup("");
|
||||
options->ExitPolicy = tor_strdup("");
|
||||
options->SocksBindAddress = tor_strdup("127.0.0.1");
|
||||
options->ORBindAddress = tor_strdup("0.0.0.0");
|
||||
options->DirBindAddress = tor_strdup("0.0.0.0");
|
||||
options->RecommendedVersions = NULL;
|
||||
options->loglevel = LOG_INFO;
|
||||
options->PidFile = NULL; // tor_strdup("tor.pid");
|
||||
options->DataDirectory = NULL;
|
||||
options->PathlenCoinWeight = 0.3;
|
||||
options->MaxConn = 900;
|
||||
options->DirFetchPostPeriod = 600;
|
||||
options->KeepalivePeriod = 300;
|
||||
options->MaxOnionsPending = 100;
|
||||
options->NewCircuitPeriod = 30; /* twice a minute */
|
||||
options->BandwidthRate = 800000; /* at most 800kB/s total sustained incoming */
|
||||
options->BandwidthBurst = 10000000; /* max burst on the token bucket */
|
||||
options->NumCpus = 1;
|
||||
options->RendConfigLines = NULL;
|
||||
}
|
||||
|
||||
/* return 0 if success, <0 if failure. */
|
||||
int getconfig(int argc, char **argv, or_options_t *options) {
|
||||
struct config_line_t *cl;
|
||||
FILE *cf;
|
||||
char *fname;
|
||||
int i;
|
||||
int result = 0;
|
||||
static int first_load = 1;
|
||||
static char **backup_argv;
|
||||
static int backup_argc;
|
||||
char *previous_pidfile = NULL;
|
||||
int previous_runasdaemon = 0;
|
||||
int previous_orport = -1;
|
||||
int using_default_torrc;
|
||||
|
||||
if(first_load) { /* first time we're called. save commandline args */
|
||||
backup_argv = argv;
|
||||
backup_argc = argc;
|
||||
first_load = 0;
|
||||
} else { /* we're reloading. need to clean up old ones first. */
|
||||
argv = backup_argv;
|
||||
argc = backup_argc;
|
||||
|
||||
/* record some previous values, so we can fail if they change */
|
||||
if(options->PidFile)
|
||||
previous_pidfile = tor_strdup(options->PidFile);
|
||||
previous_runasdaemon = options->RunAsDaemon;
|
||||
previous_orport = options->ORPort;
|
||||
free_options(options);
|
||||
}
|
||||
init_options(options);
|
||||
|
||||
if(argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1],"--help"))) {
|
||||
print_usage();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(argc > 1 && (!strcmp(argv[1],"--version"))) {
|
||||
printf("Tor version %s.\n",VERSION);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* learn config file name, get config lines, assign them */
|
||||
i = 1;
|
||||
while(i < argc-1 && strcmp(argv[i],"-f")) {
|
||||
i++;
|
||||
}
|
||||
if(i < argc-1) { /* we found one */
|
||||
fname = argv[i+1];
|
||||
using_default_torrc = 0;
|
||||
} else { /* didn't find one, try CONFDIR */
|
||||
fname = CONFDIR "/torrc";
|
||||
using_default_torrc = 1;
|
||||
}
|
||||
log(LOG_DEBUG,"Opening config file '%s'",fname);
|
||||
|
||||
cf = config_open(fname);
|
||||
if(!cf) {
|
||||
if(using_default_torrc == 1) {
|
||||
log(LOG_NOTICE, "Configuration file '%s' not present, using reasonable defaults.",fname);
|
||||
if(config_assign_default(options) < 0)
|
||||
return -1;
|
||||
} else {
|
||||
log(LOG_WARN, "Unable to open configuration file '%s'.",fname);
|
||||
return -1;
|
||||
}
|
||||
} else { /* it opened successfully. use it. */
|
||||
cl = config_get_lines(cf);
|
||||
if(!cl) return -1;
|
||||
if(config_assign(options,cl) < 0)
|
||||
return -1;
|
||||
config_free_lines(cl);
|
||||
config_close(cf);
|
||||
}
|
||||
|
||||
/* go through command-line variables too */
|
||||
cl = config_get_commandlines(argc,argv);
|
||||
if(config_assign(options,cl) < 0)
|
||||
return -1;
|
||||
config_free_lines(cl);
|
||||
|
||||
/* Validate options */
|
||||
|
||||
/* first check if any of the previous options have changed but aren't allowed to */
|
||||
if(previous_pidfile && strcmp(previous_pidfile,options->PidFile)) {
|
||||
log_fn(LOG_WARN,"During reload, PidFile changed from %s to %s. Failing.",
|
||||
previous_pidfile, options->PidFile);
|
||||
return -1;
|
||||
}
|
||||
tor_free(previous_pidfile);
|
||||
|
||||
if(previous_runasdaemon && !options->RunAsDaemon) {
|
||||
log_fn(LOG_WARN,"During reload, change from RunAsDaemon=1 to =0 not allowed. Failing.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(previous_orport == 0 && options->ORPort > 0) {
|
||||
log_fn(LOG_WARN,"During reload, change from ORPort=0 to >0 not allowed. Failing.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(options->LogLevel) {
|
||||
if(!strcmp(options->LogLevel,"err"))
|
||||
options->loglevel = LOG_ERR;
|
||||
else if(!strcmp(options->LogLevel,"warn"))
|
||||
options->loglevel = LOG_WARN;
|
||||
else if(!strcmp(options->LogLevel,"notice"))
|
||||
options->loglevel = LOG_NOTICE;
|
||||
else if(!strcmp(options->LogLevel,"info"))
|
||||
options->loglevel = LOG_INFO;
|
||||
else if(!strcmp(options->LogLevel,"debug"))
|
||||
options->loglevel = LOG_DEBUG;
|
||||
else {
|
||||
log(LOG_WARN,"LogLevel must be one of err|warn|notice|info|debug.");
|
||||
result = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(options->ORPort < 0) {
|
||||
log(LOG_WARN,"ORPort option can't be negative.");
|
||||
result = -1;
|
||||
}
|
||||
|
||||
if(options->ORPort && options->DataDirectory == NULL) {
|
||||
log(LOG_WARN,"DataDirectory option required if ORPort is set, but not found.");
|
||||
result = -1;
|
||||
}
|
||||
|
||||
if (options->ORPort) {
|
||||
if (options->Nickname == NULL) {
|
||||
log_fn(LOG_WARN,"Nickname required if ORPort is set, but not found.");
|
||||
result = -1;
|
||||
} else {
|
||||
if (strspn(options->Nickname, LEGAL_NICKNAME_CHARACTERS) !=
|
||||
strlen(options->Nickname)) {
|
||||
log_fn(LOG_WARN, "Nickname '%s' contains illegal characters.", options->Nickname);
|
||||
result = -1;
|
||||
}
|
||||
if (strlen(options->Nickname) > MAX_NICKNAME_LEN) {
|
||||
log_fn(LOG_WARN, "Nickname '%s' has more than %d characters.",
|
||||
options->Nickname, MAX_NICKNAME_LEN);
|
||||
result = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(options->ORPort) { /* get an IP for ourselves */
|
||||
if(resolve_my_address(options) < 0)
|
||||
result = -1;
|
||||
}
|
||||
|
||||
if(options->SocksPort < 0) {
|
||||
log(LOG_WARN,"SocksPort option can't be negative.");
|
||||
result = -1;
|
||||
}
|
||||
|
||||
if(options->SocksPort == 0 && options->ORPort == 0) {
|
||||
log(LOG_WARN,"SocksPort and ORPort are both undefined? Quitting.");
|
||||
result = -1;
|
||||
}
|
||||
|
||||
if(options->DirPort < 0) {
|
||||
log(LOG_WARN,"DirPort option can't be negative.");
|
||||
result = -1;
|
||||
}
|
||||
|
||||
if(options->DirPort && options->RecommendedVersions == NULL) {
|
||||
log(LOG_WARN,"Directory servers must configure RecommendedVersions.");
|
||||
result = -1;
|
||||
}
|
||||
|
||||
if(options->SocksPort > 1 &&
|
||||
(options->PathlenCoinWeight < 0.0 || options->PathlenCoinWeight >= 1.0)) {
|
||||
log(LOG_WARN,"PathlenCoinWeight option must be >=0.0 and <1.0.");
|
||||
result = -1;
|
||||
}
|
||||
|
||||
if(options->MaxConn < 1) {
|
||||
log(LOG_WARN,"MaxConn option must be a non-zero positive integer.");
|
||||
result = -1;
|
||||
}
|
||||
|
||||
if(options->MaxConn >= MAXCONNECTIONS) {
|
||||
log(LOG_WARN,"MaxConn option must be less than %d.", MAXCONNECTIONS);
|
||||
result = -1;
|
||||
}
|
||||
|
||||
if(options->DirFetchPostPeriod < 1) {
|
||||
log(LOG_WARN,"DirFetchPostPeriod option must be positive.");
|
||||
result = -1;
|
||||
}
|
||||
if(options->DirFetchPostPeriod > MIN_ONION_KEY_LIFETIME/2) {
|
||||
log(LOG_WARN,"DirFetchPostPeriod is too large; clipping.");
|
||||
options->DirFetchPostPeriod = MIN_ONION_KEY_LIFETIME/2;
|
||||
}
|
||||
|
||||
if(options->KeepalivePeriod < 1) {
|
||||
log(LOG_WARN,"KeepalivePeriod option must be positive.");
|
||||
result = -1;
|
||||
}
|
||||
|
||||
/* XXX look at the various nicknamelists and make sure they're
|
||||
* valid and don't have hostnames that are too long.
|
||||
*/
|
||||
|
||||
if (rend_config_services(options) < 0) {
|
||||
result = -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,284 @@
|
||||
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
#include "or.h"
|
||||
|
||||
extern or_options_t options; /* command-line and config-file options */
|
||||
|
||||
static int connection_tls_finish_handshake(connection_t *conn);
|
||||
static int connection_or_process_cells_from_inbuf(connection_t *conn);
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
static void cell_pack(char *dest, const cell_t *src) {
|
||||
*(uint16_t*)dest = htons(src->circ_id);
|
||||
*(uint8_t*)(dest+2) = src->command;
|
||||
memcpy(dest+3, src->payload, CELL_PAYLOAD_SIZE);
|
||||
}
|
||||
|
||||
static void cell_unpack(cell_t *dest, const char *src) {
|
||||
dest->circ_id = ntohs(*(uint16_t*)(src));
|
||||
dest->command = *(uint8_t*)(src+2);
|
||||
memcpy(dest->payload, src+3, CELL_PAYLOAD_SIZE);
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
int connection_or_process_inbuf(connection_t *conn) {
|
||||
|
||||
tor_assert(conn && conn->type == CONN_TYPE_OR);
|
||||
|
||||
if(conn->inbuf_reached_eof) {
|
||||
log_fn(LOG_INFO,"OR connection reached EOF. Closing.");
|
||||
connection_mark_for_close(conn,0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(conn->state != OR_CONN_STATE_OPEN)
|
||||
return 0; /* don't do anything */
|
||||
return connection_or_process_cells_from_inbuf(conn);
|
||||
}
|
||||
|
||||
int connection_or_finished_flushing(connection_t *conn) {
|
||||
int e, len=sizeof(e);
|
||||
|
||||
tor_assert(conn && conn->type == CONN_TYPE_OR);
|
||||
assert_connection_ok(conn,0);
|
||||
|
||||
switch(conn->state) {
|
||||
case OR_CONN_STATE_CONNECTING:
|
||||
if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { /* not yet */
|
||||
if(!ERRNO_IS_CONN_EINPROGRESS(tor_socket_errno(conn->s))) {
|
||||
log_fn(LOG_DEBUG,"in-progress connect failed. Removing.");
|
||||
connection_mark_for_close(conn,0);
|
||||
return -1;
|
||||
} else {
|
||||
return 0; /* no change, see if next time is better */
|
||||
}
|
||||
}
|
||||
/* the connect has finished. */
|
||||
|
||||
log_fn(LOG_INFO,"OR connect() to router %s:%u finished.",
|
||||
conn->address,conn->port);
|
||||
|
||||
if(connection_tls_start_handshake(conn, 0) < 0) {
|
||||
/* TLS handhaking error of some kind. */
|
||||
connection_mark_for_close(conn,0);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
case OR_CONN_STATE_OPEN:
|
||||
connection_stop_writing(conn);
|
||||
return 0;
|
||||
default:
|
||||
log_fn(LOG_WARN,"BUG: called in unexpected state %d",conn->state);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************/
|
||||
|
||||
void connection_or_init_conn_from_router(connection_t *conn, routerinfo_t *router) {
|
||||
conn->addr = router->addr;
|
||||
conn->port = router->or_port;
|
||||
conn->receiver_bucket = conn->bandwidth = router->bandwidthburst;
|
||||
conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey);
|
||||
conn->nickname = tor_strdup(router->nickname);
|
||||
tor_free(conn->address);
|
||||
conn->address = tor_strdup(router->address);
|
||||
}
|
||||
|
||||
connection_t *connection_or_connect(routerinfo_t *router) {
|
||||
connection_t *conn;
|
||||
|
||||
tor_assert(router);
|
||||
|
||||
if(router_is_me(router)) {
|
||||
log_fn(LOG_WARN,"You asked me to connect to myself! Failing.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* this function should never be called if we're already connected to router, but */
|
||||
/* check first to be sure */
|
||||
conn = connection_exact_get_by_addr_port(router->addr,router->or_port);
|
||||
if(conn)
|
||||
return conn;
|
||||
|
||||
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_router(conn, router);
|
||||
conn->state = OR_CONN_STATE_CONNECTING;
|
||||
|
||||
if(connection_add(conn) < 0) { /* no space, forget it */
|
||||
connection_free(conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch(connection_connect(conn, router->address, router->addr, router->or_port)) {
|
||||
case -1:
|
||||
connection_mark_for_close(conn, 0);
|
||||
return NULL;
|
||||
case 0:
|
||||
connection_set_poll_socket(conn);
|
||||
connection_watch_events(conn, POLLIN | POLLOUT | POLLERR);
|
||||
/* writable indicates finish, readable indicates broken link,
|
||||
error indicates broken link on windows */
|
||||
return conn;
|
||||
/* case 1: fall through */
|
||||
}
|
||||
|
||||
connection_set_poll_socket(conn);
|
||||
|
||||
if(connection_tls_start_handshake(conn, 0) >= 0)
|
||||
return conn;
|
||||
|
||||
/* failure */
|
||||
connection_mark_for_close(conn, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ********************************** */
|
||||
|
||||
int connection_tls_start_handshake(connection_t *conn, int receiving) {
|
||||
conn->state = OR_CONN_STATE_HANDSHAKING;
|
||||
conn->tls = tor_tls_new(conn->s, receiving);
|
||||
if(!conn->tls) {
|
||||
log_fn(LOG_WARN,"tor_tls_new failed. Closing.");
|
||||
return -1;
|
||||
}
|
||||
connection_start_reading(conn);
|
||||
log_fn(LOG_DEBUG,"starting the handshake");
|
||||
if(connection_tls_continue_handshake(conn) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int connection_tls_continue_handshake(connection_t *conn) {
|
||||
switch(tor_tls_handshake(conn->tls)) {
|
||||
case TOR_TLS_ERROR:
|
||||
case TOR_TLS_CLOSE:
|
||||
log_fn(LOG_INFO,"tls error. breaking.");
|
||||
return -1;
|
||||
case TOR_TLS_DONE:
|
||||
return connection_tls_finish_handshake(conn);
|
||||
case TOR_TLS_WANTWRITE:
|
||||
connection_start_writing(conn);
|
||||
log_fn(LOG_DEBUG,"wanted write");
|
||||
return 0;
|
||||
case TOR_TLS_WANTREAD: /* handshaking conns are *always* reading */
|
||||
log_fn(LOG_DEBUG,"wanted read");
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int connection_tls_finish_handshake(connection_t *conn) {
|
||||
routerinfo_t *router;
|
||||
char nickname[MAX_NICKNAME_LEN+1];
|
||||
connection_t *c;
|
||||
|
||||
conn->state = OR_CONN_STATE_OPEN;
|
||||
directory_set_dirty();
|
||||
connection_watch_events(conn, POLLIN);
|
||||
log_fn(LOG_DEBUG,"tls handshake done. verifying.");
|
||||
if (! tor_tls_peer_has_cert(conn->tls)) { /* It's an OP. */
|
||||
if (options.ORPort) { /* I'm an OR; good. */
|
||||
conn->receiver_bucket = conn->bandwidth = DEFAULT_BANDWIDTH_OP;
|
||||
return 0;
|
||||
} else { /* Neither side sent a certificate: ouch. */
|
||||
log_fn(LOG_WARN,"Neither peer sent a cert! Closing.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* Okay; the other side is an OR. */
|
||||
if (tor_tls_get_peer_cert_nickname(conn->tls, nickname, MAX_NICKNAME_LEN)) {
|
||||
log_fn(LOG_WARN,"Other side (%s:%d) has a cert without a valid nickname. Closing.",
|
||||
conn->address, conn->port);
|
||||
return -1;
|
||||
}
|
||||
log_fn(LOG_DEBUG, "Other side (%s:%d) claims to be '%s'", conn->address,
|
||||
conn->port, nickname);
|
||||
router = router_get_by_nickname(nickname);
|
||||
if (!router) {
|
||||
log_fn(LOG_INFO, "Unrecognized router with nickname '%s' at %s:%d",
|
||||
nickname, conn->address, conn->port);
|
||||
return -1;
|
||||
}
|
||||
if(tor_tls_verify(conn->tls, router->identity_pkey)<0) {
|
||||
log_fn(LOG_WARN,"Other side '%s' (%s:%d) has a cert but it's invalid. Closing.",
|
||||
nickname, conn->address, conn->port);
|
||||
return -1;
|
||||
}
|
||||
log_fn(LOG_DEBUG,"The router's cert is valid.");
|
||||
|
||||
if (conn->nickname) {
|
||||
/* I initiated this connection. */
|
||||
if (strcasecmp(conn->nickname, nickname)) {
|
||||
log_fn(options.DirPort ? LOG_WARN : LOG_INFO,
|
||||
"Other side (%s:%d) is '%s', but we tried to connect to '%s'",
|
||||
conn->address, conn->port, nickname, conn->nickname);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if((c=connection_exact_get_by_addr_port(router->addr,router->or_port))) {
|
||||
log_fn(LOG_INFO,"Router %s is already connected on fd %d. Dropping fd %d.", router->nickname, c->s, conn->s);
|
||||
return -1;
|
||||
}
|
||||
connection_or_init_conn_from_router(conn,router);
|
||||
}
|
||||
|
||||
if (!options.ORPort) { /* If I'm an OP... */
|
||||
conn->receiver_bucket = conn->bandwidth = DEFAULT_BANDWIDTH_OP;
|
||||
}
|
||||
circuit_n_conn_open(conn); /* send the pending creates, if any. */
|
||||
/* Note the success */
|
||||
rep_hist_note_connect_succeeded(nickname, time(NULL));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ********************************** */
|
||||
|
||||
void connection_or_write_cell_to_buf(const cell_t *cell, connection_t *conn) {
|
||||
char networkcell[CELL_NETWORK_SIZE];
|
||||
char *n = networkcell;
|
||||
|
||||
tor_assert(cell && conn);
|
||||
tor_assert(connection_speaks_cells(conn));
|
||||
|
||||
cell_pack(n, cell);
|
||||
|
||||
connection_write_to_buf(n, CELL_NETWORK_SIZE, conn);
|
||||
}
|
||||
|
||||
/* if there's a whole cell there, pull it off and process it. */
|
||||
static int connection_or_process_cells_from_inbuf(connection_t *conn) {
|
||||
char buf[CELL_NETWORK_SIZE];
|
||||
cell_t cell;
|
||||
|
||||
loop:
|
||||
log_fn(LOG_DEBUG,"%d: starting, inbuf_datalen %d (%d pending in tls object).",
|
||||
conn->s,(int)buf_datalen(conn->inbuf),tor_tls_get_pending_bytes(conn->tls));
|
||||
if(buf_datalen(conn->inbuf) < CELL_NETWORK_SIZE) /* entire response available? */
|
||||
return 0; /* not yet */
|
||||
|
||||
connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, conn);
|
||||
|
||||
/* retrieve cell info from buf (create the host-order struct from the
|
||||
* network-order string) */
|
||||
cell_unpack(&cell, buf);
|
||||
|
||||
command_process_cell(&cell, conn);
|
||||
|
||||
goto loop; /* process the remainder of the buffer */
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
@@ -0,0 +1,327 @@
|
||||
/* Copyright 2003 Roger Dingledine. */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
#include "or.h"
|
||||
extern or_options_t options; /* command-line and config-file options */
|
||||
|
||||
#define MAX_CPUWORKERS 16
|
||||
#define MIN_CPUWORKERS 1
|
||||
|
||||
#define TAG_LEN 8
|
||||
#define LEN_ONION_QUESTION (1+TAG_LEN+ONIONSKIN_CHALLENGE_LEN)
|
||||
#define LEN_ONION_RESPONSE (1+TAG_LEN+ONIONSKIN_REPLY_LEN+40+32)
|
||||
|
||||
static int num_cpuworkers=0;
|
||||
static int num_cpuworkers_busy=0;
|
||||
static time_t last_rotation_time=0;
|
||||
|
||||
int cpuworker_main(void *data);
|
||||
static int spawn_cpuworker(void);
|
||||
static void spawn_enough_cpuworkers(void);
|
||||
static void process_pending_task(connection_t *cpuworker);
|
||||
|
||||
void cpu_init(void) {
|
||||
last_rotation_time=time(NULL);
|
||||
spawn_enough_cpuworkers();
|
||||
}
|
||||
|
||||
int connection_cpu_finished_flushing(connection_t *conn) {
|
||||
tor_assert(conn && conn->type == CONN_TYPE_CPUWORKER);
|
||||
connection_stop_writing(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tag_pack(char *tag, uint32_t addr, uint16_t port, uint16_t circ_id) {
|
||||
*(uint32_t *)tag = addr;
|
||||
*(uint16_t *)(tag+4) = port;
|
||||
*(uint16_t *)(tag+6) = circ_id;
|
||||
}
|
||||
|
||||
static void tag_unpack(char *tag, uint32_t *addr, uint16_t *port, uint16_t *circ_id) {
|
||||
struct in_addr in;
|
||||
|
||||
*addr = *(uint32_t *)tag;
|
||||
*port = *(uint16_t *)(tag+4);
|
||||
*circ_id = *(uint16_t *)(tag+6);
|
||||
|
||||
in.s_addr = htonl(*addr);
|
||||
log_fn(LOG_DEBUG,"onion was from %s:%d, circ_id %d.", inet_ntoa(in), *port, *circ_id);
|
||||
}
|
||||
|
||||
void cpuworkers_rotate(void)
|
||||
{
|
||||
connection_t *cpuworker;
|
||||
while ((cpuworker = connection_get_by_type_state(CONN_TYPE_CPUWORKER,
|
||||
CPUWORKER_STATE_IDLE))) {
|
||||
connection_mark_for_close(cpuworker,0);
|
||||
--num_cpuworkers;
|
||||
}
|
||||
last_rotation_time = time(NULL);
|
||||
spawn_enough_cpuworkers();
|
||||
}
|
||||
|
||||
int connection_cpu_process_inbuf(connection_t *conn) {
|
||||
char success;
|
||||
unsigned char buf[LEN_ONION_RESPONSE];
|
||||
uint32_t addr;
|
||||
uint16_t port;
|
||||
uint16_t circ_id;
|
||||
connection_t *p_conn;
|
||||
circuit_t *circ;
|
||||
|
||||
tor_assert(conn && conn->type == CONN_TYPE_CPUWORKER);
|
||||
|
||||
if(conn->inbuf_reached_eof) {
|
||||
log_fn(LOG_WARN,"Read eof. Worker died unexpectedly.");
|
||||
if(conn->state != CPUWORKER_STATE_IDLE) {
|
||||
/* the circ associated with this cpuworker will have to wait until
|
||||
* it gets culled in run_connection_housekeeping(), since we have
|
||||
* no way to find out which circ it was. */
|
||||
log_fn(LOG_WARN,"...and it left a circuit queued; abandoning circ.");
|
||||
num_cpuworkers_busy--;
|
||||
}
|
||||
num_cpuworkers--;
|
||||
spawn_enough_cpuworkers(); /* try to regrow. hope we don't end up spinning. */
|
||||
connection_mark_for_close(conn,0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(conn->state == CPUWORKER_STATE_BUSY_ONION) {
|
||||
if(buf_datalen(conn->inbuf) < LEN_ONION_RESPONSE) /* entire answer available? */
|
||||
return 0; /* not yet */
|
||||
tor_assert(buf_datalen(conn->inbuf) == LEN_ONION_RESPONSE);
|
||||
|
||||
connection_fetch_from_buf(&success,1,conn);
|
||||
connection_fetch_from_buf(buf,LEN_ONION_RESPONSE-1,conn);
|
||||
|
||||
/* parse out the circ it was talking about */
|
||||
tag_unpack(buf, &addr, &port, &circ_id);
|
||||
circ = NULL;
|
||||
p_conn = connection_exact_get_by_addr_port(addr,port);
|
||||
if(p_conn)
|
||||
circ = circuit_get_by_circ_id_conn(circ_id, p_conn);
|
||||
|
||||
if(success == 0) {
|
||||
log_fn(LOG_WARN,"decoding onionskin failed. Closing.");
|
||||
if(circ)
|
||||
circuit_mark_for_close(circ);
|
||||
goto done_processing;
|
||||
}
|
||||
if(!circ) {
|
||||
log_fn(LOG_INFO,"processed onion for a circ that's gone. Dropping.");
|
||||
goto done_processing;
|
||||
}
|
||||
tor_assert(circ->p_conn);
|
||||
if(onionskin_answer(circ, buf+TAG_LEN, buf+TAG_LEN+ONIONSKIN_REPLY_LEN) < 0) {
|
||||
log_fn(LOG_WARN,"onionskin_answer failed. Closing.");
|
||||
circuit_mark_for_close(circ);
|
||||
goto done_processing;
|
||||
}
|
||||
log_fn(LOG_DEBUG,"onionskin_answer succeeded. Yay.");
|
||||
} else {
|
||||
tor_assert(0); /* don't ask me to do handshakes yet */
|
||||
}
|
||||
|
||||
done_processing:
|
||||
conn->state = CPUWORKER_STATE_IDLE;
|
||||
num_cpuworkers_busy--;
|
||||
if (conn->timestamp_created < last_rotation_time) {
|
||||
connection_mark_for_close(conn,0);
|
||||
num_cpuworkers--;
|
||||
spawn_enough_cpuworkers();
|
||||
} else {
|
||||
process_pending_task(conn);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpuworker_main(void *data) {
|
||||
unsigned char question[ONIONSKIN_CHALLENGE_LEN];
|
||||
unsigned char question_type;
|
||||
int *fdarray = data;
|
||||
int fd;
|
||||
|
||||
/* variables for onion processing */
|
||||
unsigned char keys[40+32];
|
||||
unsigned char reply_to_proxy[ONIONSKIN_REPLY_LEN];
|
||||
unsigned char buf[LEN_ONION_RESPONSE];
|
||||
char tag[TAG_LEN];
|
||||
crypto_pk_env_t *onion_key = NULL, *last_onion_key = NULL;
|
||||
|
||||
tor_close_socket(fdarray[0]); /* this is the side of the socketpair the parent uses */
|
||||
fd = fdarray[1]; /* this side is ours */
|
||||
#ifndef MS_WINDOWS
|
||||
connection_free_all(); /* so the child doesn't hold the parent's fd's open */
|
||||
#endif
|
||||
|
||||
/* XXXX WINDOWS lock here. */
|
||||
onion_key = crypto_pk_dup_key(get_onion_key());
|
||||
if (get_previous_onion_key())
|
||||
last_onion_key = crypto_pk_dup_key(get_previous_onion_key());
|
||||
|
||||
for(;;) {
|
||||
|
||||
if(recv(fd, &question_type, 1, 0) != 1) {
|
||||
// log_fn(LOG_ERR,"read type failed. Exiting.");
|
||||
log_fn(LOG_INFO,"cpuworker exiting because tor process died.");
|
||||
goto end;
|
||||
}
|
||||
tor_assert(question_type == CPUWORKER_TASK_ONION);
|
||||
|
||||
if(read_all(fd, tag, TAG_LEN, 1) != TAG_LEN) {
|
||||
log_fn(LOG_ERR,"read tag failed. Exiting.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if(read_all(fd, question, ONIONSKIN_CHALLENGE_LEN, 1) != ONIONSKIN_CHALLENGE_LEN) {
|
||||
log_fn(LOG_ERR,"read question failed. Exiting.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if(question_type == CPUWORKER_TASK_ONION) {
|
||||
if(onion_skin_server_handshake(question, onion_key, last_onion_key,
|
||||
reply_to_proxy, keys, 40+32) < 0) {
|
||||
/* failure */
|
||||
log_fn(LOG_WARN,"onion_skin_server_handshake failed.");
|
||||
memset(buf,0,LEN_ONION_RESPONSE); /* send all zeros for failure */
|
||||
} else {
|
||||
/* success */
|
||||
log_fn(LOG_INFO,"onion_skin_server_handshake succeeded.");
|
||||
buf[0] = 1; /* 1 means success */
|
||||
memcpy(buf+1,tag,TAG_LEN);
|
||||
memcpy(buf+1+TAG_LEN,reply_to_proxy,ONIONSKIN_REPLY_LEN);
|
||||
memcpy(buf+1+TAG_LEN+ONIONSKIN_REPLY_LEN,keys,40+32);
|
||||
}
|
||||
if(write_all(fd, buf, LEN_ONION_RESPONSE, 1) != LEN_ONION_RESPONSE) {
|
||||
log_fn(LOG_ERR,"writing response buf failed. Exiting.");
|
||||
spawn_exit();
|
||||
}
|
||||
log_fn(LOG_DEBUG,"finished writing response.");
|
||||
}
|
||||
}
|
||||
end:
|
||||
if (onion_key)
|
||||
crypto_free_pk_env(onion_key);
|
||||
if (last_onion_key)
|
||||
crypto_free_pk_env(last_onion_key);
|
||||
spawn_exit();
|
||||
return 0; /* windows wants this function to return an int */
|
||||
}
|
||||
|
||||
static int spawn_cpuworker(void) {
|
||||
int fd[2];
|
||||
connection_t *conn;
|
||||
|
||||
if(tor_socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) {
|
||||
log(LOG_ERR, "Couldn't construct socketpair: %s", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
spawn_func(cpuworker_main, (void*)fd);
|
||||
log_fn(LOG_DEBUG,"just spawned a worker.");
|
||||
tor_close_socket(fd[1]); /* we don't need the worker's side of the pipe */
|
||||
|
||||
conn = connection_new(CONN_TYPE_CPUWORKER);
|
||||
|
||||
set_socket_nonblocking(fd[0]);
|
||||
|
||||
/* set up conn so it's got all the data we need to remember */
|
||||
conn->s = fd[0];
|
||||
conn->address = tor_strdup("localhost");
|
||||
|
||||
if(connection_add(conn) < 0) { /* no space, forget it */
|
||||
log_fn(LOG_WARN,"connection_add failed. Giving up.");
|
||||
connection_free(conn); /* this closes fd[0] */
|
||||
return -1;
|
||||
}
|
||||
|
||||
conn->state = CPUWORKER_STATE_IDLE;
|
||||
connection_start_reading(conn);
|
||||
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
static void spawn_enough_cpuworkers(void) {
|
||||
int num_cpuworkers_needed = options.NumCpus;
|
||||
|
||||
if(num_cpuworkers_needed < MIN_CPUWORKERS)
|
||||
num_cpuworkers_needed = MIN_CPUWORKERS;
|
||||
if(num_cpuworkers_needed > MAX_CPUWORKERS)
|
||||
num_cpuworkers_needed = MAX_CPUWORKERS;
|
||||
|
||||
while(num_cpuworkers < num_cpuworkers_needed) {
|
||||
if(spawn_cpuworker() < 0) {
|
||||
log_fn(LOG_WARN,"spawn failed!");
|
||||
return;
|
||||
}
|
||||
num_cpuworkers++;
|
||||
}
|
||||
}
|
||||
|
||||
static void process_pending_task(connection_t *cpuworker) {
|
||||
circuit_t *circ;
|
||||
|
||||
tor_assert(cpuworker);
|
||||
|
||||
/* for now only process onion tasks */
|
||||
|
||||
circ = onion_next_task();
|
||||
if(!circ)
|
||||
return;
|
||||
if(assign_to_cpuworker(cpuworker, CPUWORKER_TASK_ONION, circ) < 0)
|
||||
log_fn(LOG_WARN,"assign_to_cpuworker failed. Ignoring.");
|
||||
}
|
||||
|
||||
/* if cpuworker is defined, assert that he's idle, and use him. else,
|
||||
* look for an idle cpuworker and use him. if none idle, queue task onto
|
||||
* the pending onion list and return.
|
||||
* If question_type is CPUWORKER_TASK_ONION then task is a circ.
|
||||
* No other question_types are allowed.
|
||||
*/
|
||||
int assign_to_cpuworker(connection_t *cpuworker, unsigned char question_type,
|
||||
void *task) {
|
||||
circuit_t *circ;
|
||||
char tag[TAG_LEN];
|
||||
|
||||
tor_assert(question_type == CPUWORKER_TASK_ONION);
|
||||
|
||||
if(question_type == CPUWORKER_TASK_ONION) {
|
||||
circ = task;
|
||||
|
||||
if(num_cpuworkers_busy == num_cpuworkers) {
|
||||
log_fn(LOG_DEBUG,"No idle cpuworkers. Queuing.");
|
||||
if(onion_pending_add(circ) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!cpuworker)
|
||||
cpuworker = connection_get_by_type_state(CONN_TYPE_CPUWORKER, CPUWORKER_STATE_IDLE);
|
||||
|
||||
tor_assert(cpuworker);
|
||||
|
||||
if(!circ->p_conn) {
|
||||
log_fn(LOG_INFO,"circ->p_conn gone. Failing circ.");
|
||||
return -1;
|
||||
}
|
||||
tag_pack(tag, circ->p_conn->addr, circ->p_conn->port, circ->p_circ_id);
|
||||
|
||||
cpuworker->state = CPUWORKER_STATE_BUSY_ONION;
|
||||
num_cpuworkers_busy++;
|
||||
|
||||
connection_write_to_buf(&question_type, 1, cpuworker);
|
||||
connection_write_to_buf(tag, sizeof(tag), cpuworker);
|
||||
connection_write_to_buf(circ->onionskin, ONIONSKIN_CHALLENGE_LEN, cpuworker);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,521 @@
|
||||
/* Copyright 2001,2002,2003 Roger Dingledine. */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
#include "or.h"
|
||||
|
||||
static void directory_send_command(connection_t *conn, int purpose,
|
||||
const char *payload, int payload_len);
|
||||
static int directory_handle_command(connection_t *conn);
|
||||
|
||||
/********* START VARIABLES **********/
|
||||
|
||||
extern or_options_t options; /* command-line and config-file options */
|
||||
|
||||
char rend_publish_string[] = "/rendezvous/publish";
|
||||
char rend_fetch_url[] = "/rendezvous/";
|
||||
|
||||
#define MAX_HEADERS_SIZE 10000
|
||||
#define MAX_BODY_SIZE 500000
|
||||
|
||||
/********* END VARIABLES ************/
|
||||
|
||||
void directory_initiate_command(routerinfo_t *router, int purpose,
|
||||
const char *payload, int payload_len) {
|
||||
connection_t *conn;
|
||||
|
||||
if(purpose == DIR_PURPOSE_FETCH_DIR)
|
||||
log_fn(LOG_DEBUG,"initiating directory fetch");
|
||||
if(purpose == DIR_PURPOSE_FETCH_RENDDESC)
|
||||
log_fn(LOG_DEBUG,"initiating hidden-service descriptor fetch");
|
||||
if(purpose == DIR_PURPOSE_UPLOAD_DIR)
|
||||
log_fn(LOG_DEBUG,"initiating server descriptor upload");
|
||||
if(purpose == DIR_PURPOSE_UPLOAD_RENDDESC)
|
||||
log_fn(LOG_DEBUG,"initiating hidden-service descriptor upload");
|
||||
|
||||
if (!router) { /* i guess they didn't have one in mind for me to use */
|
||||
log_fn(LOG_WARN,"No running dirservers known. Not trying. (purpose %d)", purpose);
|
||||
return;
|
||||
}
|
||||
|
||||
conn = connection_new(CONN_TYPE_DIR);
|
||||
|
||||
/* set up conn so it's got all the data we need to remember */
|
||||
conn->addr = router->addr;
|
||||
conn->port = router->dir_port;
|
||||
conn->address = tor_strdup(router->address);
|
||||
conn->nickname = tor_strdup(router->nickname);
|
||||
tor_assert(router->identity_pkey);
|
||||
conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey);
|
||||
|
||||
conn->purpose = purpose;
|
||||
|
||||
if(connection_add(conn) < 0) { /* no space, forget it */
|
||||
connection_free(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
/* queue the command on the outbuf */
|
||||
directory_send_command(conn, purpose, payload, payload_len);
|
||||
|
||||
/* give it an initial state */
|
||||
conn->state = DIR_CONN_STATE_CONNECTING;
|
||||
|
||||
if(purpose == DIR_PURPOSE_FETCH_DIR ||
|
||||
purpose == DIR_PURPOSE_UPLOAD_DIR) {
|
||||
/* then we want to connect directly */
|
||||
switch(connection_connect(conn, conn->address, conn->addr, conn->port)) {
|
||||
case -1:
|
||||
router_mark_as_down(conn->nickname); /* don't try him again */
|
||||
connection_mark_for_close(conn, 0);
|
||||
return;
|
||||
case 1:
|
||||
conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
|
||||
/* fall through */
|
||||
case 0:
|
||||
connection_set_poll_socket(conn);
|
||||
connection_watch_events(conn, POLLIN | POLLOUT | POLLERR);
|
||||
/* writable indicates finish, readable indicates broken link,
|
||||
error indicates broken link in windowsland. */
|
||||
}
|
||||
} else { /* we want to connect via tor */
|
||||
/* make an AP connection
|
||||
* 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) {
|
||||
log_fn(LOG_WARN,"Making AP bridge to dirserver failed.");
|
||||
connection_mark_for_close(conn, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->state = DIR_CONN_STATE_CLIENT_SENDING;
|
||||
connection_set_poll_socket(conn);
|
||||
connection_start_reading(conn);
|
||||
}
|
||||
}
|
||||
|
||||
static void directory_send_command(connection_t *conn, int purpose,
|
||||
const char *payload, int payload_len) {
|
||||
char fetchstring[] = "GET / HTTP/1.0\r\n\r\n";
|
||||
char tmp[8192];
|
||||
|
||||
tor_assert(conn && conn->type == CONN_TYPE_DIR);
|
||||
|
||||
switch(purpose) {
|
||||
case DIR_PURPOSE_FETCH_DIR:
|
||||
tor_assert(payload == NULL);
|
||||
connection_write_to_buf(fetchstring, strlen(fetchstring), conn);
|
||||
break;
|
||||
case DIR_PURPOSE_UPLOAD_DIR:
|
||||
tor_assert(payload);
|
||||
snprintf(tmp, sizeof(tmp), "POST / HTTP/1.0\r\nContent-Length: %d\r\n\r\n",
|
||||
payload_len);
|
||||
connection_write_to_buf(tmp, strlen(tmp), conn);
|
||||
connection_write_to_buf(payload, payload_len, conn);
|
||||
break;
|
||||
case DIR_PURPOSE_FETCH_RENDDESC:
|
||||
tor_assert(payload);
|
||||
|
||||
/* this must be true or we wouldn't be doing the lookup */
|
||||
tor_assert(payload_len <= REND_SERVICE_ID_LEN);
|
||||
memcpy(conn->rend_query, payload, payload_len);
|
||||
conn->rend_query[payload_len] = 0;
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "GET %s%s HTTP/1.0\r\n\r\n", rend_fetch_url, payload);
|
||||
connection_write_to_buf(tmp, strlen(tmp), conn);
|
||||
break;
|
||||
case DIR_PURPOSE_UPLOAD_RENDDESC:
|
||||
tor_assert(payload);
|
||||
snprintf(tmp, sizeof(tmp),
|
||||
"POST %s HTTP/1.0\r\nContent-Length: %d\r\n\r\n", rend_publish_string, payload_len);
|
||||
connection_write_to_buf(tmp, strlen(tmp), conn);
|
||||
/* could include nuls, need to write it separately */
|
||||
connection_write_to_buf(payload, payload_len, conn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse "%s %s HTTP/1..."
|
||||
* If it's well-formed, point *url to the second %s,
|
||||
* null-terminate it (this modifies headers!) and return 0.
|
||||
* Otherwise, return -1.
|
||||
*/
|
||||
int parse_http_url(char *headers, char **url) {
|
||||
char *s, *tmp;
|
||||
|
||||
s = (char *)eat_whitespace_no_nl(headers);
|
||||
if (!*s) return -1;
|
||||
s = (char *)find_whitespace(s); /* get past GET/POST */
|
||||
if (!*s) return -1;
|
||||
s = (char *)eat_whitespace_no_nl(s);
|
||||
if (!*s) return -1;
|
||||
tmp = s; /* this is it, assuming it's valid */
|
||||
s = (char *)find_whitespace(s);
|
||||
if (!*s) return -1;
|
||||
*s = 0;
|
||||
*url = tmp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parse "HTTP/1.%d %d%s\r\n".
|
||||
* If it's well-formed, assign *code, point *message to the first
|
||||
* non-space character after code if there is one and message is non-NULL
|
||||
* (else leave it alone), and return 0.
|
||||
* Otherwise, return -1.
|
||||
*/
|
||||
int parse_http_response(char *headers, int *code, char **message) {
|
||||
int n1, n2;
|
||||
tor_assert(headers && code);
|
||||
|
||||
while(isspace((int)*headers)) headers++; /* tolerate leading whitespace */
|
||||
|
||||
if(sscanf(headers, "HTTP/1.%d %d", &n1, &n2) < 2 ||
|
||||
(n1 != 0 && n1 != 1) ||
|
||||
(n2 < 100 || n2 >= 600)) {
|
||||
log_fn(LOG_WARN,"Failed to parse header '%s'",headers);
|
||||
return -1;
|
||||
}
|
||||
*code = n2;
|
||||
if(message) {
|
||||
/* XXX should set *message correctly */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int connection_dir_process_inbuf(connection_t *conn) {
|
||||
char *body;
|
||||
char *headers;
|
||||
int body_len=0;
|
||||
int status_code;
|
||||
|
||||
tor_assert(conn && conn->type == CONN_TYPE_DIR);
|
||||
|
||||
if(conn->inbuf_reached_eof) {
|
||||
if(conn->state != DIR_CONN_STATE_CLIENT_READING) {
|
||||
log_fn(LOG_INFO,"conn reached eof, not reading. Closing.");
|
||||
connection_close_immediate(conn); /* it was an error; give up on flushing */
|
||||
connection_mark_for_close(conn,0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(fetch_from_buf_http(conn->inbuf,
|
||||
&headers, MAX_HEADERS_SIZE,
|
||||
&body, &body_len, MAX_DIR_SIZE)) {
|
||||
case -1: /* overflow */
|
||||
log_fn(LOG_WARN,"'fetch' response too large. Failing.");
|
||||
connection_mark_for_close(conn,0);
|
||||
return -1;
|
||||
case 0:
|
||||
log_fn(LOG_INFO,"'fetch' response not all here, but we're at eof. Closing.");
|
||||
connection_mark_for_close(conn,0);
|
||||
return -1;
|
||||
/* case 1, fall through */
|
||||
}
|
||||
|
||||
if(parse_http_response(headers, &status_code, NULL) < 0) {
|
||||
log_fn(LOG_WARN,"Unparseable headers. Closing.");
|
||||
free(body); free(headers);
|
||||
connection_mark_for_close(conn,0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(conn->purpose == DIR_PURPOSE_FETCH_DIR) {
|
||||
/* fetch/process the directory to learn about new routers. */
|
||||
log_fn(LOG_INFO,"Received directory (size %d):\n%s", body_len, body);
|
||||
if(status_code == 503 || body_len == 0) {
|
||||
log_fn(LOG_INFO,"Empty directory. Ignoring.");
|
||||
free(body); free(headers);
|
||||
connection_mark_for_close(conn,0);
|
||||
return 0;
|
||||
}
|
||||
if(status_code != 200) {
|
||||
log_fn(LOG_WARN,"Received http status code %d from dirserver. Failing.",
|
||||
status_code);
|
||||
free(body); free(headers);
|
||||
connection_mark_for_close(conn,0);
|
||||
return -1;
|
||||
}
|
||||
if(router_set_routerlist_from_directory(body, conn->identity_pkey) < 0){
|
||||
log_fn(LOG_INFO,"...but parsing failed. Ignoring.");
|
||||
} else {
|
||||
log_fn(LOG_INFO,"updated routers.");
|
||||
}
|
||||
directory_has_arrived(); /* do things we've been waiting to do */
|
||||
}
|
||||
|
||||
if(conn->purpose == DIR_PURPOSE_UPLOAD_DIR) {
|
||||
switch(status_code) {
|
||||
case 200:
|
||||
log_fn(LOG_INFO,"eof (status 200) after uploading server descriptor: finished.");
|
||||
break;
|
||||
case 400:
|
||||
log_fn(LOG_WARN,"http status 400 (bad request) response from dirserver. Malformed server descriptor?");
|
||||
break;
|
||||
case 403:
|
||||
log_fn(LOG_WARN,"http status 403 (unapproved server) response from dirserver. Is your clock skewed? Have you mailed arma your identity fingerprint? Are you using the right key? See README.");
|
||||
|
||||
break;
|
||||
default:
|
||||
log_fn(LOG_WARN,"http status %d response unrecognized.", status_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(conn->purpose == DIR_PURPOSE_FETCH_RENDDESC) {
|
||||
log_fn(LOG_INFO,"Received rendezvous descriptor (size %d, status code %d)",
|
||||
body_len, status_code);
|
||||
switch(status_code) {
|
||||
case 200:
|
||||
if(rend_cache_store(body, body_len) < 0) {
|
||||
log_fn(LOG_WARN,"Failed to store rendezvous descriptor.");
|
||||
/* alice's ap_stream will notice when connection_mark_for_close
|
||||
* cleans it up */
|
||||
} else {
|
||||
/* success. notify pending connections about this. */
|
||||
rend_client_desc_fetched(conn->rend_query, 1);
|
||||
conn->purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
|
||||
}
|
||||
break;
|
||||
case 404:
|
||||
/* not there. pending connections will be notified when
|
||||
* connection_mark_for_close cleans it up. */
|
||||
break;
|
||||
case 400:
|
||||
log_fn(LOG_WARN,"http status 400 (bad request). Dirserver didn't like our rendezvous query?");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(conn->purpose == DIR_PURPOSE_UPLOAD_RENDDESC) {
|
||||
switch(status_code) {
|
||||
case 200:
|
||||
log_fn(LOG_INFO,"eof (status 200) after uploading rendezvous descriptor: finished.");
|
||||
break;
|
||||
case 400:
|
||||
log_fn(LOG_WARN,"http status 400 (bad request) response from dirserver. Malformed rendezvous descriptor?");
|
||||
break;
|
||||
default:
|
||||
log_fn(LOG_WARN,"http status %d response unrecognized.", status_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(body); free(headers);
|
||||
connection_mark_for_close(conn,0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(conn->state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
|
||||
if (directory_handle_command(conn) < 0) {
|
||||
connection_mark_for_close(conn,0);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX for READ states, might want to make sure inbuf isn't too big */
|
||||
|
||||
log_fn(LOG_DEBUG,"Got data, not eof. Leaving on inbuf.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char answer200[] = "HTTP/1.0 200 OK\r\n\r\n";
|
||||
static char answer400[] = "HTTP/1.0 400 Bad request\r\n\r\n";
|
||||
static char answer403[] = "HTTP/1.0 403 Unapproved server\r\n\r\n";
|
||||
static char answer404[] = "HTTP/1.0 404 Not found\r\n\r\n";
|
||||
static char answer503[] = "HTTP/1.0 503 Directory unavailable\r\n\r\n";
|
||||
|
||||
/* always returns 0 */
|
||||
static int directory_handle_command_get(connection_t *conn,
|
||||
char *headers, char *body,
|
||||
int body_len) {
|
||||
size_t dlen;
|
||||
const char *cp;
|
||||
char *url;
|
||||
char tmp[8192];
|
||||
|
||||
log_fn(LOG_DEBUG,"Received GET command.");
|
||||
|
||||
conn->state = DIR_CONN_STATE_SERVER_WRITING;
|
||||
|
||||
if (parse_http_url(headers, &url) < 0) {
|
||||
connection_write_to_buf(answer400, strlen(answer400), conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!strcmp(url,"/")) { /* directory fetch */
|
||||
dlen = dirserv_get_directory(&cp);
|
||||
|
||||
if(dlen == 0) {
|
||||
log_fn(LOG_WARN,"My directory is empty. Closing.");
|
||||
connection_write_to_buf(answer503, strlen(answer503), conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_fn(LOG_DEBUG,"Dumping directory to client.");
|
||||
snprintf(tmp, sizeof(tmp), "HTTP/1.0 200 OK\r\nContent-Length: %d\r\nContent-Type: text/plain\r\n\r\n",
|
||||
(int)dlen);
|
||||
connection_write_to_buf(tmp, strlen(tmp), conn);
|
||||
connection_write_to_buf(cp, strlen(cp), conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!strncmp(url,rend_fetch_url,strlen(rend_fetch_url))) {
|
||||
/* rendezvous descriptor fetch */
|
||||
const char *descp;
|
||||
int desc_len;
|
||||
|
||||
switch(rend_cache_lookup_desc(url+strlen(rend_fetch_url), &descp, &desc_len)) {
|
||||
case 1: /* valid */
|
||||
snprintf(tmp, sizeof(tmp), "HTTP/1.0 200 OK\r\nContent-Length: %d\r\nContent-Type: application/octet-stream\r\n\r\n",
|
||||
desc_len); /* can't include descp here, because it's got nuls */
|
||||
connection_write_to_buf(tmp, strlen(tmp), conn);
|
||||
connection_write_to_buf(descp, desc_len, conn);
|
||||
break;
|
||||
case 0: /* well-formed but not present */
|
||||
connection_write_to_buf(answer404, strlen(answer404), conn);
|
||||
break;
|
||||
case -1: /* not well-formed */
|
||||
connection_write_to_buf(answer400, strlen(answer400), conn);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we didn't recognize the url */
|
||||
connection_write_to_buf(answer404, strlen(answer404), conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* always returns 0 */
|
||||
static int directory_handle_command_post(connection_t *conn,
|
||||
char *headers, char *body,
|
||||
int body_len) {
|
||||
const char *cp;
|
||||
char *url;
|
||||
|
||||
log_fn(LOG_DEBUG,"Received POST command.");
|
||||
|
||||
conn->state = DIR_CONN_STATE_SERVER_WRITING;
|
||||
|
||||
if (parse_http_url(headers, &url) < 0) {
|
||||
connection_write_to_buf(answer400, strlen(answer400), conn);
|
||||
return 0;
|
||||
}
|
||||
log_fn(LOG_INFO,"url '%s' posted to us.", url);
|
||||
|
||||
if(!strcmp(url,"/")) { /* server descriptor post */
|
||||
cp = body;
|
||||
switch(dirserv_add_descriptor(&cp)) {
|
||||
case -1:
|
||||
/* malformed descriptor, or something wrong */
|
||||
connection_write_to_buf(answer400, strlen(answer400), conn);
|
||||
break;
|
||||
case 0:
|
||||
/* descriptor was well-formed but server has not been approved */
|
||||
connection_write_to_buf(answer403, strlen(answer403), conn);
|
||||
break;
|
||||
case 1:
|
||||
dirserv_get_directory(&cp); /* rebuild and write to disk */
|
||||
connection_write_to_buf(answer200, strlen(answer200), conn);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!strncmp(url,rend_publish_string,strlen(rend_publish_string))) {
|
||||
/* rendezvous descriptor post */
|
||||
if(rend_cache_store(body, body_len) < 0)
|
||||
connection_write_to_buf(answer400, strlen(answer400), conn);
|
||||
else
|
||||
connection_write_to_buf(answer200, strlen(answer200), conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we didn't recognize the url */
|
||||
connection_write_to_buf(answer404, strlen(answer404), conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int directory_handle_command(connection_t *conn) {
|
||||
char *headers=NULL, *body=NULL;
|
||||
int body_len=0;
|
||||
int r;
|
||||
|
||||
tor_assert(conn && conn->type == CONN_TYPE_DIR);
|
||||
|
||||
switch(fetch_from_buf_http(conn->inbuf,
|
||||
&headers, MAX_HEADERS_SIZE,
|
||||
&body, &body_len, MAX_BODY_SIZE)) {
|
||||
case -1: /* overflow */
|
||||
log_fn(LOG_WARN,"input too large. Failing.");
|
||||
return -1;
|
||||
case 0:
|
||||
log_fn(LOG_DEBUG,"command not all here yet.");
|
||||
return 0;
|
||||
/* case 1, fall through */
|
||||
}
|
||||
|
||||
log_fn(LOG_DEBUG,"headers '%s', body '%s'.", headers, body);
|
||||
|
||||
if(!strncasecmp(headers,"GET",3))
|
||||
r = directory_handle_command_get(conn, headers, body, body_len);
|
||||
else if (!strncasecmp(headers,"POST",4))
|
||||
r = directory_handle_command_post(conn, headers, body, body_len);
|
||||
else {
|
||||
log_fn(LOG_WARN,"Got headers '%s' with unknown command. Closing.", headers);
|
||||
r = -1;
|
||||
}
|
||||
|
||||
tor_free(headers); tor_free(body);
|
||||
return r;
|
||||
}
|
||||
|
||||
int connection_dir_finished_flushing(connection_t *conn) {
|
||||
int e, len=sizeof(e);
|
||||
|
||||
tor_assert(conn && conn->type == CONN_TYPE_DIR);
|
||||
|
||||
switch(conn->state) {
|
||||
case DIR_CONN_STATE_CONNECTING:
|
||||
if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { /* not yet */
|
||||
if(!ERRNO_IS_CONN_EINPROGRESS(tor_socket_errno(conn->s))) {
|
||||
log_fn(LOG_DEBUG,"in-progress connect failed. Removing.");
|
||||
router_mark_as_down(conn->nickname); /* don't try him again */
|
||||
connection_mark_for_close(conn,0);
|
||||
return -1;
|
||||
} else {
|
||||
return 0; /* no change, see if next time is better */
|
||||
}
|
||||
}
|
||||
/* the connect has finished. */
|
||||
|
||||
log_fn(LOG_INFO,"Dir connection to router %s:%u established.",
|
||||
conn->address,conn->port);
|
||||
|
||||
conn->state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */
|
||||
return 0;
|
||||
case DIR_CONN_STATE_CLIENT_SENDING:
|
||||
log_fn(LOG_DEBUG,"client finished sending command.");
|
||||
conn->state = DIR_CONN_STATE_CLIENT_READING;
|
||||
connection_stop_writing(conn);
|
||||
return 0;
|
||||
case DIR_CONN_STATE_SERVER_WRITING:
|
||||
log_fn(LOG_INFO,"Finished writing server response. Closing.");
|
||||
connection_mark_for_close(conn,0);
|
||||
return 0;
|
||||
default:
|
||||
log_fn(LOG_WARN,"BUG: called in unexpected state %d.", conn->state);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
@@ -0,0 +1,531 @@
|
||||
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
#include "or.h"
|
||||
|
||||
/* How old do we allow a router to get before removing it? (seconds) */
|
||||
#define ROUTER_MAX_AGE (60*60*24)
|
||||
|
||||
/* How far in the future do we allow a router to get? (seconds) */
|
||||
#define ROUTER_ALLOW_SKEW (30*60)
|
||||
|
||||
extern or_options_t options; /* command-line and config-file options */
|
||||
|
||||
static int the_directory_is_dirty = 1;
|
||||
|
||||
static int list_running_servers(char **nicknames_out);
|
||||
static void directory_remove_unrecognized(void);
|
||||
|
||||
/************** Fingerprint handling code ************/
|
||||
|
||||
typedef struct fingerprint_entry_t {
|
||||
char *nickname;
|
||||
char *fingerprint;
|
||||
} fingerprint_entry_t;
|
||||
|
||||
static fingerprint_entry_t fingerprint_list[MAX_ROUTERS_IN_DIR];
|
||||
static int n_fingerprints = 0;
|
||||
|
||||
void /* Should be static; exposed for testing */
|
||||
add_fingerprint_to_dir(const char *nickname, const char *fp)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n_fingerprints; ++i) {
|
||||
if (!strcasecmp(fingerprint_list[i].nickname,nickname)) {
|
||||
free(fingerprint_list[i].fingerprint);
|
||||
fingerprint_list[i].fingerprint = tor_strdup(fp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
fingerprint_list[n_fingerprints].nickname = tor_strdup(nickname);
|
||||
fingerprint_list[n_fingerprints].fingerprint = tor_strdup(fp);
|
||||
++n_fingerprints;
|
||||
}
|
||||
|
||||
int
|
||||
dirserv_add_own_fingerprint(const char *nickname, crypto_pk_env_t *pk)
|
||||
{
|
||||
char fp[FINGERPRINT_LEN+1];
|
||||
if (crypto_pk_get_fingerprint(pk, fp)<0) {
|
||||
log_fn(LOG_ERR, "Error computing fingerprint");
|
||||
return -1;
|
||||
}
|
||||
add_fingerprint_to_dir(nickname, fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return 0 on success, -1 on failure */
|
||||
int
|
||||
dirserv_parse_fingerprint_file(const char *fname)
|
||||
{
|
||||
FILE *file;
|
||||
char line[FINGERPRINT_LEN+MAX_NICKNAME_LEN+20+1];
|
||||
char *nickname, *fingerprint;
|
||||
fingerprint_entry_t fingerprint_list_tmp[MAX_ROUTERS_IN_DIR];
|
||||
int n_fingerprints_tmp = 0;
|
||||
int i, result;
|
||||
|
||||
if(!(file = fopen(fname, "r"))) {
|
||||
log_fn(LOG_WARN, "Cannot open fingerprint file %s", fname);
|
||||
return -1;
|
||||
}
|
||||
while( (result=parse_line_from_file(line, sizeof(line),file,&nickname,&fingerprint)) > 0) {
|
||||
if (strlen(nickname) > MAX_NICKNAME_LEN) {
|
||||
log(LOG_WARN, "Nickname %s too long in fingerprint file. Skipping.", nickname);
|
||||
continue;
|
||||
}
|
||||
if(strlen(fingerprint) != FINGERPRINT_LEN ||
|
||||
!crypto_pk_check_fingerprint_syntax(fingerprint)) {
|
||||
log_fn(LOG_WARN, "Invalid fingerprint (nickname %s, fingerprint %s). Skipping.",
|
||||
nickname, fingerprint);
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < n_fingerprints_tmp; ++i) {
|
||||
if (0==strcasecmp(fingerprint_list_tmp[i].nickname, nickname)) {
|
||||
log(LOG_WARN, "Duplicate nickname %s. Skipping.",nickname);
|
||||
break; /* out of the for. the 'if' below means skip to the next line. */
|
||||
}
|
||||
}
|
||||
if(i == n_fingerprints_tmp) { /* not a duplicate */
|
||||
fingerprint_list_tmp[n_fingerprints_tmp].nickname = tor_strdup(nickname);
|
||||
fingerprint_list_tmp[n_fingerprints_tmp].fingerprint = tor_strdup(fingerprint);
|
||||
++n_fingerprints_tmp;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
if(result == 0) { /* eof; replace the global fingerprints list. */
|
||||
dirserv_free_fingerprint_list();
|
||||
memcpy(fingerprint_list, fingerprint_list_tmp,
|
||||
sizeof(fingerprint_entry_t)*n_fingerprints_tmp);
|
||||
n_fingerprints = n_fingerprints_tmp;
|
||||
/* Delete any routers whose fingerprints we no longer recognize */
|
||||
directory_remove_unrecognized();
|
||||
return 0;
|
||||
}
|
||||
/* error */
|
||||
log_fn(LOG_WARN, "Error reading from fingerprint file");
|
||||
for (i = 0; i < n_fingerprints_tmp; ++i) {
|
||||
free(fingerprint_list_tmp[i].nickname);
|
||||
free(fingerprint_list_tmp[i].fingerprint);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* return 1 if router's identity and nickname match,
|
||||
* -1 if they don't match, 0 if the nickname is not known. */
|
||||
int
|
||||
dirserv_router_fingerprint_is_known(const routerinfo_t *router)
|
||||
{
|
||||
int i;
|
||||
fingerprint_entry_t *ent =NULL;
|
||||
char fp[FINGERPRINT_LEN+1];
|
||||
|
||||
log_fn(LOG_DEBUG, "%d fingerprints known.", n_fingerprints);
|
||||
for (i=0;i<n_fingerprints;++i) {
|
||||
log_fn(LOG_DEBUG,"%s vs %s", router->nickname, fingerprint_list[i].nickname);
|
||||
if (!strcasecmp(router->nickname,fingerprint_list[i].nickname)) {
|
||||
ent = &fingerprint_list[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ent) { /* No such server known */
|
||||
log_fn(LOG_INFO,"no fingerprint found for %s",router->nickname);
|
||||
return 0;
|
||||
}
|
||||
if (crypto_pk_get_fingerprint(router->identity_pkey, fp)) {
|
||||
log_fn(LOG_WARN,"error computing fingerprint");
|
||||
return -1;
|
||||
}
|
||||
if (0==strcasecmp(ent->fingerprint, fp)) {
|
||||
log_fn(LOG_DEBUG,"good fingerprint for %s",router->nickname);
|
||||
return 1; /* Right fingerprint. */
|
||||
} else {
|
||||
log_fn(LOG_WARN,"mismatched fingerprint for %s",router->nickname);
|
||||
return -1; /* Wrong fingerprint. */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dirserv_free_fingerprint_list()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n_fingerprints; ++i) {
|
||||
free(fingerprint_list[i].nickname);
|
||||
free(fingerprint_list[i].fingerprint);
|
||||
}
|
||||
n_fingerprints = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Descriptor list
|
||||
*/
|
||||
typedef struct descriptor_entry_t {
|
||||
char *nickname;
|
||||
time_t published;
|
||||
size_t desc_len;
|
||||
char *descriptor;
|
||||
routerinfo_t *router;
|
||||
} descriptor_entry_t;
|
||||
|
||||
static descriptor_entry_t *descriptor_list[MAX_ROUTERS_IN_DIR];
|
||||
static int n_descriptors = 0;
|
||||
|
||||
static void free_descriptor_entry(descriptor_entry_t *desc)
|
||||
{
|
||||
tor_free(desc->descriptor);
|
||||
tor_free(desc->nickname);
|
||||
routerinfo_free(desc->router);
|
||||
free(desc);
|
||||
}
|
||||
|
||||
void
|
||||
dirserv_free_descriptors()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n_descriptors; ++i) {
|
||||
free_descriptor_entry(descriptor_list[i]);
|
||||
}
|
||||
n_descriptors = 0;
|
||||
}
|
||||
|
||||
/* Return 1 if descriptor is well-formed and accepted;
|
||||
* 0 if well-formed and server or descriptor is unapproved;
|
||||
* -1 if not well-formed or other error.
|
||||
*
|
||||
* Update *desc to point after the descriptor if the
|
||||
* descriptor is well-formed.
|
||||
*/
|
||||
int
|
||||
dirserv_add_descriptor(const char **desc)
|
||||
{
|
||||
descriptor_entry_t **desc_ent_ptr;
|
||||
routerinfo_t *ri = NULL;
|
||||
int i, r;
|
||||
char *start, *end;
|
||||
char *desc_tmp = NULL;
|
||||
const char *cp;
|
||||
size_t desc_len;
|
||||
time_t now;
|
||||
|
||||
start = strstr(*desc, "router ");
|
||||
if (!start) {
|
||||
log_fn(LOG_WARN, "no 'router' line found. This is not a descriptor.");
|
||||
return -1;
|
||||
}
|
||||
if ((end = strstr(start+6, "\nrouter "))) {
|
||||
++end; /* Include NL. */
|
||||
} else if ((end = strstr(start+6, "\ndirectory-signature"))) {
|
||||
++end;
|
||||
} else {
|
||||
end = start+strlen(start);
|
||||
}
|
||||
desc_len = end-start;
|
||||
cp = desc_tmp = tor_strndup(start, desc_len);
|
||||
|
||||
/* Check: is the descriptor syntactically valid? */
|
||||
ri = router_get_entry_from_string(cp, NULL);
|
||||
tor_free(desc_tmp);
|
||||
if (!ri) {
|
||||
log(LOG_WARN, "Couldn't parse descriptor");
|
||||
return -1;
|
||||
}
|
||||
/* Okay. Now check whether the fingerprint is recognized. */
|
||||
r = dirserv_router_fingerprint_is_known(ri);
|
||||
if(r<1) {
|
||||
if(r==0) {
|
||||
char fp[FINGERPRINT_LEN+1];
|
||||
log_fn(LOG_WARN, "Unknown nickname %s (%s:%d). Not adding.",
|
||||
ri->nickname, ri->address, ri->or_port);
|
||||
if (crypto_pk_get_fingerprint(ri->identity_pkey, fp) < 0) {
|
||||
log_fn(LOG_WARN, "Error computing fingerprint for %s", ri->nickname);
|
||||
} else {
|
||||
log_fn(LOG_WARN, "Fingerprint line: %s %s", ri->nickname, fp);
|
||||
}
|
||||
} else {
|
||||
log_fn(LOG_WARN, "Known nickname %s, wrong fingerprint. Not adding.", ri->nickname);
|
||||
}
|
||||
routerinfo_free(ri);
|
||||
*desc = end;
|
||||
return 0;
|
||||
}
|
||||
/* Is there too much clock skew? */
|
||||
now = time(NULL);
|
||||
if (ri->published_on > now+ROUTER_ALLOW_SKEW) {
|
||||
log_fn(LOG_WARN, "Publication time for nickname %s is too far in the future; possible clock skew. Not adding.", ri->nickname);
|
||||
routerinfo_free(ri);
|
||||
*desc = end;
|
||||
return 0;
|
||||
}
|
||||
if (ri->published_on < now-ROUTER_MAX_AGE) {
|
||||
log_fn(LOG_WARN, "Publication time for router with nickname %s is too far in the past. Not adding.", ri->nickname);
|
||||
routerinfo_free(ri);
|
||||
*desc = end;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do we already have an entry for this router? */
|
||||
desc_ent_ptr = NULL;
|
||||
for (i = 0; i < n_descriptors; ++i) {
|
||||
if (!strcasecmp(ri->nickname, descriptor_list[i]->nickname)) {
|
||||
desc_ent_ptr = &descriptor_list[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (desc_ent_ptr) {
|
||||
/* if so, decide whether to update it. */
|
||||
if ((*desc_ent_ptr)->published > ri->published_on) {
|
||||
/* We already have a newer descriptor */
|
||||
log_fn(LOG_INFO,"We already have a newer desc for nickname %s. Not adding.",ri->nickname);
|
||||
/* This isn't really an error; return success. */
|
||||
routerinfo_free(ri);
|
||||
*desc = end;
|
||||
return 1;
|
||||
}
|
||||
/* We don't have a newer one; we'll update this one. */
|
||||
log_fn(LOG_INFO,"Dirserv updating desc for nickname %s",ri->nickname);
|
||||
free_descriptor_entry(*desc_ent_ptr);
|
||||
} else {
|
||||
/* Add this at the end. */
|
||||
log_fn(LOG_INFO,"Dirserv adding desc for nickname %s",ri->nickname);
|
||||
desc_ent_ptr = &descriptor_list[n_descriptors++];
|
||||
/* XXX check if n_descriptors is too big */
|
||||
}
|
||||
|
||||
(*desc_ent_ptr) = tor_malloc(sizeof(descriptor_entry_t));
|
||||
(*desc_ent_ptr)->nickname = tor_strdup(ri->nickname);
|
||||
(*desc_ent_ptr)->published = ri->published_on;
|
||||
(*desc_ent_ptr)->desc_len = desc_len;
|
||||
(*desc_ent_ptr)->descriptor = tor_malloc(desc_len+1);
|
||||
strncpy((*desc_ent_ptr)->descriptor, start, desc_len);
|
||||
(*desc_ent_ptr)->descriptor[desc_len] = '\0';
|
||||
(*desc_ent_ptr)->router = ri;
|
||||
*desc = end;
|
||||
directory_set_dirty();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
directory_remove_unrecognized(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n_descriptors; ++i) {
|
||||
if (dirserv_router_fingerprint_is_known(descriptor_list[i]->router)<=0) {
|
||||
log(LOG_INFO, "Router %s is no longer recognized",
|
||||
descriptor_list[i]->nickname);
|
||||
free_descriptor_entry(descriptor_list[i]);
|
||||
descriptor_list[i--] = descriptor_list[--n_descriptors];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
directory_set_dirty()
|
||||
{
|
||||
the_directory_is_dirty = 1;
|
||||
}
|
||||
|
||||
int
|
||||
dirserv_init_from_directory_string(const char *dir)
|
||||
{
|
||||
const char *cp = dir;
|
||||
while(1) {
|
||||
cp = strstr(cp, "\nrouter ");
|
||||
if (!cp) break;
|
||||
++cp;
|
||||
if (dirserv_add_descriptor(&cp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
--cp; /*Back up to newline.*/
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
list_running_servers(char **nicknames_out)
|
||||
{
|
||||
char *nickname_lst[MAX_ROUTERS_IN_DIR];
|
||||
connection_t **connection_array;
|
||||
int n_conns;
|
||||
connection_t *conn;
|
||||
char *cp;
|
||||
int n = 0, i;
|
||||
int length;
|
||||
*nicknames_out = NULL;
|
||||
nickname_lst[n++] = options.Nickname;
|
||||
|
||||
get_connection_array(&connection_array, &n_conns);
|
||||
for (i = 0; i<n_conns; ++i) {
|
||||
conn = connection_array[i];
|
||||
if (conn->type != CONN_TYPE_OR || conn->state != OR_CONN_STATE_OPEN)
|
||||
continue; /* only list successfully handshaked OR's. */
|
||||
if(!conn->nickname) /* it's an OP, don't list it */
|
||||
continue;
|
||||
/* XXX if conn->nickname not approved, continue. otherwise when you
|
||||
* remove them from the approved list and hup, their descriptor is
|
||||
* taken out of the directory, but they're still in the running-routers
|
||||
* line. */
|
||||
nickname_lst[n++] = conn->nickname;
|
||||
}
|
||||
length = n + 1; /* spaces + EOS + 1. */
|
||||
for (i = 0; i<n; ++i) {
|
||||
length += strlen(nickname_lst[i]);
|
||||
}
|
||||
*nicknames_out = tor_malloc_zero(length);
|
||||
cp = *nicknames_out;
|
||||
for (i = 0; i<n; ++i) {
|
||||
if (i)
|
||||
strcat(cp, " ");
|
||||
strcat(cp, nickname_lst[i]); /* can't overflow */
|
||||
while (*cp)
|
||||
++cp;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove any descriptors from the directory that are more than ROUTER_MAX_AGE
|
||||
* seconds old.
|
||||
*/
|
||||
void
|
||||
dirserv_remove_old_servers(void)
|
||||
{
|
||||
int i;
|
||||
time_t cutoff;
|
||||
cutoff = time(NULL) - ROUTER_MAX_AGE;
|
||||
for (i = 0; i < n_descriptors; ++i) {
|
||||
if (descriptor_list[i]->published < cutoff) {
|
||||
/* descriptor_list[i] is too old. Remove it. */
|
||||
free_descriptor_entry(descriptor_list[i]);
|
||||
descriptor_list[i] = descriptor_list[n_descriptors-1];
|
||||
--n_descriptors;
|
||||
directory_set_dirty();
|
||||
--i; /* Don't advance the index; consider the new value now at i. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump all routers currently in the directory into the string <s>, using
|
||||
* at most <maxlen> characters, and signing the directory with <private_key>.
|
||||
* Return 0 on success, -1 on failure.
|
||||
*/
|
||||
int
|
||||
dirserv_dump_directory_to_string(char *s, unsigned int maxlen,
|
||||
crypto_pk_env_t *private_key)
|
||||
{
|
||||
char *cp, *eos;
|
||||
char digest[20];
|
||||
char signature[128];
|
||||
char published[33];
|
||||
time_t published_on;
|
||||
int i;
|
||||
eos = s+maxlen;
|
||||
|
||||
if (list_running_servers(&cp))
|
||||
return -1;
|
||||
dirserv_remove_old_servers();
|
||||
published_on = time(NULL);
|
||||
strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&published_on));
|
||||
snprintf(s, maxlen,
|
||||
"signed-directory\n"
|
||||
"published %s\n"
|
||||
"recommended-software %s\n"
|
||||
"running-routers %s\n\n", published, options.RecommendedVersions, cp);
|
||||
free(cp);
|
||||
i = strlen(s);
|
||||
cp = s+i;
|
||||
|
||||
for (i = 0; i < n_descriptors; ++i) {
|
||||
if (strlcat(s, descriptor_list[i]->descriptor, maxlen) >= maxlen)
|
||||
goto truncated;
|
||||
}
|
||||
/* These multiple strlcat calls are inefficient, but dwarfed by the RSA
|
||||
signature.
|
||||
*/
|
||||
if (strlcat(s, "directory-signature ", maxlen) >= maxlen)
|
||||
goto truncated;
|
||||
if (strlcat(s, options.Nickname, maxlen) >= maxlen)
|
||||
goto truncated;
|
||||
if (strlcat(s, "\n", maxlen) >= maxlen)
|
||||
goto truncated;
|
||||
|
||||
|
||||
if (router_get_dir_hash(s,digest)) {
|
||||
log_fn(LOG_WARN,"couldn't compute digest");
|
||||
return -1;
|
||||
}
|
||||
if (crypto_pk_private_sign(private_key, digest, 20, signature) < 0) {
|
||||
log_fn(LOG_WARN,"couldn't sign digest");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"generated directory digest begins with %s",hex_str(digest,4));
|
||||
|
||||
if (strlcat(cp, "-----BEGIN SIGNATURE-----\n", maxlen) >= maxlen)
|
||||
goto truncated;
|
||||
|
||||
i = strlen(s);
|
||||
cp = s+i;
|
||||
if (base64_encode(cp, maxlen-i, signature, 128) < 0) {
|
||||
log_fn(LOG_WARN,"couldn't base64-encode signature");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strlcat(s, "-----END SIGNATURE-----\n", maxlen) >= maxlen)
|
||||
goto truncated;
|
||||
|
||||
return 0;
|
||||
truncated:
|
||||
log_fn(LOG_WARN,"tried to exceed string length.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *the_directory = NULL;
|
||||
static int the_directory_len = -1;
|
||||
|
||||
size_t dirserv_get_directory(const char **directory)
|
||||
{
|
||||
char *new_directory;
|
||||
char filename[512];
|
||||
if (the_directory_is_dirty) {
|
||||
new_directory = tor_malloc(MAX_DIR_SIZE);
|
||||
if (dirserv_dump_directory_to_string(new_directory, MAX_DIR_SIZE,
|
||||
get_identity_key())) {
|
||||
log(LOG_WARN, "Error creating directory.");
|
||||
free(new_directory);
|
||||
return 0;
|
||||
}
|
||||
tor_free(the_directory);
|
||||
the_directory = new_directory;
|
||||
the_directory_len = strlen(the_directory);
|
||||
log_fn(LOG_INFO,"New directory (size %d):\n%s",the_directory_len,
|
||||
the_directory);
|
||||
the_directory_is_dirty = 0;
|
||||
/* Now read the directory we just made in order to update our own
|
||||
* router lists. This does more signature checking than is strictly
|
||||
* necessary, but safe is better than sorry. */
|
||||
new_directory = tor_strdup(the_directory);
|
||||
/* use a new copy of the dir, since get_dir_from_string scribbles on it */
|
||||
if (router_set_routerlist_from_directory(new_directory, get_identity_key())) {
|
||||
log_fn(LOG_ERR, "We just generated a directory we can't parse. Dying.");
|
||||
exit(0);
|
||||
}
|
||||
free(new_directory);
|
||||
sprintf(filename,"%s/cached-directory", options.DataDirectory);
|
||||
if(write_str_to_file(filename,the_directory) < 0) {
|
||||
log_fn(LOG_WARN, "Couldn't write cached directory to disk. Ignoring.");
|
||||
}
|
||||
} else {
|
||||
log(LOG_INFO,"Directory still clean, reusing.");
|
||||
}
|
||||
*directory = the_directory;
|
||||
return the_directory_len;
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
@@ -0,0 +1,593 @@
|
||||
/* Copyright 2003 Roger Dingledine. */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
/* 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 "tree.h"
|
||||
|
||||
extern or_options_t options; /* command-line and config-file options */
|
||||
|
||||
#define MAX_ADDRESSLEN 256
|
||||
|
||||
#define MAX_DNSWORKERS 50
|
||||
#define MIN_DNSWORKERS 3
|
||||
#define MAX_IDLE_DNSWORKERS 10
|
||||
|
||||
#define DNS_RESOLVE_FAILED_TRANSIENT 1
|
||||
#define DNS_RESOLVE_FAILED_PERMANENT 2
|
||||
#define DNS_RESOLVE_SUCCEEDED 3
|
||||
|
||||
int num_dnsworkers=0;
|
||||
int num_dnsworkers_busy=0;
|
||||
|
||||
struct pending_connection_t {
|
||||
struct connection_t *conn;
|
||||
struct pending_connection_t *next;
|
||||
};
|
||||
|
||||
struct cached_resolve {
|
||||
SPLAY_ENTRY(cached_resolve) node;
|
||||
char address[MAX_ADDRESSLEN]; /* the hostname to be resolved */
|
||||
uint32_t addr; /* in host order. I know I'm horrible for assuming ipv4 */
|
||||
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 untouched items from cache after some time? */
|
||||
struct pending_connection_t *pending_connections;
|
||||
struct cached_resolve *next;
|
||||
};
|
||||
|
||||
static void purge_expired_resolves(uint32_t now);
|
||||
static int assign_to_dnsworker(connection_t *exitconn);
|
||||
static void dns_purge_resolve(struct cached_resolve *resolve);
|
||||
static void dns_found_answer(char *address, uint32_t addr, char outcome);
|
||||
int dnsworker_main(void *data);
|
||||
static int spawn_dnsworker(void);
|
||||
static void spawn_enough_dnsworkers(void);
|
||||
|
||||
static SPLAY_HEAD(cache_tree, cached_resolve) cache_root;
|
||||
|
||||
static int compare_cached_resolves(struct cached_resolve *a,
|
||||
struct cached_resolve *b) {
|
||||
/* make this smarter one day? */
|
||||
return strncasecmp(a->address, b->address, MAX_ADDRESSLEN);
|
||||
}
|
||||
|
||||
SPLAY_PROTOTYPE(cache_tree, cached_resolve, node, compare_cached_resolves);
|
||||
SPLAY_GENERATE(cache_tree, cached_resolve, node, compare_cached_resolves);
|
||||
|
||||
static void init_cache_tree(void) {
|
||||
SPLAY_INIT(&cache_root);
|
||||
}
|
||||
|
||||
void dns_init(void) {
|
||||
init_cache_tree();
|
||||
spawn_enough_dnsworkers();
|
||||
}
|
||||
|
||||
static struct cached_resolve *oldest_cached_resolve = NULL; /* linked list, */
|
||||
static struct cached_resolve *newest_cached_resolve = NULL; /* oldest to newest */
|
||||
|
||||
static void purge_expired_resolves(uint32_t now) {
|
||||
struct cached_resolve *resolve;
|
||||
|
||||
/* 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(LOG_DEBUG,"Forgetting old cached resolve (expires %lu)", (unsigned long)resolve->expire);
|
||||
if(resolve->state == CACHE_STATE_PENDING) {
|
||||
log_fn(LOG_WARN,"Expiring a dns resolve that's still pending. Forgot to cull it?");
|
||||
/* XXX if resolve->pending_connections is used, then we're probably
|
||||
* introducing bugs by closing resolve without notifying those streams.
|
||||
*/
|
||||
}
|
||||
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 */
|
||||
SPLAY_REMOVE(cache_tree, &cache_root, resolve);
|
||||
tor_free(resolve);
|
||||
}
|
||||
}
|
||||
|
||||
/* See if we have a cache entry for 'exitconn->address'. if so,
|
||||
* if resolve valid, put it into exitconn->addr and return 1.
|
||||
* If resolve failed, return -1.
|
||||
*
|
||||
* Else, if seen before and pending, add conn to the pending list,
|
||||
* and return 0.
|
||||
*
|
||||
* Else, if not seen before, add conn to pending list, hand to
|
||||
* dns farm, and return 0.
|
||||
*/
|
||||
int dns_resolve(connection_t *exitconn) {
|
||||
struct cached_resolve *resolve;
|
||||
struct cached_resolve search;
|
||||
struct pending_connection_t *pending_connection;
|
||||
struct in_addr in;
|
||||
uint32_t now = time(NULL);
|
||||
assert_connection_ok(exitconn, 0);
|
||||
|
||||
/* first check if exitconn->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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* then take this opportunity to see if there are any expired
|
||||
* resolves in the tree. */
|
||||
purge_expired_resolves(now);
|
||||
|
||||
/* now check the tree to see if 'address' is already there. */
|
||||
strncpy(search.address, exitconn->address, MAX_ADDRESSLEN);
|
||||
search.address[MAX_ADDRESSLEN-1] = 0;
|
||||
resolve = SPLAY_FIND(cache_tree, &cache_root, &search);
|
||||
if(resolve) { /* already there */
|
||||
switch(resolve->state) {
|
||||
case CACHE_STATE_PENDING:
|
||||
/* add us to the pending list */
|
||||
pending_connection = tor_malloc(sizeof(struct pending_connection_t));
|
||||
pending_connection->conn = exitconn;
|
||||
pending_connection->next = resolve->pending_connections;
|
||||
resolve->pending_connections = pending_connection;
|
||||
log_fn(LOG_DEBUG,"Connection (fd %d) waiting for pending DNS resolve of '%s'",
|
||||
exitconn->s, exitconn->address);
|
||||
exitconn->state = EXIT_CONN_STATE_RESOLVING;
|
||||
return 0;
|
||||
case CACHE_STATE_VALID:
|
||||
exitconn->addr = resolve->addr;
|
||||
log_fn(LOG_DEBUG,"Connection (fd %d) found cached answer for '%s'",
|
||||
exitconn->s, exitconn->address);
|
||||
return 1;
|
||||
case CACHE_STATE_FAILED:
|
||||
return -1;
|
||||
}
|
||||
tor_assert(0);
|
||||
}
|
||||
/* not there, need to add it */
|
||||
resolve = tor_malloc_zero(sizeof(struct cached_resolve));
|
||||
resolve->state = CACHE_STATE_PENDING;
|
||||
resolve->expire = now + MAX_DNS_ENTRY_AGE;
|
||||
strncpy(resolve->address, exitconn->address, MAX_ADDRESSLEN);
|
||||
resolve->address[MAX_ADDRESSLEN-1] = 0;
|
||||
|
||||
/* add us to the pending list */
|
||||
pending_connection = tor_malloc(sizeof(struct pending_connection_t));
|
||||
pending_connection->conn = exitconn;
|
||||
pending_connection->next = NULL;
|
||||
resolve->pending_connections = pending_connection;
|
||||
exitconn->state = EXIT_CONN_STATE_RESOLVING;
|
||||
|
||||
/* add us to the linked list of resolves */
|
||||
if (!oldest_cached_resolve) {
|
||||
oldest_cached_resolve = resolve;
|
||||
} else {
|
||||
newest_cached_resolve->next = resolve;
|
||||
}
|
||||
newest_cached_resolve = resolve;
|
||||
|
||||
SPLAY_INSERT(cache_tree, &cache_root, resolve);
|
||||
return assign_to_dnsworker(exitconn);
|
||||
}
|
||||
|
||||
static int assign_to_dnsworker(connection_t *exitconn) {
|
||||
connection_t *dnsconn;
|
||||
unsigned char len;
|
||||
|
||||
tor_assert(exitconn->state == EXIT_CONN_STATE_RESOLVING);
|
||||
|
||||
spawn_enough_dnsworkers(); /* respawn here, to be sure there are enough */
|
||||
|
||||
dnsconn = connection_get_by_type_state(CONN_TYPE_DNSWORKER, DNSWORKER_STATE_IDLE);
|
||||
|
||||
if(!dnsconn) {
|
||||
log_fn(LOG_WARN,"no idle dns workers. Failing.");
|
||||
dns_cancel_pending_resolve(exitconn->address);
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_fn(LOG_DEBUG, "Connection (fd %d) needs to resolve '%s'; assigning to DNSWorker (fd %d)",
|
||||
exitconn->s, exitconn->address, dnsconn->s);
|
||||
|
||||
tor_free(dnsconn->address);
|
||||
dnsconn->address = tor_strdup(exitconn->address);
|
||||
dnsconn->state = DNSWORKER_STATE_BUSY;
|
||||
num_dnsworkers_busy++;
|
||||
|
||||
len = strlen(dnsconn->address);
|
||||
connection_write_to_buf(&len, 1, dnsconn);
|
||||
connection_write_to_buf(dnsconn->address, len, dnsconn);
|
||||
|
||||
// log_fn(LOG_DEBUG,"submitted '%s'", exitconn->address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void connection_dns_remove(connection_t *conn)
|
||||
{
|
||||
struct pending_connection_t *pend, *victim;
|
||||
struct cached_resolve search;
|
||||
struct cached_resolve *resolve;
|
||||
|
||||
strncpy(search.address, conn->address, MAX_ADDRESSLEN);
|
||||
search.address[MAX_ADDRESSLEN-1] = 0;
|
||||
|
||||
resolve = SPLAY_FIND(cache_tree, &cache_root, &search);
|
||||
if(!resolve) {
|
||||
log_fn(LOG_WARN,"Address '%s' is not pending. Dropping.", conn->address);
|
||||
return;
|
||||
}
|
||||
|
||||
tor_assert(resolve->pending_connections);
|
||||
assert_connection_ok(conn,0);
|
||||
|
||||
pend = resolve->pending_connections;
|
||||
|
||||
if(pend->conn == conn) {
|
||||
resolve->pending_connections = pend->next;
|
||||
tor_free(pend);
|
||||
log_fn(LOG_DEBUG, "First connection (fd %d) no longer waiting for resolve of '%s'",
|
||||
conn->s, conn->address);
|
||||
return;
|
||||
} else {
|
||||
for( ; pend->next; pend = pend->next) {
|
||||
if(pend->next->conn == conn) {
|
||||
victim = pend->next;
|
||||
pend->next = victim->next;
|
||||
tor_free(victim);
|
||||
log_fn(LOG_DEBUG, "Connection (fd %d) no longer waiting for resolve of '%s'",
|
||||
conn->s, conn->address);
|
||||
return; /* more are pending */
|
||||
}
|
||||
}
|
||||
tor_assert(0); /* not reachable unless onlyconn not in pending list */
|
||||
}
|
||||
}
|
||||
|
||||
void assert_connection_edge_not_dns_pending(connection_t *conn) {
|
||||
struct pending_connection_t *pend;
|
||||
struct cached_resolve *resolve;
|
||||
|
||||
SPLAY_FOREACH(resolve, cache_tree, &cache_root) {
|
||||
for(pend = resolve->pending_connections;
|
||||
pend;
|
||||
pend = pend->next) {
|
||||
tor_assert(pend->conn != conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void assert_all_pending_dns_resolves_ok(void) {
|
||||
struct pending_connection_t *pend;
|
||||
struct cached_resolve *resolve;
|
||||
|
||||
SPLAY_FOREACH(resolve, cache_tree, &cache_root) {
|
||||
for(pend = resolve->pending_connections;
|
||||
pend;
|
||||
pend = pend->next) {
|
||||
assert_connection_ok(pend->conn, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Cancel all pending connections. Then cancel the resolve itself,
|
||||
* and remove the 'struct cached_resolve' from the cache.
|
||||
*/
|
||||
void dns_cancel_pending_resolve(char *address) {
|
||||
struct pending_connection_t *pend;
|
||||
struct cached_resolve search;
|
||||
struct cached_resolve *resolve;
|
||||
connection_t *pendconn;
|
||||
|
||||
strncpy(search.address, address, MAX_ADDRESSLEN);
|
||||
search.address[MAX_ADDRESSLEN-1] = 0;
|
||||
|
||||
resolve = SPLAY_FIND(cache_tree, &cache_root, &search);
|
||||
if(!resolve) {
|
||||
log_fn(LOG_WARN,"Address '%s' is not pending. Dropping.", address);
|
||||
return;
|
||||
}
|
||||
|
||||
tor_assert(resolve->pending_connections);
|
||||
|
||||
/* mark all pending connections to fail */
|
||||
log_fn(LOG_DEBUG, "Failing all connections waiting on DNS resolve of '%s'",
|
||||
address);
|
||||
while(resolve->pending_connections) {
|
||||
pend = resolve->pending_connections;
|
||||
/* So that mark_for_close doesn't double-remove the connection. */
|
||||
pend->conn->state = EXIT_CONN_STATE_RESOLVEFAILED;
|
||||
pendconn = pend->conn; /* don't pass complex things to the
|
||||
connection_mark_for_close macro */
|
||||
connection_mark_for_close(pendconn, END_STREAM_REASON_MISC);
|
||||
resolve->pending_connections = pend->next;
|
||||
tor_free(pend);
|
||||
}
|
||||
|
||||
dns_purge_resolve(resolve);
|
||||
}
|
||||
|
||||
static void dns_purge_resolve(struct cached_resolve *resolve) {
|
||||
struct cached_resolve *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 */
|
||||
|
||||
if(newest_cached_resolve == resolve)
|
||||
newest_cached_resolve = tmp;
|
||||
}
|
||||
|
||||
/* remove resolve from the tree */
|
||||
SPLAY_REMOVE(cache_tree, &cache_root, resolve);
|
||||
|
||||
tor_free(resolve);
|
||||
}
|
||||
|
||||
static void dns_found_answer(char *address, uint32_t addr, char outcome) {
|
||||
struct pending_connection_t *pend;
|
||||
struct cached_resolve search;
|
||||
struct cached_resolve *resolve;
|
||||
connection_t *pendconn;
|
||||
|
||||
strncpy(search.address, address, MAX_ADDRESSLEN);
|
||||
search.address[MAX_ADDRESSLEN-1] = 0;
|
||||
|
||||
resolve = SPLAY_FIND(cache_tree, &cache_root, &search);
|
||||
if(!resolve) {
|
||||
log_fn(LOG_INFO,"Resolved unasked address '%s'? Dropping.", address);
|
||||
/* XXX Why drop? Just because we don't care now doesn't mean we shouldn't
|
||||
* XXX cache the result for later. */
|
||||
return;
|
||||
}
|
||||
|
||||
if (resolve->state != CACHE_STATE_PENDING) {
|
||||
log_fn(LOG_WARN, "Resolved '%s' which was already resolved; ignoring",
|
||||
address);
|
||||
tor_assert(resolve->pending_connections == NULL);
|
||||
return;
|
||||
}
|
||||
/* Removed this assertion: in fact, we'll sometimes get a double answer
|
||||
* to the same question. This can happen when we ask one worker to resolve
|
||||
* X.Y.Z., then we cancel the request, and then we ask another worker to
|
||||
* resolve X.Y.Z. */
|
||||
/* tor_assert(resolve->state == CACHE_STATE_PENDING); */
|
||||
|
||||
resolve->addr = ntohl(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;
|
||||
|
||||
|
||||
if(resolve->state == CACHE_STATE_FAILED) {
|
||||
pendconn = pend->conn; /* don't pass complex things to the
|
||||
connection_mark_for_close macro */
|
||||
/* prevent double-remove. */
|
||||
pend->conn->state = EXIT_CONN_STATE_RESOLVEFAILED;
|
||||
connection_mark_for_close(pendconn, END_STREAM_REASON_RESOLVEFAILED);
|
||||
} else {
|
||||
/* prevent double-remove. */
|
||||
pend->conn->state = EXIT_CONN_STATE_CONNECTING;
|
||||
connection_exit_connect(pend->conn);
|
||||
}
|
||||
resolve->pending_connections = pend->next;
|
||||
tor_free(pend);
|
||||
}
|
||||
|
||||
if(outcome == DNS_RESOLVE_FAILED_TRANSIENT) { /* remove from cache */
|
||||
dns_purge_resolve(resolve);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
int connection_dns_finished_flushing(connection_t *conn) {
|
||||
tor_assert(conn && conn->type == CONN_TYPE_DNSWORKER);
|
||||
connection_stop_writing(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int connection_dns_process_inbuf(connection_t *conn) {
|
||||
char success;
|
||||
uint32_t addr;
|
||||
|
||||
tor_assert(conn && conn->type == CONN_TYPE_DNSWORKER);
|
||||
|
||||
if(conn->inbuf_reached_eof) {
|
||||
log_fn(LOG_WARN,"Read eof. Worker died unexpectedly.");
|
||||
if(conn->state == DNSWORKER_STATE_BUSY) {
|
||||
dns_cancel_pending_resolve(conn->address);
|
||||
num_dnsworkers_busy--;
|
||||
}
|
||||
num_dnsworkers--;
|
||||
connection_mark_for_close(conn,0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tor_assert(conn->state == DNSWORKER_STATE_BUSY);
|
||||
if(buf_datalen(conn->inbuf) < 5) /* entire answer available? */
|
||||
return 0; /* not yet */
|
||||
tor_assert(buf_datalen(conn->inbuf) == 5);
|
||||
|
||||
connection_fetch_from_buf(&success,1,conn);
|
||||
connection_fetch_from_buf((char *)&addr,sizeof(uint32_t),conn);
|
||||
|
||||
log_fn(LOG_DEBUG, "DNSWorker (fd %d) returned answer for '%s'",
|
||||
conn->s, conn->address);
|
||||
|
||||
tor_assert(success >= DNS_RESOLVE_FAILED_TRANSIENT);
|
||||
tor_assert(success <= DNS_RESOLVE_SUCCEEDED);
|
||||
dns_found_answer(conn->address, addr, success);
|
||||
|
||||
tor_free(conn->address);
|
||||
conn->address = tor_strdup("<idle>");
|
||||
conn->state = DNSWORKER_STATE_IDLE;
|
||||
num_dnsworkers_busy--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dnsworker_main(void *data) {
|
||||
char address[MAX_ADDRESSLEN];
|
||||
unsigned char address_len;
|
||||
char answer[5];
|
||||
uint32_t ip;
|
||||
int *fdarray = data;
|
||||
int fd;
|
||||
|
||||
tor_close_socket(fdarray[0]); /* this is the side of the socketpair the parent uses */
|
||||
fd = fdarray[1]; /* this side is ours */
|
||||
#ifndef MS_WINDOWS
|
||||
connection_free_all(); /* so the child doesn't hold the parent's fd's open */
|
||||
#endif
|
||||
|
||||
for(;;) {
|
||||
|
||||
if(recv(fd, &address_len, 1, 0) != 1) {
|
||||
log_fn(LOG_INFO,"dnsworker exiting because tor process died.");
|
||||
spawn_exit();
|
||||
}
|
||||
tor_assert(address_len > 0);
|
||||
|
||||
if(read_all(fd, address, address_len, 1) != address_len) {
|
||||
log_fn(LOG_ERR,"read hostname failed. Child exiting.");
|
||||
spawn_exit();
|
||||
}
|
||||
address[address_len] = 0; /* null terminate it */
|
||||
|
||||
switch (tor_lookup_hostname(address, &ip)) {
|
||||
case 1:
|
||||
log_fn(LOG_INFO,"Could not resolve dest addr %s (transient).",address);
|
||||
answer[0] = DNS_RESOLVE_FAILED_TRANSIENT;
|
||||
break;
|
||||
case -1:
|
||||
log_fn(LOG_INFO,"Could not resolve dest addr %s (permanent).",address);
|
||||
answer[0] = DNS_RESOLVE_FAILED_PERMANENT;
|
||||
break;
|
||||
case 0:
|
||||
log_fn(LOG_INFO,"Resolved address '%s'.",address);
|
||||
answer[0] = DNS_RESOLVE_SUCCEEDED;
|
||||
break;
|
||||
}
|
||||
set_uint32(answer+1, ip);
|
||||
if(write_all(fd, answer, 5, 1) != 5) {
|
||||
log_fn(LOG_ERR,"writing answer failed. Child exiting.");
|
||||
spawn_exit();
|
||||
}
|
||||
}
|
||||
return 0; /* windows wants this function to return an int */
|
||||
}
|
||||
|
||||
static int spawn_dnsworker(void) {
|
||||
int fd[2];
|
||||
connection_t *conn;
|
||||
|
||||
if(tor_socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) {
|
||||
log(LOG_ERR, "Couldn't construct socketpair: %s", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
spawn_func(dnsworker_main, (void*)fd);
|
||||
log_fn(LOG_DEBUG,"just spawned a worker.");
|
||||
tor_close_socket(fd[1]); /* we don't need the worker's side of the pipe */
|
||||
|
||||
conn = connection_new(CONN_TYPE_DNSWORKER);
|
||||
|
||||
set_socket_nonblocking(fd[0]);
|
||||
|
||||
/* set up conn so it's got all the data we need to remember */
|
||||
conn->s = fd[0];
|
||||
conn->address = tor_strdup("<unused>");
|
||||
|
||||
if(connection_add(conn) < 0) { /* no space, forget it */
|
||||
log_fn(LOG_WARN,"connection_add failed. Giving up.");
|
||||
connection_free(conn); /* this closes fd[0] */
|
||||
return -1;
|
||||
}
|
||||
|
||||
conn->state = DNSWORKER_STATE_IDLE;
|
||||
connection_start_reading(conn);
|
||||
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
static void spawn_enough_dnsworkers(void) {
|
||||
int num_dnsworkers_needed; /* aim to have 1 more than needed,
|
||||
* but no less than min and no more than max */
|
||||
connection_t *dnsconn;
|
||||
|
||||
/* XXX This may not be the best strategy. Maybe we should queue pending
|
||||
* requests until the old ones finish or time out: otherwise, if
|
||||
* the connection requests come fast enough, we never get any DNS done. -NM
|
||||
* XXX But if we queue them, then the adversary can pile even more
|
||||
* queries onto us, blocking legitimate requests for even longer.
|
||||
* Maybe we should compromise and only kill if it's been at it for
|
||||
* more than, e.g., 2 seconds. -RD
|
||||
*/
|
||||
if(num_dnsworkers_busy == MAX_DNSWORKERS) {
|
||||
/* We always want at least one worker idle.
|
||||
* So find the oldest busy worker and kill it.
|
||||
*/
|
||||
dnsconn = connection_get_by_type_state_lastwritten(CONN_TYPE_DNSWORKER,
|
||||
DNSWORKER_STATE_BUSY);
|
||||
tor_assert(dnsconn);
|
||||
|
||||
log_fn(LOG_WARN, "%d DNS workers are spawned; all are busy. Killing one.",
|
||||
MAX_DNSWORKERS);
|
||||
|
||||
connection_mark_for_close(dnsconn,0);
|
||||
num_dnsworkers_busy--;
|
||||
num_dnsworkers--;
|
||||
}
|
||||
|
||||
if(num_dnsworkers_busy >= MIN_DNSWORKERS)
|
||||
num_dnsworkers_needed = num_dnsworkers_busy+1;
|
||||
else
|
||||
num_dnsworkers_needed = MIN_DNSWORKERS;
|
||||
|
||||
while(num_dnsworkers < num_dnsworkers_needed) {
|
||||
if(spawn_dnsworker() < 0) {
|
||||
log(LOG_WARN,"spawn_enough_dnsworkers(): spawn failed!");
|
||||
return;
|
||||
}
|
||||
num_dnsworkers++;
|
||||
}
|
||||
|
||||
while(num_dnsworkers > num_dnsworkers_busy+MAX_IDLE_DNSWORKERS) { /* too many idle? */
|
||||
/* cull excess workers */
|
||||
log_fn(LOG_WARN,"%d of %d dnsworkers are idle. Killing one.",
|
||||
num_dnsworkers-num_dnsworkers_needed, num_dnsworkers);
|
||||
dnsconn = connection_get_by_type_state(CONN_TYPE_DNSWORKER, DNSWORKER_STATE_IDLE);
|
||||
tor_assert(dnsconn);
|
||||
connection_mark_for_close(dnsconn,0);
|
||||
num_dnsworkers--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
@@ -0,0 +1,849 @@
|
||||
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
#include "or.h"
|
||||
|
||||
/********* PROTOTYPES **********/
|
||||
|
||||
static void dumpstats(int severity); /* log stats */
|
||||
static int init_from_config(int argc, char **argv);
|
||||
|
||||
/********* START VARIABLES **********/
|
||||
|
||||
extern char *conn_state_to_string[][_CONN_TYPE_MAX+1];
|
||||
|
||||
or_options_t options; /* command-line and config-file options */
|
||||
int global_read_bucket; /* max number of bytes I can read this second */
|
||||
|
||||
static int stats_prev_global_read_bucket;
|
||||
static uint64_t stats_n_bytes_read = 0;
|
||||
static long stats_n_seconds_reading = 0;
|
||||
|
||||
static connection_t *connection_array[MAXCONNECTIONS] =
|
||||
{ NULL };
|
||||
|
||||
static struct pollfd poll_array[MAXCONNECTIONS];
|
||||
|
||||
static int nfds=0; /* number of connections currently active */
|
||||
|
||||
#ifndef MS_WINDOWS /* do signal stuff only on unix */
|
||||
static int please_dumpstats=0; /* whether we should dump stats during the loop */
|
||||
static int please_reset=0; /* whether we just got a sighup */
|
||||
static int please_reap_children=0; /* whether we should waitpid for exited children */
|
||||
#endif /* signal stuff */
|
||||
|
||||
int has_fetched_directory=0;
|
||||
/* we set this to 1 when we've fetched a dir, to know whether to complain
|
||||
* yet about unrecognized nicknames in entrynodes, exitnodes, etc.
|
||||
* Also, we don't try building circuits unless this is 1. */
|
||||
|
||||
int has_completed_circuit=0;
|
||||
/* 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. */
|
||||
|
||||
/********* END VARIABLES ************/
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* 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).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int connection_add(connection_t *conn) {
|
||||
tor_assert(conn);
|
||||
|
||||
if(nfds >= options.MaxConn-1) {
|
||||
log_fn(LOG_WARN,"failing because nfds is too high.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
conn->poll_index = nfds;
|
||||
connection_set_poll_socket(conn);
|
||||
connection_array[nfds] = conn;
|
||||
|
||||
/* zero these out here, because otherwise we'll inherit values from the previously freed one */
|
||||
poll_array[nfds].events = 0;
|
||||
poll_array[nfds].revents = 0;
|
||||
|
||||
nfds++;
|
||||
|
||||
log_fn(LOG_INFO,"new conn type %s, socket %d, nfds %d.",
|
||||
CONN_TYPE_TO_STRING(conn->type), conn->s, nfds);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void connection_set_poll_socket(connection_t *conn) {
|
||||
poll_array[conn->poll_index].fd = conn->s;
|
||||
}
|
||||
|
||||
/* Remove the connection from the global list, and remove the
|
||||
* corresponding poll entry. Calling this function will shift the last
|
||||
* connection (if any) into the position occupied by conn.
|
||||
*/
|
||||
int connection_remove(connection_t *conn) {
|
||||
int current_index;
|
||||
|
||||
tor_assert(conn);
|
||||
tor_assert(nfds>0);
|
||||
|
||||
log_fn(LOG_INFO,"removing socket %d (type %s), nfds now %d",
|
||||
conn->s, CONN_TYPE_TO_STRING(conn->type), nfds-1);
|
||||
/* if it's an edge conn, remove it from the list
|
||||
* of conn's on this circuit. If it's not on an edge,
|
||||
* flush and send destroys for all circuits on this conn
|
||||
*/
|
||||
circuit_about_to_close_connection(conn);
|
||||
|
||||
current_index = conn->poll_index;
|
||||
if(current_index == nfds-1) { /* this is the end */
|
||||
nfds--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* replace this one with the one at the end */
|
||||
nfds--;
|
||||
poll_array[current_index].fd = poll_array[nfds].fd;
|
||||
poll_array[current_index].events = poll_array[nfds].events;
|
||||
poll_array[current_index].revents = poll_array[nfds].revents;
|
||||
connection_array[current_index] = connection_array[nfds];
|
||||
connection_array[current_index]->poll_index = current_index;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void get_connection_array(connection_t ***array, int *n) {
|
||||
*array = connection_array;
|
||||
*n = nfds;
|
||||
}
|
||||
|
||||
void connection_watch_events(connection_t *conn, short events) {
|
||||
|
||||
tor_assert(conn && conn->poll_index < nfds);
|
||||
|
||||
poll_array[conn->poll_index].events = events;
|
||||
}
|
||||
|
||||
int connection_is_reading(connection_t *conn) {
|
||||
return poll_array[conn->poll_index].events & POLLIN;
|
||||
}
|
||||
|
||||
void connection_stop_reading(connection_t *conn) {
|
||||
|
||||
tor_assert(conn && conn->poll_index < nfds);
|
||||
|
||||
log(LOG_DEBUG,"connection_stop_reading() called.");
|
||||
if(poll_array[conn->poll_index].events & POLLIN)
|
||||
poll_array[conn->poll_index].events -= POLLIN;
|
||||
}
|
||||
|
||||
void connection_start_reading(connection_t *conn) {
|
||||
|
||||
tor_assert(conn && conn->poll_index < nfds);
|
||||
|
||||
poll_array[conn->poll_index].events |= POLLIN;
|
||||
}
|
||||
|
||||
int connection_is_writing(connection_t *conn) {
|
||||
return poll_array[conn->poll_index].events & POLLOUT;
|
||||
}
|
||||
|
||||
void connection_stop_writing(connection_t *conn) {
|
||||
|
||||
tor_assert(conn && conn->poll_index < nfds);
|
||||
|
||||
if(poll_array[conn->poll_index].events & POLLOUT)
|
||||
poll_array[conn->poll_index].events -= POLLOUT;
|
||||
}
|
||||
|
||||
void connection_start_writing(connection_t *conn) {
|
||||
|
||||
tor_assert(conn && conn->poll_index < nfds);
|
||||
|
||||
poll_array[conn->poll_index].events |= POLLOUT;
|
||||
}
|
||||
|
||||
static void conn_read(int i) {
|
||||
connection_t *conn = connection_array[i];
|
||||
|
||||
if (conn->marked_for_close)
|
||||
return;
|
||||
|
||||
/* see http://www.greenend.org.uk/rjk/2001/06/poll.html for
|
||||
* discussion of POLLIN vs POLLHUP */
|
||||
if(!(poll_array[i].revents & (POLLIN|POLLHUP|POLLERR)))
|
||||
if(!connection_is_reading(conn) ||
|
||||
!connection_has_pending_tls_data(conn))
|
||||
return; /* this conn should not read */
|
||||
|
||||
log_fn(LOG_DEBUG,"socket %d wants to read.",conn->s);
|
||||
|
||||
assert_connection_ok(conn, time(NULL));
|
||||
assert_all_pending_dns_resolves_ok();
|
||||
|
||||
if(
|
||||
/* XXX does POLLHUP also mean it's definitely broken? */
|
||||
#ifdef MS_WINDOWS
|
||||
(poll_array[i].revents & POLLERR) ||
|
||||
#endif
|
||||
connection_handle_read(conn) < 0) {
|
||||
if (!conn->marked_for_close) {
|
||||
/* this connection is broken. remove it */
|
||||
/* XXX This shouldn't ever happen anymore. */
|
||||
/* XXX but it'll clearly happen on MS_WINDOWS from POLLERR, right? */
|
||||
log_fn(LOG_ERR,"Unhandled error on read for %s connection (fd %d); removing",
|
||||
CONN_TYPE_TO_STRING(conn->type), conn->s);
|
||||
connection_mark_for_close(conn,0);
|
||||
}
|
||||
}
|
||||
assert_connection_ok(conn, time(NULL));
|
||||
assert_all_pending_dns_resolves_ok();
|
||||
}
|
||||
|
||||
static void conn_write(int i) {
|
||||
connection_t *conn;
|
||||
|
||||
if(!(poll_array[i].revents & POLLOUT))
|
||||
return; /* this conn doesn't want to write */
|
||||
|
||||
conn = connection_array[i];
|
||||
log_fn(LOG_DEBUG,"socket %d wants to write.",conn->s);
|
||||
if (conn->marked_for_close)
|
||||
return;
|
||||
|
||||
assert_connection_ok(conn, time(NULL));
|
||||
assert_all_pending_dns_resolves_ok();
|
||||
|
||||
if (connection_handle_write(conn) < 0) {
|
||||
if (!conn->marked_for_close) {
|
||||
/* this connection is broken. remove it. */
|
||||
log_fn(LOG_WARN,"Unhandled error on read for %s connection (fd %d); removing",
|
||||
CONN_TYPE_TO_STRING(conn->type), conn->s);
|
||||
conn->has_sent_end = 1; /* otherwise we cry wolf about duplicate close */
|
||||
connection_mark_for_close(conn,0);
|
||||
}
|
||||
}
|
||||
assert_connection_ok(conn, time(NULL));
|
||||
assert_all_pending_dns_resolves_ok();
|
||||
}
|
||||
|
||||
static void conn_close_if_marked(int i) {
|
||||
connection_t *conn;
|
||||
int retval;
|
||||
|
||||
conn = connection_array[i];
|
||||
assert_connection_ok(conn, time(NULL));
|
||||
assert_all_pending_dns_resolves_ok();
|
||||
if(!conn->marked_for_close)
|
||||
return; /* nothing to see here, move along */
|
||||
|
||||
log_fn(LOG_INFO,"Cleaning up connection (fd %d).",conn->s);
|
||||
if(conn->s >= 0 && connection_wants_to_flush(conn)) {
|
||||
/* -1 means it's an incomplete edge connection, or that the socket
|
||||
* has already been closed as unflushable. */
|
||||
if(!conn->hold_open_until_flushed)
|
||||
log_fn(LOG_WARN,
|
||||
"Conn (fd %d, type %s, state %d) marked, but wants to flush %d bytes. "
|
||||
"(Marked at %s:%d)",
|
||||
conn->s, CONN_TYPE_TO_STRING(conn->type), conn->state,
|
||||
conn->outbuf_flushlen, 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, &conn->outbuf_flushlen);
|
||||
/* XXX actually, some non-zero results are maybe ok. which ones? */
|
||||
} else
|
||||
retval = -1; /* never flush non-open broken tls connections */
|
||||
} else {
|
||||
retval = flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen);
|
||||
}
|
||||
if(retval >= 0 &&
|
||||
conn->hold_open_until_flushed && connection_wants_to_flush(conn)) {
|
||||
log_fn(LOG_INFO,"Holding conn (fd %d) open for more flushing.",conn->s);
|
||||
/* XXX should we reset timestamp_lastwritten here? */
|
||||
return;
|
||||
}
|
||||
if(connection_wants_to_flush(conn)) {
|
||||
log_fn(LOG_WARN,"Conn (fd %d, type %s, state %d) still wants to flush. Losing %d bytes! (Marked at %s:%d)",
|
||||
conn->s, CONN_TYPE_TO_STRING(conn->type), conn->state,
|
||||
(int)buf_datalen(conn->outbuf), conn->marked_for_close_file,
|
||||
conn->marked_for_close);
|
||||
}
|
||||
}
|
||||
connection_remove(conn);
|
||||
if(conn->type == CONN_TYPE_EXIT) {
|
||||
assert_connection_edge_not_dns_pending(conn);
|
||||
}
|
||||
connection_free(conn);
|
||||
if(i<nfds) { /* we just replaced the one at i with a new one.
|
||||
process it too. */
|
||||
conn_close_if_marked(i);
|
||||
}
|
||||
}
|
||||
|
||||
/* This function is called whenever we successfully pull
|
||||
* down a directory */
|
||||
void directory_has_arrived(void) {
|
||||
|
||||
log_fn(LOG_INFO, "A directory has arrived.");
|
||||
|
||||
/* just for testing */
|
||||
// directory_initiate_command(router_pick_directory_server(),
|
||||
// DIR_PURPOSE_FETCH_RENDDESC, "foo", 3);
|
||||
|
||||
has_fetched_directory=1;
|
||||
|
||||
if(options.ORPort) { /* connect to them all */
|
||||
router_retry_connections();
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform regular maintenance tasks for a single connection. This
|
||||
* function gets run once per second per connection by run_housekeeping.
|
||||
*/
|
||||
static void run_connection_housekeeping(int i, time_t now) {
|
||||
cell_t cell;
|
||||
connection_t *conn = connection_array[i];
|
||||
|
||||
if(conn->type == CONN_TYPE_DIR &&
|
||||
!conn->marked_for_close &&
|
||||
conn->timestamp_lastwritten + 5*60 < now) {
|
||||
log_fn(LOG_WARN,"Expiring wedged directory conn (purpose %d)", conn->purpose);
|
||||
connection_mark_for_close(conn,0);
|
||||
conn->hold_open_until_flushed = 1; /* give it a last chance */
|
||||
return;
|
||||
}
|
||||
|
||||
/* check connections to see whether we should send a keepalive, expire, or wait */
|
||||
if(!connection_speaks_cells(conn))
|
||||
return;
|
||||
|
||||
if(now >= conn->timestamp_lastwritten + options.KeepalivePeriod) {
|
||||
if((!options.ORPort && !circuit_get_by_conn(conn)) ||
|
||||
(!connection_state_is_open(conn))) {
|
||||
/* we're an onion proxy, with no circuits; or our handshake has expired. kill it. */
|
||||
log_fn(LOG_INFO,"Expiring connection to %d (%s:%d).",
|
||||
i,conn->address, conn->port);
|
||||
/* flush anything waiting, e.g. a destroy for a just-expired circ */
|
||||
connection_mark_for_close(conn,CLOSE_REASON_UNUSED_OR_CONN);
|
||||
conn->hold_open_until_flushed = 1;
|
||||
} else {
|
||||
/* either a full router, or we've got a circuit. send a padding cell. */
|
||||
log_fn(LOG_DEBUG,"Sending keepalive to (%s:%d)",
|
||||
conn->address, conn->port);
|
||||
memset(&cell,0,sizeof(cell_t));
|
||||
cell.command = CELL_PADDING;
|
||||
connection_or_write_cell_to_buf(&cell, conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform regular maintenance tasks. This function gets run once per
|
||||
* second by prepare_for_poll.
|
||||
*/
|
||||
static void run_scheduled_events(time_t now) {
|
||||
static long time_to_fetch_directory = 0;
|
||||
static time_t last_uploaded_services = 0;
|
||||
static time_t last_rotated_certificate = 0;
|
||||
int i;
|
||||
|
||||
|
||||
/* 1a. Every MIN_ONION_KEY_LIFETIME seconds, rotate the onion keys,
|
||||
* shut down and restart all cpuworkers, and update the directory if
|
||||
* necessary.
|
||||
*/
|
||||
if (options.ORPort && get_onion_key_set_at()+MIN_ONION_KEY_LIFETIME < now) {
|
||||
log_fn(LOG_INFO,"Rotating onion key.");
|
||||
rotate_onion_key();
|
||||
cpuworkers_rotate();
|
||||
if (router_rebuild_descriptor()<0) {
|
||||
log_fn(LOG_WARN, "Couldn't rebuild router descriptor");
|
||||
}
|
||||
router_upload_dir_desc_to_dirservers();
|
||||
}
|
||||
|
||||
/* 1b. Every MAX_SSL_KEY_LIFETIME seconds, we change our TLS context. */
|
||||
if (!last_rotated_certificate)
|
||||
last_rotated_certificate = now;
|
||||
if (options.ORPort && last_rotated_certificate+MAX_SSL_KEY_LIFETIME < now) {
|
||||
log_fn(LOG_INFO,"Rotating tls context.");
|
||||
if (tor_tls_context_new(get_identity_key(), 1, options.Nickname,
|
||||
MAX_SSL_KEY_LIFETIME) < 0) {
|
||||
log_fn(LOG_WARN, "Error reinitializing TLS context");
|
||||
}
|
||||
last_rotated_certificate = now;
|
||||
/* XXXX We should rotate TLS connections as well; this code doesn't change
|
||||
* XXXX them at all. */
|
||||
}
|
||||
|
||||
/* 1c. Every DirFetchPostPeriod seconds, we get a new directory and upload
|
||||
* our descriptor (if any). */
|
||||
if(time_to_fetch_directory < now) {
|
||||
/* it's time to fetch a new directory and/or post our descriptor */
|
||||
if(options.ORPort) {
|
||||
router_rebuild_descriptor();
|
||||
router_upload_dir_desc_to_dirservers();
|
||||
}
|
||||
if(!options.DirPort) {
|
||||
/* NOTE directory servers do not currently fetch directories.
|
||||
* Hope this doesn't bite us later. */
|
||||
directory_initiate_command(router_pick_directory_server(),
|
||||
DIR_PURPOSE_FETCH_DIR, NULL, 0);
|
||||
} else {
|
||||
/* We're a directory; dump any old descriptors. */
|
||||
dirserv_remove_old_servers();
|
||||
}
|
||||
/* Force an upload of our descriptors every DirFetchPostPeriod seconds. */
|
||||
rend_services_upload(1);
|
||||
last_uploaded_services = now;
|
||||
rend_cache_clean(); /* should this go elsewhere? */
|
||||
time_to_fetch_directory = now + options.DirFetchPostPeriod;
|
||||
}
|
||||
|
||||
|
||||
/* 2. Every second, we examine pending circuits and prune the
|
||||
* ones which have been pending for more than a few seconds.
|
||||
* We do this before step 3, so it can try building more if
|
||||
* it's not comfortable with the number of available circuits.
|
||||
*/
|
||||
circuit_expire_building(now);
|
||||
|
||||
/* 2b. Also look at pending streams and prune the ones that 'began'
|
||||
* a long time ago but haven't gotten a 'connected' yet.
|
||||
* Do this before step 3, so we can put them back into pending
|
||||
* state to be picked up by the new circuit.
|
||||
*/
|
||||
connection_ap_expire_beginning();
|
||||
|
||||
|
||||
/* 2c. And expire connections that we've held open for too long.
|
||||
*/
|
||||
connection_expire_held_open();
|
||||
|
||||
/* 3. Every second, we try a new circuit if there are no valid
|
||||
* circuits. Every NewCircuitPeriod seconds, we expire circuits
|
||||
* that became dirty more than NewCircuitPeriod seconds ago,
|
||||
* and we make a new circ if there are no clean circuits.
|
||||
*/
|
||||
if(has_fetched_directory)
|
||||
circuit_build_needed_circs(now);
|
||||
|
||||
/* 4. We do housekeeping for each connection... */
|
||||
for(i=0;i<nfds;i++) {
|
||||
run_connection_housekeeping(i, now);
|
||||
}
|
||||
|
||||
/* 5. And remove any marked circuits... */
|
||||
circuit_close_all_marked();
|
||||
|
||||
/* 6. And upload service descriptors for any services whose intro points
|
||||
* have changed in the last second. */
|
||||
if (last_uploaded_services < now-5) {
|
||||
rend_services_upload(0);
|
||||
last_uploaded_services = now;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* 6. and blow away any connections that need to die. can't do this later
|
||||
* because we might open up a circuit and not realize we're about to cull
|
||||
* the connection it's running over.
|
||||
* XXX we can remove this step once we audit circuit-building to make sure
|
||||
* it doesn't pick a marked-for-close conn. -RD
|
||||
*/
|
||||
for(i=0;i<nfds;i++)
|
||||
conn_close_if_marked(i);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int prepare_for_poll(void) {
|
||||
static long current_second = 0; /* from previous calls to gettimeofday */
|
||||
connection_t *conn;
|
||||
struct timeval now;
|
||||
int i;
|
||||
|
||||
tor_gettimeofday(&now);
|
||||
|
||||
/* Check how much bandwidth we've consumed,
|
||||
* and increment the token buckets. */
|
||||
stats_n_bytes_read += stats_prev_global_read_bucket-global_read_bucket;
|
||||
connection_bucket_refill(&now);
|
||||
stats_prev_global_read_bucket = global_read_bucket;
|
||||
|
||||
if(now.tv_sec > current_second) { /* the second has rolled over. check more stuff. */
|
||||
|
||||
++stats_n_seconds_reading;
|
||||
assert_all_pending_dns_resolves_ok();
|
||||
run_scheduled_events(now.tv_sec);
|
||||
assert_all_pending_dns_resolves_ok();
|
||||
|
||||
current_second = now.tv_sec; /* remember which second it is, for next time */
|
||||
}
|
||||
|
||||
for(i=0;i<nfds;i++) {
|
||||
conn = connection_array[i];
|
||||
if(connection_has_pending_tls_data(conn) &&
|
||||
connection_is_reading(conn)) {
|
||||
log_fn(LOG_DEBUG,"sock %d has pending bytes.",conn->s);
|
||||
return 0; /* has pending bytes to read; don't let poll wait. */
|
||||
}
|
||||
}
|
||||
|
||||
return (1000 - (now.tv_usec / 1000)); /* how many milliseconds til the next second? */
|
||||
}
|
||||
|
||||
static int init_from_config(int argc, char **argv) {
|
||||
if(getconfig(argc,argv,&options)) {
|
||||
log_fn(LOG_ERR,"Reading config failed. For usage, try -h.");
|
||||
return -1;
|
||||
}
|
||||
close_logs(); /* we'll close, then open with correct loglevel if necessary */
|
||||
|
||||
if(options.User || options.Group) {
|
||||
if(switch_id(options.User, options.Group) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.RunAsDaemon) {
|
||||
start_daemon(options.DataDirectory);
|
||||
}
|
||||
|
||||
if(!options.LogFile && !options.RunAsDaemon)
|
||||
add_stream_log(options.loglevel, "<stdout>", stdout);
|
||||
if(options.LogFile) {
|
||||
if (add_file_log(options.loglevel, options.LogFile) != 0) {
|
||||
/* opening the log file failed! Use stderr and log a warning */
|
||||
add_stream_log(options.loglevel, "<stderr>", stderr);
|
||||
log_fn(LOG_WARN, "Cannot write to LogFile '%s': %s.", options.LogFile, strerror(errno));
|
||||
}
|
||||
log_fn(LOG_NOTICE, "Successfully opened LogFile '%s', redirecting output.",
|
||||
options.LogFile);
|
||||
}
|
||||
if(options.DebugLogFile) {
|
||||
if (add_file_log(LOG_DEBUG, options.DebugLogFile) != 0)
|
||||
log_fn(LOG_WARN, "Cannot write to DebugLogFile '%s': %s.", options.DebugLogFile, strerror(errno));
|
||||
log_fn(LOG_DEBUG, "Successfully opened DebugLogFile '%s'.", options.DebugLogFile);
|
||||
}
|
||||
|
||||
connection_bucket_init();
|
||||
stats_prev_global_read_bucket = global_read_bucket;
|
||||
|
||||
if(options.RunAsDaemon) {
|
||||
/* XXXX Can we delay this any more? */
|
||||
finish_daemon();
|
||||
}
|
||||
|
||||
/* write our pid to the pid file, if we do not have write permissions we will log a warning */
|
||||
if(options.PidFile)
|
||||
write_pidfile(options.PidFile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_hup(void) {
|
||||
char keydir[512];
|
||||
|
||||
log_fn(LOG_NOTICE,"Received sighup. Reloading config.");
|
||||
has_completed_circuit=0;
|
||||
/* first, reload config variables, in case they've changed */
|
||||
/* no need to provide argc/v, they've been cached inside init_from_config */
|
||||
if (init_from_config(0, NULL) < 0) {
|
||||
exit(1);
|
||||
}
|
||||
/* reload keys as needed for rendezvous services. */
|
||||
if (rend_service_load_keys()<0) {
|
||||
log_fn(LOG_ERR,"Error reloading rendezvous service keys");
|
||||
exit(1);
|
||||
}
|
||||
if(retry_all_connections() < 0) {
|
||||
log_fn(LOG_ERR,"Failed to bind one of the listener ports.");
|
||||
return -1;
|
||||
}
|
||||
if(options.DirPort) {
|
||||
/* reload the approved-routers file */
|
||||
sprintf(keydir,"%s/approved-routers", options.DataDirectory);
|
||||
log_fn(LOG_INFO,"Reloading approved fingerprints from %s...",keydir);
|
||||
if(dirserv_parse_fingerprint_file(keydir) < 0) {
|
||||
log_fn(LOG_WARN, "Error reloading fingerprints. Continuing with old list.");
|
||||
}
|
||||
/* Since we aren't fetching a directory, we won't retry rendezvous points
|
||||
* when it gets in. Try again now. */
|
||||
rend_services_introduce();
|
||||
} else {
|
||||
/* fetch a new directory */
|
||||
directory_initiate_command(router_pick_directory_server(),
|
||||
DIR_PURPOSE_FETCH_DIR, NULL, 0);
|
||||
}
|
||||
if(options.ORPort) {
|
||||
router_rebuild_descriptor();
|
||||
sprintf(keydir,"%s/router.desc", options.DataDirectory);
|
||||
log_fn(LOG_INFO,"Dumping descriptor to %s...",keydir);
|
||||
if (write_str_to_file(keydir, router_get_my_descriptor())) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_main_loop(void) {
|
||||
int i;
|
||||
int timeout;
|
||||
int poll_result;
|
||||
|
||||
/* Initialize the history structures. */
|
||||
rep_hist_init();
|
||||
/* Intialize the service cache. */
|
||||
rend_cache_init();
|
||||
|
||||
/* load the private keys, if we're supposed to have them, and set up the
|
||||
* TLS context. */
|
||||
if (init_keys() < 0 || rend_service_load_keys() < 0) {
|
||||
log_fn(LOG_ERR,"Error initializing keys; exiting");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* load the routers file */
|
||||
if(options.RouterFile &&
|
||||
router_set_routerlist_from_file(options.RouterFile) < 0) {
|
||||
log_fn(LOG_ERR,"Error loading router list.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(options.DirPort) { /* the directory is already here, run startup things */
|
||||
has_fetched_directory = 1;
|
||||
directory_has_arrived();
|
||||
}
|
||||
|
||||
if(options.ORPort) {
|
||||
cpu_init(); /* launch cpuworkers. Need to do this *after* we've read the onion key. */
|
||||
}
|
||||
|
||||
/* start up the necessary connections based on which ports are
|
||||
* non-zero. This is where we try to connect to all the other ORs,
|
||||
* and start the listeners.
|
||||
*/
|
||||
if(retry_all_connections() < 0) {
|
||||
log_fn(LOG_ERR,"Failed to bind one of the listener ports.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
#ifndef MS_WINDOWS /* do signal stuff only on unix */
|
||||
if(please_dumpstats) {
|
||||
/* prefer to log it at INFO, but make sure we always see it */
|
||||
dumpstats(options.loglevel>LOG_INFO ? options.loglevel : LOG_INFO);
|
||||
please_dumpstats = 0;
|
||||
}
|
||||
if(please_reset) {
|
||||
do_hup();
|
||||
please_reset = 0;
|
||||
}
|
||||
if(please_reap_children) {
|
||||
while(waitpid(-1,NULL,WNOHANG)) ; /* keep reaping until no more zombies */
|
||||
please_reap_children = 0;
|
||||
}
|
||||
#endif /* signal stuff */
|
||||
|
||||
timeout = prepare_for_poll();
|
||||
|
||||
/* poll until we have an event, or the second ends */
|
||||
poll_result = tor_poll(poll_array, nfds, timeout);
|
||||
|
||||
/* let catch() handle things like ^c, and otherwise don't worry about it */
|
||||
if(poll_result < 0) {
|
||||
/* let the program survive things like ^z */
|
||||
if(tor_socket_errno(-1) != EINTR) {
|
||||
log_fn(LOG_ERR,"poll failed: %s [%d]",
|
||||
strerror(tor_socket_errno(-1)), tor_socket_errno(-1));
|
||||
return -1;
|
||||
} else {
|
||||
log_fn(LOG_DEBUG,"poll interrupted.");
|
||||
}
|
||||
}
|
||||
|
||||
/* do all the reads and errors first, so we can detect closed sockets */
|
||||
for(i=0;i<nfds;i++)
|
||||
conn_read(i); /* this also marks broken connections */
|
||||
|
||||
/* then do the writes */
|
||||
for(i=0;i<nfds;i++)
|
||||
conn_write(i);
|
||||
|
||||
/* any of the conns need to be closed now? */
|
||||
for(i=0;i<nfds;i++)
|
||||
conn_close_if_marked(i);
|
||||
|
||||
/* refilling buckets and sending cells happens at the beginning of the
|
||||
* next iteration of the loop, inside prepare_for_poll()
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
static void catch(int the_signal) {
|
||||
|
||||
#ifndef MS_WINDOWS /* do signal stuff only on unix */
|
||||
switch(the_signal) {
|
||||
// case SIGABRT:
|
||||
case SIGTERM:
|
||||
case SIGINT:
|
||||
log(LOG_ERR,"Catching signal %d, exiting cleanly.", the_signal);
|
||||
/* we don't care if there was an error when we unlink, nothing
|
||||
we could do about it anyways */
|
||||
if(options.PidFile)
|
||||
unlink(options.PidFile);
|
||||
exit(0);
|
||||
case SIGPIPE:
|
||||
log(LOG_WARN,"Bug: caught sigpipe. Ignoring.");
|
||||
break;
|
||||
case SIGHUP:
|
||||
please_reset = 1;
|
||||
break;
|
||||
case SIGUSR1:
|
||||
please_dumpstats = 1;
|
||||
break;
|
||||
case SIGCHLD:
|
||||
please_reap_children = 1;
|
||||
break;
|
||||
default:
|
||||
log(LOG_WARN,"Caught signal %d that we can't handle??", the_signal);
|
||||
}
|
||||
#endif /* signal stuff */
|
||||
}
|
||||
|
||||
static void dumpstats(int severity) {
|
||||
int i;
|
||||
connection_t *conn;
|
||||
time_t now = time(NULL);
|
||||
|
||||
log(severity, "Dumping stats:");
|
||||
|
||||
for(i=0;i<nfds;i++) {
|
||||
conn = connection_array[i];
|
||||
log(severity, "Conn %d (socket %d) type %d (%s), state %d (%s), created %d secs ago",
|
||||
i, conn->s, conn->type, CONN_TYPE_TO_STRING(conn->type),
|
||||
conn->state, conn_state_to_string[conn->type][conn->state], (int)(now - conn->timestamp_created));
|
||||
if(!connection_is_listener(conn)) {
|
||||
log(severity,"Conn %d is to '%s:%d'.",i,conn->address, conn->port);
|
||||
log(severity,"Conn %d: %d bytes waiting on inbuf (last read %d secs ago)",i,
|
||||
(int)buf_datalen(conn->inbuf),
|
||||
(int)(now - conn->timestamp_lastread));
|
||||
log(severity,"Conn %d: %d bytes waiting on outbuf (last written %d secs ago)",i,
|
||||
(int)buf_datalen(conn->outbuf), (int)(now - conn->timestamp_lastwritten));
|
||||
}
|
||||
circuit_dump_by_conn(conn, severity); /* dump info about all the circuits using this conn */
|
||||
}
|
||||
log(severity,
|
||||
"Cells processed: %10lu padding\n"
|
||||
" %10lu create\n"
|
||||
" %10lu created\n"
|
||||
" %10lu relay\n"
|
||||
" (%10lu relayed)\n"
|
||||
" (%10lu delivered)\n"
|
||||
" %10lu destroy",
|
||||
stats_n_padding_cells_processed,
|
||||
stats_n_create_cells_processed,
|
||||
stats_n_created_cells_processed,
|
||||
stats_n_relay_cells_processed,
|
||||
stats_n_relay_cells_relayed,
|
||||
stats_n_relay_cells_delivered,
|
||||
stats_n_destroy_cells_processed);
|
||||
if (stats_n_data_cells_packaged)
|
||||
log(severity,"Average packaged cell fullness: %2.3f%%",
|
||||
100*(((double)stats_n_data_bytes_packaged) /
|
||||
(stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)) );
|
||||
if (stats_n_data_cells_received)
|
||||
log(severity,"Average delivered cell fullness: %2.3f%%",
|
||||
100*(((double)stats_n_data_bytes_received) /
|
||||
(stats_n_data_cells_received*RELAY_PAYLOAD_SIZE)) );
|
||||
|
||||
if (stats_n_seconds_reading)
|
||||
log(severity,"Average bandwidth used: %d bytes/sec",
|
||||
(int) (stats_n_bytes_read/stats_n_seconds_reading));
|
||||
|
||||
rep_hist_dump_stats(now,severity);
|
||||
rend_service_dump_stats(severity);
|
||||
}
|
||||
|
||||
int network_init(void)
|
||||
{
|
||||
#ifdef MS_WINDOWS
|
||||
/* This silly exercise is necessary before windows will allow gethostbyname to work.
|
||||
*/
|
||||
WSADATA WSAData;
|
||||
int r;
|
||||
r = WSAStartup(0x101,&WSAData);
|
||||
if (r) {
|
||||
log_fn(LOG_WARN,"Error initializing windows network layer: code was %d",r);
|
||||
return -1;
|
||||
}
|
||||
/* XXXX We should call WSACleanup on exit, I think. */
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void exit_function(void)
|
||||
{
|
||||
#ifdef MS_WINDOWS
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
int tor_main(int argc, char *argv[]) {
|
||||
|
||||
/* give it somewhere to log to initially */
|
||||
add_stream_log(LOG_INFO, "<stdout>", stdout);
|
||||
log_fn(LOG_NOTICE,"Tor v%s. This is experimental software. Do not use it if you need anonymity.",VERSION);
|
||||
|
||||
if (network_init()<0) {
|
||||
log_fn(LOG_ERR,"Error initializing network; exiting.");
|
||||
return 1;
|
||||
}
|
||||
atexit(exit_function);
|
||||
|
||||
if (init_from_config(argc,argv) < 0)
|
||||
return -1;
|
||||
|
||||
#ifndef MS_WINDOWS
|
||||
if(geteuid()==0)
|
||||
log_fn(LOG_WARN,"You are running Tor as root. You don't need to, and you probably shouldn't.");
|
||||
#endif
|
||||
|
||||
if(options.ORPort) { /* only spawn dns handlers if we're a router */
|
||||
dns_init(); /* initialize the dns resolve tree, and spawn workers */
|
||||
}
|
||||
if(options.SocksPort) {
|
||||
client_dns_init(); /* init the client dns cache */
|
||||
}
|
||||
|
||||
#ifndef MS_WINDOWS /* do signal stuff only on unix */
|
||||
{
|
||||
struct sigaction action;
|
||||
action.sa_flags = 0;
|
||||
sigemptyset(&action.sa_mask);
|
||||
|
||||
action.sa_handler = catch;
|
||||
sigaction(SIGINT, &action, NULL);
|
||||
sigaction(SIGTERM, &action, NULL);
|
||||
sigaction(SIGPIPE, &action, NULL);
|
||||
sigaction(SIGUSR1, &action, NULL);
|
||||
sigaction(SIGHUP, &action, NULL); /* to reload config, retry conns, etc */
|
||||
sigaction(SIGCHLD, &action, NULL); /* handle dns/cpu workers that exit */
|
||||
}
|
||||
#endif /* signal stuff */
|
||||
|
||||
crypto_global_init();
|
||||
crypto_seed_rng();
|
||||
do_main_loop();
|
||||
crypto_global_cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
indent-tabs-mode:nil
|
||||
c-basic-offset:2
|
||||
End:
|
||||
*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user