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 'src'.
svn:r6
This commit is contained in:
+124
@@ -0,0 +1,124 @@
|
||||
|
||||
Obvious things I'd like to do that won't break anything:
|
||||
|
||||
* Abstract out crypto calls, with the eventual goal of moving
|
||||
from openssl to something with a more flexible license.
|
||||
|
||||
* Test suite. We need one.
|
||||
|
||||
* Switch the "return -1" cases that really mean "you've got a bug"
|
||||
into calls to assert().
|
||||
|
||||
* Since my OR can handle multiple circuits through a given OP,
|
||||
I think it's clear that the OP should pass new create cells through the
|
||||
same channel. Thus we can take advantage of the padding we're already
|
||||
getting. Does that mean the choose_onion functions should be changed
|
||||
to always pick a favorite OR first, so the OP can minimize the number
|
||||
of outgoing connections it must sustain?
|
||||
|
||||
* Rewrite the OP to be non-blocking single-process.
|
||||
|
||||
* Add autoconf support.
|
||||
Figure out what .h files we're actually using, and how portable
|
||||
those are.
|
||||
|
||||
* Since we're using a stream cipher, an adversary's cell arriving with the
|
||||
same aci will forever trash our circuit. Since each side picks half
|
||||
the aci, for each cell the adversary has a 1/256 chance of trashing a
|
||||
circuit. This is really nasty. We want to make ACIs something reasonably
|
||||
hard to collide with, such as 20 bytes.
|
||||
|
||||
While we're at it, I'd like more than 4 bits for Version. :)
|
||||
|
||||
* Exit policies. Since we don't really know what protocol is being spoken,
|
||||
it really comes down to an IP range and port range that we
|
||||
allow/disallow. The 'application' connection can evaluate it and make
|
||||
a decision.
|
||||
|
||||
* We currently block on gethostbyname in OR. This is poor. The complex
|
||||
solution is to have a separate process that we talk to. There are some
|
||||
free software versions we can use, but they'll still be tricky. The
|
||||
better answer is to realize that the OP can do the resolution and
|
||||
simply hand the OR an IP directly.
|
||||
A) This prevents us from doing sneaky things like having the name resolve
|
||||
differently at the OR than at the OP. I'm ok with that.
|
||||
B) It actually just shunts the "dns lookups block" problem back onto the
|
||||
OP. But that's ok too, because the OP doesn't have to be as robust.
|
||||
(Heck, can we have the application proxy resolve it, even?)
|
||||
|
||||
* I'd like a cleaner interface for the configuration files, keys, etc.
|
||||
Perhaps the next step is a central repository where we download router
|
||||
lists? Something that takes the human more out of the loop.
|
||||
|
||||
We should look into a 'topology communication protocol'; there's one
|
||||
mentioned in the spec that Paul has, but I haven't looked at it to
|
||||
know how complete it is or how well it would work. This would also
|
||||
allow us to add new ORs on the fly. Directory servers, a la the ones
|
||||
we're developing for Mixminion (see http://mixminion.net/), are also
|
||||
a very nice approach to consider.
|
||||
|
||||
* Should ORs rotate their link keys periodically?
|
||||
|
||||
* We probably want OAEP padding for RSA.
|
||||
|
||||
* The parts of the code that say 'FIXME'
|
||||
|
||||
Non-obvious things I'd like to do:
|
||||
|
||||
(Many of these topics are inter-related. It's clear that we need more
|
||||
analysis before we can guess which approaches are good.)
|
||||
|
||||
* Padding between ORs, and correct padding between OPs. Currently
|
||||
the OP seems to send padding at a steady rate, but data cells can
|
||||
come more quickly than that. This doesn't provide much protection
|
||||
at all. I'd like to investigate a synchronous mixing approach, where
|
||||
cells are sent at fixed intervals. We need to investigate the effects
|
||||
of this on DoS resistance -- what do we do when we have too many
|
||||
packets? One approach is to do traffic shaping rather than traffic
|
||||
padding -- we gain a bit more resistance to DoS at the expense of some
|
||||
anonymity. Can we compare this analysis to that of the Cottrell Mix,
|
||||
and learn something new? We'll need to decide on exactly how the
|
||||
traffic shaping algorithm works.
|
||||
|
||||
* Make the connection buf's grow dynamically as needed. This won't
|
||||
really solve the fundamental problem above, though, that a buffer
|
||||
can be given an adversary-controlled number of cells.
|
||||
|
||||
* I'd like to add a scheduler of some sort. Currently we only need one
|
||||
for sending out padding cells, and if these events are periodic and
|
||||
synchronized, we don't yet need a scheduler per se, but rather we just
|
||||
need to have poll return every so often and avoid sending cells onto
|
||||
the sockets except at the appointed time. We're nearly ready to do
|
||||
that as it is, with the separation of write_to_buf() and flush_buf().
|
||||
|
||||
Edge case: what do we do with circuits that receive a destroy
|
||||
cell before all data has been sent out? Currently there's only one
|
||||
(outgoing) buffer per connection, so since it's crypted, a circuit
|
||||
can't recognize its own packet once it's been queued. We could mark
|
||||
the circuits for destruction, and go through and cull them once the
|
||||
buffer is entirely flushed; but with the synchronous approach above,
|
||||
the buffer may never become empty. Perhaps I should implement a callback
|
||||
system, so a function can get called when a particular cell gets sent
|
||||
out. That sounds very flexible, but might also be overkill.
|
||||
|
||||
* Currently when a connection goes down, it generates a destroy cell
|
||||
(either in both directions or just the appropriate one). When a
|
||||
destroy cell arrives to an OR (and it gets read after all previous
|
||||
cells have arrived), it delivers a destroy cell for the "other side"
|
||||
of the circuit: if the other side is an OP or APP, it closes the entire
|
||||
connection as well.
|
||||
|
||||
But by "a connection going down", I mean "I read eof from it". Yet
|
||||
reading an eof simply means that it promises not to send any more
|
||||
data. It may still be perfectly fine receiving data (read "man 2
|
||||
shutdown"). In fact, some webservers work that way -- the client sends
|
||||
his entire request, and when the webserver reads an eof it begins
|
||||
its response. We currently don't support that sort of protocol; we
|
||||
may want to switch to some sort of a two-way-destry-ripple technique
|
||||
(where a destroy makes its way all the way to the end of the circuit
|
||||
before being echoed back, and data stops flowing only when a destroy
|
||||
has been received from both sides of the circuit); this extends the
|
||||
one-hop-ack approach that Matej used.
|
||||
|
||||
* Reply onions. Hrm.
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
SRC=log.c config.c utils.c key.c onion.c cell.c routent.c scheduler.c
|
||||
OBJ=${SRC:.c=.o}
|
||||
INCLUDE=-I/usr/local/ssl/include
|
||||
|
||||
CFLAGS=${INCLUDE} -Wall -Wpointer-arith -O2
|
||||
|
||||
all: ${OBJ}
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ)
|
||||
|
||||
depend:
|
||||
makedepend -- $(CFLAGS) -- $(SRC)
|
||||
|
||||
# DO NOT DELETE
|
||||
|
||||
|
||||
cell.o: cell.h log.h /usr/include/alloca.h /usr/include/asm/socket.h
|
||||
cell.o: /usr/include/asm/sockios.h /usr/include/bits/byteswap.h
|
||||
cell.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
|
||||
cell.o: /usr/include/bits/environments.h /usr/include/bits/in.h
|
||||
cell.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
|
||||
cell.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
|
||||
cell.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
|
||||
cell.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
|
||||
cell.o: /usr/include/bits/sockaddr.h /usr/include/bits/socket.h
|
||||
cell.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
|
||||
cell.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
|
||||
cell.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
|
||||
cell.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
|
||||
cell.o: /usr/include/endian.h /usr/include/features.h /usr/include/getopt.h
|
||||
cell.o: /usr/include/gnu/stubs.h /usr/include/limits.h
|
||||
cell.o: /usr/include/linux/limits.h /usr/include/netinet/in.h
|
||||
cell.o: /usr/include/openssl/rand.h /usr/include/stdint.h
|
||||
cell.o: /usr/include/stdlib.h /usr/include/string.h /usr/include/sys/cdefs.h
|
||||
cell.o: /usr/include/syslog.h /usr/include/sys/select.h
|
||||
cell.o: /usr/include/sys/syslog.h /usr/include/sys/sysmacros.h
|
||||
cell.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/unistd.h
|
||||
cell.o: /usr/include/xlocale.h
|
||||
cell.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
|
||||
cell.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
cell.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
cell.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
|
||||
config.o: config.h log.h /usr/include/alloca.h /usr/include/asm/errno.h
|
||||
config.o: /usr/include/bits/endian.h /usr/include/bits/errno.h
|
||||
config.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
|
||||
config.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
|
||||
config.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
|
||||
config.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
|
||||
config.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
|
||||
config.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
|
||||
config.o: /usr/include/features.h /usr/include/_G_config.h
|
||||
config.o: /usr/include/gconv.h /usr/include/gnu/stubs.h /usr/include/libio.h
|
||||
config.o: /usr/include/linux/errno.h /usr/include/stdio.h
|
||||
config.o: /usr/include/stdlib.h /usr/include/string.h /usr/include/sys/cdefs.h
|
||||
config.o: /usr/include/syslog.h /usr/include/sys/select.h
|
||||
config.o: /usr/include/sys/syslog.h /usr/include/sys/sysmacros.h
|
||||
config.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/wchar.h
|
||||
config.o: /usr/include/xlocale.h
|
||||
config.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
config.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
key.o: config.h key.h log.h /usr/include/alloca.h /usr/include/asm/errno.h
|
||||
key.o: /usr/include/bits/endian.h /usr/include/bits/errno.h
|
||||
key.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
|
||||
key.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
|
||||
key.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
|
||||
key.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
|
||||
key.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
|
||||
key.o: /usr/include/endian.h /usr/include/errno.h /usr/include/features.h
|
||||
key.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/gnu/stubs.h
|
||||
key.o: /usr/include/libio.h /usr/include/linux/errno.h
|
||||
key.o: /usr/include/openssl/asn1.h /usr/include/openssl/bio.h
|
||||
key.o: /usr/include/openssl/blowfish.h /usr/include/openssl/bn.h
|
||||
key.o: /usr/include/openssl/buffer.h /usr/include/openssl/cast.h
|
||||
key.o: /usr/include/openssl/crypto.h /usr/include/openssl/des.h
|
||||
key.o: /usr/include/openssl/dh.h /usr/include/openssl/dsa.h
|
||||
key.o: /usr/include/openssl/e_os2.h /usr/include/openssl/err.h
|
||||
key.o: /usr/include/openssl/evp.h /usr/include/openssl/lhash.h
|
||||
key.o: /usr/include/openssl/md2.h /usr/include/openssl/md4.h
|
||||
key.o: /usr/include/openssl/md5.h /usr/include/openssl/objects.h
|
||||
key.o: /usr/include/openssl/obj_mac.h /usr/include/openssl/opensslconf.h
|
||||
key.o: /usr/include/openssl/opensslv.h /usr/include/openssl/pem2.h
|
||||
key.o: /usr/include/openssl/pem.h /usr/include/openssl/pkcs7.h
|
||||
key.o: /usr/include/openssl/rc2.h /usr/include/openssl/rc4.h
|
||||
key.o: /usr/include/openssl/ripemd.h /usr/include/openssl/rsa.h
|
||||
key.o: /usr/include/openssl/safestack.h /usr/include/openssl/sha.h
|
||||
key.o: /usr/include/openssl/stack.h /usr/include/openssl/symhacks.h
|
||||
key.o: /usr/include/openssl/x509.h /usr/include/openssl/x509_vfy.h
|
||||
key.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
|
||||
key.o: /usr/include/sys/cdefs.h /usr/include/syslog.h
|
||||
key.o: /usr/include/sys/select.h /usr/include/sys/syslog.h
|
||||
key.o: /usr/include/sys/sysmacros.h /usr/include/sys/types.h
|
||||
key.o: /usr/include/time.h /usr/include/wchar.h /usr/include/xlocale.h
|
||||
key.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
key.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
log.o: log.h /usr/include/asm/errno.h /usr/include/bits/errno.h
|
||||
log.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
|
||||
log.o: /usr/include/bits/stdio_lim.h /usr/include/bits/types.h
|
||||
log.o: /usr/include/bits/wchar.h /usr/include/errno.h /usr/include/features.h
|
||||
log.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/gnu/stubs.h
|
||||
log.o: /usr/include/libio.h /usr/include/linux/errno.h /usr/include/stdio.h
|
||||
log.o: /usr/include/string.h /usr/include/sys/cdefs.h /usr/include/syslog.h
|
||||
log.o: /usr/include/sys/syslog.h /usr/include/wchar.h /usr/include/xlocale.h
|
||||
log.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
log.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
onion.o: cell.h log.h onion.h routent.h /usr/include/alloca.h
|
||||
onion.o: /usr/include/arpa/inet.h /usr/include/asm/errno.h
|
||||
onion.o: /usr/include/asm/socket.h /usr/include/asm/sockios.h
|
||||
onion.o: /usr/include/bits/byteswap.h /usr/include/bits/confname.h
|
||||
onion.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
|
||||
onion.o: /usr/include/bits/errno.h /usr/include/bits/in.h
|
||||
onion.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
|
||||
onion.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
|
||||
onion.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
|
||||
onion.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
|
||||
onion.o: /usr/include/bits/sockaddr.h /usr/include/bits/socket.h
|
||||
onion.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
|
||||
onion.o: /usr/include/bits/types.h /usr/include/bits/uio.h
|
||||
onion.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
|
||||
onion.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
|
||||
onion.o: /usr/include/bits/xopen_lim.h /usr/include/endian.h
|
||||
onion.o: /usr/include/errno.h /usr/include/features.h /usr/include/_G_config.h
|
||||
onion.o: /usr/include/gconv.h /usr/include/getopt.h /usr/include/gnu/stubs.h
|
||||
onion.o: /usr/include/libio.h /usr/include/limits.h /usr/include/linux/errno.h
|
||||
onion.o: /usr/include/linux/limits.h /usr/include/netinet/in.h
|
||||
onion.o: /usr/include/openssl/asn1.h /usr/include/openssl/bio.h
|
||||
onion.o: /usr/include/openssl/blowfish.h /usr/include/openssl/bn.h
|
||||
onion.o: /usr/include/openssl/cast.h /usr/include/openssl/crypto.h
|
||||
onion.o: /usr/include/openssl/des.h /usr/include/openssl/dh.h
|
||||
onion.o: /usr/include/openssl/dsa.h /usr/include/openssl/e_os2.h
|
||||
onion.o: /usr/include/openssl/err.h /usr/include/openssl/evp.h
|
||||
onion.o: /usr/include/openssl/lhash.h /usr/include/openssl/md2.h
|
||||
onion.o: /usr/include/openssl/md4.h /usr/include/openssl/md5.h
|
||||
onion.o: /usr/include/openssl/objects.h /usr/include/openssl/obj_mac.h
|
||||
onion.o: /usr/include/openssl/opensslconf.h /usr/include/openssl/opensslv.h
|
||||
onion.o: /usr/include/openssl/rand.h /usr/include/openssl/rc2.h
|
||||
onion.o: /usr/include/openssl/rc4.h /usr/include/openssl/ripemd.h
|
||||
onion.o: /usr/include/openssl/rsa.h /usr/include/openssl/safestack.h
|
||||
onion.o: /usr/include/openssl/sha.h /usr/include/openssl/stack.h
|
||||
onion.o: /usr/include/openssl/symhacks.h /usr/include/stdint.h
|
||||
onion.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
|
||||
onion.o: /usr/include/sys/cdefs.h /usr/include/syslog.h
|
||||
onion.o: /usr/include/sys/select.h /usr/include/sys/socket.h
|
||||
onion.o: /usr/include/sys/syslog.h /usr/include/sys/sysmacros.h
|
||||
onion.o: /usr/include/sys/timeb.h /usr/include/sys/time.h
|
||||
onion.o: /usr/include/sys/types.h /usr/include/sys/uio.h /usr/include/time.h
|
||||
onion.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
|
||||
onion.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
|
||||
onion.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
onion.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
onion.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h version.h
|
||||
routent.o: cell.h routent.h /usr/include/alloca.h /usr/include/bits/confname.h
|
||||
routent.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
|
||||
routent.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
|
||||
routent.o: /usr/include/bits/sched.h /usr/include/bits/select.h
|
||||
routent.o: /usr/include/bits/sigset.h /usr/include/bits/stdio_lim.h
|
||||
routent.o: /usr/include/bits/time.h /usr/include/bits/types.h
|
||||
routent.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
|
||||
routent.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
|
||||
routent.o: /usr/include/endian.h /usr/include/features.h
|
||||
routent.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
|
||||
routent.o: /usr/include/gnu/stubs.h /usr/include/libio.h
|
||||
routent.o: /usr/include/openssl/asn1.h /usr/include/openssl/bio.h
|
||||
routent.o: /usr/include/openssl/blowfish.h /usr/include/openssl/bn.h
|
||||
routent.o: /usr/include/openssl/cast.h /usr/include/openssl/crypto.h
|
||||
routent.o: /usr/include/openssl/des.h /usr/include/openssl/dh.h
|
||||
routent.o: /usr/include/openssl/dsa.h /usr/include/openssl/e_os2.h
|
||||
routent.o: /usr/include/openssl/evp.h /usr/include/openssl/md2.h
|
||||
routent.o: /usr/include/openssl/md4.h /usr/include/openssl/md5.h
|
||||
routent.o: /usr/include/openssl/objects.h /usr/include/openssl/obj_mac.h
|
||||
routent.o: /usr/include/openssl/opensslconf.h /usr/include/openssl/opensslv.h
|
||||
routent.o: /usr/include/openssl/rc2.h /usr/include/openssl/rc4.h
|
||||
routent.o: /usr/include/openssl/ripemd.h /usr/include/openssl/rsa.h
|
||||
routent.o: /usr/include/openssl/safestack.h /usr/include/openssl/sha.h
|
||||
routent.o: /usr/include/openssl/stack.h /usr/include/openssl/symhacks.h
|
||||
routent.o: /usr/include/stdint.h /usr/include/stdio.h /usr/include/stdlib.h
|
||||
routent.o: /usr/include/sys/cdefs.h /usr/include/sys/select.h
|
||||
routent.o: /usr/include/sys/sysmacros.h /usr/include/sys/timeb.h
|
||||
routent.o: /usr/include/sys/time.h /usr/include/sys/types.h
|
||||
routent.o: /usr/include/time.h /usr/include/unistd.h /usr/include/wchar.h
|
||||
routent.o: /usr/include/xlocale.h
|
||||
routent.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
routent.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
scheduler.o: log.h scheduler.h /usr/include/bits/confname.h
|
||||
scheduler.o: /usr/include/bits/environments.h /usr/include/bits/posix_opt.h
|
||||
scheduler.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
|
||||
scheduler.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
|
||||
scheduler.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
|
||||
scheduler.o: /usr/include/bits/types.h /usr/include/bits/wchar.h
|
||||
scheduler.o: /usr/include/bits/wordsize.h /usr/include/features.h
|
||||
scheduler.o: /usr/include/_G_config.h /usr/include/gconv.h
|
||||
scheduler.o: /usr/include/getopt.h /usr/include/gnu/stubs.h
|
||||
scheduler.o: /usr/include/libio.h /usr/include/malloc.h /usr/include/stdio.h
|
||||
scheduler.o: /usr/include/sys/cdefs.h /usr/include/syslog.h
|
||||
scheduler.o: /usr/include/sys/select.h /usr/include/sys/syslog.h
|
||||
scheduler.o: /usr/include/sys/time.h /usr/include/time.h /usr/include/unistd.h
|
||||
scheduler.o: /usr/include/wchar.h
|
||||
scheduler.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
scheduler.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
utils.o: log.h /usr/include/alloca.h /usr/include/asm/errno.h
|
||||
utils.o: /usr/include/asm/socket.h /usr/include/asm/sockios.h
|
||||
utils.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
|
||||
utils.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
|
||||
utils.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
|
||||
utils.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
|
||||
utils.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
|
||||
utils.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
|
||||
utils.o: /usr/include/bits/sockaddr.h /usr/include/bits/socket.h
|
||||
utils.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
|
||||
utils.o: /usr/include/bits/types.h /usr/include/bits/uio.h
|
||||
utils.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
|
||||
utils.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
|
||||
utils.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
|
||||
utils.o: /usr/include/endian.h /usr/include/errno.h /usr/include/features.h
|
||||
utils.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
|
||||
utils.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
|
||||
utils.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
|
||||
utils.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
|
||||
utils.o: /usr/include/sys/cdefs.h /usr/include/syslog.h
|
||||
utils.o: /usr/include/sys/select.h /usr/include/sys/socket.h
|
||||
utils.o: /usr/include/sys/syslog.h /usr/include/sys/sysmacros.h
|
||||
utils.o: /usr/include/sys/time.h /usr/include/sys/types.h
|
||||
utils.o: /usr/include/sys/uio.h /usr/include/sys/un.h /usr/include/time.h
|
||||
utils.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
|
||||
utils.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
|
||||
utils.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
utils.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
utils.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h utils.h
|
||||
@@ -0,0 +1,355 @@
|
||||
/**
|
||||
* cell.c
|
||||
* Cell manipulation.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.16 2002/06/14 20:41:19 mp292
|
||||
* Parameter checking error - thanks Roger.
|
||||
*
|
||||
* Revision 1.15 2002/04/02 14:27:11 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.14 2002/04/02 10:19:37 badbytes
|
||||
* Stricter parameter checking.
|
||||
*
|
||||
* Revision 1.13 2002/03/12 23:30:19 mp292
|
||||
* Removed some memory overruns.
|
||||
*
|
||||
* Revision 1.12 2002/03/03 00:06:45 mp292
|
||||
* Modifications to support re-transmission.
|
||||
*
|
||||
* Revision 1.11 2002/02/03 22:41:45 mp292
|
||||
* Changes to cell size.
|
||||
*
|
||||
* Revision 1.10 2002/01/21 20:57:19 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.9 2002/01/17 15:00:43 mp292
|
||||
* Fixed a bug which caused malloc() generate a seg fault.
|
||||
*
|
||||
* Revision 1.8 2002/01/16 23:01:54 mp292
|
||||
* First phase of system testing completed (main functionality).
|
||||
*
|
||||
* Revision 1.7 2002/01/14 13:05:37 badbytes
|
||||
* System testing in progress.
|
||||
*
|
||||
* Revision 1.6 2002/01/10 13:15:54 badbytes
|
||||
* Fixed ACI size from 32bits to 16bits.
|
||||
*
|
||||
* Revision 1.5 2002/01/07 13:06:06 badbytes
|
||||
* cell.ACI is now cell.aci
|
||||
*
|
||||
* Revision 1.4 2002/01/07 09:26:00 badbytes
|
||||
* Added pack_create() and pack_data().
|
||||
*
|
||||
* Revision 1.3 2002/01/07 07:48:34 badbytes
|
||||
* fixed new_create_cell()
|
||||
*
|
||||
* Revision 1.2 2002/01/04 12:11:54 badbytes
|
||||
* Syntax errors fixed.
|
||||
*
|
||||
* Revision 1.1 2002/01/04 12:08:34 badbytes
|
||||
* Added functions for cell creation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "cell.h"
|
||||
#include "log.h"
|
||||
|
||||
cell_t *new_padding_cell()
|
||||
{
|
||||
cell_t *c = NULL;
|
||||
int retval;
|
||||
|
||||
c = malloc(sizeof(cell_t));
|
||||
if (!c) /* malloc() error */
|
||||
return NULL;
|
||||
|
||||
retval = RAND_pseudo_bytes((unsigned char *)c,sizeof(cell_t));
|
||||
if (retval == -1) /* RAND_pseudo_bytes() error */
|
||||
{
|
||||
free((void *)c);
|
||||
return NULL;
|
||||
} /* RAND_pseudo_bytes() error */
|
||||
|
||||
c->command = CELL_PADDING;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
cell_t *new_destroy_cell(uint16_t aci)
|
||||
{
|
||||
cell_t *c = NULL;
|
||||
int retval;
|
||||
|
||||
if (aci) /* valid ACI */
|
||||
{
|
||||
c = (cell_t *)malloc(sizeof(cell_t));
|
||||
if (!c) /* malloc error */
|
||||
return NULL;
|
||||
|
||||
retval = RAND_pseudo_bytes((unsigned char *)c+3,sizeof(cell_t)-3);
|
||||
if (retval == -1) /* RAND_pseudo_bytes() error */
|
||||
{
|
||||
free((void *)c);
|
||||
return NULL;
|
||||
} /* RAND_pseudo_bytes() error */
|
||||
|
||||
c->aci = aci;
|
||||
c->command = CELL_DESTROY;
|
||||
|
||||
return c;
|
||||
} /* valid ACI */
|
||||
else /* invalid ACI */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cell_t *new_ack_cell(uint16_t aci)
|
||||
{
|
||||
cell_t *c = NULL;
|
||||
int retval;
|
||||
|
||||
if (aci) /* valid ACI */
|
||||
{
|
||||
c = (cell_t *)malloc(sizeof(cell_t));
|
||||
if (!c) /* malloc error */
|
||||
return NULL;
|
||||
|
||||
retval = RAND_pseudo_bytes((unsigned char *)c+3,sizeof(cell_t)-3);
|
||||
if (retval == -1) /* RAND_pseudo_bytes() error */
|
||||
{
|
||||
free((void *)c);
|
||||
return NULL;
|
||||
} /* RAND_pseudo_bytes() error */
|
||||
|
||||
c->aci = aci;
|
||||
c->command = CELL_ACK;
|
||||
|
||||
return c;
|
||||
} /* valid ACI */
|
||||
else /* invalid ACI */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cell_t *new_nack_cell(uint16_t aci)
|
||||
{
|
||||
cell_t *c = NULL;
|
||||
int retval;
|
||||
|
||||
if (aci) /* valid ACI */
|
||||
{
|
||||
c = (cell_t *)malloc(sizeof(cell_t));
|
||||
if (!c) /* malloc error */
|
||||
return NULL;
|
||||
|
||||
retval = RAND_pseudo_bytes((unsigned char *)c+3,sizeof(cell_t)-3);
|
||||
if (retval == -1) /* RAND_pseudo_bytes() error */
|
||||
{
|
||||
free((void *)c);
|
||||
return NULL;
|
||||
} /* RAND_pseudo_bytes() error */
|
||||
|
||||
c->aci = aci;
|
||||
c->command = CELL_NACK;
|
||||
|
||||
return c;
|
||||
} /* valid ACI */
|
||||
else /* invalid ACI */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cell_t *new_create_cell(uint16_t aci, unsigned char length, unsigned char *buf)
|
||||
{
|
||||
cell_t *c = NULL;
|
||||
int retval;
|
||||
|
||||
if ((aci) && (buf) && (length <= CELL_PAYLOAD_SIZE)) /* valid parameters */
|
||||
{
|
||||
c = (cell_t *)malloc(sizeof(cell_t));
|
||||
if (!c) /* malloc() error */
|
||||
return NULL;
|
||||
|
||||
c->command = CELL_CREATE;
|
||||
c->aci = aci;
|
||||
c->length = length;
|
||||
c->seq = 0;
|
||||
|
||||
memcpy((void *)c->payload, (void *)buf, length);
|
||||
retval = RAND_pseudo_bytes((unsigned char *)(c->payload+length),CELL_PAYLOAD_SIZE-length);
|
||||
if (retval == -1) /* RAND_pseudo_bytes() error */
|
||||
{
|
||||
free((void *)c);
|
||||
return NULL;
|
||||
} /* RAND_pseudo_bytes() error */
|
||||
|
||||
return c;
|
||||
} /* valid parameters */
|
||||
else /* invalid parameters */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
cell_t *new_data_cell(uint16_t aci, unsigned char length, unsigned char *buf)
|
||||
{
|
||||
cell_t *c = NULL;
|
||||
int retval;
|
||||
|
||||
if ((aci) && (buf) && (length <= CELL_PAYLOAD_SIZE)) /* valid parameters */
|
||||
{
|
||||
c = malloc(sizeof(cell_t));
|
||||
if (!c) /* malloc() error */
|
||||
return NULL;
|
||||
|
||||
c->command = CELL_DATA;
|
||||
c->aci = aci;
|
||||
c->length = length;
|
||||
c->seq = 0;
|
||||
|
||||
memcpy((void *)c->payload, (void *)buf, length);
|
||||
retval = RAND_pseudo_bytes((unsigned char *)(c->payload+length),CELL_PAYLOAD_SIZE-length);
|
||||
if (retval == -1) /* RAND_pseudo_bytes() error */
|
||||
{
|
||||
free((void *)c);
|
||||
return NULL;
|
||||
} /* RAND_pseudo_bytes() error */
|
||||
|
||||
return c;
|
||||
} /* valid parameters */
|
||||
else /* invalid parameters */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int pack_create(uint16_t aci, unsigned char *onion, uint32_t onionlen, unsigned char **cellbuf, unsigned int *cellbuflen)
|
||||
{
|
||||
cell_t *c;
|
||||
unsigned char *buf;
|
||||
unsigned int buflen;
|
||||
unsigned int cells;
|
||||
unsigned int dataleft;
|
||||
unsigned int i;
|
||||
|
||||
if ((aci) && (onion) && (cellbuf) && (cellbuflen) && (onionlen)) /* valid parameters */
|
||||
{
|
||||
/* copy the onion into a buffer, prepend with onion length */
|
||||
buflen = onionlen+4;
|
||||
buf = (unsigned char *)malloc(buflen);
|
||||
if (!buf) /* malloc() error */
|
||||
return -1;
|
||||
|
||||
log(LOG_DEBUG,"pack_create() : Setting onion length to %u.",onionlen);
|
||||
onionlen=htonl(onionlen);
|
||||
memcpy((void *)buf,(void *)&onionlen,4);
|
||||
onionlen=ntohl(onionlen);
|
||||
memcpy((void *)(buf+4),(void *)onion,onionlen);
|
||||
|
||||
/* calculate number of cells required */
|
||||
if (buflen%CELL_PAYLOAD_SIZE == 0)
|
||||
cells = buflen/CELL_PAYLOAD_SIZE;
|
||||
else
|
||||
cells = buflen/CELL_PAYLOAD_SIZE+1;
|
||||
|
||||
/* allocate memory for the cells */
|
||||
*cellbuflen = cells * sizeof(cell_t);
|
||||
*cellbuf = malloc(*cellbuflen);
|
||||
if (!*cellbuf) /* malloc() error */
|
||||
return -1;
|
||||
|
||||
log(LOG_DEBUG,"pack_create() : Allocated memory for %u cells.",cells);
|
||||
|
||||
/* create cells one by one */
|
||||
dataleft = buflen;
|
||||
for(i=0; i<cells; i++)
|
||||
{
|
||||
log(LOG_DEBUG,"pack_create() : Packing %u bytes of data.",dataleft);
|
||||
if (dataleft >= CELL_PAYLOAD_SIZE)
|
||||
{
|
||||
c = new_create_cell(aci,CELL_PAYLOAD_SIZE,buf+i*CELL_PAYLOAD_SIZE);
|
||||
dataleft -= CELL_PAYLOAD_SIZE;
|
||||
}
|
||||
else
|
||||
c = new_create_cell(aci,dataleft,buf+i*CELL_PAYLOAD_SIZE);
|
||||
|
||||
if (!c) /* cell creation failed */
|
||||
{
|
||||
free((void *)*cellbuf);
|
||||
return -1;
|
||||
} /* cell creation failed */
|
||||
|
||||
log(LOG_DEBUG,"pack_create() : new_create_cell succeeded; copying the cell into output buffer");
|
||||
/* cell has been created, now copy into buffer */
|
||||
memcpy((void *)(*cellbuf+i*sizeof(cell_t)),(void *)c,sizeof(cell_t));
|
||||
free((void *)c);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
} /* valid parameters */
|
||||
else /* invalid parameters */
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pack_data(uint16_t aci,unsigned char *buf, size_t buflen, unsigned char **cellbuf, unsigned int *cellbuflen)
|
||||
{
|
||||
cell_t *c;
|
||||
unsigned int cells;
|
||||
unsigned int dataleft;
|
||||
unsigned int i;
|
||||
|
||||
if ((aci) && (buf) && (cellbuf) && (cellbuflen) && (buflen)) /* valid parameters */
|
||||
{
|
||||
/* calculate number of cells required */
|
||||
if (buflen%CELL_PAYLOAD_SIZE == 0)
|
||||
cells = buflen/CELL_PAYLOAD_SIZE;
|
||||
else
|
||||
cells = buflen/CELL_PAYLOAD_SIZE+1;
|
||||
|
||||
/* allocate memory for the cells */
|
||||
*cellbuf = malloc(cells * sizeof(cell_t));
|
||||
if (!*cellbuf) /* malloc() error */
|
||||
return -1;
|
||||
|
||||
log(LOG_DEBUG,"pack_data() : Allocated memory for %u cells.",cells);
|
||||
/* create cells one by one */
|
||||
dataleft = buflen;
|
||||
for(i=0; i<cells; i++)
|
||||
{
|
||||
log(LOG_DEBUG,"pack_data() : Packing %u bytes of data.",dataleft);
|
||||
if (dataleft >= CELL_PAYLOAD_SIZE)
|
||||
{
|
||||
c = new_data_cell(aci,CELL_PAYLOAD_SIZE,buf+i*CELL_PAYLOAD_SIZE);
|
||||
dataleft -= CELL_PAYLOAD_SIZE;
|
||||
}
|
||||
else
|
||||
c = new_data_cell(aci,dataleft,buf+i*CELL_PAYLOAD_SIZE);
|
||||
|
||||
if (!c) /* cell creation failed */
|
||||
{
|
||||
free((void *)*cellbuf);
|
||||
return -1;
|
||||
} /* cell creation failed */
|
||||
|
||||
/* cell has been created, now copy into buffer */
|
||||
memcpy((void *)(*cellbuf+i*sizeof(cell_t)),(void *)c,sizeof(cell_t));
|
||||
free((void *)c);
|
||||
}
|
||||
|
||||
*cellbuflen = cells * sizeof(cell_t);
|
||||
return 0;
|
||||
} /* valid parameters */
|
||||
else /* invalid parameters */
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* cell.h
|
||||
* Cell definition.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.14 2002/04/02 14:27:11 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.13 2002/03/03 00:06:45 mp292
|
||||
* Modifications to support re-transmission.
|
||||
*
|
||||
* Revision 1.12 2002/02/09 17:51:52 mp292
|
||||
* CELL_ACK should be 4 not 3
|
||||
*
|
||||
* Revision 1.11 2002/02/03 22:41:45 mp292
|
||||
* Changes to cell size.
|
||||
*
|
||||
* Revision 1.10 2002/01/21 20:57:19 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.9 2002/01/17 15:00:43 mp292
|
||||
* Fixed a bug which caused malloc() generate a seg fault.
|
||||
*
|
||||
* Revision 1.8 2002/01/14 13:05:37 badbytes
|
||||
* System testing in progress.
|
||||
*
|
||||
* Revision 1.7 2002/01/10 13:15:54 badbytes
|
||||
* Fixed ACI size from 32bits to 16bits.
|
||||
*
|
||||
* Revision 1.6 2002/01/09 08:10:32 badbytes
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.5 2002/01/07 13:03:28 badbytes
|
||||
* cell.ACI is now cell.aci
|
||||
*
|
||||
* Revision 1.4 2002/01/07 09:26:00 badbytes
|
||||
* Added pack_create() and pack_data().
|
||||
*
|
||||
* Revision 1.3 2002/01/07 07:48:34 badbytes
|
||||
* fixed new_create_cell()
|
||||
*
|
||||
* Revision 1.2 2002/01/04 12:08:34 badbytes
|
||||
* Added functions for cell creation.
|
||||
*
|
||||
* Revision 1.1 2002/01/04 10:02:07 badbytes
|
||||
* Added cell definition.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CELL_H
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* cell commands */
|
||||
#define CELL_PADDING 0
|
||||
#define CELL_CREATE 1
|
||||
#define CELL_DATA 2
|
||||
#define CELL_DESTROY 3
|
||||
#define CELL_ACK 4
|
||||
#define CELL_NACK 5
|
||||
|
||||
#define CELL_PAYLOAD_SIZE 120
|
||||
|
||||
/* cell definition */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t aci; /* Anonymous Connection Identifier */
|
||||
unsigned char command;
|
||||
unsigned char length; /* of payload */
|
||||
uint32_t seq; /* sequence number */
|
||||
unsigned char payload[120];
|
||||
} cell_t;
|
||||
|
||||
cell_t *new_padding_cell(void);
|
||||
cell_t *new_create_cell(uint16_t aci, unsigned char length, unsigned char *buf);
|
||||
cell_t *new_destroy_cell(uint16_t aci);
|
||||
cell_t *new_data_cell(uint16_t aci, unsigned char length, unsigned char *buf);
|
||||
cell_t *new_ack_cell(uint16_t aci);
|
||||
cell_t *new_nack_cell(uint16_t aci);
|
||||
|
||||
int pack_create(uint16_t aci, unsigned char *onion, uint32_t onionlen, unsigned char **cellbuf, unsigned int *cellbuflen);
|
||||
int pack_data(uint16_t aci, unsigned char *buf, size_t buflen, unsigned char **cellbuf, unsigned int *cellbuflen);
|
||||
|
||||
#define __CELL_H
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
* config.c
|
||||
* Functions for the manipulation of configuration files.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.7 2002/04/02 14:27:11 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.6 2002/01/27 19:23:03 mp292
|
||||
* Fixed a bug in parameter checking.
|
||||
*
|
||||
* Revision 1.5 2002/01/26 18:42:15 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.4 2002/01/21 21:07:56 mp292
|
||||
* Parameter checking was missing in some functions.
|
||||
*
|
||||
* Revision 1.3 2001/12/07 09:38:03 badbytes
|
||||
* Tested.
|
||||
*
|
||||
* Revision 1.2 2001/12/06 15:43:50 badbytes
|
||||
* config.c compiles. Proceeding to test it.
|
||||
*
|
||||
* Revision 1.1 2001/11/22 01:20:27 mp292
|
||||
* Functions for dealing with configuration files.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
|
||||
/* open configuration file for reading */
|
||||
FILE *open_config(const unsigned char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
if (filename) /* non-NULL filename */
|
||||
{
|
||||
if (strspn(filename,CONFIG_LEGAL_FILENAME_CHARACTERS) == strlen(filename)) /* filename consists of legal characters only */
|
||||
{
|
||||
f = fopen(filename, "r");
|
||||
|
||||
return f;
|
||||
} /* filename consists of legal characters only */
|
||||
else /* illegal values in filename */
|
||||
{
|
||||
return NULL;
|
||||
} /* illegal values in filename */
|
||||
} /* non-NULL filename */
|
||||
else /* NULL filename */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* close configuration file */
|
||||
int close_config(FILE *f)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
if (f) /* valid file descriptor */
|
||||
{
|
||||
retval = fclose(f);
|
||||
|
||||
return retval;
|
||||
} /* valid file descriptor */
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* parse the config file and obtain the required option values */
|
||||
int parse_config(FILE *f, config_opt_t *option)
|
||||
{
|
||||
unsigned char keyword[CONFIG_KEYWORD_MAXLEN+1]; /* for storing the option keyword */
|
||||
|
||||
unsigned char *buffer = NULL; /* option value */
|
||||
size_t buflen = 0;
|
||||
|
||||
char *errtest = NULL; /* used for testing correctness of strtol() etc. */
|
||||
|
||||
unsigned int i_keyword = 0; /* current position within keyword */
|
||||
unsigned int i_buf = 0; /* current position within buffer */
|
||||
|
||||
char c=0; /* input char */
|
||||
|
||||
unsigned int state=0; /* internal state
|
||||
* 0 - trying to find a keyword
|
||||
* 1 - reading a keyword
|
||||
* 2 - keyword read and recognized, looking for the option value
|
||||
* 3 - reading the option value
|
||||
* 4 - option value read
|
||||
* 5 - inside a comment
|
||||
*/
|
||||
|
||||
int retval=0; /* return value */
|
||||
|
||||
int lineno=1; /* current line number */
|
||||
int curopt=-1; /* current option, as an indexed in config_opt_t */
|
||||
int i;
|
||||
|
||||
if ( (f==NULL) || (option==NULL) ) /* invalid parameters */
|
||||
return -1;
|
||||
|
||||
fseek(f,0,SEEK_SET); /* make sure we start at the beginning of file */
|
||||
|
||||
for (;;) /* infinite loop */
|
||||
{
|
||||
c = getc(f);
|
||||
|
||||
if ((c == '\n') || (c == EOF))
|
||||
{
|
||||
if (state == 1) /* reading a keyboard */
|
||||
{
|
||||
log(LOG_ERR,"Error parsing the configuration file on line %d.", lineno);
|
||||
i_keyword = 0;
|
||||
state = 0;
|
||||
retval = -1;
|
||||
break;
|
||||
} /* reading a keyboard */
|
||||
else if (state == 2) /* keyword read and recognized */
|
||||
{
|
||||
log(LOG_ERR,"Error parsing option %s on line %d.",option[curopt].keyword, lineno);
|
||||
i_keyword = 0;
|
||||
state = 0;
|
||||
option[curopt].err=-1;
|
||||
retval = -1;
|
||||
break;
|
||||
} /* keyboard read and recognized */
|
||||
else if (state == 3) /* reading the option value */
|
||||
{
|
||||
buffer[i_buf++] = 0; /* add NULL character to terminate the string */
|
||||
state = 4;
|
||||
/* conversion and copying the value into config_opt_t is done later on */
|
||||
} /* reading the option value */
|
||||
else if (state == 5) /* reached end of comment */
|
||||
state = 0;
|
||||
|
||||
if (c == EOF)
|
||||
{
|
||||
log(LOG_DEBUG,"parse_config() : Reached eof on line %d.",lineno);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
log(LOG_DEBUG,"parse_config() : Reached eol on line %d.", lineno);
|
||||
lineno++;
|
||||
}
|
||||
}
|
||||
else if ( (state==0) && (c == '#') ) /* lines beginning with # are ignored */
|
||||
{
|
||||
log(LOG_DEBUG,"parse_config() : Line %d begins with #.",lineno);
|
||||
state = 5;
|
||||
}
|
||||
else if ( (state==0) && (isspace(c)) ) /* leading whitespace is ignored */
|
||||
;
|
||||
else if ( (state==1) && (isspace(c)) ) /* have apparently read in all of the keyword */
|
||||
{
|
||||
keyword[i_keyword++] = 0;
|
||||
curopt = -1;
|
||||
for (i=0;option[i].keyword != NULL;i++) /* try and identify the keyword */
|
||||
{
|
||||
if (!strncmp(keyword,option[i].keyword,CONFIG_KEYWORD_MAXLEN))
|
||||
{
|
||||
curopt = i;
|
||||
break;
|
||||
}
|
||||
} /* try and identify the keyword */
|
||||
|
||||
if (curopt == -1) /* can't recognise the keyword */
|
||||
{
|
||||
log(LOG_ERR,"Error parsing the configuration file. Cannot recognize keyword %s on line %d.",keyword,lineno);
|
||||
retval=-1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
state = 2;
|
||||
}
|
||||
else if ( (state==2) && (isspace(c)) ) /* whitespace separating keyword and value is ignored */
|
||||
;
|
||||
else if ( (state==3) && (isspace(c)) ) /* have apparently finished reading the option value */
|
||||
{
|
||||
buffer[i_buf++]=0;
|
||||
state = 4;
|
||||
}
|
||||
else /* all other characters */
|
||||
{
|
||||
if (state == 0) /* first character of the keyword */
|
||||
{
|
||||
log(LOG_DEBUG, "parse_config() : %c is the start of a keyword on line %d.",c,lineno);
|
||||
state = 1;
|
||||
i_keyword = 0;
|
||||
keyword[i_keyword++] = c;
|
||||
}
|
||||
else if (state == 1) /* keep on reading the keyword */
|
||||
{
|
||||
log(LOG_DEBUG,"parse_config() : %c is a character in the keyword on line %d.",c,lineno);
|
||||
if (i_keyword < CONFIG_KEYWORD_MAXLEN) /* check for buffer overflow */
|
||||
keyword[i_keyword++] = c;
|
||||
else
|
||||
{
|
||||
log(LOG_ERR,"Error parsing the configuration file. Keyword on line %d exceeds %d characters.",lineno,CONFIG_KEYWORD_MAXLEN);
|
||||
retval=-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (state == 2) /* first character of the value */
|
||||
{
|
||||
log(LOG_DEBUG,"parse_config() : %c is the first character of the option value on line %d.",c,lineno);
|
||||
state = 3;
|
||||
i_buf=0;
|
||||
buflen = CONFIG_VALUE_MAXLEN+1; /* allocate memory for the value buffer */
|
||||
buffer = (char *)malloc(buflen);
|
||||
if (!buffer)
|
||||
{
|
||||
log(LOG_ERR,"Could not allocate memory.");
|
||||
retval=-1;
|
||||
break;
|
||||
} else
|
||||
buffer[i_buf++]=c;
|
||||
}
|
||||
else if (state == 3) /* keep on reading the value */
|
||||
{
|
||||
log(LOG_DEBUG,"parse_config() : %c is a character in the value of the keyword on line %d.",c,lineno);
|
||||
if (i_buf >= buflen)
|
||||
{
|
||||
log(LOG_ERR,"Length of keyword value on line %u exceeds the length limit (%u).",lineno, CONFIG_VALUE_MAXLEN);
|
||||
retval=-1;
|
||||
break;
|
||||
}
|
||||
|
||||
buffer[i_buf++]=c;
|
||||
}
|
||||
else if (state == 5)
|
||||
; /* character is part of a comment, skip */
|
||||
else /* unexpected error */
|
||||
{
|
||||
log(LOG_ERR,"Unexpected error while parsing the configuration file.");
|
||||
log(LOG_DEBUG,"parse_config() : Encountered a non-delimiter character while not in states 0,1,2 or 3!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state==4) /* convert the value of the option to the appropriate type and write into OPT */
|
||||
{
|
||||
switch(option[curopt].r_type) /* consider each type separately */
|
||||
{
|
||||
case CONFIG_TYPE_STRING:
|
||||
/* resize the buffer to fit the data exactly */
|
||||
buffer = (char *)realloc(buffer,i_buf);
|
||||
if (!buffer)
|
||||
{
|
||||
log(LOG_ERR,"Could not allocate memory.");
|
||||
return -1;
|
||||
}
|
||||
option[curopt].r.str = buffer;
|
||||
option[curopt].err = 1;
|
||||
break;
|
||||
|
||||
case CONFIG_TYPE_CHAR:
|
||||
option[curopt].r.c = *buffer;
|
||||
option[curopt].err = 1;
|
||||
break;
|
||||
|
||||
case CONFIG_TYPE_INT:
|
||||
errtest = NULL;
|
||||
option[curopt].r.i = (int)strtol(buffer,&errtest,0);
|
||||
if ((unsigned char *)errtest == buffer)
|
||||
{
|
||||
log(LOG_ERR, "Error parsing configuration file. Option %s on line %d does not seem to be of the required type.\n",option[curopt].keyword,--lineno);
|
||||
option[curopt].err = -1;
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
option[curopt].err = 1;
|
||||
break;
|
||||
|
||||
case CONFIG_TYPE_LONG:
|
||||
errtest = NULL;
|
||||
option[curopt].r.l = strtol(buffer,&errtest,0);
|
||||
if ((unsigned char *)errtest == buffer)
|
||||
{
|
||||
log(LOG_ERR, "Error parsing configuration file. Option %s on line %d does not seem to be of the required type.\n",option[curopt].keyword,--lineno);
|
||||
option[curopt].err = -1;
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
option[curopt].err = 1;
|
||||
break;
|
||||
|
||||
case CONFIG_TYPE_DOUBLE:
|
||||
errtest = NULL;
|
||||
option[curopt].r.d = strtod(buffer,&errtest);
|
||||
if ((unsigned char *)errtest == buffer)
|
||||
{
|
||||
log(LOG_ERR, "Error parsing configuration file. Option %s on line %d does not seem to be of the required type.\n",option[curopt].keyword,--lineno);
|
||||
option[curopt].err = -1;
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
option[curopt].err = 1;
|
||||
break;
|
||||
|
||||
default: /* unexpected type */
|
||||
log(LOG_ERR, "Error parsing configuration file. Unrecognized option type!");
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* clean up */
|
||||
if (option[curopt].r_type != CONFIG_TYPE_STRING)
|
||||
{
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
buflen=0;
|
||||
}
|
||||
|
||||
state = 0;
|
||||
curopt = -1;
|
||||
i_buf=0;
|
||||
i_keyword=0;
|
||||
}
|
||||
|
||||
|
||||
} /* infinite loop */
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* config.h
|
||||
* Functions for the manipulation of configuration files.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.7 2002/04/02 14:27:11 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.6 2002/01/26 18:42:15 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.5 2002/01/21 21:07:56 mp292
|
||||
* Parameter checking was missing in some functions.
|
||||
*
|
||||
* Revision 1.4 2001/12/18 10:37:47 badbytes
|
||||
* Header files now only apply if they were not previously included from somewhere else.
|
||||
*
|
||||
* Revision 1.3 2001/12/07 09:38:03 badbytes
|
||||
* Tested.
|
||||
*
|
||||
* Revision 1.2 2001/12/06 15:43:50 badbytes
|
||||
* config.c compiles. Proceeding to test it.
|
||||
*
|
||||
* Revision 1.1 2001/11/22 01:20:27 mp292
|
||||
* Functions for dealing with configuration files.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_H
|
||||
|
||||
# include <stdio.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
|
||||
|
||||
/* max. length of an option keyword */
|
||||
#define CONFIG_KEYWORD_MAXLEN 255
|
||||
|
||||
/* max. length (in characters) of an option value */
|
||||
#define CONFIG_VALUE_MAXLEN 255
|
||||
|
||||
/* legal characters in a filename */
|
||||
#define CONFIG_LEGAL_FILENAME_CHARACTERS "abcdefghijklmopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_/"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char *keyword; /* option keyword */
|
||||
|
||||
unsigned int r_type; /* return type as defined above */
|
||||
|
||||
union /* return value */
|
||||
{
|
||||
char *str;
|
||||
char c;
|
||||
int i;
|
||||
long l;
|
||||
double d;
|
||||
} r;
|
||||
|
||||
int err; /* 1 OK
|
||||
* 0 keyword not found
|
||||
* -1 error while parsing */
|
||||
} config_opt_t;
|
||||
|
||||
/* open configuration file for reading */
|
||||
FILE *open_config(const unsigned char *filename);
|
||||
|
||||
/* close configuration file */
|
||||
int close_config(FILE *f);
|
||||
|
||||
/* parse the config file and obtain required option values */
|
||||
int parse_config(FILE *f, config_opt_t *option);
|
||||
|
||||
#define __CONFIG_H
|
||||
#endif
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* key.c
|
||||
* Key management.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.5 2002/03/12 23:28:26 mp292
|
||||
* Removed calls to ERR_load_crypto_strings() (libcrypt).
|
||||
*
|
||||
* Revision 1.4 2002/01/27 19:23:03 mp292
|
||||
* Fixed a bug in parameter checking.
|
||||
*
|
||||
* Revision 1.3 2002/01/26 18:50:11 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.2 2002/01/04 07:19:03 badbytes
|
||||
* Key generation moved to a separate utility (orkeygen).
|
||||
*
|
||||
* Revision 1.1 2001/12/14 12:16:33 badbytes
|
||||
* Added routine for reading a private key from a file.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#include "key.h"
|
||||
#include "log.h"
|
||||
#include "config.h"
|
||||
|
||||
RSA *load_prkey(unsigned char *keyfile)
|
||||
{
|
||||
RSA *rsa_private=NULL;
|
||||
FILE *f_pr;
|
||||
int retval = 0;
|
||||
|
||||
if (keyfile) /* non-NULL filename */
|
||||
{
|
||||
if (strspn(keyfile,CONFIG_LEGAL_FILENAME_CHARACTERS) == strlen(keyfile)) /* filename contains legal characters only */
|
||||
{
|
||||
/* open the keyfile */
|
||||
f_pr=fopen(keyfile,"r");
|
||||
if (!f_pr)
|
||||
{
|
||||
log(LOG_ERR,"Failed to open keyfile %s.",keyfile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* read the private key */
|
||||
rsa_private = PEM_read_RSAPrivateKey(f_pr,&rsa_private,NULL,NULL);
|
||||
fclose(f_pr);
|
||||
if (!rsa_private)
|
||||
{
|
||||
log(LOG_ERR,"Error reading private key : %s",ERR_reason_error_string(ERR_get_error()));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* check the private key */
|
||||
retval = RSA_check_key(rsa_private);
|
||||
if (retval == 0)
|
||||
{
|
||||
log(LOG_ERR,"Private key read but is invalid : %s.", ERR_reason_error_string(ERR_get_error()));
|
||||
RSA_free(rsa_private);
|
||||
return NULL;
|
||||
}
|
||||
else if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Private key read but validity checking failed : %s",ERR_reason_error_string(ERR_get_error()));
|
||||
RSA_free(rsa_private);
|
||||
return NULL;
|
||||
}
|
||||
else if (retval == 1)
|
||||
{
|
||||
return rsa_private;
|
||||
}
|
||||
} /* filename contains legal characters only */
|
||||
}
|
||||
|
||||
return NULL; /* report error */
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* key.h
|
||||
* Routines for generating key pairs and loading private keys.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.3 2002/01/26 18:50:11 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.2 2001/12/18 10:37:47 badbytes
|
||||
* Header files now only apply if they were not previously included from somewhere else.
|
||||
*
|
||||
* Revision 1.1 2001/12/14 12:16:33 badbytes
|
||||
* Added routine for reading a private key from a file.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KEY_H
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
/* read the private key in keyfile into memory */
|
||||
RSA *load_prkey(unsigned char *keyfile);
|
||||
|
||||
#define __KEY_H
|
||||
#endif
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* log.c
|
||||
* Logging facilities.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.11 2002/06/14 20:44:57 mp292
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.10 2002/03/12 23:31:36 mp292
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.9 2002/03/02 18:55:50 mp292
|
||||
* LOG_DEBUG messages don't print the last errno error anymore.
|
||||
*
|
||||
* Revision 1.8 2002/01/26 22:46:48 mp292
|
||||
* Reviewd according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.7 2002/01/17 15:00:43 mp292
|
||||
* Fixed a bug which caused malloc() generate a seg fault.
|
||||
*
|
||||
* Revision 1.6 2001/12/12 16:02:55 badbytes
|
||||
* Minor changes in output format.
|
||||
*
|
||||
* Revision 1.5 2001/12/12 06:48:07 badbytes
|
||||
* Correction - last error message now only shown if severity==LOG_DEBUG.
|
||||
*
|
||||
* Revision 1.4 2001/12/12 06:28:46 badbytes
|
||||
* Modified log() to print error message for last error in addition to the user-specified message.
|
||||
*
|
||||
* Revision 1.3 2001/12/07 09:38:03 badbytes
|
||||
* Tested.
|
||||
*
|
||||
* Revision 1.2 2001/12/06 15:43:50 badbytes
|
||||
* config.c compiles. Proceeding to test it.
|
||||
*
|
||||
* Revision 1.1 2001/11/21 23:03:41 mp292
|
||||
* log function coded and tested.
|
||||
* Top-level makefile.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "log.h"
|
||||
|
||||
void log_internal(int severity, const char *format, va_list ap);
|
||||
|
||||
/* Outputs a message to stdout */
|
||||
void log(int severity, const char *format, ...)
|
||||
{
|
||||
extern int loglevel;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap,format);
|
||||
|
||||
if (severity <= loglevel)
|
||||
{
|
||||
vprintf(format,ap);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* log.h
|
||||
* Logging facilities.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.5 2002/01/26 18:52:00 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.4 2001/12/18 10:37:47 badbytes
|
||||
* Header files now only apply if they were not previously included from somewhere else.
|
||||
*
|
||||
* Revision 1.3 2001/12/07 09:38:03 badbytes
|
||||
* Tested.
|
||||
*
|
||||
* Revision 1.2 2001/12/06 15:43:50 badbytes
|
||||
* config.c compiles. Proceeding to test it.
|
||||
*
|
||||
* Revision 1.1 2001/11/21 23:03:41 mp292
|
||||
* log function coded and tested.
|
||||
* Top-level makefile.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __LOG_H
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
/* Outputs a message to stdout and also logs the same message using syslog. */
|
||||
void log(int severity, const char *format, ...);
|
||||
|
||||
# define __LOG_H
|
||||
#endif
|
||||
@@ -0,0 +1,633 @@
|
||||
/**
|
||||
* onion.c
|
||||
* Routines for creating/manipulating onions.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.24 2002/06/14 20:42:02 mp292
|
||||
* Bug caused infinite loop when router list had <= 2 entries.
|
||||
*
|
||||
* Revision 1.23 2002/04/02 14:27:11 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.22 2002/04/02 10:20:09 badbytes
|
||||
* Memory overflow bug.
|
||||
*
|
||||
* Revision 1.21 2002/03/25 09:11:23 badbytes
|
||||
* Added a list of onions being tracked for replay attacks.
|
||||
*
|
||||
* Revision 1.20 2002/03/12 23:32:41 mp292
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.19 2002/01/27 19:23:21 mp292
|
||||
* Fixed a bug in parameter checking.
|
||||
*
|
||||
* Revision 1.18 2002/01/26 19:24:29 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.17 2002/01/18 20:40:40 mp292
|
||||
* Fixed a bug in en/decrypt_onion() functions.
|
||||
*
|
||||
* Revision 1.16 2002/01/17 23:48:31 mp292
|
||||
* Added some extra debugging messages to fix a bug in encrypt_onion() which
|
||||
* seems to corrupt the routent *route list.
|
||||
*
|
||||
* Revision 1.15 2002/01/17 15:00:43 mp292
|
||||
* Fixed a bug which caused malloc() generate a seg fault.
|
||||
*
|
||||
* Revision 1.14 2002/01/16 23:01:54 mp292
|
||||
* First phase of system testing completed (main functionality).
|
||||
*
|
||||
* Revision 1.13 2002/01/14 13:05:37 badbytes
|
||||
* System testing in progress.
|
||||
*
|
||||
* Revision 1.12 2002/01/11 15:47:17 badbytes
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.11 2002/01/09 07:58:23 badbytes
|
||||
* Fixed a bug so that backward crypto engines are now initialized with DecryptInit.
|
||||
*
|
||||
* Revision 1.10 2002/01/09 07:55:23 badbytes
|
||||
* Ciphers got out of sync. Hopefully fixed.
|
||||
*
|
||||
* Revision 1.9 2002/01/03 11:01:22 badbytes
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.8 2001/12/19 08:29:00 badbytes
|
||||
* Macro DEFAULT_CIPHER now holds the default crypto algorithm
|
||||
*
|
||||
* Revision 1.7 2001/12/18 14:12:47 badbytes
|
||||
* Default cipher is now IDENTITY, for testing purposes.
|
||||
*
|
||||
* Revision 1.6 2001/12/18 10:36:51 badbytes
|
||||
* create_onion() now also computes a crypt_path
|
||||
*
|
||||
* Revision 1.5 2001/12/17 13:35:17 badbytes
|
||||
* Still writing handle_connection()
|
||||
*
|
||||
* Revision 1.4 2001/12/14 14:44:37 badbytes
|
||||
* chooselen() tested
|
||||
*
|
||||
* Revision 1.3 2001/12/14 13:30:48 badbytes
|
||||
* peel_onion() was redundant, removed it
|
||||
*
|
||||
* Revision 1.2 2001/12/14 13:14:03 badbytes
|
||||
* Split types.h into routent.h and ss.h. Keeping them all in one file created unnecesary dependencies.
|
||||
*
|
||||
* Revision 1.1 2001/12/14 12:41:12 badbytes
|
||||
* Moved from op/ as it will be reused by other modules.
|
||||
*
|
||||
* Revision 1.1 2001/12/13 15:15:10 badbytes
|
||||
* Started coding the onion proxy.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "onion.h"
|
||||
#include "log.h"
|
||||
|
||||
/* uses a weighted coin with weight cw to choose a route length */
|
||||
int chooselen(double cw)
|
||||
{
|
||||
int len = 2;
|
||||
int retval = 0;
|
||||
unsigned char coin;
|
||||
|
||||
if ((cw < 0) || (cw >= 1)) /* invalid parameter */
|
||||
return -1;
|
||||
|
||||
while(1)
|
||||
{
|
||||
retval = RAND_pseudo_bytes(&coin,1);
|
||||
if (retval == -1)
|
||||
return -1;
|
||||
|
||||
if (coin > cw*255) /* don't extend */
|
||||
break;
|
||||
else
|
||||
len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* returns an array of pointers to routent that define a new route through the OR network
|
||||
* int cw is the coin weight to use when choosing the route
|
||||
* order of routers is from last to first
|
||||
*/
|
||||
unsigned int *new_route(double cw, routent_t **rarray, size_t rarray_len, size_t *rlen)
|
||||
{
|
||||
int routelen = 0;
|
||||
int i = 0;
|
||||
int retval = 0;
|
||||
unsigned int *route = NULL;
|
||||
unsigned int oldchoice, choice;
|
||||
|
||||
if ( (cw >= 0) && (cw < 1) && (rarray) && (rlen) ) /* valid parameters */
|
||||
{
|
||||
routelen = chooselen(cw);
|
||||
if (routelen == -1)
|
||||
{
|
||||
log(LOG_ERR,"Choosing route length failed.");
|
||||
return NULL;
|
||||
}
|
||||
log(LOG_DEBUG,"new_route(): Chosen route length %u.",routelen);
|
||||
|
||||
/* allocate memory for the new route */
|
||||
route = (unsigned int *)malloc(routelen * sizeof(unsigned int));
|
||||
if (!route)
|
||||
{
|
||||
log(LOG_ERR,"Memory allocation failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
oldchoice = rarray_len;
|
||||
for(i=0;i<routelen;i++)
|
||||
{
|
||||
log(LOG_DEBUG,"new_route() : Choosing hop %u.",i);
|
||||
retval = RAND_pseudo_bytes((unsigned char *)&choice,sizeof(unsigned int));
|
||||
if (retval == -1)
|
||||
{
|
||||
free((void *)route);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
choice = choice % (rarray_len);
|
||||
log(LOG_DEBUG,"new_route() : Chosen router %u.",choice);
|
||||
if (choice == oldchoice) /* same router */
|
||||
{
|
||||
/* try again */
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
oldchoice = choice;
|
||||
route[i] = choice;
|
||||
}
|
||||
|
||||
*rlen = routelen;
|
||||
return route;
|
||||
} /* valid parameters */
|
||||
else /* invalid parameters */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* creates a new onion from route, stores it and its length into bufp and lenp respectively */
|
||||
unsigned char *create_onion(routent_t **rarray, size_t rarray_len, unsigned int *route, size_t routelen, size_t *lenp, crypt_path_t **cpathp)
|
||||
{
|
||||
int i,j;
|
||||
int retval = 0;
|
||||
onion_layer_t *layer = NULL;
|
||||
crypt_path_t *hop = NULL;
|
||||
unsigned char *retbuf = NULL;
|
||||
unsigned char *bufp;
|
||||
routent_t *router;
|
||||
|
||||
if ( (rarray) && (route) && (lenp) ) /* valid parameters */
|
||||
{
|
||||
/* calculate the size of the onion */
|
||||
*lenp = routelen * 28 + 100; /* 28 bytes per layer + 100 bytes padding for the innermost layer */
|
||||
log(LOG_DEBUG,"create_onion() : Size of the onion is %u.",*lenp);
|
||||
|
||||
/* allocate memory for the onion */
|
||||
bufp = (unsigned char *)malloc(*lenp);
|
||||
if (!bufp)
|
||||
{
|
||||
log(LOG_ERR,"Error allocating memory.");
|
||||
return NULL;
|
||||
}
|
||||
log(LOG_DEBUG,"create_onion() : Allocated memory for the onion.");
|
||||
|
||||
for (retval=0; retval<routelen;retval++)
|
||||
{
|
||||
log(LOG_DEBUG,"create_onion() : %u : %s:%u, %u/%u",routelen-retval,inet_ntoa(*((struct in_addr *)&((rarray[route[retval]])->addr))),ntohs((rarray[route[retval]])->port),(rarray[route[retval]])->pkey,RSA_size((rarray[route[retval]])->pkey));
|
||||
}
|
||||
|
||||
layer = (onion_layer_t *)(bufp + *lenp - 128); /* pointer to innermost layer */
|
||||
/* create the onion layer by layer, starting with the innermost */
|
||||
for (i=0;i<routelen;i++)
|
||||
{
|
||||
router = rarray[route[i]];
|
||||
|
||||
log(LOG_DEBUG,"create_onion() : %u",router);
|
||||
log(LOG_DEBUG,"create_onion() : This router is %s:%u",inet_ntoa(*((struct in_addr *)&router->addr)),ntohs(router->port));
|
||||
log(LOG_DEBUG,"create_onion() : Key pointer = %u.",router->pkey);
|
||||
log(LOG_DEBUG,"create_onion() : Key size = %u.",RSA_size(router->pkey));
|
||||
|
||||
/* 0 bit */
|
||||
layer->zero = 0;
|
||||
/* version */
|
||||
layer->version = VERSION;
|
||||
/* Back F + Forw F both use DES OFB*/
|
||||
layer->backf = ONION_DEFAULT_CIPHER;
|
||||
layer->forwf = ONION_DEFAULT_CIPHER;
|
||||
/* Dest Port */
|
||||
if (i) /* not last hop */
|
||||
layer->port = rarray[route[i-1]]->port;
|
||||
else
|
||||
layer->port = 0;
|
||||
/* Dest Addr */
|
||||
if (i) /* not last hop */
|
||||
layer->addr = rarray[route[i-1]]->addr;
|
||||
else
|
||||
layer->addr = 0;
|
||||
/* Expiration Time */
|
||||
layer->expire = time(NULL) + 3600; /* NOW + 1 hour */
|
||||
/* Key Seed Material */
|
||||
retval = RAND_bytes(layer->keyseed,16);
|
||||
if (retval < 1) /* error */
|
||||
{
|
||||
log(LOG_ERR,"Error generating random data.");
|
||||
free((void *)bufp);
|
||||
if (cpathp)
|
||||
{
|
||||
for (j=0;j<i;j++)
|
||||
free((void *)cpathp[i]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
log(LOG_DEBUG,"create_onion() : Onion layer %u built : %u, %u, %u, %s, %u.",i+1,layer->zero,layer->backf,layer->forwf,inet_ntoa(*((struct in_addr *)&layer->addr)),ntohs(layer->port));
|
||||
|
||||
/* build up the crypt_path */
|
||||
if (cpathp)
|
||||
{
|
||||
cpathp[i] = (crypt_path_t *)malloc(sizeof(crypt_path_t));
|
||||
if (!cpathp[i])
|
||||
{
|
||||
log(LOG_ERR,"Error allocating memory.");
|
||||
free((void *)bufp);
|
||||
for (j=0;j<i;j++)
|
||||
free((void *)cpathp[i]);
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"create_onion() : Building hop %u of crypt path.",i+1);
|
||||
hop = cpathp[i];
|
||||
/* set crypto functions */
|
||||
hop->backf = layer->backf;
|
||||
hop->forwf = layer->forwf;
|
||||
|
||||
/* calculate keys */
|
||||
SHA1(layer->keyseed,16,hop->digest3);
|
||||
log(LOG_DEBUG,"create_onion() : First SHA pass performed.");
|
||||
SHA1(hop->digest3,20,hop->digest2);
|
||||
log(LOG_DEBUG,"create_onion() : Second SHA pass performed.");
|
||||
SHA1(hop->digest2,20,hop->digest3);
|
||||
log(LOG_DEBUG,"create_onion() : Third SHA pass performed.");
|
||||
log(LOG_DEBUG,"create_onion() : Keys generated.");
|
||||
/* set IVs */
|
||||
memset((void *)hop->f_iv,0,16);
|
||||
memset((void *)hop->b_iv,0,16);
|
||||
|
||||
/* initialize cipher contexts */
|
||||
EVP_CIPHER_CTX_init(&hop->f_ctx);
|
||||
EVP_CIPHER_CTX_init(&hop->b_ctx);
|
||||
|
||||
/* initialize cipher engines */
|
||||
switch(layer->forwf)
|
||||
{
|
||||
case ONION_CIPHER_DES :
|
||||
retval = EVP_EncryptInit(&hop->f_ctx, EVP_des_ofb(), hop->digest3, hop->f_iv);
|
||||
break;
|
||||
case ONION_CIPHER_RC4 :
|
||||
retval = EVP_EncryptInit(&hop->f_ctx, EVP_rc4(), hop->digest3, hop->f_iv);
|
||||
break;
|
||||
case ONION_CIPHER_IDENTITY :
|
||||
retval = EVP_EncryptInit(&hop->f_ctx, EVP_enc_null(), hop->digest3, hop->f_iv);
|
||||
break;
|
||||
}
|
||||
if (!retval) /* cipher initialization failed */
|
||||
{
|
||||
log(LOG_ERR,"Could not initialize crypto engines.");
|
||||
free((void *)bufp);
|
||||
for (j=0;j<i;j++)
|
||||
free((void *)cpathp[i]);
|
||||
return NULL;
|
||||
}
|
||||
switch(layer->backf)
|
||||
{
|
||||
case ONION_CIPHER_DES :
|
||||
retval = EVP_DecryptInit(&hop->b_ctx, EVP_des_ofb(), hop->digest2, hop->b_iv);
|
||||
break;
|
||||
case ONION_CIPHER_RC4 :
|
||||
retval = EVP_DecryptInit(&hop->b_ctx, EVP_rc4(), hop->digest2, hop->b_iv);
|
||||
break;
|
||||
case ONION_CIPHER_IDENTITY :
|
||||
retval = EVP_DecryptInit(&hop->b_ctx, EVP_enc_null(), hop->digest2, hop->b_iv);
|
||||
break;
|
||||
}
|
||||
if (!retval) /* cipher initialization failed */
|
||||
{
|
||||
log(LOG_ERR,"Could not initialize crypto engines.");
|
||||
free((void *)bufp);
|
||||
for (j=0;j<i;j++)
|
||||
free((void *)cpathp[i]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"create_onion() : Built corresponding crypt path hop.");
|
||||
}
|
||||
|
||||
/* padding if this is the innermost layer */
|
||||
if (!i)
|
||||
{
|
||||
retval=RAND_pseudo_bytes((unsigned char *)layer + 28,100);
|
||||
if (retval == -1) /* error */
|
||||
{
|
||||
log(LOG_ERR,"Error generating pseudo-random data.");
|
||||
free((void *)bufp);
|
||||
if (cpathp)
|
||||
{
|
||||
for (j=0;j<i;j++)
|
||||
free((void *)cpathp[i]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
log(LOG_DEBUG,"create_onion() : This is the innermost layer. Adding 100 bytes of padding.");
|
||||
}
|
||||
|
||||
/* encrypt */
|
||||
retbuf = encrypt_onion(layer,128+(i*28),router->pkey);
|
||||
if (!retbuf)
|
||||
{
|
||||
log(LOG_ERR,"Error encrypting onion layer.");
|
||||
free((void *)bufp);
|
||||
if (cpathp)
|
||||
{
|
||||
for (j=0;j<i;j++)
|
||||
free((void *)cpathp[i]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
log(LOG_DEBUG,"create_onion() : Encrypted layer.");
|
||||
|
||||
/* calculate pointer to next layer */
|
||||
layer = (onion_layer_t *)bufp + (routelen-i-2)*sizeof(onion_layer_t);
|
||||
}
|
||||
|
||||
return bufp;
|
||||
} /* valid parameters */
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* encrypts 128 bytes of the onion with the specified public key, the rest with
|
||||
* DES OFB with the key as defined in the outter layer */
|
||||
unsigned char *encrypt_onion(onion_layer_t *onion, uint32_t onionlen, RSA *pkey)
|
||||
{
|
||||
unsigned char *tmpbuf = NULL; /* temporary buffer for crypto operations */
|
||||
unsigned char digest[20]; /* stores SHA1 output - 160 bits */
|
||||
unsigned char *retbuf = NULL;
|
||||
unsigned char iv[8];
|
||||
int retval = 0;
|
||||
int outlen = 0;
|
||||
|
||||
EVP_CIPHER_CTX ctx; /* cipher context */
|
||||
|
||||
if ( (onion) && (pkey) ) /* valid parameters */
|
||||
{
|
||||
memset((void *)iv,0,8);
|
||||
|
||||
log(LOG_DEBUG,"Onion layer : %u, %u, %u, %s, %u.",onion->zero,onion->backf,onion->forwf,inet_ntoa(*((struct in_addr *)&onion->addr)),ntohs(onion->port));
|
||||
/* allocate space for tmpbuf */
|
||||
tmpbuf = (unsigned char *)malloc(onionlen);
|
||||
if (!tmpbuf)
|
||||
{
|
||||
log(LOG_ERR,"Could not allocate memory.");
|
||||
return NULL;
|
||||
}
|
||||
log(LOG_DEBUG,"encrypt_onion() : allocated %u bytes of memory for the encrypted onion (at %u).",onionlen,tmpbuf);
|
||||
|
||||
/* get key1 = SHA1(KeySeed) */
|
||||
retbuf = SHA1(((onion_layer_t *)onion)->keyseed,16,digest);
|
||||
if (!retbuf)
|
||||
{
|
||||
log(LOG_ERR,"Error computing SHA1 digest.");
|
||||
free((void *)tmpbuf);
|
||||
return NULL;
|
||||
}
|
||||
log(LOG_DEBUG,"encrypt_onion() : Computed DES key.");
|
||||
|
||||
log(LOG_DEBUG,"encrypt_onion() : Trying to RSA encrypt.");
|
||||
/* encrypt 128 bytes with RSA *pkey */
|
||||
retval = RSA_public_encrypt(128, (unsigned char *)onion, tmpbuf, pkey, RSA_NO_PADDING);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Error RSA-encrypting data :%s",ERR_reason_error_string(ERR_get_error()));
|
||||
free((void *)tmpbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"encrypt_onion() : RSA encrypted first 128 bytes of the onion.");
|
||||
|
||||
/* now encrypt the rest with DES OFB */
|
||||
|
||||
EVP_CIPHER_CTX_init(&ctx);
|
||||
retval = EVP_EncryptInit(&ctx,EVP_des_ofb(),digest,iv);
|
||||
if (!retval) /* error */
|
||||
{
|
||||
log(LOG_ERR,"Error initializing DES engine:%s",ERR_reason_error_string(ERR_get_error()));
|
||||
free((void *)tmpbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retval = EVP_EncryptUpdate(&ctx,(unsigned char *)tmpbuf+128,&outlen,(unsigned char *)onion+128,onionlen-128);
|
||||
if (!retval) /* error */
|
||||
{
|
||||
log(LOG_ERR,"Error performing DES encryption:%s",ERR_reason_error_string(ERR_get_error()));
|
||||
free((void *)tmpbuf);
|
||||
return NULL;
|
||||
}
|
||||
log(LOG_DEBUG,"encrypt_onion() : DES OFB encrypted the rest of the onion.");
|
||||
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
|
||||
/* now copy tmpbuf to onion */
|
||||
memcpy((void *)onion,(void *)tmpbuf,onionlen);
|
||||
log(LOG_DEBUG,"encrypt_onion() : Copied cipher to original onion buffer.");
|
||||
free((void *)tmpbuf);
|
||||
return (unsigned char *)onion;
|
||||
} /* valid parameters */
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* decrypts the first 128 bytes using RSA and prkey, decrypts the rest with DES OFB with key1 */
|
||||
unsigned char *decrypt_onion(onion_layer_t *onion, uint32_t onionlen, RSA *prkey)
|
||||
{
|
||||
void *tmpbuf = NULL; /* temporary buffer for crypto operations */
|
||||
unsigned char digest[20]; /* stores SHA1 output - 160 bits */
|
||||
unsigned char *retbuf = NULL;
|
||||
unsigned char iv[8];
|
||||
int retval = 0;
|
||||
int outlen = 0;
|
||||
|
||||
EVP_CIPHER_CTX ctx; /* cipher context */
|
||||
|
||||
if ( (onion) && (prkey) ) /* valid parameters */
|
||||
{
|
||||
memset((void *)iv,0,8);
|
||||
|
||||
/* allocate space for tmpbuf */
|
||||
tmpbuf = malloc(onionlen);
|
||||
if (!tmpbuf)
|
||||
{
|
||||
log(LOG_ERR,"Could not allocate memory.");
|
||||
return NULL;
|
||||
}
|
||||
log(LOG_DEBUG,"decrypt_onion() : Allocated memory for the temporary buffer.");
|
||||
|
||||
/* decrypt 128 bytes with RSA *prkey */
|
||||
retval = RSA_private_decrypt(128, (unsigned char*)onion, (unsigned char *)tmpbuf, prkey, RSA_NO_PADDING);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Error RSA-decrypting data :%s",ERR_reason_error_string(ERR_get_error()));
|
||||
free((void *)tmpbuf);
|
||||
return NULL;
|
||||
}
|
||||
log(LOG_DEBUG,"decrypt_onion() : RSA decryption complete.");
|
||||
|
||||
/* get key1 = SHA1(KeySeed) */
|
||||
retbuf = SHA1(((onion_layer_t *)tmpbuf)->keyseed,16,digest);
|
||||
if (!retbuf)
|
||||
{
|
||||
log(LOG_ERR,"Error computing SHA1 digest.");
|
||||
free((void *)tmpbuf);
|
||||
return NULL;
|
||||
}
|
||||
log(LOG_DEBUG,"decrypt_onion() : Computed DES key.");
|
||||
|
||||
/* now decrypt the rest with DES OFB */
|
||||
EVP_CIPHER_CTX_init(&ctx);
|
||||
retval = EVP_DecryptInit(&ctx,EVP_des_ofb(),digest,iv);
|
||||
if (!retval) /* error */
|
||||
{
|
||||
log(LOG_ERR,"Error initializing DES engine:%s",ERR_reason_error_string(ERR_get_error()));
|
||||
free((void *)tmpbuf);
|
||||
return NULL;
|
||||
}
|
||||
retval = EVP_DecryptUpdate(&ctx,(unsigned char *)tmpbuf+128,&outlen,(unsigned char *)onion+128,onionlen-128);
|
||||
if (!retval) /* error */
|
||||
{
|
||||
log(LOG_ERR,"Error performing DES decryption:%s",ERR_reason_error_string(ERR_get_error()));
|
||||
free((void *)tmpbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
log(LOG_DEBUG,"decrypt_onion() : DES decryption complete.");
|
||||
|
||||
/* now copy tmpbuf to onion */
|
||||
memcpy((void *)onion,(void *)tmpbuf,onionlen);
|
||||
free((void *)tmpbuf);
|
||||
return (unsigned char *)onion;
|
||||
} /* valid parameters */
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* delete first n bytes of the onion and pads the end with n bytes of random data */
|
||||
void pad_onion(unsigned char *onion, uint32_t onionlen, size_t n)
|
||||
{
|
||||
if (onion) /* valid parameter */
|
||||
{
|
||||
memmove((void *)onion,(void *)(onion+n),onionlen-n);
|
||||
RAND_pseudo_bytes(onion+onionlen-n,n);
|
||||
}
|
||||
}
|
||||
|
||||
/* create a new tracked_onion entry */
|
||||
tracked_onion_t *new_tracked_onion(unsigned char *onion, uint32_t onionlen, tracked_onion_t **tracked_onions, tracked_onion_t **last_tracked_onion)
|
||||
{
|
||||
tracked_onion_t *to = NULL;
|
||||
|
||||
if (!onion || !tracked_onions || !last_tracked_onion) /* invalid parameters */
|
||||
return NULL;
|
||||
|
||||
to = (tracked_onion_t *)malloc(sizeof(tracked_onion_t));
|
||||
if (!to)
|
||||
return NULL;
|
||||
|
||||
to->expire = ((onion_layer_t *)onion)->expire; /* set the expiration date */
|
||||
/* compute the SHA digest */
|
||||
SHA1(onion, onionlen, to->digest);
|
||||
if (!to->digest)
|
||||
{
|
||||
log(LOG_DEBUG,"new_tracked_onion() : Failed to compute a SHA1 digest of the onion.");
|
||||
free((void *)to);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
to->next = NULL;
|
||||
|
||||
if (!*tracked_onions)
|
||||
{
|
||||
to->prev = NULL;
|
||||
*tracked_onions = to;
|
||||
}
|
||||
else
|
||||
{
|
||||
to->prev = (void *)*last_tracked_onion;
|
||||
(*last_tracked_onion)->next = (void *)to;
|
||||
}
|
||||
*last_tracked_onion = to;
|
||||
|
||||
return to;
|
||||
}
|
||||
|
||||
/* delete a tracked onion entry */
|
||||
void remove_tracked_onion(tracked_onion_t *to, tracked_onion_t **tracked_onions, tracked_onion_t **last_tracked_onion)
|
||||
{
|
||||
if (!*tracked_onions || !*last_tracked_onion || !to)
|
||||
return;
|
||||
|
||||
if (to->prev)
|
||||
((tracked_onion_t *)to->prev)->next = to->next;
|
||||
if (to->next)
|
||||
((tracked_onion_t *)to->next)->prev = to->prev;
|
||||
|
||||
if (to == *tracked_onions)
|
||||
*tracked_onions = (tracked_onion_t *)to->next;
|
||||
|
||||
if (to == *last_tracked_onion)
|
||||
*last_tracked_onion = (tracked_onion_t *)to->prev;
|
||||
|
||||
free((void *)to);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* find a tracked onion in the linked list of tracked onions */
|
||||
tracked_onion_t *id_tracked_onion(unsigned char *onion, uint32_t onionlen, tracked_onion_t *tracked_onions)
|
||||
{
|
||||
tracked_onion_t *to = tracked_onions;
|
||||
unsigned char digest[20];
|
||||
|
||||
/* compute the SHA digest of the onion */
|
||||
SHA1(onion,onionlen, digest);
|
||||
|
||||
while(to)
|
||||
{
|
||||
if (!memcmp((void *)digest, (void *)to->digest, 20))
|
||||
return to;
|
||||
to = (tracked_onion_t *)to->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* onion.h
|
||||
* Routines for creating/manipulating onions.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.17 2002/04/02 14:27:11 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.16 2002/03/25 09:11:23 badbytes
|
||||
* Added a list of onions being tracked for replay attacks.
|
||||
*
|
||||
* Revision 1.15 2002/01/26 19:24:29 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.14 2002/01/18 20:40:40 mp292
|
||||
* Fixed a bug in en/decrypt_onion() functions.
|
||||
*
|
||||
* Revision 1.13 2002/01/17 23:48:31 mp292
|
||||
* Added some extra debugging messages to fix a bug in encrypt_onion() which
|
||||
* seems to corrupt the routent *route list.
|
||||
*
|
||||
* Revision 1.12 2002/01/11 15:47:17 badbytes
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.11 2002/01/09 07:55:23 badbytes
|
||||
* Ciphers got out of sync. Hopefully fixed.
|
||||
*
|
||||
* Revision 1.10 2002/01/04 13:48:54 badbytes
|
||||
* Changed unsigned short/long to uint16_t and uint32_t respectively.
|
||||
*
|
||||
* Revision 1.9 2001/12/19 08:29:00 badbytes
|
||||
* Macro DEFAULT_CIPHER now holds the default crypto algorithm
|
||||
*
|
||||
* Revision 1.8 2001/12/18 10:37:47 badbytes
|
||||
* Header files now only apply if they were not previously included from somewhere else.
|
||||
*
|
||||
* Revision 1.7 2001/12/18 07:26:47 badbytes
|
||||
* Added a new definition of onion_layer_t, depending on the byte order.
|
||||
*
|
||||
* Revision 1.6 2001/12/17 13:35:17 badbytes
|
||||
* Still writing handle_connection()
|
||||
*
|
||||
* Revision 1.5 2001/12/14 14:44:37 badbytes
|
||||
* chooselen() tested
|
||||
*
|
||||
* Revision 1.4 2001/12/14 13:31:08 badbytes
|
||||
* peel_onion() was redundant, removed it
|
||||
*
|
||||
* Revision 1.3 2001/12/14 13:14:03 badbytes
|
||||
* Split types.h into routent.h and ss.h. Keeping them all in one file created unnecesary dependencies.
|
||||
*
|
||||
* Revision 1.2 2001/12/14 12:44:47 badbytes
|
||||
* Minor modifications to reflect new paths ...
|
||||
*
|
||||
* Revision 1.1 2001/12/14 12:41:12 badbytes
|
||||
* Moved from op/ as it will be reused by other modules.
|
||||
*
|
||||
* Revision 1.1 2001/12/13 15:15:10 badbytes
|
||||
* Started coding the onion proxy.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ONION_H
|
||||
|
||||
#include <endian.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "routent.h"
|
||||
#include "version.h"
|
||||
|
||||
/* available cipher functions */
|
||||
#define ONION_CIPHER_IDENTITY 0
|
||||
#define ONION_CIPHER_DES 1
|
||||
#define ONION_CIPHER_RC4 2
|
||||
|
||||
/* default cipher function */
|
||||
#define ONION_DEFAULT_CIPHER ONION_CIPHER_DES
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int zero:1;
|
||||
int version:7;
|
||||
int backf:4;
|
||||
int forwf:4;
|
||||
uint16_t port;
|
||||
uint32_t addr;
|
||||
time_t expire;
|
||||
unsigned char keyseed[16];
|
||||
} onion_layer_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int forwf;
|
||||
unsigned int backf;
|
||||
char digest2[20]; /* second SHA output for onion_layer_t.keyseed */
|
||||
char digest3[20]; /* third SHA output for onion_layer_t.keyseed */
|
||||
|
||||
/* IVs */
|
||||
char f_iv[16];
|
||||
char b_iv[16];
|
||||
|
||||
/* cipher contexts */
|
||||
EVP_CIPHER_CTX f_ctx;
|
||||
EVP_CIPHER_CTX b_ctx;
|
||||
|
||||
} crypt_path_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
time_t expire;
|
||||
char digest[20]; /* SHA digest of the onion */
|
||||
void *prev;
|
||||
void *next;
|
||||
} tracked_onion_t;
|
||||
|
||||
/* returns an array of indexes into a router array that define a new route through the OR network
|
||||
* int cw is the coin weight to use when choosing the route
|
||||
* order of routers is from last to first */
|
||||
unsigned int *new_route(double cw, routent_t **rarray, size_t rarray_len, size_t *rlen);
|
||||
|
||||
/* creates a new onion from route, stores it and its length into bufp and lenp respectively */
|
||||
/* if cpathp not NULL then also compute the corresponding crypt_path */
|
||||
unsigned char *create_onion(routent_t **rarray, size_t rarray_len, unsigned int *route, size_t routelen, size_t *lenp, crypt_path_t **cpathp);
|
||||
|
||||
/* encrypts 128 bytes of the onion with the specified public key, the rest with
|
||||
* DES OFB with the key as defined in the outter layer */
|
||||
unsigned char *encrypt_onion(onion_layer_t *onion, uint32_t onionlen, RSA *pkey);
|
||||
|
||||
/* decrypts the onion */
|
||||
unsigned char *decrypt_onion(onion_layer_t *onion, uint32_t onionlen, RSA *prkey);
|
||||
|
||||
/* deletes the first n bytes of the onion and pads the end with n bytes of random data */
|
||||
void pad_onion(unsigned char *onion, uint32_t onionlen, size_t n);
|
||||
|
||||
/* create a new tracked_onion entry */
|
||||
tracked_onion_t *new_tracked_onion(unsigned char *onion, uint32_t onionlen, tracked_onion_t **tracked_onions, tracked_onion_t **last_tracked_onion);
|
||||
|
||||
/* delete a tracked onion entry */
|
||||
void remove_tracked_onion(tracked_onion_t *to, tracked_onion_t **tracked_onions, tracked_onion_t **last_tracked_onion);
|
||||
|
||||
/* find a tracked onion in the linked list of tracked onions */
|
||||
tracked_onion_t *id_tracked_onion(unsigned char *onion, uint32_t onionlen, tracked_onion_t *tracked_onions);
|
||||
|
||||
#define __ONION_H
|
||||
#endif
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* opcell.c
|
||||
* Onion Proxy Cell
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.1 2002/03/03 12:08:18 mp292
|
||||
* Added a new type of cell - used for data going between the onion proxy and
|
||||
* the first or hop. Payload size identical to that of a normal cell.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "opcell.h"
|
||||
#include "log.h"
|
||||
|
||||
opcell_t *new_padding_opcell()
|
||||
{
|
||||
opcell_t *c = NULL;
|
||||
int retval;
|
||||
|
||||
c = malloc(sizeof(opcell_t));
|
||||
if (!c) /* malloc() error */
|
||||
return NULL;
|
||||
|
||||
retval = RAND_pseudo_bytes((unsigned char *)c,sizeof(opcell_t));
|
||||
if (retval == -1) /* RAND_pseudo_bytes() error */
|
||||
{
|
||||
free((void *)c);
|
||||
return NULL;
|
||||
} /* RAND_pseudo_bytes() error */
|
||||
|
||||
c->command = OPCELL_PADDING;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
opcell_t *new_data_opcell(unsigned char length, unsigned char *buf)
|
||||
{
|
||||
opcell_t *c = NULL;
|
||||
int retval;
|
||||
|
||||
if ((length <= OPCELL_PAYLOAD_SIZE) && (buf)) /* valid parameters */
|
||||
{
|
||||
c = malloc(sizeof(opcell_t));
|
||||
if (!c) /* malloc() error */
|
||||
return NULL;
|
||||
|
||||
c->command = OPCELL_DATA;
|
||||
c->length = length;
|
||||
|
||||
memcpy((void *)c->payload, (void *)buf, length);
|
||||
retval = RAND_pseudo_bytes((unsigned char *)(c->payload+length),OPCELL_PAYLOAD_SIZE-length);
|
||||
if (retval == -1) /* RAND_pseudo_bytes() error */
|
||||
{
|
||||
free((void *)c);
|
||||
return NULL;
|
||||
} /* RAND_pseudo_bytes() error */
|
||||
|
||||
return c;
|
||||
} /* valid parameters */
|
||||
else /* invalid parameters */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* opcell.h
|
||||
* Onion Proxy Cell.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.1 2002/03/03 12:08:18 mp292
|
||||
* Added a new type of cell - used for data going between the onion proxy and
|
||||
* the first or hop. Payload size identical to that of a normal cell.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OPCELL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cell.h"
|
||||
|
||||
#define OPCELL_PAYLOAD_SIZE CELL_PAYLOAD_SIZE
|
||||
|
||||
#define OPCELL_PADDING 0
|
||||
#define OPCELL_DATA 1
|
||||
|
||||
/* cell definition */
|
||||
typedef struct
|
||||
{
|
||||
unsigned char command;
|
||||
unsigned char length; /* of payload */
|
||||
unsigned char payload[OPCELL_PAYLOAD_SIZE];
|
||||
} opcell_t;
|
||||
|
||||
opcell_t *new_data_opcell(unsigned char length, unsigned char *buf);
|
||||
opcell_t *new_padding_opcell();
|
||||
|
||||
#define __OPCELL_H
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* policies.h
|
||||
* Traffic shaping policies for the network funnel.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.2 2002/03/12 23:42:37 mp292
|
||||
* Various bugfixes.
|
||||
*
|
||||
* Revision 1.1 2002/03/03 00:03:49 mp292
|
||||
* Moved from or/network (merged core and network funnel into a single thread).
|
||||
*
|
||||
* Revision 1.3 2002/02/09 17:00:42 mp292
|
||||
* Added core_sock to list of parameters for comms with the router core.
|
||||
*
|
||||
* Revision 1.2 2002/02/03 22:40:44 mp292
|
||||
* Changes to cell size.
|
||||
*
|
||||
* Revision 1.1 2002/02/03 20:34:38 mp292
|
||||
* Traffic shaping policies for the network funnel.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* traffic shaping policies */
|
||||
#define POLICY_DROP_CONNECTIONS 0 /* buffer data and drop the connections that cannot be allocated resources */
|
||||
#define POLICY_DROP_CELLS 1 /* buffer data and drop cells, which can't be bufered, do re-transmission */
|
||||
|
||||
#define DEFAULT_POLICY POLICY_DROP_CONNECTIONS
|
||||
|
||||
#define DEFAULT_ACK_TIMEOUT 3000 /* ms */
|
||||
#define DEFAULT_WINDOW_SIZE 5 /* cells */
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* routent.c
|
||||
* Onion Router and related definitions.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.6 2002/04/02 14:27:11 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.5 2002/03/12 23:38:54 mp292
|
||||
* Being pedantic about some pointer conversions.
|
||||
*
|
||||
* Revision 1.4 2002/03/03 00:24:26 mp292
|
||||
* Corrected paths to some #include files.
|
||||
*
|
||||
* Revision 1.3 2002/03/03 00:06:45 mp292
|
||||
* Modifications to support re-transmission.
|
||||
*
|
||||
* Revision 1.2 2002/01/26 19:26:55 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.1 2002/01/10 08:28:33 badbytes
|
||||
* routent and routentEX related routines
|
||||
*
|
||||
*/
|
||||
|
||||
#include "policies.h"
|
||||
|
||||
#include "routent.h"
|
||||
|
||||
routentEX_t *id_router(routentEX_t **routerarray, size_t rarray_len, uint32_t addr, uint16_t port)
|
||||
{
|
||||
routentEX_t *router;
|
||||
int i;
|
||||
|
||||
if (!routerarray)
|
||||
return NULL;
|
||||
|
||||
for(i=0;i<rarray_len;i++)
|
||||
{
|
||||
router = routerarray[i];
|
||||
if ((router->addr == addr) && (router->port == port))
|
||||
return router;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
routentEX_t *id_routerbys(routentEX_t **routerarray, size_t rarray_len, int s)
|
||||
{
|
||||
routentEX_t *router;
|
||||
int i;
|
||||
|
||||
if (!routerarray)
|
||||
return NULL;
|
||||
|
||||
for(i=0;i<rarray_len;i++)
|
||||
{
|
||||
router = routerarray[i];
|
||||
if (router->s == s)
|
||||
return router;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
conn_buf_t *new_conn_buf(uint16_t aci, int policy, conn_buf_t **conn_bufs, conn_buf_t **last_conn_buf)
|
||||
{
|
||||
conn_buf_t *conn_buf;
|
||||
|
||||
if ((!aci) || (!conn_bufs) || (!last_conn_buf)) /* invalid parameters */
|
||||
return NULL;
|
||||
|
||||
conn_buf = (conn_buf_t *)malloc(sizeof(conn_buf_t));
|
||||
if (!conn_buf)
|
||||
return NULL;
|
||||
|
||||
memset((void *)conn_buf,0,sizeof(conn_buf_t));
|
||||
conn_buf->win_size = DEFAULT_WINDOW_SIZE;
|
||||
conn_buf->win_avail = DEFAULT_WINDOW_SIZE;
|
||||
conn_buf->aci = aci;
|
||||
conn_buf->policy = policy;
|
||||
|
||||
if (!*conn_bufs)
|
||||
{
|
||||
*conn_bufs = conn_buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
(*last_conn_buf)->next=(void *)conn_buf;
|
||||
conn_buf->prev = (void *)*last_conn_buf;
|
||||
}
|
||||
|
||||
*last_conn_buf = conn_buf;
|
||||
|
||||
return conn_buf;
|
||||
}
|
||||
|
||||
int remove_conn_buf(conn_buf_t *conn_buf, conn_buf_t **conn_bufs, conn_buf_t **last_conn_buf)
|
||||
{
|
||||
if ( (!conn_buf) || (!*conn_bufs) || (!*last_conn_buf) ) /* invalid parameters */
|
||||
return -1;
|
||||
|
||||
if (conn_buf->next)
|
||||
((conn_buf_t *)(conn_buf->next))->prev = conn_buf->prev;
|
||||
if (conn_buf->prev)
|
||||
((conn_buf_t *)(conn_buf->prev))->next = conn_buf->next;
|
||||
|
||||
if (conn_buf == *last_conn_buf)
|
||||
*last_conn_buf = (conn_buf_t *)conn_buf->prev;
|
||||
|
||||
if (conn_buf == *conn_bufs)
|
||||
*conn_bufs = (conn_buf_t *)conn_buf->next;
|
||||
|
||||
if (conn_buf->buf)
|
||||
free((void *)conn_buf->buf);
|
||||
|
||||
free((void *)conn_buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
conn_buf_t *id_conn_buf(conn_buf_t *conn_bufs, uint16_t aci)
|
||||
{
|
||||
conn_buf_t *conn_buf;
|
||||
|
||||
if ( (!aci) || (!conn_bufs) )
|
||||
return NULL;
|
||||
|
||||
conn_buf = conn_bufs;
|
||||
while (conn_buf)
|
||||
{
|
||||
if (conn_buf->aci == aci)
|
||||
return conn_buf;
|
||||
|
||||
conn_buf = conn_buf->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* routent.h
|
||||
* Onion Router and related definitions.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.25 2002/04/02 14:27:11 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.24 2002/03/29 09:54:19 badbytes
|
||||
* Fixed type of routentEX.min_interval to struct timeval.
|
||||
*
|
||||
* Revision 1.23 2002/03/21 07:20:59 badbytes
|
||||
* Added a dependency to <sys/time.h>.
|
||||
*
|
||||
* Revision 1.22 2002/03/12 23:37:14 mp292
|
||||
* Additional flag - destory_buf saying whether the buffer should be destroyed
|
||||
* when the destroy cell is sent.
|
||||
*
|
||||
* Revision 1.21 2002/03/03 00:06:45 mp292
|
||||
* Modifications to support re-transmission.
|
||||
*
|
||||
* Revision 1.20 2002/02/09 16:58:53 mp292
|
||||
* Postponed implementtion of POLICY_DROP_CONNECTIONS due to problems. Need to
|
||||
* discuss with Andrei first.
|
||||
*
|
||||
* Revision 1.19 2002/02/09 16:54:59 mp292
|
||||
* routentEX now contains a per anonymous connection packet count
|
||||
*
|
||||
* Revision 1.18 2002/01/29 00:59:16 mp292
|
||||
* Slight changes in the way timers are kept, c.f. changes in the network funnel.
|
||||
*
|
||||
* Revision 1.17 2002/01/28 21:37:36 mp292
|
||||
* Router's output buffer is now dynamic. Time of last output to the router
|
||||
* added to routentEX.
|
||||
*
|
||||
* Revision 1.16 2002/01/26 19:26:55 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.15 2002/01/18 22:55:40 mp292
|
||||
* Added a cell buffer to struct routent so that a cell can be received in
|
||||
* several bursts of data. This prevents a DoS attack on the network funnel.
|
||||
*
|
||||
* Revision 1.14 2002/01/14 13:05:37 badbytes
|
||||
* System testing in progress.
|
||||
*
|
||||
* Revision 1.13 2002/01/11 15:47:17 badbytes
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.12 2002/01/10 08:28:33 badbytes
|
||||
* routent and routentEX related routines
|
||||
*
|
||||
* Revision 1.11 2002/01/08 15:13:30 badbytes
|
||||
* Added cipher context to routentEX
|
||||
*
|
||||
* Revision 1.10 2002/01/08 13:18:48 badbytes
|
||||
* Added a connection buffer to routentEX
|
||||
*
|
||||
* Revision 1.9 2002/01/08 13:02:16 badbytes
|
||||
* routentEX now contains f_key and b_key, 56-bit DES keys for link encryption
|
||||
*
|
||||
* Revision 1.8 2002/01/03 11:17:01 badbytes
|
||||
* routentEX.max and routentEX.min values changed to 32bit not 64bit.
|
||||
*
|
||||
* Revision 1.7 2002/01/03 11:04:16 badbytes
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.6 2002/01/03 11:03:14 badbytes
|
||||
* Added an extended version of routent which includes link utilisation info.
|
||||
*
|
||||
* Revision 1.5 2001/12/18 15:26:34 badbytes
|
||||
* Added #inclusion of <stdint.h>
|
||||
*
|
||||
* Revision 1.4 2001/12/18 15:19:41 badbytes
|
||||
* In struct routent, changed long and short types to uint32_t and uint16_t
|
||||
*
|
||||
* Revision 1.3 2001/12/18 10:37:47 badbytes
|
||||
* Header files now only apply if they were not previously included from somewhere else.
|
||||
*
|
||||
* Revision 1.2 2001/12/17 13:35:17 badbytes
|
||||
* Still writing handle_connection()
|
||||
*
|
||||
* Revision 1.1 2001/12/14 13:14:03 badbytes
|
||||
* Split types.h into routent.h and ss.h. Keeping them all in one file created unnecesary dependencies.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ROUTENT_H
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <sys/timeb.h>
|
||||
|
||||
#include "cell.h"
|
||||
|
||||
/* per-anonymous-connection cell buffer */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t aci;
|
||||
int policy;
|
||||
unsigned int cells;
|
||||
unsigned char *buf;
|
||||
unsigned int buflen;
|
||||
unsigned int offset; /* offset to the position of the first cell in the buffer */
|
||||
cell_t dc; /* static buffer for the destroy cell - so we are always able to destroy a connection */
|
||||
unsigned char dc_set; /* flag that signifies presence of a destroy cell */
|
||||
unsigned char destroy_buf; /* flag that signifies that the buffer shuld be destroyed when the destroy cell is sent */
|
||||
|
||||
/* POLICY_DROP_CELLS only */
|
||||
unsigned int win_size; /* window size for the connection (number of cells)*/
|
||||
unsigned int win_avail; /* available window size */
|
||||
uint32_t seq_out; /* next sequence number to use for outgoing cells */
|
||||
uint32_t seq_in; /* next expected sequence number */
|
||||
uint32_t ack; /* next expected ack/nack */
|
||||
struct timeval last_ack; /* time of last ACK/NACK */
|
||||
|
||||
void *prev;
|
||||
void *next;
|
||||
} conn_buf_t;
|
||||
|
||||
/* onion router as seen by the onion proxy */
|
||||
typedef struct
|
||||
{
|
||||
char *address;
|
||||
uint32_t addr; /* address in network byte order */
|
||||
uint16_t port; /* network port in network byte order */
|
||||
uint16_t entry_port; /* entry port in network byte order */
|
||||
RSA *pkey;
|
||||
void *next;
|
||||
} routent_t;
|
||||
|
||||
/* onion router as seen by other routers */
|
||||
typedef struct
|
||||
{
|
||||
char *address;
|
||||
|
||||
uint32_t addr;
|
||||
uint16_t port;
|
||||
|
||||
RSA *pkey; /* public RSA key */
|
||||
/* 64-bit DES keys for link encryption */
|
||||
char f_key[8];
|
||||
char b_key[8];
|
||||
char f_iv[8];
|
||||
char b_iv[8];
|
||||
EVP_CIPHER_CTX f_ctx;
|
||||
EVP_CIPHER_CTX b_ctx;
|
||||
|
||||
/* link info */
|
||||
uint32_t min;
|
||||
uint32_t max;
|
||||
struct timeval min_interval;
|
||||
|
||||
/* time when last data was sent to that router */
|
||||
struct timeval lastsend;
|
||||
|
||||
/* socket */
|
||||
int s;
|
||||
|
||||
/* connection buffers */
|
||||
conn_buf_t *conn_bufs; /* linked list of connection buffers */
|
||||
conn_buf_t *last_conn_buf; /* last item in the list */
|
||||
unsigned int next_to_service; /* offset to the connection buffer that is next in turn to be serviced */
|
||||
|
||||
/* cell buffer */
|
||||
unsigned char cellbuf[128];
|
||||
unsigned int celllen;
|
||||
|
||||
void *next;
|
||||
} routentEX_t;
|
||||
|
||||
routentEX_t *id_router(routentEX_t **routerarray, size_t rarray_len, uint32_t addr, uint16_t port);
|
||||
routentEX_t *id_routerbys(routentEX_t **routerarray, size_t rarray_len, int s);
|
||||
|
||||
conn_buf_t *new_conn_buf(uint16_t aci, int policy, conn_buf_t **conn_bufs, conn_buf_t **last_conn_buf);
|
||||
int remove_conn_buf(conn_buf_t *conn_buf, conn_buf_t **conn_bufs, conn_buf_t **last_conn_buf);
|
||||
conn_buf_t *id_conn_buf(conn_buf_t *conn_bufs, uint16_t aci);
|
||||
|
||||
#define __ROUTENT_H
|
||||
#endif
|
||||
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* scheduler.c
|
||||
* Scheduler
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.3 2002/04/02 10:20:37 badbytes
|
||||
* Bug fixes.
|
||||
*
|
||||
* Revision 1.2 2002/03/28 10:49:07 badbytes
|
||||
* Renamed get_trigger() to sched_trigger().
|
||||
*
|
||||
* Revision 1.1 2002/03/28 10:36:55 badbytes
|
||||
* A generic scheduler.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <malloc.h>
|
||||
#include "log.h"
|
||||
#include "scheduler.h"
|
||||
|
||||
/* create a new scheduler */
|
||||
sched_t *new_sched()
|
||||
{
|
||||
sched_t *sched;
|
||||
|
||||
sched = (sched_t *)malloc(sizeof(sched_t));
|
||||
if (!sched)
|
||||
return NULL;
|
||||
|
||||
sched->entries = NULL;
|
||||
return sched;
|
||||
}
|
||||
|
||||
/* delete a scheduler from memory */
|
||||
void free_sched(sched_t *sched)
|
||||
{
|
||||
sched_entry_t *entry;
|
||||
if (!sched)
|
||||
return;
|
||||
|
||||
while(sched->entries)
|
||||
{
|
||||
entry = (sched_entry_t *)sched->entries->next;
|
||||
free((void *)sched->entries);
|
||||
sched->entries = entry;
|
||||
}
|
||||
}
|
||||
|
||||
/* add a new item to the scheduler */
|
||||
int add_sched_entry(sched_t *sched, struct timeval last, struct timeval interval)
|
||||
{
|
||||
sched_entry_t *new_entry;
|
||||
sched_entry_t *prev;
|
||||
sched_entry_t *next;
|
||||
|
||||
if (!sched) /* invalid parameters */
|
||||
return -1;
|
||||
|
||||
new_entry = (sched_entry_t *)malloc(sizeof(sched_entry_t));
|
||||
if (!new_entry)
|
||||
return -1;
|
||||
|
||||
new_entry->last = last;
|
||||
new_entry->interval = interval;
|
||||
|
||||
if (!sched->entries) /* empty list */
|
||||
{
|
||||
sched->entries = new_entry;
|
||||
new_entry->prev = NULL;
|
||||
new_entry->next = NULL;
|
||||
}
|
||||
else /* maintain a priority queue of items */
|
||||
{
|
||||
/* find the next largest element in the list */
|
||||
next = sched->entries;
|
||||
while(next)
|
||||
{
|
||||
if (sched_entry_geq(next->last, next->interval, last, interval))
|
||||
{
|
||||
prev = (sched_entry_t *)next->prev;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev = next;
|
||||
next = (sched_entry_t *)next->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (prev)
|
||||
prev->next = (void *)new_entry;
|
||||
else
|
||||
sched->entries = new_entry;
|
||||
|
||||
if (next)
|
||||
next->prev = (void *)new_entry;
|
||||
|
||||
new_entry->prev = (void *)prev;
|
||||
new_entry->next = (void *)next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int remove_sched_entry(sched_t *sched, struct timeval last, struct timeval interval)
|
||||
{
|
||||
sched_entry_t *entry;
|
||||
|
||||
if (!sched)
|
||||
return -1;
|
||||
|
||||
if (!sched->entries)
|
||||
return -1;
|
||||
|
||||
entry = sched->entries;
|
||||
while(entry)
|
||||
{
|
||||
if ((entry->last.tv_sec == last.tv_sec) && (entry->last.tv_usec = last.tv_usec) && (entry->interval.tv_sec == interval.tv_sec) && (entry->interval.tv_usec == interval.tv_usec))
|
||||
{
|
||||
if (entry->prev)
|
||||
((sched_entry_t *)(entry->prev))->next = entry->next;
|
||||
else
|
||||
sched->entries = (sched_entry_t *)entry->next;
|
||||
|
||||
if (entry->next)
|
||||
((sched_entry_t *)(entry->next))->prev = entry->prev;
|
||||
|
||||
free((void *)entry);
|
||||
break;
|
||||
}
|
||||
else
|
||||
entry = (sched_entry_t *)entry->next;
|
||||
}
|
||||
|
||||
if (entry) /* found and deleted */
|
||||
return 0;
|
||||
else /* not found */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* update an existing item with new values */
|
||||
int update_sched_entry(sched_t *sched, struct timeval old_last, struct timeval old_interval, struct timeval new_last, struct timeval new_interval)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (!sched)
|
||||
return -1;
|
||||
|
||||
/* remove the old entry first */
|
||||
retval = remove_sched_entry(sched, old_last, old_interval);
|
||||
if (!retval)
|
||||
{
|
||||
/* add the new one */
|
||||
retval = add_sched_entry(sched, new_last, new_interval);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* get the time interval from now until the next time an item needs to be serviced */
|
||||
int sched_trigger(sched_t *sched, struct timeval **result)
|
||||
{
|
||||
int retval;
|
||||
struct timeval *result_val;
|
||||
struct timeval now;
|
||||
struct timeval next;
|
||||
|
||||
if (!sched) /* invalid parameters */
|
||||
return -1;
|
||||
|
||||
if (!sched->entries) /* no entries */
|
||||
{
|
||||
*result = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* take the minimum element in the queue and calculate its next service time */
|
||||
next.tv_sec = sched->entries->last.tv_sec + sched->entries->interval.tv_sec;
|
||||
if (sched->entries->last.tv_usec + sched->entries->interval.tv_usec <= 999999)
|
||||
next.tv_usec = sched->entries->last.tv_usec + sched->entries->interval.tv_usec;
|
||||
else
|
||||
{
|
||||
next.tv_sec++;
|
||||
next.tv_usec = sched->entries->last.tv_usec + sched->entries->interval.tv_usec - 1000000;
|
||||
}
|
||||
|
||||
/* get current time */
|
||||
retval = gettimeofday(&now,NULL);
|
||||
if (retval == -1)
|
||||
return -1;
|
||||
|
||||
/* allocate memory for the result */
|
||||
result_val = (struct timeval *)malloc(sizeof(struct timeval));
|
||||
if (!result_val)
|
||||
return -1;
|
||||
|
||||
/* subtract now from next (return zero if negative) */
|
||||
if ((next.tv_sec > now.tv_sec) || ((next.tv_sec == now.tv_sec) && (next.tv_usec >= now.tv_usec)))
|
||||
{
|
||||
result_val->tv_sec = next.tv_sec - now.tv_sec;
|
||||
if (next.tv_usec >= now.tv_usec)
|
||||
result_val->tv_usec = next.tv_usec - now.tv_usec;
|
||||
else
|
||||
{
|
||||
result_val->tv_sec--;
|
||||
result_val->tv_usec = 1000000 + next.tv_usec - now.tv_usec;
|
||||
}
|
||||
}
|
||||
else /* next service time has already passed, return a timeout of zero */
|
||||
{
|
||||
result_val->tv_sec = 0;
|
||||
result_val->tv_usec = 0;
|
||||
}
|
||||
|
||||
*result = result_val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sched_entry_geq(struct timeval last1, struct timeval interval1, struct timeval last2, struct timeval interval2)
|
||||
{
|
||||
struct timeval next1;
|
||||
struct timeval next2;
|
||||
|
||||
/* calculate next service time for entry1 */
|
||||
next1.tv_sec = last1.tv_sec + interval1.tv_sec;
|
||||
if (last1.tv_usec + interval1.tv_usec <= 999999)
|
||||
next1.tv_usec = last1.tv_usec + interval1.tv_usec;
|
||||
else
|
||||
{
|
||||
next1.tv_sec++;
|
||||
next1.tv_usec = last1.tv_usec + interval1.tv_usec - 1000000;
|
||||
}
|
||||
|
||||
/* calculate next service time for entry2 */
|
||||
next2.tv_sec = last2.tv_sec + interval2.tv_sec;
|
||||
if (last2.tv_usec + interval2.tv_usec <= 999999)
|
||||
next2.tv_usec = last2.tv_usec + interval2.tv_usec;
|
||||
else
|
||||
{
|
||||
next2.tv_sec++;
|
||||
next2.tv_usec = last2.tv_usec + interval2.tv_usec - 1000000;
|
||||
}
|
||||
|
||||
/* compare */
|
||||
if ((next1.tv_sec > next2.tv_sec) || ((next1.tv_sec == next2.tv_sec) && (next1.tv_usec >= next2.tv_usec)))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* scheduler.h
|
||||
* Scheduler
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.2 2002/03/28 10:49:07 badbytes
|
||||
* Renamed get_trigger() to sched_trigger().
|
||||
*
|
||||
* Revision 1.1 2002/03/28 10:36:55 badbytes
|
||||
* A generic scheduler.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SCHEDULER_H
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct timeval last;
|
||||
struct timeval interval;
|
||||
void *prev;
|
||||
void *next;
|
||||
} sched_entry_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
sched_entry_t *entries;
|
||||
} sched_t;
|
||||
|
||||
/* create a new scheduler */
|
||||
sched_t *new_sched();
|
||||
/* delete a scheduler from memory */
|
||||
void free_sched(sched_t *sched);
|
||||
|
||||
/* add a new item to the scheduler */
|
||||
int add_sched_entry(sched_t *sched, struct timeval last, struct timeval interval);
|
||||
/* remove an item from the scheduler */
|
||||
int remove_sched_entry(sched_t *sched, struct timeval last, struct timeval interval);
|
||||
/* update an existing item with new values */
|
||||
int update_sched_entry(sched_t *sched, struct timeval old_last, struct timeval old_interval, struct timeval new_last, struct timeval new_interval);
|
||||
|
||||
/* get the time interval from now until the next time an item needs to be serviced */
|
||||
int sched_trigger(sched_t *sched, struct timeval **result);
|
||||
/* compare two scheduler entries (returns 1 if entry1 >= entry2, 0 otherwise */
|
||||
int sched_entry_geq(struct timeval last1, struct timeval interval1, struct timeval last2, struct timeval interval2);
|
||||
|
||||
# define __SCHEDULER_H
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* ss.h
|
||||
* Standard structure and related definitions.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.5 2002/04/02 14:27:11 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.4 2002/01/26 22:45:34 mp292
|
||||
* Added ss-related error codes.
|
||||
*
|
||||
* Revision 1.3 2002/01/26 19:30:09 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.2 2001/12/18 10:37:47 badbytes
|
||||
* Header files now only apply if they were not previously included from somewhere else.
|
||||
*
|
||||
* Revision 1.1 2001/12/14 13:14:03 badbytes
|
||||
* Split types.h into routent.h and ss.h. Keeping them all in one file created unnecesary dependencies.
|
||||
*
|
||||
* Revision 1.2 2001/12/11 16:31:03 badbytes
|
||||
* Changed type from ss to SS.
|
||||
*
|
||||
* Revision 1.1 2001/12/07 11:15:28 badbytes
|
||||
* Added the definition for the standard structure.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SS_H
|
||||
|
||||
/* protocol types, as used in the standard structure */
|
||||
#define SS_PROTOCOL_TELNET 1
|
||||
#define SS_PROTOCOL_HTTP 2
|
||||
#define SS_PROTOCOL_SMTP 3
|
||||
|
||||
/* address format types, as used in the standard structure */
|
||||
#define SS_ADDR_FMT_ASCII_HOST_PORT 1
|
||||
|
||||
/* error codes returned by the onion proxy */
|
||||
#define SS_ERROR_SUCCESS 0
|
||||
#define SS_ERROR_VERSION_UNSUPPORTED 1
|
||||
#define SS_ERROR_ADDR_FMT_UNSUPPORTED 2
|
||||
#define SS_ERROR_INVALID_ADDRESS 3
|
||||
#define SS_ERROR_INVALID_PORT 4
|
||||
|
||||
/* standard structure */
|
||||
typedef struct
|
||||
{
|
||||
unsigned char version; /* version */
|
||||
unsigned char protocol; /* protocol */
|
||||
unsigned char retry_count; /* retry count */
|
||||
unsigned char addr_fmt; /* address format */
|
||||
} ss_t;
|
||||
#define __SS_H
|
||||
#endif
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* utils.c
|
||||
* Miscellaneous utils.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.6 2002/03/03 00:06:45 mp292
|
||||
* Modifications to support re-transmission.
|
||||
*
|
||||
* Revision 1.5 2002/01/29 02:22:41 mp292
|
||||
* Bugfix.
|
||||
*
|
||||
* Revision 1.4 2002/01/29 00:58:23 mp292
|
||||
* Timeout parametes to read_tout() and write_tout() are now pointers.
|
||||
*
|
||||
* Revision 1.3 2002/01/27 19:24:16 mp292
|
||||
* Added read_tout(), write_tout() which read/write from a blocking socket but
|
||||
* impose a timeout on the I/O operation.
|
||||
*
|
||||
* Revision 1.2 2002/01/26 19:30:09 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.1 2001/12/14 09:18:00 badbytes
|
||||
* *** empty log message ***
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "log.h"
|
||||
|
||||
/* converts string to lower case */
|
||||
unsigned char *stolower(unsigned char *str)
|
||||
{
|
||||
int i=0;
|
||||
|
||||
if (str) /* valid parameters */
|
||||
{
|
||||
for (i=0; str[i] != 0; i++)
|
||||
str[i] = tolower(str[i]);
|
||||
|
||||
return str;
|
||||
}
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
/* reads data from a descriptor, just like read(), but imposes a timeout */
|
||||
/* the timeout refers to the connection being idle, not to a time limit in which the data
|
||||
* should be received*/
|
||||
int read_tout(int s, unsigned char *buf, size_t buflen, int flags, struct timeval *conn_tout)
|
||||
{
|
||||
int retval=0;
|
||||
int received = 0;
|
||||
struct timeval tout;
|
||||
|
||||
fd_set mask,rmask;
|
||||
|
||||
FD_ZERO(&mask);
|
||||
FD_SET(s,&mask);
|
||||
|
||||
while(1)
|
||||
{
|
||||
rmask=mask;
|
||||
tout = *conn_tout;
|
||||
retval = select(s+1,&rmask,NULL,NULL,&tout);
|
||||
if (retval == -1)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (FD_ISSET(s,&rmask))
|
||||
{
|
||||
retval = read(s,buf+received,buflen-received);
|
||||
if (retval <= 0)
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
received += retval;
|
||||
if ((received < buflen) && (flags == MSG_WAITALL))
|
||||
continue;
|
||||
else
|
||||
return received;
|
||||
}
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* writes data to a file descriptor, just like write(), but imposes a timeout */
|
||||
/* again this refers to the connection being idle, not a time limit in which the data should
|
||||
* be sent */
|
||||
int write_tout(int s, unsigned char *buf, size_t buflen, struct timeval *conn_tout)
|
||||
{
|
||||
int retval = 0;
|
||||
int sent = 0;
|
||||
fd_set mask,wmask;
|
||||
struct timeval tout;
|
||||
|
||||
FD_ZERO(&mask);
|
||||
FD_SET(s,&mask);
|
||||
|
||||
while(1)
|
||||
{
|
||||
wmask = mask;
|
||||
tout = *conn_tout;
|
||||
retval = select(s+1,NULL,&wmask,NULL, &tout);
|
||||
if (retval == -1)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (FD_ISSET(s,&wmask))
|
||||
{
|
||||
retval = write(s,buf+sent,buflen-sent);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
sent += retval;
|
||||
if (sent < buflen)
|
||||
continue;
|
||||
else
|
||||
return sent;
|
||||
}
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* utils.h
|
||||
* Miscellaneous utils.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.8 2002/03/21 07:20:59 badbytes
|
||||
* Added a dependency to <sys/time.h>.
|
||||
*
|
||||
* Revision 1.7 2002/03/03 00:06:45 mp292
|
||||
* Modifications to support re-transmission.
|
||||
*
|
||||
* Revision 1.6 2002/01/29 02:22:41 mp292
|
||||
* Bugfix.
|
||||
*
|
||||
* Revision 1.5 2002/01/29 00:58:23 mp292
|
||||
* Timeout parametes to read_tout() and write_tout() are now pointers.
|
||||
*
|
||||
* Revision 1.4 2002/01/27 19:24:16 mp292
|
||||
* Added read_tout(), write_tout() which read/write from a blocking socket but
|
||||
* impose a timeout on the I/O operation.
|
||||
*
|
||||
* Revision 1.3 2002/01/26 19:30:09 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.2 2001/12/18 10:37:47 badbytes
|
||||
* Header files now only apply if they were not previously included from somewhere else.
|
||||
*
|
||||
* Revision 1.1 2001/12/14 09:18:00 badbytes
|
||||
* *** empty log message ***
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __UTILS_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
unsigned char *stolower(unsigned char *str);
|
||||
int read_tout(int s, unsigned char *buf, size_t buflen, int flags, struct timeval *conn_tout);
|
||||
int write_tout(int s, unsigned char *buf, size_t buflen, struct timeval *conn_tout);
|
||||
|
||||
#define __UTILS_H
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* version.h
|
||||
* Protocol version.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.3 2002/04/02 14:27:11 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.2 2001/12/18 10:37:47 badbytes
|
||||
* Header files now only apply if they were not previously included from somewhere else.
|
||||
*
|
||||
* Revision 1.1 2001/12/18 09:12:05 badbytes
|
||||
* Defines VERSION to hold the current protocol version.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __VERSION_H
|
||||
#define VERSION 2
|
||||
#define __VERSION_H
|
||||
#endif
|
||||
@@ -0,0 +1,99 @@
|
||||
SRC=httpap.c http.c
|
||||
OBJ=${SRC:.c=.o}
|
||||
PROGS=httpap
|
||||
LIB=
|
||||
LIBS=
|
||||
INCLUDE =
|
||||
|
||||
CFLAGS= $(INCLUDE) -Wall -Wpointer-arith -O2 -ggdb
|
||||
LDFLAGS = $(LIB) $(LIBS)
|
||||
|
||||
all: ${PROGS}
|
||||
|
||||
clean:
|
||||
rm -f *.o ${PROGS}
|
||||
|
||||
depend:
|
||||
makedepend -- ${CFLAGS} -- ${SRC}
|
||||
|
||||
httpap: ${OBJ}
|
||||
$(LINK.c) -o $@ $(OBJ) ../common/log.o ../common/config.o ../common/utils.o
|
||||
|
||||
# DO NOT DELETE
|
||||
|
||||
|
||||
httpap.o: ../common/config.h ../common/log.h ../common/ss.h ../common/utils.h
|
||||
httpap.o: ../common/version.h httpap.h http.h /usr/include/alloca.h
|
||||
httpap.o: /usr/include/arpa/inet.h /usr/include/asm/errno.h
|
||||
httpap.o: /usr/include/asm/sigcontext.h /usr/include/asm/socket.h
|
||||
httpap.o: /usr/include/asm/sockios.h /usr/include/bits/byteswap.h
|
||||
httpap.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
|
||||
httpap.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
|
||||
httpap.o: /usr/include/bits/in.h /usr/include/bits/local_lim.h
|
||||
httpap.o: /usr/include/bits/netdb.h /usr/include/bits/posix1_lim.h
|
||||
httpap.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
|
||||
httpap.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/resource.h
|
||||
httpap.o: /usr/include/bits/sched.h /usr/include/bits/select.h
|
||||
httpap.o: /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h
|
||||
httpap.o: /usr/include/bits/siginfo.h /usr/include/bits/signum.h
|
||||
httpap.o: /usr/include/bits/sigset.h /usr/include/bits/sigstack.h
|
||||
httpap.o: /usr/include/bits/sigthread.h /usr/include/bits/sockaddr.h
|
||||
httpap.o: /usr/include/bits/socket.h /usr/include/bits/stdio_lim.h
|
||||
httpap.o: /usr/include/bits/time.h /usr/include/bits/types.h
|
||||
httpap.o: /usr/include/bits/uio.h /usr/include/bits/waitflags.h
|
||||
httpap.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
|
||||
httpap.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
|
||||
httpap.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
|
||||
httpap.o: /usr/include/features.h /usr/include/_G_config.h
|
||||
httpap.o: /usr/include/gconv.h /usr/include/getopt.h /usr/include/gnu/stubs.h
|
||||
httpap.o: /usr/include/libio.h /usr/include/limits.h
|
||||
httpap.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
|
||||
httpap.o: /usr/include/netdb.h /usr/include/netinet/in.h
|
||||
httpap.o: /usr/include/rpc/netdb.h /usr/include/signal.h /usr/include/stdint.h
|
||||
httpap.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
|
||||
httpap.o: /usr/include/sys/cdefs.h /usr/include/syslog.h
|
||||
httpap.o: /usr/include/sys/resource.h /usr/include/sys/select.h
|
||||
httpap.o: /usr/include/sys/socket.h /usr/include/sys/syslog.h
|
||||
httpap.o: /usr/include/sys/sysmacros.h /usr/include/sys/time.h
|
||||
httpap.o: /usr/include/sys/types.h /usr/include/sys/ucontext.h
|
||||
httpap.o: /usr/include/sys/uio.h /usr/include/sys/un.h /usr/include/sys/wait.h
|
||||
httpap.o: /usr/include/time.h /usr/include/ucontext.h /usr/include/unistd.h
|
||||
httpap.o: /usr/include/wait.h /usr/include/wchar.h /usr/include/xlocale.h
|
||||
httpap.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
|
||||
httpap.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
httpap.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
httpap.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
|
||||
http.o: ../common/log.h ../common/utils.h http.h /usr/include/alloca.h
|
||||
http.o: /usr/include/arpa/inet.h /usr/include/asm/errno.h
|
||||
http.o: /usr/include/asm/socket.h /usr/include/asm/sockios.h
|
||||
http.o: /usr/include/bits/byteswap.h /usr/include/bits/confname.h
|
||||
http.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
|
||||
http.o: /usr/include/bits/errno.h /usr/include/bits/in.h
|
||||
http.o: /usr/include/bits/local_lim.h /usr/include/bits/netdb.h
|
||||
http.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
|
||||
http.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
|
||||
http.o: /usr/include/bits/sched.h /usr/include/bits/select.h
|
||||
http.o: /usr/include/bits/siginfo.h /usr/include/bits/sigset.h
|
||||
http.o: /usr/include/bits/sockaddr.h /usr/include/bits/socket.h
|
||||
http.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
|
||||
http.o: /usr/include/bits/types.h /usr/include/bits/uio.h
|
||||
http.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
|
||||
http.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
|
||||
http.o: /usr/include/bits/xopen_lim.h /usr/include/ctype.h
|
||||
http.o: /usr/include/endian.h /usr/include/errno.h /usr/include/features.h
|
||||
http.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
|
||||
http.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
|
||||
http.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
|
||||
http.o: /usr/include/netdb.h /usr/include/netinet/in.h
|
||||
http.o: /usr/include/rpc/netdb.h /usr/include/stdint.h /usr/include/stdio.h
|
||||
http.o: /usr/include/stdlib.h /usr/include/string.h /usr/include/sys/cdefs.h
|
||||
http.o: /usr/include/syslog.h /usr/include/sys/select.h
|
||||
http.o: /usr/include/sys/socket.h /usr/include/sys/syslog.h
|
||||
http.o: /usr/include/sys/sysmacros.h /usr/include/sys/time.h
|
||||
http.o: /usr/include/sys/types.h /usr/include/sys/uio.h /usr/include/sys/un.h
|
||||
http.o: /usr/include/time.h /usr/include/unistd.h /usr/include/wchar.h
|
||||
http.o: /usr/include/xlocale.h
|
||||
http.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
|
||||
http.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
http.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
http.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* http.c
|
||||
* HTTP parsers.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.2 2002/04/02 14:27:33 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.1 2002/03/12 23:46:14 mp292
|
||||
* HTTP-related routines.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../common/log.h"
|
||||
#include "../common/utils.h"
|
||||
|
||||
#include "http.h"
|
||||
|
||||
int http_get_line(int s, unsigned char **line, size_t *len, struct timeval *conn_tout)
|
||||
{
|
||||
int retval =0; /* function return value */
|
||||
unsigned char buf[HTTPAP_MAXLEN]; /* line buffer */
|
||||
unsigned int buflen = 0; /* length of the received data */
|
||||
char got_cr = 0; /* received a CR character and hence expecting a LF */
|
||||
unsigned char c; /* input character */
|
||||
|
||||
if (!line || !len) /* invalid parameters */
|
||||
return -1;
|
||||
|
||||
while(1)
|
||||
{
|
||||
retval = read_tout(s, &c, 1, MSG_WAITALL, conn_tout);
|
||||
if (retval < 1)
|
||||
return -1;
|
||||
|
||||
if (buflen >= HTTPAP_MAXLEN)
|
||||
return -1;
|
||||
|
||||
buf[buflen++] = c;
|
||||
|
||||
if (got_cr)
|
||||
{
|
||||
if (c != HTTPAP_LF)
|
||||
return -1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c == HTTPAP_CR)
|
||||
got_cr = 1;
|
||||
}
|
||||
}
|
||||
|
||||
*len = buflen;
|
||||
if (buflen)
|
||||
{
|
||||
*line = (unsigned char *)malloc(buflen+1);
|
||||
if (!*line)
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
memcpy((void *)*line,(void *)buf,buflen);
|
||||
(*line)[buflen] = 0; /* add the terminating null character */
|
||||
}
|
||||
}
|
||||
else
|
||||
*line = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int http_get_version(unsigned char *rl, unsigned char **http_ver)
|
||||
{
|
||||
unsigned char *start;
|
||||
unsigned char *end;
|
||||
|
||||
if (!rl || !http_ver) /* invalid parameters */
|
||||
return -1;
|
||||
|
||||
start = strrchr(rl, ' ');
|
||||
if (!start)
|
||||
return -1;
|
||||
|
||||
end = strrchr(rl, HTTPAP_CR);
|
||||
if (!end)
|
||||
return -1;
|
||||
|
||||
start++;
|
||||
*http_ver = (unsigned char *)malloc(end-start+1);
|
||||
if (!*http_ver)
|
||||
return -1;
|
||||
|
||||
strncpy(*http_ver, start, end-start);
|
||||
(*http_ver)[end-start] = 0; /* terminating NULL character */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int http_get_dest(unsigned char *rl, unsigned char **addr, unsigned char **port)
|
||||
{
|
||||
unsigned char *start;
|
||||
unsigned char *end;
|
||||
unsigned char *colon;
|
||||
|
||||
if (!rl || !addr || !port) /* invalid parameters */
|
||||
return -1;
|
||||
|
||||
start = strchr(rl, ' ');
|
||||
if (!start)
|
||||
return -1;
|
||||
start++;
|
||||
/* make sure this is really an http:// address */
|
||||
if (strncmp(start,"http://",7))
|
||||
return -1;
|
||||
|
||||
start += 7;
|
||||
|
||||
end = strchr(start,'/');
|
||||
if (!end)
|
||||
return -1;
|
||||
|
||||
/* check for a :port in the address */
|
||||
colon = strchr(start,':');
|
||||
if (colon)
|
||||
{
|
||||
colon++;
|
||||
*port = (unsigned char *)malloc(end-colon+1);
|
||||
if (!*port)
|
||||
return -1;
|
||||
strncpy(*port,colon, end-colon);
|
||||
(*port)[end-colon] = 0; /* terminating NULL character */
|
||||
end = colon-1;
|
||||
}
|
||||
else
|
||||
*port = NULL;
|
||||
|
||||
/* extract the server address */
|
||||
*addr = (unsigned char *)malloc(end-start+1);
|
||||
if (!*addr)
|
||||
{
|
||||
if (*port)
|
||||
free((void *)*port);
|
||||
return -1;
|
||||
}
|
||||
strncpy(*addr,start, end-start);
|
||||
(*addr)[end-start] = 0; /* terminating NULL character */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int http_get_header_name(unsigned char *rl, unsigned char **hname)
|
||||
{
|
||||
unsigned char *end;
|
||||
|
||||
if (!rl || !hname) /* invalid parameters */
|
||||
return -1;
|
||||
|
||||
end = strchr(rl, ':');
|
||||
if (!end)
|
||||
return -1;
|
||||
|
||||
*hname = (unsigned char *)malloc(end-rl+1);
|
||||
if (!*hname)
|
||||
return -1;
|
||||
|
||||
strncpy(*hname,rl,end-rl);
|
||||
(*hname)[end-rl] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* http.h
|
||||
* HTTP parsers.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.2 2002/04/02 14:27:33 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.1 2002/03/12 23:46:14 mp292
|
||||
* HTTP-related routines.
|
||||
*
|
||||
*/
|
||||
|
||||
#define HTTPAP_MAXLEN 1024 /* maximum length of a line */
|
||||
|
||||
#define HTTPAP_CR '\015'
|
||||
#define HTTPAP_LF '\012'
|
||||
#define HTTPAP_CRLF "\015\012"
|
||||
|
||||
#define HTTPAP_VERSION "HTTP/1.0"
|
||||
|
||||
#define HTTPAP_STATUS_LINE_FORBIDDEN HTTPAP_VERSION " 403 Only local connections are allowed." HTTPAP_CRLF
|
||||
#define HTTPAP_STATUS_LINE_VERSION_NOT_SUPPORTED HTTPAP_VERSION " 505 Only HTTP/1.0 is supported." HTTPAP_CRLF
|
||||
#define HTTPAP_STATUS_LINE_UNAVAILABLE HTTPAP_VERSION " 503 Connection to the server failed." HTTPAP_CRLF
|
||||
#define HTTPAP_STATUS_LINE_BAD_REQUEST HTTPAP_VERSION " 400 Invalid syntax." HTTPAP_CRLF
|
||||
#define HTTPAP_STATUS_LINE_UNEXPECTED HTTPAP_VERSION " 500 Internal server error." HTTPAP_CRLF
|
||||
|
||||
#define HTTPAP_HEADER_PROXY_CONNECTION "Proxy-Connection"
|
||||
#define HTTPAP_HEADER_USER_AGENT "User-Agent"
|
||||
#define HTTPAP_HEADER_REFERER "Referer"
|
||||
|
||||
int http_get_line(int s, unsigned char **line, size_t *len, struct timeval *conn_tout);
|
||||
|
||||
int http_get_version(unsigned char *rl, unsigned char **http_ver);
|
||||
|
||||
int http_get_dest(unsigned char *rl, unsigned char **addr, unsigned char **port);
|
||||
|
||||
int http_get_header_name(unsigned char *rl, unsigned char **hname);
|
||||
@@ -0,0 +1,702 @@
|
||||
/**
|
||||
* httpap.c
|
||||
* HTTP Application Proxy for Onion Routing
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.4 2002/06/14 20:45:26 mp292
|
||||
* Extra debugging message.
|
||||
*
|
||||
* Revision 1.3 2002/04/02 14:27:33 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.2 2002/03/12 23:40:58 mp292
|
||||
* Tested.
|
||||
*
|
||||
* Revision 1.1 2002/03/11 00:21:53 mp292
|
||||
* Coding completed. Pending testing.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <wait.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../common/log.h"
|
||||
#include "../common/config.h"
|
||||
#include "../common/ss.h"
|
||||
#include "../common/utils.h"
|
||||
#include "../common/version.h"
|
||||
|
||||
#include "httpap.h"
|
||||
#include "http.h"
|
||||
|
||||
int loglevel = LOG_ERR;
|
||||
struct timeval conn_tout;
|
||||
struct timeval *conn_toutp = &conn_tout;
|
||||
|
||||
/* valid command-line options */
|
||||
static const char *args = "hf:p:l:";
|
||||
|
||||
/* valid config file options */
|
||||
static config_opt_t options[] =
|
||||
{
|
||||
{"OnionProxy", CONFIG_TYPE_INT, {0}, 0},
|
||||
{"MaxConn", CONFIG_TYPE_INT, {0}, 0},
|
||||
{"Anonimize", CONFIG_TYPE_INT, {0}, 0},
|
||||
{"ConnTimeout", CONFIG_TYPE_INT, {0}, 0},
|
||||
{0}
|
||||
};
|
||||
enum opts {
|
||||
OnionProxy=0,MaxConn, Anonimize, ConnTimeout
|
||||
};
|
||||
|
||||
/* number of open connections */
|
||||
int connections=0;
|
||||
|
||||
/* prints help on using httpap */
|
||||
void print_usage()
|
||||
{
|
||||
char *program = "httpap";
|
||||
|
||||
printf("\n%s - HTTP application proxy for Onion Routing.\nUsage : %s -f config [-p port -l loglevel -h]\n-h : display this help\n-f config : config file\n-p port : port number which %s should bind to\n-l loglevel : logging threshold; one of alert|crit|err|warning|notice|info|debug\n\n", program,program,program);
|
||||
}
|
||||
|
||||
/* used for reaping zombie processes */
|
||||
void sigchld_handler(int s)
|
||||
{
|
||||
while (wait(NULL) > 0);
|
||||
connections--;
|
||||
}
|
||||
|
||||
int handle_connection(int new_sock, struct hostent *local, struct sockaddr_in remote, uint16_t op_port)
|
||||
{
|
||||
int retval = 0;
|
||||
int i;
|
||||
char islocal = 0; /* is the accepted connection local? */
|
||||
|
||||
char *cp; /* character pointer used for checking whether the connection is local */
|
||||
|
||||
unsigned char *line; /* one line of input */
|
||||
int len; /* length of the line */
|
||||
|
||||
unsigned char *http_ver; /* HTTP version of the incoming request */
|
||||
unsigned char *addr; /* destination address */
|
||||
unsigned char *port; /* destination port */
|
||||
unsigned char *header_name; /* name of a request header */
|
||||
|
||||
uint16_t portn; /* destination port converted into an integer */
|
||||
char *errtest; /* error check when converting the port into an integer */
|
||||
|
||||
ss_t ss; /* standard structure */
|
||||
unsigned char errcode; /* error code returned by the onion proxy */
|
||||
|
||||
int sop; /* socket for connecting to the onion proxy */
|
||||
struct sockaddr_in op_addr; /* onion proxy address */
|
||||
|
||||
/* for use with select() */
|
||||
fd_set mask,rmask;
|
||||
int maxfd;
|
||||
|
||||
unsigned char buf[1024]; /* data buffer */
|
||||
|
||||
log(LOG_DEBUG, "handle_connection() : Local address = %s.", inet_ntoa(*(struct in_addr *)local->h_addr));
|
||||
log(LOG_DEBUG, "handle_connection() : Remote address = %s.", inet_ntoa(remote.sin_addr));
|
||||
|
||||
/* first check that the connection is from the local host, otherwise it will be rejected */
|
||||
if (*(uint32_t *)&remote.sin_addr == inet_addr("127.0.0.1"))
|
||||
islocal = 1;
|
||||
for (i=0; (local->h_addr_list[i] != NULL) && (!islocal); i++)
|
||||
{
|
||||
cp = local->h_addr_list[i];
|
||||
log(LOG_DEBUG,"handle_connection() : Checking if connection is from address %s.",inet_ntoa(*(struct in_addr *)cp));
|
||||
if (!memcmp(&remote.sin_addr, cp, sizeof(struct in_addr)))
|
||||
islocal = 1;
|
||||
}
|
||||
|
||||
/* bypass this check for testing purposes */
|
||||
islocal = 1;
|
||||
|
||||
/* reject a non-local connection */
|
||||
if (!islocal)
|
||||
{
|
||||
close(new_sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get the request-line */
|
||||
retval = http_get_line(new_sock, &line, &len, conn_toutp);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection : Malformed input or connection lost.");
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_BAD_REQUEST, strlen(HTTPAP_STATUS_LINE_BAD_REQUEST), conn_toutp);
|
||||
close(new_sock);
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection : Received this from client : %s.", line);
|
||||
|
||||
/* check the HTTP version */
|
||||
retval = http_get_version(line, &http_ver);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection : Unable to extract the HTTP version of the incoming request.");
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_BAD_REQUEST, strlen(HTTPAP_STATUS_LINE_BAD_REQUEST), conn_toutp);
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection : Client's version is : %s.",http_ver);
|
||||
if (strcmp(http_ver, HTTPAP_VERSION)) /* not supported */
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection : Client's version is %s, I only support HTTP/1.0.",http_ver);
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_VERSION_NOT_SUPPORTED, strlen(HTTPAP_STATUS_LINE_VERSION_NOT_SUPPORTED), conn_toutp);
|
||||
return -1;
|
||||
}
|
||||
free((void *)http_ver);
|
||||
|
||||
/* extract the destination address and port */
|
||||
retval = http_get_dest(line, &addr, &port);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection : Unable to extract destination address and port number.");
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_BAD_REQUEST, strlen(HTTPAP_STATUS_LINE_BAD_REQUEST), conn_toutp);
|
||||
return -1;
|
||||
}
|
||||
if (!port) /* no destination port specified, assume the default */
|
||||
{
|
||||
port = (unsigned char *)malloc(6);
|
||||
if (!port)
|
||||
{
|
||||
log(LOG_ERR,"Insufficient memory.");
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_UNEXPECTED, strlen(HTTPAP_STATUS_LINE_UNEXPECTED), conn_toutp);
|
||||
return -1;
|
||||
}
|
||||
snprintf(port,6,"%u",htons(HTTPAP_DEFAULT_HTTP_PORT));
|
||||
}
|
||||
else
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : Destination address is %s.",addr);
|
||||
log(LOG_DEBUG,"handle_connection() : Destination port is %s.",port);
|
||||
|
||||
/* conver the port to an integer */
|
||||
portn = (uint16_t)strtoul(port,&errtest,0);
|
||||
if ((*port == '\0') || (*errtest != '\0')) /* port conversion was unsuccessful */
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection : Unable to convert destination port.");
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_BAD_REQUEST, strlen(HTTPAP_STATUS_LINE_BAD_REQUEST), conn_toutp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* convert to network order and write back to a string */
|
||||
free((void *)port);
|
||||
port = (unsigned char *)malloc(6);
|
||||
if (!port)
|
||||
{
|
||||
log(LOG_ERR,"Insufficient memory.");
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_UNEXPECTED, strlen(HTTPAP_STATUS_LINE_UNEXPECTED), conn_toutp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(port,6,"%u",htons(portn));
|
||||
}
|
||||
|
||||
/* create a standard structure */
|
||||
ss.version = VERSION;
|
||||
ss.protocol = SS_PROTOCOL_HTTP;
|
||||
ss.retry_count = 0;
|
||||
ss.addr_fmt = SS_ADDR_FMT_ASCII_HOST_PORT;
|
||||
|
||||
/* open a socket for connecting to the proxy */
|
||||
sop = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
|
||||
if (sop < 0)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : Error opening socket.");
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_UNEXPECTED, strlen(HTTPAP_STATUS_LINE_UNEXPECTED), conn_toutp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"handle_connection() : Socket opened.");
|
||||
memset((void *)&op_addr,0,sizeof(op_addr)); /* clear the structure first */
|
||||
/* set up the sockaddr_in structure */
|
||||
op_addr.sin_family=AF_INET;
|
||||
op_addr.sin_port=htons(op_port);
|
||||
memcpy((void *)&op_addr.sin_addr,local->h_addr,local->h_length);
|
||||
log(LOG_DEBUG,"handle_connection() : Trying to connect to %s at port %u.",inet_ntoa(*((struct in_addr *)local->h_addr)),op_port);
|
||||
|
||||
/* try to connect */
|
||||
retval = connect(sop,(struct sockaddr *)&op_addr,sizeof(op_addr));
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : Connection to the onion proxy failed.");
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_UNAVAILABLE, strlen(HTTPAP_STATUS_LINE_UNAVAILABLE), conn_toutp);
|
||||
close(sop);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* send the standard structure and the destination address+port */
|
||||
retval = write_tout(sop,(unsigned char *)&ss, sizeof(ss), conn_toutp);
|
||||
if (retval < sizeof(ss))
|
||||
{
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_UNAVAILABLE, strlen(HTTPAP_STATUS_LINE_UNAVAILABLE), conn_toutp);
|
||||
close(sop);
|
||||
return -1;
|
||||
}
|
||||
retval = write_tout(sop,addr,strlen(addr)+1, conn_toutp);
|
||||
if (retval < strlen(addr)+1)
|
||||
{
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_UNAVAILABLE, strlen(HTTPAP_STATUS_LINE_UNAVAILABLE), conn_toutp);
|
||||
close(sop);
|
||||
return -1;
|
||||
}
|
||||
retval = write_tout(sop,port,strlen(port)+1, conn_toutp);
|
||||
if (retval < strlen(port)+1)
|
||||
{
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_UNAVAILABLE, strlen(HTTPAP_STATUS_LINE_UNAVAILABLE), conn_toutp);
|
||||
close(sop);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* wait for a return code */
|
||||
retval = read_tout(sop, &errcode, 1, MSG_WAITALL, conn_toutp);
|
||||
if (retval < 1)
|
||||
{
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_UNAVAILABLE, strlen(HTTPAP_STATUS_LINE_UNAVAILABLE), conn_toutp);
|
||||
close(sop);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!errcode) /* onion proxy says OK */
|
||||
{
|
||||
/* send the request-line */
|
||||
retval = write_tout(sop, line, strlen(line), conn_toutp);
|
||||
if (retval < strlen(line))
|
||||
{
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_UNAVAILABLE, strlen(HTTPAP_STATUS_LINE_UNAVAILABLE), conn_toutp);
|
||||
close(new_sock);
|
||||
return -1;
|
||||
}
|
||||
free((void *)line);
|
||||
|
||||
/* read the request headers (if any) and sanitize if necessary */
|
||||
while(1)
|
||||
{
|
||||
retval = http_get_line(new_sock, &line, &len, conn_toutp);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : Malformed input or connection lost.");
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_BAD_REQUEST, strlen(HTTPAP_STATUS_LINE_BAD_REQUEST), conn_toutp);
|
||||
close(new_sock);
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection() : Received this from client : %s.", line);
|
||||
|
||||
if (len == 2) /* empty line (CRLF only) signifying the end of headers */
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : Empty line received.");
|
||||
retval = write_tout(sop,line,strlen(line),conn_toutp);
|
||||
if (retval < strlen(line))
|
||||
{
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_UNAVAILABLE, strlen(HTTPAP_STATUS_LINE_UNAVAILABLE), conn_toutp);
|
||||
close(new_sock);
|
||||
return -1;
|
||||
}
|
||||
free((void *)line);
|
||||
break;
|
||||
}
|
||||
else /* process the header */
|
||||
{
|
||||
retval = http_get_header_name(line, &header_name);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection : Unable to extract header name.");
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_BAD_REQUEST, strlen(HTTPAP_STATUS_LINE_BAD_REQUEST), conn_toutp);
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection : Identified the header as %s.", header_name);
|
||||
|
||||
/* discard the Proxy-Connection header */
|
||||
if (!strcmp(header_name,HTTPAP_HEADER_PROXY_CONNECTION))
|
||||
free((void *)line);
|
||||
else if (options[Anonimize].r.i) /* did the user request anonimization? */
|
||||
{
|
||||
if (!strcmp(header_name,HTTPAP_HEADER_USER_AGENT))
|
||||
free((void *)line);
|
||||
else if (!strcmp(header_name, HTTPAP_HEADER_REFERER))
|
||||
free((void *)line);
|
||||
else
|
||||
{
|
||||
retval = write_tout(sop, line, strlen(line), conn_toutp);
|
||||
if (retval < strlen(line))
|
||||
{
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_UNAVAILABLE, strlen(HTTPAP_STATUS_LINE_UNAVAILABLE), conn_toutp);
|
||||
close(new_sock);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = write_tout(sop, line, strlen(line), conn_toutp);
|
||||
if (retval < strlen(line))
|
||||
{
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_UNAVAILABLE, strlen(HTTPAP_STATUS_LINE_UNAVAILABLE), conn_toutp);
|
||||
close(new_sock);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
free((void *)header_name);
|
||||
}
|
||||
}
|
||||
|
||||
/* forward data in both directions until one of the principals closes it */
|
||||
/* set up for select() */
|
||||
log(LOG_DEBUG,"Header processed, forwarding data in both directions.");
|
||||
FD_ZERO(&mask);
|
||||
FD_ZERO(&rmask);
|
||||
FD_SET(new_sock, &mask);
|
||||
FD_SET(sop, &mask);
|
||||
if (sop > new_sock)
|
||||
maxfd = sop;
|
||||
else
|
||||
maxfd = new_sock;
|
||||
|
||||
while(1)
|
||||
{
|
||||
rmask = mask;
|
||||
retval = select(maxfd+1,&rmask,NULL,NULL,NULL);
|
||||
if (retval < 0)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : select() returned a negative integer");
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(sop,&rmask)) /* data from the onion proxy */
|
||||
{
|
||||
retval = read_tout(sop,buf,1024,0,conn_toutp);
|
||||
if (retval <= 0)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection : Conection to the onion proxy lost.");
|
||||
close(sop);
|
||||
close(new_sock);
|
||||
break;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection() : Received %u bytes from the onion proxy.",retval);
|
||||
|
||||
retval = write_tout(new_sock, buf, retval, conn_toutp);
|
||||
if (retval <= 0)
|
||||
{
|
||||
log(LOG_DEBUG, "handle_connection : Connection to the client lost.");
|
||||
close(sop);
|
||||
close(new_sock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(new_sock, &rmask))
|
||||
{
|
||||
retval = read_tout(new_sock,buf,1024,0,conn_toutp);
|
||||
if (retval <= 0)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection : Conection to the client lost.");
|
||||
close(sop);
|
||||
close(new_sock);
|
||||
break;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection() : Received %u bytes from the client.",retval);
|
||||
|
||||
retval = write_tout(sop, buf, retval, conn_toutp);
|
||||
if (retval <= 0)
|
||||
{
|
||||
log(LOG_DEBUG, "handle_connection : Connection to the onion proxy lost.");
|
||||
close(sop);
|
||||
close(new_sock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : Onion proxy returned a non-zero error code (%d)!", errcode);
|
||||
write_tout(new_sock, HTTPAP_STATUS_LINE_UNEXPECTED, strlen(HTTPAP_STATUS_LINE_UNEXPECTED), conn_toutp);
|
||||
close(sop);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
char c; /* command-line option */
|
||||
|
||||
/* configuration file */
|
||||
char *conf_filename = NULL;
|
||||
FILE *cf = NULL;
|
||||
|
||||
struct hostent *local_host;
|
||||
char local_hostname[512];
|
||||
|
||||
struct sockaddr_in local, remote; /* local and remote address info */
|
||||
|
||||
int request_sock; /* where we listen for connections */
|
||||
int new_sock; /* for accepted connections */
|
||||
|
||||
size_t sin_size; /* for accept() calls */
|
||||
|
||||
u_short p; /* http proxy port */
|
||||
u_short op_port; /* onion proxy port */
|
||||
|
||||
/* used for reaping zombie processes */
|
||||
struct sigaction sa;
|
||||
|
||||
char *errtest = NULL; /* for detecting strtoul() errors */
|
||||
|
||||
/* set default listening port */
|
||||
p = htons(HTTPAP_LISTEN_PORT);
|
||||
|
||||
/* deal with program arguments */
|
||||
if ((argc < 2) && (argc > 5)) /* to few or too many arguments*/
|
||||
{
|
||||
print_usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
opterr = 0;
|
||||
while ((c = getopt(argc,argv,args)) != -1)
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case 'f': /* config file */
|
||||
conf_filename = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
p = htons((u_short)strtoul(optarg,&errtest,0));
|
||||
if (errtest == optarg) /* error */
|
||||
{
|
||||
log(LOG_ERR,"Error : -p must be followed by an unsigned positive integer value.");
|
||||
print_usage();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
print_usage();
|
||||
return 0;
|
||||
break;
|
||||
case 'l':
|
||||
if (!strcmp(optarg,"emerg"))
|
||||
loglevel = LOG_EMERG;
|
||||
else if (!strcmp(optarg,"alert"))
|
||||
loglevel = LOG_ALERT;
|
||||
else if (!strcmp(optarg,"crit"))
|
||||
loglevel = LOG_CRIT;
|
||||
else if (!strcmp(optarg,"err"))
|
||||
loglevel = LOG_ERR;
|
||||
else if (!strcmp(optarg,"warning"))
|
||||
loglevel = LOG_WARNING;
|
||||
else if (!strcmp(optarg,"notice"))
|
||||
loglevel = LOG_NOTICE;
|
||||
else if (!strcmp(optarg,"info"))
|
||||
loglevel = LOG_INFO;
|
||||
else if (!strcmp(optarg,"debug"))
|
||||
loglevel = LOG_DEBUG;
|
||||
else
|
||||
{
|
||||
log(LOG_ERR,"Error : argument to -l must be one of alert|crit|err|warning|notice|info|debug.");
|
||||
print_usage();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
if (isprint(c))
|
||||
log(LOG_ERR,"Missing argument or unknown option '-%c'.",optopt);
|
||||
else
|
||||
log(LOG_ERR,"Unknown option character 'x%x'.",optopt);
|
||||
print_usage();
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* the -f option is mandatory */
|
||||
if (conf_filename == NULL)
|
||||
{
|
||||
log(LOG_ERR,"You must specify a config file with the -f option. See help (-h).");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* load config file */
|
||||
cf = open_config(conf_filename);
|
||||
if (!cf)
|
||||
{
|
||||
log(LOG_ERR,"Could not open configuration file %s.",conf_filename);
|
||||
return -1;
|
||||
}
|
||||
retval = parse_config(cf,options);
|
||||
if (retval)
|
||||
return -1;
|
||||
|
||||
if (options[OnionProxy].err != 1)
|
||||
{
|
||||
log(LOG_ERR,"The OnionProxy option is mandatory.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (options[MaxConn].err != 1)
|
||||
{
|
||||
log(LOG_ERR,"The MaxConn option is mandatory.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (options[Anonimize].err != 1)
|
||||
{
|
||||
log(LOG_ERR,"The Anonimize option is mandatory.");
|
||||
return -1;
|
||||
}
|
||||
else if ((options[Anonimize].r.i != 0) && (options[Anonimize].r.i != 1))
|
||||
{
|
||||
log(LOG_ERR,"The Anonimize option takes the values 1 or 0.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (options[ConnTimeout].err != 1)
|
||||
{
|
||||
conn_tout.tv_sec = HTTPAP_DEFAULT_CONN_TIMEOUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!options[ConnTimeout].r.i)
|
||||
conn_toutp = NULL;
|
||||
else
|
||||
conn_tout.tv_sec = options[ConnTimeout].r.i;
|
||||
}
|
||||
conn_tout.tv_usec = 0;
|
||||
|
||||
op_port = (u_short)options[OnionProxy].r.i;
|
||||
|
||||
/* get local address so that we know where to get the onion proxy when we need it */
|
||||
retval = gethostname(local_hostname, (size_t)512);
|
||||
if (retval < 0)
|
||||
{
|
||||
log(LOG_ERR,"Error getting local hostname");
|
||||
return -1;
|
||||
}
|
||||
local_host = gethostbyname(local_hostname);
|
||||
if (!local_host)
|
||||
{
|
||||
log(LOG_ERR,"Error getting local address.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"main() : Got local address : %s.",local_hostname);
|
||||
|
||||
/* get the server up and running */
|
||||
request_sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
|
||||
if (request_sock < 0)
|
||||
{
|
||||
log(LOG_ERR,"Error opening socket.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"Socket opened.");
|
||||
memset((void *)&local,0,sizeof(local)); /* clear the structure first */
|
||||
/* set up the sockaddr_in structure */
|
||||
local.sin_family=AF_INET;
|
||||
local.sin_addr.s_addr = INADDR_ANY;
|
||||
local.sin_port=p;
|
||||
/* bind it to the socket */
|
||||
retval = bind(request_sock,(struct sockaddr *)&local, sizeof(local));
|
||||
if (retval < 0)
|
||||
{
|
||||
log(LOG_ERR,"Error binding socket to local port %d.",ntohs(p));
|
||||
return retval;
|
||||
}
|
||||
log(LOG_DEBUG,"Socket bound to port %d.",ntohs(p));
|
||||
/* listen for connections */
|
||||
retval = listen(request_sock,SOMAXCONN);
|
||||
if (retval < 0)
|
||||
{
|
||||
log(LOG_ERR,"Could not listen for connections.");
|
||||
return retval;
|
||||
}
|
||||
log(LOG_DEBUG,"Listening for connections.");
|
||||
/* server should now be up and running */
|
||||
|
||||
/* install the signal handler for making sure zombie processes are killed */
|
||||
sa.sa_handler = sigchld_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
retval = sigaction(SIGCHLD,&sa,NULL);
|
||||
if (retval < 0)
|
||||
{
|
||||
log(LOG_ERR,"Could not install a signal handler.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* main server loop */
|
||||
/* I use a forking server technique - this isn't the most efficient way to do it,
|
||||
* but it is simpler. */
|
||||
while(1)
|
||||
{
|
||||
sin_size = sizeof(struct sockaddr_in);
|
||||
new_sock = accept(request_sock,(struct sockaddr *)&remote,&sin_size);
|
||||
if (new_sock == -1)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
log(LOG_ERR,"Could not accept socket connection.");
|
||||
else
|
||||
log(LOG_DEBUG,"Interrupt received.");
|
||||
continue;
|
||||
}
|
||||
if (connections >= options[MaxConn].r.i)
|
||||
{
|
||||
log(LOG_NOTICE,"Number of maximum connections reached. Rejecting incoming request.");
|
||||
close(new_sock);
|
||||
continue;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"Accepted a connection from %s.",inet_ntoa(remote.sin_addr));
|
||||
connections++;
|
||||
|
||||
if (!fork()) /* this is the child process */
|
||||
{
|
||||
close(request_sock); /* the child doesn't need the request socket anymore */
|
||||
|
||||
/* Main logic of httpap. */
|
||||
retval = handle_connection(new_sock, local_host, remote, op_port);
|
||||
/* End main logic */
|
||||
|
||||
exit(retval); /* done, exit */
|
||||
}
|
||||
|
||||
close(new_sock); /* don't need this anymore */
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* http.h
|
||||
* HTTP Application Proxy for Onion Routing
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.1 2002/03/11 00:21:53 mp292
|
||||
* Coding completed. Pending testing.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __HTTPAP_H
|
||||
|
||||
#define __HTTPAP_H
|
||||
|
||||
/* default listening port */
|
||||
#define HTTPAP_LISTEN_PORT 8080
|
||||
|
||||
/* default SMTP port */
|
||||
#define HTTPAP_DEFAULT_HTTP_PORT 80
|
||||
|
||||
/* default connection timeout */
|
||||
#define HTTPAP_DEFAULT_CONN_TIMEOUT 120; /* 120s */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,285 @@
|
||||
SRC=args.c config.c op.c routers.c auth.c ss.c buffers.c crypto.c
|
||||
OBJ=${SRC:.c=.o}
|
||||
PROGS=op
|
||||
LIB=-L/usr/local/ssl/lib
|
||||
LIBS=-lcrypto
|
||||
INCLUDE = -I/usr/local/ssl/include
|
||||
|
||||
CFLAGS= $(INCLUDE) -Wall -Wpointer-arith -O2 -ggdb
|
||||
LDFLAGS = $(LIB) $(LIBS)
|
||||
|
||||
all: ${PROGS}
|
||||
|
||||
clean:
|
||||
rm -f *.o ${PROGS}
|
||||
|
||||
depend:
|
||||
makedepend -- ${CFLAGS} -- ${SRC}
|
||||
|
||||
${PROGS}: ${OBJ}
|
||||
$(LINK.c) -o $@ $(OBJ) ../common/log.o ../common/config.o ../common/onion.o ../common/utils.o ../common/cell.o ../common/scheduler.o
|
||||
|
||||
# DO NOT DELETE
|
||||
|
||||
|
||||
args.o: args.h ../common/log.h /usr/include/alloca.h
|
||||
args.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
|
||||
args.o: /usr/include/bits/environments.h /usr/include/bits/posix_opt.h
|
||||
args.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
|
||||
args.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
|
||||
args.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
|
||||
args.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
|
||||
args.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
|
||||
args.o: /usr/include/bits/wordsize.h /usr/include/ctype.h
|
||||
args.o: /usr/include/endian.h /usr/include/features.h /usr/include/_G_config.h
|
||||
args.o: /usr/include/gconv.h /usr/include/getopt.h /usr/include/gnu/stubs.h
|
||||
args.o: /usr/include/libio.h /usr/include/stdio.h /usr/include/stdlib.h
|
||||
args.o: /usr/include/sys/cdefs.h /usr/include/syslog.h
|
||||
args.o: /usr/include/sys/select.h /usr/include/sys/syslog.h
|
||||
args.o: /usr/include/sys/sysmacros.h /usr/include/sys/types.h
|
||||
args.o: /usr/include/time.h /usr/include/unistd.h /usr/include/wchar.h
|
||||
args.o: /usr/include/xlocale.h
|
||||
args.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
args.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
auth.o: auth.h ../common/log.h /usr/include/alloca.h /usr/include/asm/socket.h
|
||||
auth.o: /usr/include/asm/sockios.h /usr/include/bits/byteswap.h
|
||||
auth.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
|
||||
auth.o: /usr/include/bits/environments.h /usr/include/bits/in.h
|
||||
auth.o: /usr/include/bits/local_lim.h /usr/include/bits/posix1_lim.h
|
||||
auth.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
|
||||
auth.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
|
||||
auth.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
|
||||
auth.o: /usr/include/bits/sockaddr.h /usr/include/bits/socket.h
|
||||
auth.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
|
||||
auth.o: /usr/include/bits/types.h /usr/include/bits/uio.h
|
||||
auth.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
|
||||
auth.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
|
||||
auth.o: /usr/include/bits/xopen_lim.h /usr/include/endian.h
|
||||
auth.o: /usr/include/features.h /usr/include/_G_config.h /usr/include/gconv.h
|
||||
auth.o: /usr/include/getopt.h /usr/include/gnu/stubs.h /usr/include/libio.h
|
||||
auth.o: /usr/include/limits.h /usr/include/linux/limits.h
|
||||
auth.o: /usr/include/netinet/in.h /usr/include/openssl/bio.h
|
||||
auth.o: /usr/include/openssl/bn.h /usr/include/openssl/crypto.h
|
||||
auth.o: /usr/include/openssl/opensslconf.h /usr/include/openssl/opensslv.h
|
||||
auth.o: /usr/include/openssl/rand.h /usr/include/openssl/rsa.h
|
||||
auth.o: /usr/include/openssl/safestack.h /usr/include/openssl/stack.h
|
||||
auth.o: /usr/include/openssl/symhacks.h /usr/include/stdint.h
|
||||
auth.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
|
||||
auth.o: /usr/include/sys/cdefs.h /usr/include/syslog.h
|
||||
auth.o: /usr/include/sys/select.h /usr/include/sys/socket.h
|
||||
auth.o: /usr/include/sys/syslog.h /usr/include/sys/sysmacros.h
|
||||
auth.o: /usr/include/sys/types.h /usr/include/sys/uio.h /usr/include/time.h
|
||||
auth.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
|
||||
auth.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
|
||||
auth.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
auth.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
auth.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
|
||||
buffers.o: buffers.h ../common/cell.h ../common/log.h ../common/onion.h
|
||||
buffers.o: ../common/routent.h ../common/version.h crypto.h op.h
|
||||
buffers.o: /usr/include/alloca.h /usr/include/bits/confname.h
|
||||
buffers.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
|
||||
buffers.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
|
||||
buffers.o: /usr/include/bits/sched.h /usr/include/bits/select.h
|
||||
buffers.o: /usr/include/bits/sigset.h /usr/include/bits/stdio_lim.h
|
||||
buffers.o: /usr/include/bits/time.h /usr/include/bits/types.h
|
||||
buffers.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
|
||||
buffers.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
|
||||
buffers.o: /usr/include/endian.h /usr/include/features.h
|
||||
buffers.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
|
||||
buffers.o: /usr/include/gnu/stubs.h /usr/include/libio.h
|
||||
buffers.o: /usr/include/openssl/asn1.h /usr/include/openssl/bio.h
|
||||
buffers.o: /usr/include/openssl/blowfish.h /usr/include/openssl/bn.h
|
||||
buffers.o: /usr/include/openssl/cast.h /usr/include/openssl/crypto.h
|
||||
buffers.o: /usr/include/openssl/des.h /usr/include/openssl/dh.h
|
||||
buffers.o: /usr/include/openssl/dsa.h /usr/include/openssl/e_os2.h
|
||||
buffers.o: /usr/include/openssl/evp.h /usr/include/openssl/md2.h
|
||||
buffers.o: /usr/include/openssl/md4.h /usr/include/openssl/md5.h
|
||||
buffers.o: /usr/include/openssl/objects.h /usr/include/openssl/obj_mac.h
|
||||
buffers.o: /usr/include/openssl/opensslconf.h /usr/include/openssl/opensslv.h
|
||||
buffers.o: /usr/include/openssl/rc2.h /usr/include/openssl/rc4.h
|
||||
buffers.o: /usr/include/openssl/ripemd.h /usr/include/openssl/rsa.h
|
||||
buffers.o: /usr/include/openssl/safestack.h /usr/include/openssl/sha.h
|
||||
buffers.o: /usr/include/openssl/stack.h /usr/include/openssl/symhacks.h
|
||||
buffers.o: /usr/include/stdint.h /usr/include/stdio.h /usr/include/stdlib.h
|
||||
buffers.o: /usr/include/sys/cdefs.h /usr/include/syslog.h
|
||||
buffers.o: /usr/include/sys/select.h /usr/include/sys/syslog.h
|
||||
buffers.o: /usr/include/sys/sysmacros.h /usr/include/sys/timeb.h
|
||||
buffers.o: /usr/include/sys/time.h /usr/include/sys/types.h
|
||||
buffers.o: /usr/include/time.h /usr/include/unistd.h /usr/include/wchar.h
|
||||
buffers.o: /usr/include/xlocale.h
|
||||
buffers.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
buffers.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
config.o: ../common/config.h ../common/log.h config.h
|
||||
config.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
|
||||
config.o: /usr/include/bits/stdio_lim.h /usr/include/bits/types.h
|
||||
config.o: /usr/include/bits/wchar.h /usr/include/features.h
|
||||
config.o: /usr/include/_G_config.h /usr/include/gconv.h
|
||||
config.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/stdio.h
|
||||
config.o: /usr/include/sys/cdefs.h /usr/include/syslog.h
|
||||
config.o: /usr/include/sys/syslog.h /usr/include/wchar.h
|
||||
config.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
config.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
crypto.o: ../common/cell.h ../common/log.h ../common/onion.h
|
||||
crypto.o: ../common/routent.h ../common/version.h crypto.h
|
||||
crypto.o: /usr/include/alloca.h /usr/include/asm/errno.h
|
||||
crypto.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
|
||||
crypto.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
|
||||
crypto.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
|
||||
crypto.o: /usr/include/bits/sched.h /usr/include/bits/select.h
|
||||
crypto.o: /usr/include/bits/sigset.h /usr/include/bits/stdio_lim.h
|
||||
crypto.o: /usr/include/bits/time.h /usr/include/bits/types.h
|
||||
crypto.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
|
||||
crypto.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
|
||||
crypto.o: /usr/include/endian.h /usr/include/errno.h /usr/include/features.h
|
||||
crypto.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
|
||||
crypto.o: /usr/include/gnu/stubs.h /usr/include/libio.h
|
||||
crypto.o: /usr/include/linux/errno.h /usr/include/malloc.h
|
||||
crypto.o: /usr/include/openssl/asn1.h /usr/include/openssl/bio.h
|
||||
crypto.o: /usr/include/openssl/blowfish.h /usr/include/openssl/bn.h
|
||||
crypto.o: /usr/include/openssl/cast.h /usr/include/openssl/crypto.h
|
||||
crypto.o: /usr/include/openssl/des.h /usr/include/openssl/dh.h
|
||||
crypto.o: /usr/include/openssl/dsa.h /usr/include/openssl/e_os2.h
|
||||
crypto.o: /usr/include/openssl/err.h /usr/include/openssl/evp.h
|
||||
crypto.o: /usr/include/openssl/lhash.h /usr/include/openssl/md2.h
|
||||
crypto.o: /usr/include/openssl/md4.h /usr/include/openssl/md5.h
|
||||
crypto.o: /usr/include/openssl/objects.h /usr/include/openssl/obj_mac.h
|
||||
crypto.o: /usr/include/openssl/opensslconf.h /usr/include/openssl/opensslv.h
|
||||
crypto.o: /usr/include/openssl/rc2.h /usr/include/openssl/rc4.h
|
||||
crypto.o: /usr/include/openssl/ripemd.h /usr/include/openssl/rsa.h
|
||||
crypto.o: /usr/include/openssl/safestack.h /usr/include/openssl/sha.h
|
||||
crypto.o: /usr/include/openssl/stack.h /usr/include/openssl/symhacks.h
|
||||
crypto.o: /usr/include/stdint.h /usr/include/stdio.h /usr/include/stdlib.h
|
||||
crypto.o: /usr/include/sys/cdefs.h /usr/include/syslog.h
|
||||
crypto.o: /usr/include/sys/select.h /usr/include/sys/syslog.h
|
||||
crypto.o: /usr/include/sys/sysmacros.h /usr/include/sys/timeb.h
|
||||
crypto.o: /usr/include/sys/time.h /usr/include/sys/types.h /usr/include/time.h
|
||||
crypto.o: /usr/include/unistd.h /usr/include/wchar.h /usr/include/xlocale.h
|
||||
crypto.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
crypto.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
op.o: args.h auth.h buffers.h ../common/cell.h ../common/config.h
|
||||
op.o: ../common/log.h ../common/onion.h ../common/routent.h
|
||||
op.o: ../common/scheduler.h ../common/ss.h ../common/utils.h
|
||||
op.o: ../common/version.h config.h crypto.h op.h routers.h ss.h
|
||||
op.o: /usr/include/alloca.h /usr/include/arpa/inet.h /usr/include/asm/errno.h
|
||||
op.o: /usr/include/asm/sigcontext.h /usr/include/asm/socket.h
|
||||
op.o: /usr/include/asm/sockios.h /usr/include/bits/byteswap.h
|
||||
op.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
|
||||
op.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
|
||||
op.o: /usr/include/bits/in.h /usr/include/bits/local_lim.h
|
||||
op.o: /usr/include/bits/netdb.h /usr/include/bits/posix1_lim.h
|
||||
op.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
|
||||
op.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/resource.h
|
||||
op.o: /usr/include/bits/sched.h /usr/include/bits/select.h
|
||||
op.o: /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h
|
||||
op.o: /usr/include/bits/siginfo.h /usr/include/bits/signum.h
|
||||
op.o: /usr/include/bits/sigset.h /usr/include/bits/sigstack.h
|
||||
op.o: /usr/include/bits/sigthread.h /usr/include/bits/sockaddr.h
|
||||
op.o: /usr/include/bits/socket.h /usr/include/bits/stdio_lim.h
|
||||
op.o: /usr/include/bits/time.h /usr/include/bits/types.h
|
||||
op.o: /usr/include/bits/uio.h /usr/include/bits/waitflags.h
|
||||
op.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
|
||||
op.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
|
||||
op.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
|
||||
op.o: /usr/include/features.h /usr/include/_G_config.h /usr/include/gconv.h
|
||||
op.o: /usr/include/getopt.h /usr/include/gnu/stubs.h /usr/include/libio.h
|
||||
op.o: /usr/include/limits.h /usr/include/linux/errno.h
|
||||
op.o: /usr/include/linux/limits.h /usr/include/netdb.h
|
||||
op.o: /usr/include/netinet/in.h /usr/include/openssl/asn1.h
|
||||
op.o: /usr/include/openssl/bio.h /usr/include/openssl/blowfish.h
|
||||
op.o: /usr/include/openssl/bn.h /usr/include/openssl/buffer.h
|
||||
op.o: /usr/include/openssl/cast.h /usr/include/openssl/crypto.h
|
||||
op.o: /usr/include/openssl/des.h /usr/include/openssl/dh.h
|
||||
op.o: /usr/include/openssl/dsa.h /usr/include/openssl/e_os2.h
|
||||
op.o: /usr/include/openssl/err.h /usr/include/openssl/evp.h
|
||||
op.o: /usr/include/openssl/lhash.h /usr/include/openssl/md2.h
|
||||
op.o: /usr/include/openssl/md4.h /usr/include/openssl/md5.h
|
||||
op.o: /usr/include/openssl/objects.h /usr/include/openssl/obj_mac.h
|
||||
op.o: /usr/include/openssl/opensslconf.h /usr/include/openssl/opensslv.h
|
||||
op.o: /usr/include/openssl/pem2.h /usr/include/openssl/pem.h
|
||||
op.o: /usr/include/openssl/pkcs7.h /usr/include/openssl/rand.h
|
||||
op.o: /usr/include/openssl/rc2.h /usr/include/openssl/rc4.h
|
||||
op.o: /usr/include/openssl/ripemd.h /usr/include/openssl/rsa.h
|
||||
op.o: /usr/include/openssl/safestack.h /usr/include/openssl/sha.h
|
||||
op.o: /usr/include/openssl/stack.h /usr/include/openssl/symhacks.h
|
||||
op.o: /usr/include/openssl/x509.h /usr/include/openssl/x509_vfy.h
|
||||
op.o: /usr/include/rpc/netdb.h /usr/include/signal.h /usr/include/stdint.h
|
||||
op.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
|
||||
op.o: /usr/include/sys/cdefs.h /usr/include/syslog.h
|
||||
op.o: /usr/include/sys/resource.h /usr/include/sys/select.h
|
||||
op.o: /usr/include/sys/socket.h /usr/include/sys/syslog.h
|
||||
op.o: /usr/include/sys/sysmacros.h /usr/include/sys/timeb.h
|
||||
op.o: /usr/include/sys/time.h /usr/include/sys/types.h
|
||||
op.o: /usr/include/sys/ucontext.h /usr/include/sys/uio.h /usr/include/sys/un.h
|
||||
op.o: /usr/include/sys/wait.h /usr/include/time.h /usr/include/ucontext.h
|
||||
op.o: /usr/include/unistd.h /usr/include/wait.h /usr/include/wchar.h
|
||||
op.o: /usr/include/xlocale.h
|
||||
op.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
|
||||
op.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
op.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
op.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
|
||||
routers.o: ../common/cell.h ../common/config.h ../common/log.h
|
||||
routers.o: ../common/routent.h ../common/utils.h routers.h
|
||||
routers.o: /usr/include/alloca.h /usr/include/asm/errno.h
|
||||
routers.o: /usr/include/asm/socket.h /usr/include/asm/sockios.h
|
||||
routers.o: /usr/include/bits/byteswap.h /usr/include/bits/confname.h
|
||||
routers.o: /usr/include/bits/endian.h /usr/include/bits/environments.h
|
||||
routers.o: /usr/include/bits/errno.h /usr/include/bits/in.h
|
||||
routers.o: /usr/include/bits/local_lim.h /usr/include/bits/netdb.h
|
||||
routers.o: /usr/include/bits/posix1_lim.h /usr/include/bits/posix2_lim.h
|
||||
routers.o: /usr/include/bits/posix_opt.h /usr/include/bits/pthreadtypes.h
|
||||
routers.o: /usr/include/bits/sched.h /usr/include/bits/select.h
|
||||
routers.o: /usr/include/bits/siginfo.h /usr/include/bits/sigset.h
|
||||
routers.o: /usr/include/bits/sockaddr.h /usr/include/bits/socket.h
|
||||
routers.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
|
||||
routers.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
|
||||
routers.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
|
||||
routers.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
|
||||
routers.o: /usr/include/endian.h /usr/include/errno.h /usr/include/features.h
|
||||
routers.o: /usr/include/_G_config.h /usr/include/gconv.h /usr/include/getopt.h
|
||||
routers.o: /usr/include/gnu/stubs.h /usr/include/libio.h /usr/include/limits.h
|
||||
routers.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
|
||||
routers.o: /usr/include/netdb.h /usr/include/netinet/in.h
|
||||
routers.o: /usr/include/openssl/asn1.h /usr/include/openssl/bio.h
|
||||
routers.o: /usr/include/openssl/blowfish.h /usr/include/openssl/bn.h
|
||||
routers.o: /usr/include/openssl/buffer.h /usr/include/openssl/cast.h
|
||||
routers.o: /usr/include/openssl/crypto.h /usr/include/openssl/des.h
|
||||
routers.o: /usr/include/openssl/dh.h /usr/include/openssl/dsa.h
|
||||
routers.o: /usr/include/openssl/e_os2.h /usr/include/openssl/err.h
|
||||
routers.o: /usr/include/openssl/evp.h /usr/include/openssl/lhash.h
|
||||
routers.o: /usr/include/openssl/md2.h /usr/include/openssl/md4.h
|
||||
routers.o: /usr/include/openssl/md5.h /usr/include/openssl/objects.h
|
||||
routers.o: /usr/include/openssl/obj_mac.h /usr/include/openssl/opensslconf.h
|
||||
routers.o: /usr/include/openssl/opensslv.h /usr/include/openssl/pem2.h
|
||||
routers.o: /usr/include/openssl/pem.h /usr/include/openssl/pkcs7.h
|
||||
routers.o: /usr/include/openssl/rc2.h /usr/include/openssl/rc4.h
|
||||
routers.o: /usr/include/openssl/ripemd.h /usr/include/openssl/rsa.h
|
||||
routers.o: /usr/include/openssl/safestack.h /usr/include/openssl/sha.h
|
||||
routers.o: /usr/include/openssl/stack.h /usr/include/openssl/symhacks.h
|
||||
routers.o: /usr/include/openssl/x509.h /usr/include/openssl/x509_vfy.h
|
||||
routers.o: /usr/include/rpc/netdb.h /usr/include/stdint.h /usr/include/stdio.h
|
||||
routers.o: /usr/include/stdlib.h /usr/include/string.h
|
||||
routers.o: /usr/include/sys/cdefs.h /usr/include/syslog.h
|
||||
routers.o: /usr/include/sys/select.h /usr/include/sys/syslog.h
|
||||
routers.o: /usr/include/sys/sysmacros.h /usr/include/sys/timeb.h
|
||||
routers.o: /usr/include/sys/time.h /usr/include/sys/types.h
|
||||
routers.o: /usr/include/sys/un.h /usr/include/time.h /usr/include/unistd.h
|
||||
routers.o: /usr/include/wchar.h /usr/include/xlocale.h
|
||||
routers.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
|
||||
routers.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
routers.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
routers.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
|
||||
ss.o: ../common/log.h ../common/ss.h ../common/utils.h ../common/version.h
|
||||
ss.o: ss.h /usr/include/bits/confname.h /usr/include/bits/endian.h
|
||||
ss.o: /usr/include/bits/environments.h /usr/include/bits/posix_opt.h
|
||||
ss.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
|
||||
ss.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
|
||||
ss.o: /usr/include/bits/sockaddr.h /usr/include/bits/time.h
|
||||
ss.o: /usr/include/bits/types.h /usr/include/bits/wordsize.h
|
||||
ss.o: /usr/include/endian.h /usr/include/features.h /usr/include/getopt.h
|
||||
ss.o: /usr/include/gnu/stubs.h /usr/include/malloc.h /usr/include/string.h
|
||||
ss.o: /usr/include/sys/cdefs.h /usr/include/syslog.h /usr/include/sys/select.h
|
||||
ss.o: /usr/include/sys/syslog.h /usr/include/sys/sysmacros.h
|
||||
ss.o: /usr/include/sys/time.h /usr/include/sys/types.h /usr/include/sys/un.h
|
||||
ss.o: /usr/include/time.h /usr/include/unistd.h /usr/include/xlocale.h
|
||||
ss.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
ss.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* args.c
|
||||
* Routines for processing command-line arguments.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.3 2002/01/26 22:08:40 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.2 2001/12/14 11:26:23 badbytes
|
||||
* Tested
|
||||
*
|
||||
* Revision 1.1 2001/12/13 15:15:10 badbytes
|
||||
* Started coding the onion proxy.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "../common/log.h"
|
||||
#include "args.h"
|
||||
|
||||
/* prints help on using op */
|
||||
void print_usage()
|
||||
{
|
||||
char *program = "op";
|
||||
|
||||
printf("\n%s - Onion Proxy for Onion Routing.\nUsage : %s -f config -p port [-l loglevel -h]\n-h : display this help\n-f config : config file\n-p port : port number which %s should bind to\n-l loglevel : logging threshold; one of alert|crit|err|warning|notice|info|debug\n\n", program,program,program);
|
||||
}
|
||||
|
||||
/* get command-line arguments */
|
||||
int getargs(int argc, char *argv[], char *args, unsigned short *p, char **conf_filename, int *loglevel)
|
||||
{
|
||||
char c; /* next option character */
|
||||
char *errtest = NULL; /* for detecting strtoul() errors */
|
||||
int gotf=0; int gotp=0;
|
||||
|
||||
if ((!args) || (!conf_filename) || (!loglevel)) /* invalid parameters */
|
||||
return -1;
|
||||
|
||||
while ((c = getopt(argc,argv,args)) != -1)
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case 'f': /* config file */
|
||||
*conf_filename = optarg;
|
||||
gotf=1;
|
||||
break;
|
||||
case 'p':
|
||||
*p = (u_short)strtoul(optarg,&errtest,0);
|
||||
if (errtest == optarg) /* error */
|
||||
{
|
||||
log(LOG_ERR,"Error : -p must be followed by an unsigned positive integer value. See help (-h).");
|
||||
return -1;
|
||||
}
|
||||
gotp=1;
|
||||
break;
|
||||
case 'h':
|
||||
print_usage();
|
||||
exit(0);
|
||||
case 'l':
|
||||
if (!strcmp(optarg,"emerg"))
|
||||
*loglevel = LOG_EMERG;
|
||||
else if (!strcmp(optarg,"alert"))
|
||||
*loglevel = LOG_ALERT;
|
||||
else if (!strcmp(optarg,"crit"))
|
||||
*loglevel = LOG_CRIT;
|
||||
else if (!strcmp(optarg,"err"))
|
||||
*loglevel = LOG_ERR;
|
||||
else if (!strcmp(optarg,"warning"))
|
||||
*loglevel = LOG_WARNING;
|
||||
else if (!strcmp(optarg,"notice"))
|
||||
*loglevel = LOG_NOTICE;
|
||||
else if (!strcmp(optarg,"info"))
|
||||
*loglevel = LOG_INFO;
|
||||
else if (!strcmp(optarg,"debug"))
|
||||
*loglevel = LOG_DEBUG;
|
||||
else
|
||||
{
|
||||
log(LOG_ERR,"Error : argument to -l must be one of alert|crit|err|warning|notice|info|debug.");
|
||||
print_usage();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
if (isprint(c))
|
||||
log(LOG_ERR,"Missing argument or unknown option '-%c'. See help (-h).",optopt);
|
||||
else
|
||||
log(LOG_ERR,"Unknown option character 'x%x'. See help (-h).",optopt);
|
||||
print_usage();
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* the -f option is mandatory */
|
||||
if (!gotf)
|
||||
{
|
||||
log(LOG_ERR,"You must specify a config file with the -f option. See help (-h).");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* the -p option is mandatory */
|
||||
if (!gotp)
|
||||
{
|
||||
log(LOG_ERR,"You must specify a port with the -p option. See help (-h).");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* args.h
|
||||
* Routines for processing command-line arguments.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.4 2002/01/26 22:22:09 mp292
|
||||
* Prevented duplicate definitions.
|
||||
*
|
||||
* Revision 1.3 2002/01/26 22:08:40 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.2 2001/12/14 11:26:23 badbytes
|
||||
* Tested
|
||||
*
|
||||
* Revision 1.1 2001/12/13 15:15:10 badbytes
|
||||
* Started coding the onion proxy.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ARGS_H
|
||||
|
||||
#define __ARGS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* print help */
|
||||
void print_usage();
|
||||
|
||||
/* get command-line arguments */
|
||||
int getargs(int argc,char *argv[], char *args, unsigned short *p, char **conf_filename, int *loglevel);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* auth.h
|
||||
* Key exchange with an onion router.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.1 2002/03/28 11:00:57 badbytes
|
||||
* Key exchange with an onion router.
|
||||
*
|
||||
*/
|
||||
#include <openssl/rand.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "../common/log.h"
|
||||
|
||||
#include "auth.h"
|
||||
|
||||
/* send session keys and bandwidth info to the router */
|
||||
int send_auth(int or_sock, uint32_t bandwidth, RSA *pkey, unsigned char *f_session_key, unsigned char *b_session_key)
|
||||
{
|
||||
int retval;
|
||||
int x;
|
||||
unsigned char message[20]; /* bandwidth(32bits), forward key(64bits), backward key(64bits) */
|
||||
unsigned char cipher[128];
|
||||
if ((or_sock <= 0) || (bandwidth <= 0) || !pkey || !f_session_key || !b_session_key) /* invalid parameters */
|
||||
return -1;
|
||||
|
||||
bandwidth = htonl(bandwidth); /* convert to network order */
|
||||
|
||||
/* generate the session keys */
|
||||
retval = RAND_bytes(f_session_key, 8);
|
||||
if (!retval)
|
||||
{
|
||||
log(LOG_ERR,"Not enough randomness to generate a session key.");
|
||||
return -1;
|
||||
}
|
||||
retval = RAND_bytes(b_session_key, 8);
|
||||
if (!retval)
|
||||
{
|
||||
log(LOG_ERR,"Not enough randomness to generate a session key.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* compose the message */
|
||||
memcpy((void *)message, (void *)&bandwidth, 4);
|
||||
memcpy((void *)(message + 4), (void *)f_session_key, 8);
|
||||
memcpy((void *)(message + 12), (void *)b_session_key, 8);
|
||||
printf("f_session_key: ");
|
||||
for(x=0;x<8;x++) {
|
||||
printf("%d ",f_session_key[x]);
|
||||
}
|
||||
printf("\nb_session_key: ");
|
||||
for(x=0;x<8;x++) {
|
||||
printf("%d ",b_session_key[x]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* encrypt with RSA */
|
||||
retval = RSA_public_encrypt(20, message, cipher, pkey, RSA_PKCS1_PADDING);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Public key encryption failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* send the ciphertext */
|
||||
retval = send(or_sock, cipher, 128, 0);
|
||||
if (retval < 128)
|
||||
{
|
||||
log(LOG_ERR,"Connection to router lost while exchanging session keys.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* auth.h
|
||||
* Key exchange with an onion router.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.1 2002/03/28 11:00:57 badbytes
|
||||
* Key exchange with an onion router.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* send session keys and bandwidth info to the router */
|
||||
int send_auth(int or_sock, uint32_t bandwidth, RSA *pkey, unsigned char *f_session_key, unsigned char *b_session_key);
|
||||
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* buffers.c
|
||||
* Buffers.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.1 2002/04/02 14:28:01 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <unistd.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "../common/cell.h"
|
||||
#include "../common/log.h"
|
||||
|
||||
#include "buffers.h"
|
||||
#include "crypto.h"
|
||||
#include "op.h"
|
||||
|
||||
int buffer_data(uint16_t aci, unsigned char *buf, size_t buflen, unsigned char **outbuf, size_t *outbuflen, size_t *outbuf_dataoffset, size_t *outbuf_datalen, crypt_path_t **cpath, size_t cpathlen)
|
||||
{
|
||||
int retval;
|
||||
int i;
|
||||
cell_t *cellbuf;
|
||||
cell_t *c;
|
||||
size_t cellbuflen;
|
||||
size_t cells;
|
||||
unsigned char *tmpbuf; /* temporary buffer for realloc() operations */
|
||||
|
||||
if (!buf || !outbuf || !outbuflen) /* invalid parameters */
|
||||
return -1;
|
||||
|
||||
/* split the plaintext into DATA cells */
|
||||
retval = pack_data(aci,buf, buflen, (unsigned char **)&cellbuf, &cellbuflen);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_DEBUG,"buffer_data() : Could not pack data into cells.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"buffer_data() : DATA cells created.");
|
||||
|
||||
cells = cellbuflen/(sizeof(cell_t));
|
||||
/* encrypt the cells */
|
||||
for (i=0; i<cells; i++)
|
||||
{
|
||||
c = cellbuf+i;
|
||||
/* encrypt the payload length */
|
||||
retval = crypt_f((unsigned char *)&c->length, 1, cpath, cpathlen);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Could not encrypt the payload length of a DATA cell.");
|
||||
free((void *)cellbuf);
|
||||
return -1;
|
||||
}
|
||||
/* encrypt the payload */
|
||||
retval = crypt_f((unsigned char *)c->payload, CELL_PAYLOAD_SIZE, cpath, cpathlen);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Could not encrypt the payload of a DATA cell.");
|
||||
free((void *)cellbuf);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* now copy the cells into the output buffer */
|
||||
if (*outbuflen-*outbuf_dataoffset-*outbuf_datalen < cellbuflen) /* increase the buffer size if necessary */
|
||||
{
|
||||
/* allocate a new buffer (in OP_DEFAULT_BUFSIZE chunks)*/
|
||||
tmpbuf = (unsigned char *)malloc(((cellbuflen+*outbuf_datalen)/OP_DEFAULT_BUFSIZE+1)*OP_DEFAULT_BUFSIZE);
|
||||
if (!tmpbuf)
|
||||
{
|
||||
log(LOG_ERR,"Error allocating memory.");
|
||||
free((void *)cellbuf);
|
||||
return -1;
|
||||
}
|
||||
/* copy old data to the new buffer */
|
||||
memcpy((void *)tmpbuf,(void *)(*outbuf+*outbuf_dataoffset),*outbuf_datalen);
|
||||
/* replace the old buffer with the new one */
|
||||
if (*outbuf)
|
||||
free((void *)*outbuf);
|
||||
*outbuf = tmpbuf;
|
||||
*outbuflen = ((cellbuflen+*outbuf_datalen)/OP_DEFAULT_BUFSIZE+1) * OP_DEFAULT_BUFSIZE;
|
||||
*outbuf_dataoffset = 0;
|
||||
}
|
||||
memcpy((void *)(*outbuf + *outbuf_dataoffset + *outbuf_datalen), (void *)cellbuf, cellbuflen);
|
||||
*outbuf_datalen += cellbuflen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int buffer_create(uint16_t aci, unsigned char *onion, size_t onionlen, unsigned char **outbuf, size_t *outbuflen, size_t *outbuf_dataoffset, size_t *outbuf_datalen, crypt_path_t **cpath, size_t cpathlen)
|
||||
{
|
||||
int retval;
|
||||
cell_t *cellbuf;
|
||||
size_t cells;
|
||||
size_t cellbuflen;
|
||||
unsigned char *tmpbuf; /* temporary buffer for realloc() operations */
|
||||
|
||||
if (!onion || !outbuf || !outbuflen || !outbuf_dataoffset || !outbuf_datalen) /* invalid parameters */
|
||||
return -1;
|
||||
|
||||
retval = pack_create(aci,onion, onionlen, (unsigned char **)&cellbuf, &cellbuflen);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_DEBUG,"buffer_create() : Could not pack the onion into cells.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"buffer_create() : CREATE cells created.");
|
||||
|
||||
cells = cellbuflen/(sizeof(cell_t));
|
||||
|
||||
/* now copy the cells into the output buffer */
|
||||
if (*outbuflen-*outbuf_dataoffset-*outbuf_datalen < cellbuflen) /* increase the buffer size if necessary */
|
||||
{
|
||||
/* allocate a new buffer (in OP_DEFAULT_BUFSIZE chunks)*/
|
||||
tmpbuf = (unsigned char *)malloc(((cellbuflen+*outbuf_datalen)/OP_DEFAULT_BUFSIZE+1)*OP_DEFAULT_BUFSIZE);
|
||||
if (!tmpbuf)
|
||||
{
|
||||
log(LOG_ERR,"Error allocating memory.");
|
||||
free((void *)cellbuf);
|
||||
return -1;
|
||||
}
|
||||
/* copy old data to the new buffer */
|
||||
memcpy((void *)tmpbuf,(void *)(*outbuf+*outbuf_dataoffset),*outbuf_datalen);
|
||||
/* replace the old buffer with the new one */
|
||||
if (*outbuf)
|
||||
free((void *)*outbuf);
|
||||
*outbuf = tmpbuf;
|
||||
*outbuflen = ((cellbuflen+*outbuf_datalen)/OP_DEFAULT_BUFSIZE+1) * OP_DEFAULT_BUFSIZE;
|
||||
*outbuf_dataoffset = 0;
|
||||
}
|
||||
memcpy((void *)(*outbuf + *outbuf_dataoffset + *outbuf_datalen), (void *)cellbuf, cellbuflen);
|
||||
*outbuf_datalen += cellbuflen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* buffers.h
|
||||
* Buffers.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.1 2002/04/02 14:28:01 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../common/onion.h"
|
||||
|
||||
int buffer_data(uint16_t aci, unsigned char *buf, size_t buflen, unsigned char **outbuf, size_t *outbuflen, size_t *outbuf_dataoffset, size_t *outbuf_datalen, crypt_path_t **cpath, size_t cpathlen);
|
||||
int buffer_create(uint16_t aci, unsigned char *onion, size_t onionlen, unsigned char **outbuf, size_t *outbuflen, size_t *outbuf_dataoffset, size_t *outbuf_datalen, crypt_path_t **cpath, size_t cpathlen);
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* config.c
|
||||
* Routines for loading the configuration file.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.3 2002/04/02 14:28:01 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.2 2002/01/26 22:09:53 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.1 2001/12/13 15:15:10 badbytes
|
||||
* Started coding the onion proxy.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "../common/log.h"
|
||||
|
||||
/* loads the configuration file */
|
||||
int getconfig(char *conf_filename, config_opt_t *options)
|
||||
{
|
||||
FILE *cf = NULL;
|
||||
int retval = 0;
|
||||
|
||||
if ((!conf_filename) || (!options))
|
||||
return -1;
|
||||
|
||||
/* load config file */
|
||||
cf = open_config(conf_filename);
|
||||
if (!cf)
|
||||
{
|
||||
log(LOG_ERR,"Could not open configuration file %s.",conf_filename);
|
||||
return -1;
|
||||
}
|
||||
retval = parse_config(cf,options);
|
||||
if (retval)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* config.h
|
||||
* Routines for loading the configuration file.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.4 2002/04/02 14:28:01 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.3 2002/01/26 22:55:11 mp292
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.2 2002/01/26 22:22:09 mp292
|
||||
* Prevented duplicate definitions.
|
||||
*
|
||||
* Revision 1.1 2001/12/13 15:15:10 badbytes
|
||||
* Started coding the onion proxy.
|
||||
*
|
||||
*/
|
||||
#include "../common/config.h"
|
||||
|
||||
/* loads the configuration file */
|
||||
int getconfig(char *filename, config_opt_t *options);
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* crypto.c
|
||||
* Crypto calls.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.1 2002/04/02 14:28:01 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
#include <unistd.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "../common/log.h"
|
||||
|
||||
#include "crypto.h"
|
||||
|
||||
int crypt_f(unsigned char *buf, size_t buflen, crypt_path_t **cpath, size_t cpathlen)
|
||||
{
|
||||
int i=0;
|
||||
int retval = 0;
|
||||
unsigned char *ciphertext = NULL;
|
||||
crypt_path_t *thishop;
|
||||
|
||||
/* allocate the ciphertext buffer */
|
||||
ciphertext = (unsigned char *)malloc(buflen);
|
||||
if (!ciphertext)
|
||||
{
|
||||
log(LOG_ERR,"Error allocating memory.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i=0; i < cpathlen; i++) /* moving from last to first hop
|
||||
* Remember : cpath is in reverse order, i.e. last hop first
|
||||
*/
|
||||
{
|
||||
log(LOG_DEBUG,"crypt_f() : Processing hop %u",cpathlen-i);
|
||||
thishop = cpath[i];
|
||||
|
||||
/* encrypt */
|
||||
retval = EVP_EncryptUpdate(&thishop->f_ctx,ciphertext, &buflen, buf, buflen);
|
||||
if (!retval) /* error */
|
||||
{
|
||||
log(LOG_ERR,"Error performing encryption:%s",ERR_reason_error_string(ERR_get_error()));
|
||||
free(ciphertext);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* copy ciphertext back to buf */
|
||||
memcpy((void *)buf,(void *)ciphertext,buflen);
|
||||
}
|
||||
free((void *)ciphertext);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_b(unsigned char *buf, size_t buflen, crypt_path_t **cpath, size_t cpathlen)
|
||||
{
|
||||
int i=0;
|
||||
int retval=0;
|
||||
unsigned char *plaintext=NULL;
|
||||
crypt_path_t *thishop;
|
||||
|
||||
/* allocate the plaintext buffer */
|
||||
plaintext = (unsigned char *)malloc(buflen);
|
||||
if (!plaintext)
|
||||
{
|
||||
log(LOG_ERR,"Error allocating memory.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i=cpathlen-1; i >= 0; i--) /* moving from first to last hop
|
||||
* Remember : cpath is in reverse order, i.e. last hop first
|
||||
*/
|
||||
{
|
||||
thishop = cpath[i];
|
||||
|
||||
/* encrypt */
|
||||
retval = EVP_DecryptUpdate(&thishop->b_ctx,plaintext, &buflen, buf, buflen);
|
||||
if (!retval) /* error */
|
||||
{
|
||||
log(LOG_ERR,"Error performing decryption:%s",ERR_reason_error_string(ERR_get_error()));
|
||||
free(plaintext);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* copy plaintext back to buf */
|
||||
memcpy((void *)buf,(void *)plaintext,buflen);
|
||||
}
|
||||
|
||||
free(plaintext);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* crypto.h
|
||||
* Crypto calls.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.1 2002/04/02 14:28:01 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../common/onion.h"
|
||||
|
||||
int crypt_f(unsigned char *buf, size_t buflen, crypt_path_t **cpath, size_t cpathlen);
|
||||
|
||||
int crypt_b(unsigned char *buf, size_t buflen, crypt_path_t **cpath, size_t cpathlen);
|
||||
@@ -0,0 +1,916 @@
|
||||
/**
|
||||
* op.c
|
||||
* Onion Proxy
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.37 2002/06/14 20:45:56 mp292
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.36 2002/04/02 14:28:01 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.35 2002/04/02 10:21:07 badbytes
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.34 2002/03/29 08:35:12 badbytes
|
||||
* Link encryption is now done on the entire cell header for simplicity.
|
||||
*
|
||||
* Revision 1.33 2002/03/28 17:57:59 badbytes
|
||||
* Bug fix.
|
||||
*
|
||||
* Revision 1.32 2002/03/28 11:01:43 badbytes
|
||||
* Now does link-encryption and link-padding.
|
||||
*
|
||||
* Revision 1.31 2002/03/12 23:40:32 mp292
|
||||
* Started on op<->router connection padding.
|
||||
*
|
||||
* Revision 1.30 2002/01/29 02:22:58 mp292
|
||||
* Put a timeout on all network I/O.
|
||||
*
|
||||
* Revision 1.29 2002/01/26 23:01:55 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.28 2002/01/18 20:42:06 mp292
|
||||
* Reflects changes to common/onion.c:new_route()
|
||||
*
|
||||
* Revision 1.27 2002/01/17 23:49:15 mp292
|
||||
* Added size of public key to one of the debugging messages.
|
||||
*
|
||||
* Revision 1.26 2002/01/16 23:01:58 mp292
|
||||
* First phase of system testing completed (main functionality).
|
||||
*
|
||||
* Revision 1.25 2002/01/16 17:01:56 mp292
|
||||
* There was a bug in checking whether the incoming connection is local or not.
|
||||
*
|
||||
* Revision 1.24 2002/01/16 16:09:32 mp292
|
||||
* A pointer cast was missing. Fixed.
|
||||
*
|
||||
* Revision 1.23 2002/01/14 13:05:39 badbytes
|
||||
* System testing in progress.
|
||||
*
|
||||
* Revision 1.22 2002/01/11 15:47:25 badbytes
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.21 2002/01/09 09:18:35 badbytes
|
||||
* Now handles EINTR error from accept().
|
||||
*
|
||||
* Revision 1.20 2002/01/09 07:57:18 badbytes
|
||||
* Ciphers got out of sync, hopefully fixed.
|
||||
*
|
||||
* Revision 1.19 2001/12/19 11:15:41 badbytes
|
||||
* Corrected AF_INET to PF_INET in socket() calls.
|
||||
*
|
||||
* Revision 1.18 2001/12/19 08:38:38 badbytes
|
||||
* Zombie problems hopefully fixed.
|
||||
*
|
||||
* Revision 1.17 2001/12/19 08:29:29 badbytes
|
||||
* Tested. Still some problems with zombies in both op and smtpap.
|
||||
*
|
||||
* Revision 1.16 2001/12/18 15:51:58 badbytes
|
||||
* Connection with onion router established. Will continue testing tomorrow.
|
||||
*
|
||||
* Revision 1.15 2001/12/18 14:12:05 badbytes
|
||||
* Tested up to connect() to onion router.
|
||||
*
|
||||
* Revision 1.14 2001/12/18 12:21:11 badbytes
|
||||
* Forgot to convert port to network order :-)
|
||||
*
|
||||
* Revision 1.13 2001/12/18 11:52:27 badbytes
|
||||
* Coding completed. Proceeding to test.
|
||||
*
|
||||
* Revision 1.12 2001/12/17 13:36:15 badbytes
|
||||
* Writing handle_connection()
|
||||
*
|
||||
* Revision 1.11 2001/12/17 08:42:44 badbytes
|
||||
* getrouters() now returns an array of routers and also writes the length of the array to an int*.
|
||||
*
|
||||
* Revision 1.10 2001/12/14 14:45:13 badbytes
|
||||
* Added range checking for CoinWeight.
|
||||
*
|
||||
* Revision 1.9 2001/12/14 14:08:50 badbytes
|
||||
* getrouters() now returns an array of pointers rather than a linked list
|
||||
*
|
||||
* Revision 1.8 2001/12/14 13:31:20 badbytes
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.7 2001/12/14 13:17:12 badbytes
|
||||
* Corrected references to types.h
|
||||
*
|
||||
* Revision 1.6 2001/12/14 13:00:30 badbytes
|
||||
* Changed my mind, routers.c and routers.h stay where they are :-)
|
||||
*
|
||||
* Revision 1.5 2001/12/14 12:56:55 badbytes
|
||||
* Moved routers* to common/
|
||||
*
|
||||
* Revision 1.4 2001/12/14 12:42:50 badbytes
|
||||
* References to onion.h and onion.o now point to the common/ directory.
|
||||
*
|
||||
* Revision 1.3 2001/12/14 12:40:26 badbytes
|
||||
* Was being stupid - op doesn't need a private key!! Have removed ...
|
||||
*
|
||||
* Revision 1.2 2001/12/14 11:27:16 badbytes
|
||||
* Configuration and server setup completed.
|
||||
*
|
||||
* Revision 1.1 2001/12/13 15:15:11 badbytes
|
||||
* Started coding the onion proxy.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <wait.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "../common/log.h"
|
||||
#include "../common/version.h"
|
||||
#include "../common/onion.h"
|
||||
#include "../common/utils.h"
|
||||
#include "../common/cell.h"
|
||||
#include "../common/scheduler.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "routers.h"
|
||||
#include "args.h"
|
||||
#include "auth.h"
|
||||
#include "op.h"
|
||||
#include "ss.h"
|
||||
#include "crypto.h"
|
||||
#include "buffers.h"
|
||||
|
||||
/* global variables */
|
||||
|
||||
/* default logging threshold */
|
||||
int loglevel = LOG_ERR;
|
||||
struct timeval conn_tout;
|
||||
struct timeval *conn_toutp = &conn_tout;
|
||||
|
||||
/* valid command-line options */
|
||||
static char *args = "hf:p:l:";
|
||||
|
||||
/* valid config file options */
|
||||
static config_opt_t options[] =
|
||||
{
|
||||
{"RouterFile", CONFIG_TYPE_STRING, {0}, 0},
|
||||
{"CoinWeight", CONFIG_TYPE_DOUBLE, {0}, 0},
|
||||
{"MaxConn", CONFIG_TYPE_INT, {0}, 0},
|
||||
{"ConnTimeout", CONFIG_TYPE_INT, {0}, 0},
|
||||
{"Bandwidth", CONFIG_TYPE_INT, {0}, 0},
|
||||
{0}
|
||||
};
|
||||
enum opts {
|
||||
RouterFile=0, CoinWeight, MaxConn, ConnTimeout, Bandwidth
|
||||
};
|
||||
|
||||
int connections = 0; /* number of active connections */
|
||||
|
||||
/* local host info */
|
||||
struct hostent *local_host;
|
||||
char local_hostname[512];
|
||||
|
||||
struct sockaddr_in local, remote; /* local and remote address info */
|
||||
struct sockaddr_in or_addr; /* onion router address */
|
||||
|
||||
int request_sock; /* where we listen for connections */
|
||||
int new_sock; /* for accepted connections */
|
||||
int or_sock; /* for connecting to the first onion router */
|
||||
|
||||
/* router array */
|
||||
routent_t **routerarray = NULL;
|
||||
int rarray_len = 0;
|
||||
|
||||
/* end of global variables */
|
||||
|
||||
void send_to_router(int s,unsigned char **outbuf, size_t *outbuflen, size_t *outbuf_dataoffset, size_t *outbuf_datalen, struct timeval *lastsend, struct timeval *interval, sched_t *scheduler, EVP_CIPHER_CTX *ctx)
|
||||
{
|
||||
int retval;
|
||||
int cells;
|
||||
int datacells;
|
||||
int paddingcells;
|
||||
int i;
|
||||
int x;
|
||||
char *px;
|
||||
struct timeval now;
|
||||
cell_t cipher;
|
||||
cell_t *padding;
|
||||
int cipherlen;
|
||||
unsigned long elapsed;
|
||||
|
||||
/* calculate the number of cells that need to be sent */
|
||||
retval = gettimeofday(&now,NULL);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Could not get current time!");
|
||||
return;
|
||||
}
|
||||
|
||||
elapsed = 1000000*(now.tv_sec-lastsend->tv_sec) + now.tv_usec-lastsend->tv_usec;
|
||||
|
||||
if (elapsed < 1000000)
|
||||
{
|
||||
cells = ((options[Bandwidth].r.i) * 512) / /* number of bytes per second, divided by two */
|
||||
(1000000/elapsed); /* fractions of second since last send */
|
||||
}
|
||||
else
|
||||
{
|
||||
cells = ((options[Bandwidth].r.i) * 512) * /* number of bytes per second, divided by two */
|
||||
(elapsed/1000000); /* 1/fractions of second since last send */
|
||||
}
|
||||
cells /= sizeof(cell_t);
|
||||
|
||||
datacells = (*outbuf_datalen)/sizeof(cell_t); /* number of data cells available */
|
||||
if (datacells > cells)
|
||||
datacells = cells;
|
||||
paddingcells = cells - datacells;
|
||||
|
||||
/* send the data cells first */
|
||||
for (i=0; i<datacells; i++)
|
||||
{
|
||||
/* link-encrypt the cell header */
|
||||
printf("Cell header plaintext: ");
|
||||
for(x=0;x<8;x++) {
|
||||
printf("%u ",*(char *)(*outbuf+*outbuf_dataoffset+x));
|
||||
}
|
||||
printf("\n");
|
||||
retval = EVP_EncryptUpdate(ctx, (unsigned char *)&cipher, &cipherlen, *outbuf+*outbuf_dataoffset, 8);
|
||||
if (!retval)
|
||||
{
|
||||
log(LOG_ERR,"Link encryption failed. Exiting.");
|
||||
exit(-1);
|
||||
}
|
||||
printf("Cell header crypttext: ");
|
||||
px = (char *)&cipher;
|
||||
for(x=0;x<8;x++) {
|
||||
printf("%u ",px[x]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* copy the payload */
|
||||
memcpy((void *)cipher.payload, (void *)(*outbuf+*outbuf_dataoffset+8), CELL_PAYLOAD_SIZE);
|
||||
|
||||
/* send the cell */
|
||||
log(LOG_DEBUG,"send_to_router(): Trying to send a data/create cell to router.");
|
||||
retval = write_tout(s,(unsigned char *)&cipher, sizeof(cell_t), conn_toutp);
|
||||
if (retval < sizeof(cell_t))
|
||||
{
|
||||
log(LOG_ERR,"Connection to the router seems to be lost. Exiting.");
|
||||
exit(-1);
|
||||
}
|
||||
*outbuf_dataoffset += sizeof(cell_t);
|
||||
*outbuf_datalen -= sizeof(cell_t);
|
||||
|
||||
}
|
||||
|
||||
/* send padding */
|
||||
for (i=0; i<cells-datacells; i++)
|
||||
{
|
||||
padding = new_padding_cell();
|
||||
if (!padding)
|
||||
{
|
||||
log(LOG_ERR,"Memory allocation error. Exiting.");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* link encrypt the cell header */
|
||||
retval = EVP_EncryptUpdate(ctx, (unsigned char *)&cipher, &cipherlen, (unsigned char *)padding, 8);
|
||||
if (!retval)
|
||||
{
|
||||
log(LOG_ERR,"Link encryption failed. Exiting.");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* copy the payload */
|
||||
memcpy((void *)cipher.payload, (void *)((unsigned char *)padding+8), CELL_PAYLOAD_SIZE);
|
||||
|
||||
/* send the cell */
|
||||
log(LOG_DEBUG,"send_to_router(): Trying to send a padding cell to router.");
|
||||
retval = write_tout(s, (unsigned char *)&cipher, sizeof(cell_t), conn_toutp);
|
||||
if (retval < sizeof(cell_t))
|
||||
{
|
||||
log(LOG_ERR,"Connection to the router seems to be lost. Exiting.");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
free((void *)padding);
|
||||
}
|
||||
|
||||
/* update scheduler state, if we've sent anything to the router */
|
||||
if (cells)
|
||||
{
|
||||
retval = update_sched_entry(scheduler, *lastsend, *interval, now, *interval);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Scheduler error. Exiting.");
|
||||
exit(-1);
|
||||
}
|
||||
memcpy((void *)lastsend,(void *)&now, sizeof(struct timeval));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* deal with a client */
|
||||
int handle_connection()
|
||||
{
|
||||
int retval = 0;
|
||||
int routelen = 0; /* length of the route */
|
||||
unsigned int *route = NULL; /* hops in the route as an array of indexes into rarray */
|
||||
routent_t *firsthop = NULL;
|
||||
|
||||
uint32_t aci; /* ACI for this connection */
|
||||
|
||||
unsigned char *onion = NULL; /* holds the onion */
|
||||
int onionlen = 0; /* onion length in host order */
|
||||
|
||||
crypt_path_t **cpath = NULL; /* defines the crypt operations that need to be performed on incoming/outgoing data */
|
||||
char *dest_addr = NULL; /* destination address in ASCII format */
|
||||
|
||||
int dest_addrlen = 0;
|
||||
char *dest_port = NULL; /* destination port in ASCII format */
|
||||
int dest_portlen = 0;
|
||||
ss_t *ss; /* standard structure */
|
||||
|
||||
uint32_t router_addr_net; /* address of the first onion router in network order */
|
||||
|
||||
unsigned char inbuf[1024]; /* buffer for forwarding data between ap and or */
|
||||
|
||||
unsigned char *outbuf = NULL; /* buffer for cells which are to be transmitted to the first core onion router in the route */
|
||||
size_t outbuflen = 0;
|
||||
size_t outbuf_dataoffset = 0; /* offset to the beginning of the data */
|
||||
size_t outbuf_datalen = 0; /* length of the data stored in the buffer */
|
||||
|
||||
cell_t cellbuf;
|
||||
int cellbuflen = 0;
|
||||
|
||||
struct timeval lastsend; /* time of last transmission to the onion router */
|
||||
struct timeval interval; /* transmission interval */
|
||||
|
||||
/* link encryption */
|
||||
unsigned char f_session_key[8];
|
||||
unsigned char f_session_iv[8] = {0,0,0,0,0,0,0,0};
|
||||
unsigned char b_session_key[8];
|
||||
unsigned char b_session_iv[8] = {0,0,0,0,0,0,0,0};
|
||||
EVP_CIPHER_CTX f_ctx;
|
||||
EVP_CIPHER_CTX b_ctx;
|
||||
|
||||
/* scheduler */
|
||||
sched_t *scheduler;
|
||||
|
||||
/* for use with select() */
|
||||
fd_set rmask, mask;
|
||||
int maxfd;
|
||||
struct timeval *timeout;
|
||||
|
||||
/* get the standard structure */
|
||||
retval = process_ss(new_sock, conn_toutp, &ss,&dest_addr, &dest_addrlen, &dest_port, &dest_portlen);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Error processing the standard structure.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection() : Destination = %s:%s",dest_addr,dest_port);
|
||||
|
||||
/* choose a route */
|
||||
route = (unsigned int *)new_route(options[CoinWeight].r.d, routerarray,rarray_len, &routelen);
|
||||
if (!route)
|
||||
{
|
||||
log(LOG_ERR,"Error choosing a route through the OR network.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection() : Chosen a route of length %u : ",routelen);
|
||||
for (retval=routelen-1;retval>=0;retval--)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : %u : %s:%u, %u",routelen-retval,(routerarray[route[retval]])->address,ntohs((routerarray[route[retval]])->port),RSA_size((routerarray[route[retval]])->pkey));
|
||||
}
|
||||
|
||||
/* allocate memory for the crypt path */
|
||||
cpath = malloc(routelen * sizeof(crypt_path_t *));
|
||||
if (!cpath)
|
||||
{
|
||||
log(LOG_ERR,"Error allocating memory.");
|
||||
free(route);
|
||||
return -1;
|
||||
}
|
||||
/* create an onion and calculate crypto keys */
|
||||
onion = create_onion(routerarray,rarray_len,route,routelen,&onionlen,cpath);
|
||||
if (!onion)
|
||||
{
|
||||
log(LOG_ERR,"Error creating an onion.");
|
||||
free(route);
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection() : Created an onion of size %u bytes.",onionlen);
|
||||
log(LOG_DEBUG,"handle_connection() : Crypt path :");
|
||||
for (retval=0;retval<routelen;retval++)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : %u/%u",(cpath[retval])->forwf, (cpath[retval])->backf);
|
||||
}
|
||||
|
||||
/* connect to first onion router */
|
||||
or_sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
|
||||
if (or_sock < 0)
|
||||
{
|
||||
free(route);
|
||||
free(onion);
|
||||
free(cpath);
|
||||
close(new_sock);
|
||||
log(LOG_ERR,"Error creating socket.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection() : Socket created.");
|
||||
|
||||
firsthop = routerarray[route[routelen-1]];
|
||||
memset((void *)&or_addr,0,sizeof(or_addr));
|
||||
or_addr.sin_family=AF_INET;
|
||||
or_addr.sin_port=firsthop->entry_port;
|
||||
router_addr_net = firsthop->addr;
|
||||
memcpy(&or_addr.sin_addr,&router_addr_net,sizeof(struct sockaddr_in));
|
||||
log(LOG_DEBUG,"handle_connection() : Trying to connect to %s:%u",inet_ntoa(or_addr.sin_addr), ntohs(or_addr.sin_port));
|
||||
retval = connect(or_sock,(struct sockaddr *)&or_addr, sizeof(or_addr));
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Could not connect to onion router.");
|
||||
free(route);
|
||||
free(onion);
|
||||
free(cpath);
|
||||
close(or_sock);
|
||||
close(new_sock);
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection() : Connected to first onion router.");
|
||||
|
||||
/* send session key and bandwidth info */
|
||||
retval = send_auth(or_sock, options[Bandwidth].r.i, firsthop->pkey, f_session_key, b_session_key);
|
||||
if (retval == -1)
|
||||
{
|
||||
close(or_sock);
|
||||
close(new_sock);
|
||||
log(LOG_ERR,"Lost connection to an onion router. Exiting.");
|
||||
return -1;
|
||||
}
|
||||
/* initialize crypto engines */
|
||||
EVP_CIPHER_CTX_init(&f_ctx);
|
||||
EVP_CIPHER_CTX_init(&b_ctx);
|
||||
EVP_EncryptInit(&f_ctx, EVP_des_ofb(), f_session_key, f_session_iv);
|
||||
EVP_DecryptInit(&b_ctx, EVP_des_ofb(), b_session_key, b_session_iv);
|
||||
|
||||
/* chose an ACI */
|
||||
do
|
||||
{
|
||||
retval = RAND_pseudo_bytes((unsigned char *)&aci, 2);
|
||||
if (retval==-1)
|
||||
{
|
||||
log(LOG_ERR,"Random data generator doesn't seem to work. Exiting.");
|
||||
return -1;
|
||||
}
|
||||
} while(!aci); /* don't allow zero ACIs */
|
||||
log(LOG_DEBUG,"handle_connection() : ACI %u chosen.",aci);
|
||||
|
||||
/* initialize last time of transmission to now */
|
||||
retval = gettimeofday(&lastsend, NULL);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Could not get current time.");
|
||||
return -1;
|
||||
}
|
||||
/* calculate the transmission interval */
|
||||
interval.tv_sec = 0;
|
||||
interval.tv_usec = 250000/options[Bandwidth].r.i;
|
||||
/* initialize the scheduler */
|
||||
scheduler = new_sched();
|
||||
if (!scheduler)
|
||||
{
|
||||
log(LOG_ERR,"Could not initialize scheduler.");
|
||||
return -1;
|
||||
}
|
||||
retval = add_sched_entry(scheduler, lastsend, interval);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Could not initialize scheduler.");
|
||||
return -1;
|
||||
}
|
||||
timeout = NULL;
|
||||
|
||||
/* write the onion into the output buffer */
|
||||
retval = buffer_create(aci, (unsigned char *)onion, onionlen, &outbuf, &outbuflen, &outbuf_dataoffset, &outbuf_datalen, cpath, routelen);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : Could not buffer the onion.");
|
||||
close(or_sock);
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection() : Onion buffered for output.");
|
||||
|
||||
/* send standard structure */
|
||||
log(LOG_DEBUG,"handle_connection() : Calling send_crypt ... routelen=%u, sizeof(SS) = %u",routelen,sizeof(ss_t));
|
||||
retval = buffer_data(aci, (unsigned char *)ss, sizeof(ss_t), &outbuf, &outbuflen, &outbuf_dataoffset, &outbuf_datalen, cpath, routelen);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : Could not buffer the standard structure for output.");
|
||||
close(or_sock);
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection() : Buffered the standard structure header.");
|
||||
retval = buffer_data(aci, dest_addr,dest_addrlen, &outbuf, &outbuflen, &outbuf_dataoffset, &outbuf_datalen, cpath, routelen);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : Could not buffer the standard structure (dest. address) for output.");
|
||||
close(or_sock);
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection() : Buffered the destination address.");
|
||||
retval = buffer_data(aci, dest_port, dest_portlen, &outbuf, &outbuflen, &outbuf_dataoffset, &outbuf_datalen, cpath, routelen);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : Could not buffer the standard structure (dest. port) for output.");
|
||||
close(or_sock);
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection() : Buffered the destination port.");
|
||||
|
||||
|
||||
/* forward data in both directions, crypt as necessary */
|
||||
/* use select() */
|
||||
|
||||
FD_ZERO(&mask);
|
||||
FD_SET(new_sock, &mask);
|
||||
FD_SET(or_sock, &mask);
|
||||
if (new_sock > or_sock)
|
||||
maxfd = new_sock;
|
||||
else
|
||||
maxfd = or_sock;
|
||||
|
||||
while(1)
|
||||
{
|
||||
rmask = mask;
|
||||
|
||||
/* delete old timeout */
|
||||
if (timeout)
|
||||
free((void *)timeout);
|
||||
/* get the new one */
|
||||
retval = sched_trigger(scheduler, &timeout);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_DEBUG,"Scheduler error.");
|
||||
break;
|
||||
}
|
||||
retval = select(maxfd+1,&rmask,NULL,NULL,timeout);
|
||||
if (retval < 0)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : select() returned negative integer");
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(new_sock,&rmask))
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : FD_ISSET(new_sock)");
|
||||
retval = read_tout(new_sock, inbuf, 1024, 0, conn_toutp);
|
||||
if (retval <= 0)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : Received EOF on new_sock.");
|
||||
break;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection() : Received %u bytes from client.",retval);
|
||||
retval = buffer_data(aci, inbuf, retval, &outbuf, &outbuflen, &outbuf_dataoffset, &outbuf_datalen, cpath, routelen);
|
||||
|
||||
if (retval < 0)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : Could not buffer data for output to OR.");
|
||||
break;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection() : Buffered %u bytes for output to the OR.",retval);
|
||||
}
|
||||
|
||||
if (FD_ISSET(or_sock, &rmask))
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : FD_ISSET(or_sock)");
|
||||
/* read the remainder of the cell (or whatever we can get) */
|
||||
retval = read_tout(or_sock, ((unsigned char *)&cellbuf)+cellbuflen, sizeof(cell_t) - cellbuflen, 0, conn_toutp);
|
||||
if (retval <= 0)
|
||||
{
|
||||
log(LOG_DEBUG,"handle_connection() : Received EOF on or_sock.");
|
||||
break;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection() : Received %u bytes from router.",retval);
|
||||
cellbuflen += retval;
|
||||
|
||||
if (cellbuflen == sizeof(cell_t)) /* received an entire cell */
|
||||
{
|
||||
/* link decrypt the cell header */
|
||||
retval = EVP_DecryptUpdate(&b_ctx, (unsigned char *)inbuf, &cellbuflen, (unsigned char *)&cellbuf, 8);
|
||||
if (!retval)
|
||||
{
|
||||
log(LOG_ERR,"Decryption error. Closing the connection and exiting.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (((cell_t *)inbuf)->command == CELL_PADDING) /* padding, discard */
|
||||
{
|
||||
log(LOG_DEBUG,"Received a PADDING cell. Discarding.");
|
||||
; /* discard */
|
||||
}
|
||||
else if (((cell_t *)inbuf)->command == CELL_DATA) /* only process DATA cells , discard otherwise */
|
||||
{
|
||||
/* decrypt the payload length */
|
||||
retval = crypt_b((unsigned char *)&((cell_t *)inbuf)->length, 1, cpath, routelen);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Decryption error. Closing the connection and exiting.");
|
||||
break;
|
||||
}
|
||||
|
||||
/* decrypt the payload */
|
||||
retval = crypt_b((unsigned char *)cellbuf.payload, CELL_PAYLOAD_SIZE, cpath, routelen);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Decryption error. Closing the connection and exiting.");
|
||||
break;
|
||||
}
|
||||
|
||||
/* send the payload to the application proxy */
|
||||
retval = write_tout(new_sock, (unsigned char *)cellbuf.payload, ((cell_t *)inbuf)->length, conn_toutp);
|
||||
if (retval < ((cell_t *)inbuf)->length)
|
||||
{
|
||||
log(LOG_ERR,"Connection to the application proxy seems to be lost.");
|
||||
break;
|
||||
}
|
||||
log(LOG_DEBUG,"handle_connection() : Sent %u bytes to client.",retval);
|
||||
}
|
||||
else
|
||||
log(LOG_DEBUG,"handle_connection() : Recived cell has incorrect command or ACI. Discarding.");
|
||||
|
||||
cellbuflen = 0; /* get ready for the next cell */
|
||||
}
|
||||
}
|
||||
|
||||
/* send cells to the router */
|
||||
send_to_router(or_sock,&outbuf, &outbuflen, &outbuf_dataoffset, &outbuf_datalen, &lastsend, &interval, scheduler, &f_ctx);
|
||||
}
|
||||
|
||||
/* clean up */
|
||||
log(LOG_DEBUG,"handle_connection() : handle_connection() exiting.");
|
||||
close(or_sock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* used for reaping zombie processes */
|
||||
void sigchld_handler(int s)
|
||||
{
|
||||
while (wait(NULL) > 0);
|
||||
connections--;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int one = 1;
|
||||
int retval = 0;
|
||||
|
||||
char *cp; /* temporary storage */
|
||||
int i=0; /* iteration counter */
|
||||
|
||||
char *conf_filename = NULL; /* configuration file */
|
||||
|
||||
size_t sin_size; /* for accept() calls */
|
||||
|
||||
u_short p; /* onion proxy port */
|
||||
|
||||
/* used for reaping zombie processes */
|
||||
struct sigaction sa;
|
||||
|
||||
int islocal = 0; /* is the incoming connection local? */
|
||||
|
||||
struct rlimit cd_limit; /* resource limit to prevent core dumps */
|
||||
|
||||
/* prevent core dump */
|
||||
retval = getrlimit(RLIMIT_CORE, &cd_limit);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Could not tell the OS to prevent core dumps for the process.");
|
||||
return -1;
|
||||
}
|
||||
cd_limit.rlim_cur = 0;
|
||||
retval = setrlimit(RLIMIT_CORE, &cd_limit);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Could not tell the OS to prevent core dumps for the process.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* get command-line arguments */
|
||||
retval = getargs(argc,argv,args,&p,&conf_filename,&loglevel);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Error processing command-line arguments.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* load config file */
|
||||
retval = getconfig(conf_filename,options);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Error loading configuration file.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (options[RouterFile].err != 1)
|
||||
{
|
||||
log(LOG_ERR,"RouterFile option required, but not found.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (options[CoinWeight].err == -1)
|
||||
{
|
||||
log(LOG_ERR,"Error reading the CoinWeight option.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (options[CoinWeight].err == 0)
|
||||
{
|
||||
/* this is optional, so if not found, set default value */
|
||||
options[CoinWeight].r.d = OP_DEFAULT_COIN_WEIGHT;
|
||||
}
|
||||
else if ((options[CoinWeight].r.d < 0) || (options[CoinWeight].r.d >= 1))
|
||||
{
|
||||
/* must be a value in [0,1) */
|
||||
log(LOG_ERR,"CoinWeight option must be >= 0 and < 1.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (options[Bandwidth].err == 0)
|
||||
{
|
||||
/* optional, set to default */
|
||||
options[Bandwidth].r.i = OP_DEFAULT_BANDWIDTH;
|
||||
}
|
||||
else if (options[Bandwidth].r.i <= 0)
|
||||
{
|
||||
log(LOG_ERR,"The Bandwidth option must be an integer greater than zero.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (options[ConnTimeout].err != 1)
|
||||
{
|
||||
conn_tout.tv_sec = OP_DEFAULT_CONN_TIMEOUT;
|
||||
conn_tout.tv_usec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!options[ConnTimeout].r.i)
|
||||
conn_toutp = NULL;
|
||||
else
|
||||
conn_tout.tv_sec = options[ConnTimeout].r.i;
|
||||
conn_tout.tv_usec = 0;
|
||||
}
|
||||
|
||||
/* load the routers file */
|
||||
routerarray = getrouters(options[RouterFile].r.str,&rarray_len);
|
||||
if (!routerarray)
|
||||
{
|
||||
log(LOG_ERR,"Error loading router list.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* get local address so that we know where to allow connections from*/
|
||||
retval = gethostname(local_hostname, (size_t)512);
|
||||
if (retval < 0)
|
||||
{
|
||||
log(LOG_ERR,"Error getting local hostname.");
|
||||
return -1;
|
||||
}
|
||||
local_host = gethostbyname(local_hostname);
|
||||
if (!local_host)
|
||||
{
|
||||
log(LOG_ERR,"Error getting local address.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"main() : Got local address : %s.",local_hostname);
|
||||
|
||||
/* get the server up and running */
|
||||
request_sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
|
||||
if (request_sock < 0)
|
||||
{
|
||||
log(LOG_ERR,"Error opening socket.");
|
||||
return -1;
|
||||
}
|
||||
setsockopt(request_sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
|
||||
log(LOG_DEBUG,"main() : Socket opened.");
|
||||
|
||||
memset((void *)&local,0,sizeof(local)); /* clear the structure first */
|
||||
/* set up the sockaddr_in structure */
|
||||
local.sin_family=AF_INET;
|
||||
local.sin_addr.s_addr = INADDR_ANY;
|
||||
local.sin_port=htons(p);
|
||||
/* bind it to the socket */
|
||||
retval = bind(request_sock,(struct sockaddr *)&local, sizeof(local));
|
||||
if (retval < 0)
|
||||
{
|
||||
log(LOG_ERR,"Error binding socket to local port %d.",p);
|
||||
return retval;
|
||||
}
|
||||
log(LOG_DEBUG,"main() : Socket bound to port %d.",p);
|
||||
/* listen for connections */
|
||||
retval = listen(request_sock,SOMAXCONN);
|
||||
if (retval < 0)
|
||||
{
|
||||
log(LOG_ERR,"Could not listen for connections.");
|
||||
return retval;
|
||||
}
|
||||
log(LOG_DEBUG,"main() : Listening for connections.");
|
||||
/* server should now be up and running */
|
||||
|
||||
/* install the signal handler for making sure zombie processes are killed */
|
||||
sa.sa_handler = sigchld_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
retval = sigaction(SIGCHLD,&sa,NULL);
|
||||
if (retval < 0)
|
||||
{
|
||||
log(LOG_ERR,"Could not install a signal handler.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* main server loop */
|
||||
/* I use a forking server technique - this isn't the most efficient way to do it,
|
||||
* but it is simpler. */
|
||||
while(1)
|
||||
{
|
||||
sin_size = sizeof(struct sockaddr_in);
|
||||
new_sock = accept(request_sock,(struct sockaddr *)&remote,&sin_size);
|
||||
if (new_sock == -1)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
log(LOG_ERR,"Could not accept socket connection.");
|
||||
else
|
||||
log(LOG_DEBUG,"main() : Interrupt received.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (connections == options[MaxConn].r.i)
|
||||
{
|
||||
close(new_sock);
|
||||
log(LOG_NOTICE,"Maximum connection limit exceeded. Rejecting incoming request.");
|
||||
}
|
||||
connections++;
|
||||
log(LOG_DEBUG,"main() : Accepted a connection from %s.",inet_ntoa(remote.sin_addr));
|
||||
|
||||
/* see if the connection is local, otherwise reject */
|
||||
/* first check that the connection is from the local host, otherwise reject */
|
||||
if (*(uint32_t *)&remote.sin_addr == inet_addr("127.0.0.1"))
|
||||
islocal=1;
|
||||
for (i=0; (local_host->h_addr_list[i] != NULL) && (!islocal); i++)
|
||||
{
|
||||
cp = local_host->h_addr_list[i];
|
||||
if (!memcmp(&remote.sin_addr, cp,sizeof(struct in_addr)))
|
||||
islocal = 1;
|
||||
}
|
||||
|
||||
if (!islocal)
|
||||
{
|
||||
log(LOG_DEBUG,"main() : Incoming connection is not local. Will reject.");
|
||||
close(new_sock);
|
||||
}
|
||||
else
|
||||
{
|
||||
log(LOG_DEBUG,"main() : Incoming connection seems to be local. Will accept.");
|
||||
/* fork a process to deal with the customer */
|
||||
if (!fork()) /* this is the child process */
|
||||
{
|
||||
close(request_sock); /* the child doesn't need the request socket anymore */
|
||||
|
||||
/* Main logic of op. */
|
||||
retval = handle_connection();
|
||||
log(LOG_DEBUG,"main() : Handle connection returned %d.",retval);
|
||||
/* End main logic */
|
||||
|
||||
exit(retval); /* done, exit */
|
||||
}
|
||||
|
||||
close(new_sock); /* don't need this anymore */
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* op.h
|
||||
* Onion Proxy
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.7 2002/03/28 11:01:43 badbytes
|
||||
* Now does link-encryption and link-padding.
|
||||
*
|
||||
* Revision 1.6 2002/03/12 23:40:32 mp292
|
||||
* Started on op<->router connection padding.
|
||||
*
|
||||
* Revision 1.5 2002/01/29 02:22:58 mp292
|
||||
* Put a timeout on all network I/O.
|
||||
*
|
||||
* Revision 1.4 2002/01/26 23:01:55 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.3 2001/12/18 11:52:27 badbytes
|
||||
* Coding completed. Proceeding to test.
|
||||
*
|
||||
* Revision 1.2 2001/12/17 13:36:15 badbytes
|
||||
* Writing handle_connection()
|
||||
*
|
||||
* Revision 1.1 2001/12/13 15:15:11 badbytes
|
||||
* Started coding the onion proxy.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OP_H
|
||||
|
||||
#define __OP_H
|
||||
|
||||
/* choosing the length of a route uses a weighted coin
|
||||
* this is the default value for it */
|
||||
#define OP_DEFAULT_COIN_WEIGHT 0.8
|
||||
|
||||
/* default connection timeout */
|
||||
#define OP_DEFAULT_CONN_TIMEOUT 120 /* 120s */
|
||||
|
||||
/* default connection bandwidth */
|
||||
#define OP_DEFAULT_BANDWIDTH 1 /* 1kb/s */
|
||||
|
||||
/* default buffer size per connection */
|
||||
#define OP_DEFAULT_BUFSIZE 4096 /* 4kb */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,364 @@
|
||||
/**
|
||||
* routers.c
|
||||
* Routines for loading the list of routers and their public RSA keys.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.16 2002/04/02 14:28:01 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.15 2002/03/25 10:48:48 badbytes
|
||||
* Added explicit dependency on <netinet/in.h>.
|
||||
*
|
||||
* Revision 1.14 2002/01/27 19:24:33 mp292
|
||||
* Fixed a bug in parameter checking.
|
||||
*
|
||||
* Revision 1.13 2002/01/26 22:19:15 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.12 2002/01/18 20:42:25 mp292
|
||||
* Slight modification to the way keys are read from the route file.
|
||||
*
|
||||
* Revision 1.11 2002/01/14 13:05:39 badbytes
|
||||
* System testing in progress.
|
||||
*
|
||||
* Revision 1.10 2002/01/11 15:47:25 badbytes
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.9 2001/12/18 15:51:58 badbytes
|
||||
* Connection with onion router established. Will continue testing tomorrow.
|
||||
*
|
||||
* Revision 1.8 2001/12/17 13:36:15 badbytes
|
||||
* Writing handle_connection()
|
||||
*
|
||||
* Revision 1.7 2001/12/17 08:42:45 badbytes
|
||||
* getrouters() now returns an array of routers and also writes the length of the array to an int*.
|
||||
*
|
||||
* Revision 1.6 2001/12/14 14:08:50 badbytes
|
||||
* getrouters() now returns an array of pointers rather than a linked list
|
||||
*
|
||||
* Revision 1.5 2001/12/14 14:05:56 badbytes
|
||||
* Added routent_t** make_rarray(routent_t* list);
|
||||
*
|
||||
* Revision 1.4 2001/12/14 13:25:17 badbytes
|
||||
* Moved back from common/
|
||||
*
|
||||
* Revision 1.2 2001/12/14 11:24:57 badbytes
|
||||
* Tested.
|
||||
*
|
||||
* Revision 1.1 2001/12/13 15:15:11 badbytes
|
||||
* Started coding the onion proxy.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
#include <netdb.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "routers.h"
|
||||
#include "../common/log.h"
|
||||
#include "../common/utils.h"
|
||||
#include "../common/config.h"
|
||||
|
||||
/* delete a list of routers from memory */
|
||||
void delete_routerlist(routent_t *list)
|
||||
{
|
||||
routent_t *tmp = NULL;
|
||||
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
do
|
||||
{
|
||||
tmp=list->next;
|
||||
free(list->address);
|
||||
RSA_free(list->pkey);
|
||||
free(list);
|
||||
list = tmp;
|
||||
}
|
||||
while (list != NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* create an NULL-terminated array of pointers pointing to elements of a router list */
|
||||
/* this is done in two passes through the list - inefficient but irrelevant as this is
|
||||
* only done once when op/or start up */
|
||||
routent_t **make_rarray(routent_t* list, size_t *len)
|
||||
{
|
||||
routent_t *tmp=NULL;
|
||||
int listlen = 0;
|
||||
routent_t **array=NULL;
|
||||
routent_t **p=NULL;
|
||||
|
||||
if ((!list) || (!len))
|
||||
return NULL;
|
||||
|
||||
/* get the length of the list */
|
||||
tmp = list;
|
||||
do
|
||||
{
|
||||
listlen++;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
while (tmp != NULL);
|
||||
|
||||
array = malloc((listlen+1)*sizeof(routent_t *));
|
||||
if (!array)
|
||||
{
|
||||
log(LOG_ERR,"Error allocating memory.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tmp=list;
|
||||
p = array;
|
||||
do
|
||||
{
|
||||
*p = tmp;
|
||||
p++;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
while(tmp != NULL);
|
||||
*p=NULL;
|
||||
|
||||
*len = listlen;
|
||||
return array;
|
||||
}
|
||||
|
||||
/* load the router list */
|
||||
routent_t **getrouters(char *routerfile, size_t *lenp)
|
||||
{
|
||||
int retval = 0;
|
||||
char *retp = NULL;
|
||||
routent_t *router=NULL, *routerlist=NULL, *lastrouter=NULL;
|
||||
FILE *rf; /* router file */
|
||||
fpos_t fpos;
|
||||
char line[512];
|
||||
char *token;
|
||||
char *errtest; /* detecting errors in strtoul() calls */
|
||||
struct hostent *rent;
|
||||
|
||||
if ((!routerfile) || (!lenp)) /* invalid parameters */
|
||||
return NULL;
|
||||
|
||||
if (strspn(routerfile,CONFIG_LEGAL_FILENAME_CHARACTERS) != strlen(routerfile)) /* invalid filename */
|
||||
{
|
||||
log(LOG_ERR,"Could not open %s because it contains illegal characters.",routerfile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* open the router list */
|
||||
rf = fopen(routerfile,"r");
|
||||
if (!rf)
|
||||
{
|
||||
log(LOG_ERR,"Could not open %s.",routerfile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retp= fgets(line,512,rf);
|
||||
while (retp)
|
||||
{
|
||||
log(LOG_DEBUG,"getrouters() : Line :%s",line);
|
||||
token = (char *)strtok(line,OP_ROUTERLIST_SEPCHARS);
|
||||
if (token)
|
||||
{
|
||||
log(LOG_DEBUG,"getrouters() : Token : %s",token);
|
||||
if (token[0] != '#') /* ignore comment lines */
|
||||
{
|
||||
router = malloc(sizeof(routent_t));
|
||||
if (!router)
|
||||
{
|
||||
log(LOG_ERR,"Could not allocate memory.");
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* read the address */
|
||||
router->address = malloc(strlen(token)+1);
|
||||
if (!router->address)
|
||||
{
|
||||
log(LOG_ERR,"Could not allocate memory.");
|
||||
fclose(rf);
|
||||
free(router);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
strcpy(router->address,token);
|
||||
|
||||
rent = (struct hostent *)gethostbyname(router->address);
|
||||
if (!rent)
|
||||
{
|
||||
log(LOG_ERR,"Could not get address for router %s.",router->address);
|
||||
fclose(rf);
|
||||
free(router->address);
|
||||
free(router);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(&router->addr, rent->h_addr,rent->h_length);
|
||||
|
||||
/* read the network port */
|
||||
token = (char *)strtok(NULL,OP_ROUTERLIST_SEPCHARS);
|
||||
if (token) /* network port */
|
||||
{
|
||||
log(LOG_DEBUG,"getrouters() : Token :%s",token);
|
||||
router->port = (uint16_t)strtoul(token,&errtest,0);
|
||||
if ((*token != '\0') && (*errtest == '\0')) /* network port conversion was successful */
|
||||
{
|
||||
router->port = htons(router->port);
|
||||
/* read the entry port */
|
||||
token = (char *)strtok(NULL,OP_ROUTERLIST_SEPCHARS);
|
||||
if (token) /* entry port */
|
||||
{
|
||||
log(LOG_DEBUG,"getrouters() : Token :%s",token);
|
||||
router->entry_port = (uint16_t)strtoul(token,&errtest,0);
|
||||
if ((*token != '\0') && (*errtest == '\0')) /* entry port number conversion was successful */
|
||||
{
|
||||
router->entry_port = htons(router->entry_port);
|
||||
/* check that there is a public key entry for that router */
|
||||
retval = fgetpos(rf, &fpos); /* save the current file position
|
||||
* we wil return to it later if we find a public key */
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Could not save position in %s.",routerfile);
|
||||
free(router->address);
|
||||
free(router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
do /* read through to the next non-empty line */
|
||||
{
|
||||
retp=fgets(line,512,rf);
|
||||
if (!retp)
|
||||
{
|
||||
log(LOG_ERR,"Could not find a public key entry for router %s:%u.",router->address,router->port);
|
||||
free(router->address);
|
||||
free(router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
log(LOG_DEBUG,"getrouters() : Line:%s",line);
|
||||
if ((*line != '#') && (strspn(line,OP_ROUTERLIST_SEPCHARS) != strlen(line) ))
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
if (!strcmp(line,OP_PUBLICKEY_BEGIN_TAG)) /* we've got the public key */
|
||||
{
|
||||
retval = fsetpos(rf,&fpos); /* get us back to where we were otherwise crypto lib won't find the key */
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Could not set position in %s.",routerfile);
|
||||
free(router->address);
|
||||
free(router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else /* we found something else; this isn't right */
|
||||
{
|
||||
log(LOG_ERR,"Could not find a public key entry for router %s:%u.",router->address,router->port);
|
||||
free(router->address);
|
||||
free(router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"getrouters() : Reading the key ...");
|
||||
/* read the public key into router->pkey */
|
||||
router->pkey=NULL;
|
||||
router->pkey = PEM_read_RSAPublicKey(rf,NULL,NULL,NULL);
|
||||
if (!router->pkey) /* something went wrong */
|
||||
{
|
||||
log(LOG_ERR,"Could not read public key for router %s:%u.",router->address,router->port);
|
||||
free(router->address);
|
||||
free(router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
else /* read the key */
|
||||
{
|
||||
log(LOG_DEBUG,"getrouters() : Public key size = %u.", RSA_size(router->pkey));
|
||||
if (RSA_size(router->pkey) != 128) /* keys MUST be 1024 bits in size */
|
||||
{
|
||||
log(LOG_ERR,"Key for router %s:%u is not 1024 bits. All keys must be exactly 1024 bits long.",router->address,router->port);
|
||||
free(router->address);
|
||||
RSA_free(router->pkey);
|
||||
free(router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
router->next = NULL;
|
||||
/* save the entry into the routerlist linked list */
|
||||
if (!routerlist) /* this is the first entry */
|
||||
routerlist = router;
|
||||
else
|
||||
lastrouter->next = (void *)router;
|
||||
lastrouter = router;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log(LOG_ERR,"Entry for router %s doesn't seem to contain a valid entry funnel port.",router->address);
|
||||
free(router->address);
|
||||
free(router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log(LOG_ERR,"Entry for router %s doesn't seem to contain an entry funnel port.",router->address);
|
||||
free(router->address);
|
||||
free(router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log(LOG_ERR,"Entry for router %s doesn't seem to contain a valid network funnel port.",router->address);
|
||||
free(router->address);
|
||||
free(router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log(LOG_ERR,"Entry for router %s doesn't seem to contain a network funnel port.",router->address);
|
||||
free(router->address);
|
||||
free(router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
retp=fgets(line,512,rf);
|
||||
}
|
||||
|
||||
fclose(rf);
|
||||
return make_rarray(routerlist, lenp);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* routers.h
|
||||
* Routines for loading the list of routers and their public RSA keys.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.11 2002/04/02 14:28:01 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.10 2002/01/26 22:22:09 mp292
|
||||
* Prevented duplicate definitions.
|
||||
*
|
||||
* Revision 1.9 2002/01/26 22:19:15 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.8 2001/12/17 08:42:45 badbytes
|
||||
* getrouters() now returns an array of routers and also writes the length of the array to an int*.
|
||||
*
|
||||
* Revision 1.7 2001/12/14 14:08:50 badbytes
|
||||
* getrouters() now returns an array of pointers rather than a linked list
|
||||
*
|
||||
* Revision 1.6 2001/12/14 14:05:56 badbytes
|
||||
* Added routent** make_rarray(routent_t* list);
|
||||
*
|
||||
* Revision 1.5 2001/12/14 13:32:18 badbytes
|
||||
* No longer contains the definition of routent_t. This is now in common/routent_t.h
|
||||
*
|
||||
* Revision 1.4 2001/12/14 13:25:17 badbytes
|
||||
* Moved back from common/
|
||||
*
|
||||
* Revision 1.2 2001/12/14 11:24:57 badbytes
|
||||
* Tested.
|
||||
*
|
||||
* Revision 1.1 2001/12/13 15:15:11 badbytes
|
||||
* Started coding the onion proxy.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ROUTERS_H
|
||||
|
||||
#define __ROUTERS_H
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include "../common/routent.h"
|
||||
|
||||
#define OP_ROUTERLIST_SEPCHARS " \t\n"
|
||||
|
||||
#define OP_PUBLICKEY_BEGIN_TAG "-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
|
||||
/* load the list of routers into memory */
|
||||
routent_t **getrouters(char *routerfile, size_t *listlenp);
|
||||
|
||||
/* free the router list pointed to by list */
|
||||
void delete_routerlist(routent_t *list);
|
||||
|
||||
/* create an NULL-terminated array of pointers pointing to elements of a router list */
|
||||
routent_t **make_rarray(routent_t* list, size_t *listlenp);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* ss.c
|
||||
* Standard structure processing.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.1 2002/04/02 14:28:01 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <malloc.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../common/log.h"
|
||||
#include "../common/version.h"
|
||||
#include "../common/utils.h"
|
||||
|
||||
#include "ss.h"
|
||||
|
||||
/* read the standard structure, check if it's acceptable and send an appropriate error code
|
||||
* Returns :
|
||||
* -1 processing error
|
||||
* 0 OK
|
||||
* 1 no error, but standard structure rejected
|
||||
*/
|
||||
int process_ss(int s, struct timeval *conn_toutp, ss_t **ssp, char **addrp, int *addrlenp, char **portp, int *portlenp)
|
||||
{
|
||||
int retval = 0;
|
||||
int len = 0; /* number of bytes read */
|
||||
ss_t *ss; /* standard structure */
|
||||
char errcode = SS_ERROR_SUCCESS; /* error code which we send back to the client */
|
||||
char inbuf;
|
||||
char *addr = NULL; /* destination address */
|
||||
int addrlen = 0;
|
||||
char *port = NULL; /* destination port */
|
||||
int portlen = 0;
|
||||
char *tmp = NULL; /* temporary storage */
|
||||
|
||||
if ((!ssp) || (!addrp) || (!addrlenp) || (!portp) || (!portlenp)) /* invalid parameters */
|
||||
return -1;
|
||||
|
||||
/* allocate memory for SS */
|
||||
ss = malloc(sizeof(ss_t));
|
||||
if (!ss)
|
||||
{
|
||||
log(LOG_ERR,"Error allocating memory.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"Allocated memory for ss.");
|
||||
|
||||
len = 0;
|
||||
while (len < sizeof(ss_t)) /* need to make sure the entire ss is read */
|
||||
{
|
||||
retval = read_tout(s,(char *)ss+len,sizeof(ss_t)-len,0, conn_toutp);
|
||||
if (retval <= 0)
|
||||
{
|
||||
free(ss);
|
||||
log(LOG_ERR,"Could not receive standard structure.");
|
||||
return -1;
|
||||
}
|
||||
len +=retval;
|
||||
}
|
||||
|
||||
if ((ss->version == 0) || (ss->version != VERSION)) /* unsupported version */
|
||||
{
|
||||
log(LOG_DEBUG,"Unsupported version.");
|
||||
free(ss);
|
||||
errcode = SS_ERROR_VERSION_UNSUPPORTED;
|
||||
write_tout(s,&errcode,1,conn_toutp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ss->addr_fmt != SS_ADDR_FMT_ASCII_HOST_PORT) /* unrecognized address format */
|
||||
{
|
||||
log(LOG_DEBUG,"Unrecognized address format.");
|
||||
free(ss);
|
||||
errcode = SS_ERROR_ADDR_FMT_UNSUPPORTED;
|
||||
write_tout(s,&errcode,1,conn_toutp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* allocate memory for the destination address - 512 bytes maximum */
|
||||
addrlen=512;
|
||||
addr = malloc(addrlen);
|
||||
if (!addr)
|
||||
{
|
||||
free(ss);
|
||||
log(LOG_ERR,"Error allocating memory.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* now read the destination address */
|
||||
len = 0;
|
||||
do /* need to keep going until the entire string is read in */
|
||||
{
|
||||
if (len == addrlen) /* we've run out of space, abort */
|
||||
{
|
||||
free(ss);
|
||||
free(addr);
|
||||
log(LOG_ERR,"Client tried to send address > 512 characters.");
|
||||
errcode = SS_ERROR_INVALID_ADDRESS;
|
||||
write_tout(s,&errcode,1,conn_toutp);
|
||||
return -1;
|
||||
}
|
||||
retval = read_tout(s,(void *)&inbuf, 1, 0, conn_toutp);
|
||||
if (retval <= 0)
|
||||
{
|
||||
free(ss);
|
||||
free(addr);
|
||||
log(LOG_ERR,"Error receiving destination address.");
|
||||
return -1;
|
||||
}
|
||||
*(addr+len) = inbuf;
|
||||
len++;
|
||||
} while (inbuf != 0);
|
||||
|
||||
|
||||
/* allocate memory for the destination port - 6 bytes maximum */
|
||||
portlen = 6;
|
||||
port = malloc(portlen);
|
||||
if (!port)
|
||||
{
|
||||
free(ss);
|
||||
log(LOG_ERR,"Error allocating memory.");
|
||||
free(addr);
|
||||
return -1;
|
||||
}
|
||||
/* now read the destination port */
|
||||
len = 0;
|
||||
do /* keep going until the entire string is read in */
|
||||
{
|
||||
if (len == portlen) /* no more space, abort */
|
||||
{
|
||||
free(ss);
|
||||
free(addr);
|
||||
free(port);
|
||||
log(LOG_ERR,"Client tried to send port > 6 characters.");
|
||||
errcode = SS_ERROR_INVALID_PORT;
|
||||
write_tout(s,&errcode,1,conn_toutp);
|
||||
return -1;
|
||||
}
|
||||
retval = read_tout(s,(void *)&inbuf, 1, 0, conn_toutp);
|
||||
if (retval <= 0)
|
||||
{
|
||||
free(ss);
|
||||
free(addr);
|
||||
free(port);
|
||||
log(LOG_ERR,"Error receiving destination port.");
|
||||
return -1;
|
||||
}
|
||||
*(port+len)=inbuf;
|
||||
len++;
|
||||
} while (inbuf != 0);
|
||||
|
||||
/* send a success error code back to the client */
|
||||
errcode = SS_ERROR_SUCCESS;
|
||||
write_tout(s,&errcode,1,conn_toutp);
|
||||
|
||||
/* done, now save */
|
||||
addrlen = strlen(addr)+1;
|
||||
tmp = addr;
|
||||
addr = realloc(addr,addrlen);
|
||||
/* if realloc() fails, we just ignore it and use the previously allocated memory, although this may be wasteful */
|
||||
if (!addr)
|
||||
addr=tmp; /* restore previous state */
|
||||
else
|
||||
addr[addrlen-1]=0;
|
||||
|
||||
portlen = strlen(port)+1;
|
||||
tmp=port;
|
||||
port = realloc(port,portlen);
|
||||
if (!port)
|
||||
port=tmp;
|
||||
else
|
||||
port[portlen-1]=0;
|
||||
|
||||
*ssp = ss;
|
||||
*addrp = addr;
|
||||
*addrlenp = addrlen;
|
||||
*portp = port;
|
||||
*portlenp = portlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* ss.h
|
||||
* Standard structure processing.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.1 2002/04/02 14:28:01 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "../common/ss.h"
|
||||
|
||||
int process_ss(int s, struct timeval *conn_toutp, ss_t **ssp, char **addrp, int *addrlenp, char **portp, int *portlenp);
|
||||
@@ -0,0 +1,18 @@
|
||||
SRC=args.c buffers.c cell.c circuit.c command.c connection.c connection_app.c connection_op.c connection_or.c config.c main.c onion.c routers.c
|
||||
OBJ=${SRC:.c=.o}
|
||||
PROGS=or
|
||||
LIB=
|
||||
LIBS=
|
||||
INCLUDE = -I/usr/local/ssl/include
|
||||
|
||||
CFLAGS= $(INCLUDE) -Wall -Wpointer-arith -ggdb
|
||||
LDFLAGS = $(LIB) $(LIBS)
|
||||
|
||||
all: ${OBJ} ${PROGS}
|
||||
|
||||
or: ${OBJ}
|
||||
gcc -o or $(CFLAGS) *.o ../common/*.o -lcrypto
|
||||
|
||||
clean:
|
||||
rm -f *.o ${PROGS}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* args.c
|
||||
* Routines for processing command-line arguments.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.3 2002/01/27 00:42:50 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.2 2002/01/04 10:05:28 badbytes
|
||||
* Completed.
|
||||
*
|
||||
* Revision 1.1 2002/01/03 10:23:43 badbytes
|
||||
* Code based on that in op. Needs to be modified.
|
||||
*/
|
||||
|
||||
#include "or.h"
|
||||
|
||||
/* prints help on using or */
|
||||
void print_usage()
|
||||
{
|
||||
char *program = "or";
|
||||
printf("\n%s - Onion Router.\nUsage : %s -f config [-l loglevel -h]\n-h : display this help\n-f config : config file\n-l loglevel : logging threshold; one of alert|crit|err|warning|notice|info|debug\n\n", program,program);
|
||||
}
|
||||
|
||||
|
||||
/* get command-line arguments */
|
||||
int getargs(int argc,char *argv[], char *args, char **conf_filename, int *loglevel)
|
||||
{
|
||||
char c; /* next option character */
|
||||
int gotf=0;
|
||||
|
||||
if ((!args) || (!conf_filename) || (!loglevel))
|
||||
return -1;
|
||||
|
||||
while ((c = getopt(argc,argv,args)) != -1)
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case 'f': /* config file */
|
||||
*conf_filename = optarg;
|
||||
gotf=1;
|
||||
break;
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
exit(0);
|
||||
case 'l':
|
||||
if (!strcmp(optarg,"emerg"))
|
||||
*loglevel = LOG_EMERG;
|
||||
else if (!strcmp(optarg,"alert"))
|
||||
*loglevel = LOG_ALERT;
|
||||
else if (!strcmp(optarg,"crit"))
|
||||
*loglevel = LOG_CRIT;
|
||||
else if (!strcmp(optarg,"err"))
|
||||
*loglevel = LOG_ERR;
|
||||
else if (!strcmp(optarg,"warning"))
|
||||
*loglevel = LOG_WARNING;
|
||||
else if (!strcmp(optarg,"notice"))
|
||||
*loglevel = LOG_NOTICE;
|
||||
else if (!strcmp(optarg,"info"))
|
||||
*loglevel = LOG_INFO;
|
||||
else if (!strcmp(optarg,"debug"))
|
||||
*loglevel = LOG_DEBUG;
|
||||
else
|
||||
{
|
||||
log(LOG_ERR,"Error : argument to -l must be one of alert|crit|err|warning|notice|info|debug.");
|
||||
print_usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
if (isprint(c))
|
||||
log(LOG_ERR,"Missing argument or unknown option '-%c'. See help (-h).",optopt);
|
||||
else
|
||||
log(LOG_ERR,"Unknown option character 'x%x'. See help (-h).",optopt);
|
||||
print_usage(argv[0]);
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* the -f option is mandatory */
|
||||
if (!gotf)
|
||||
{
|
||||
log(LOG_ERR,"You must specify a config file with the -f option. See help (-h).");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
|
||||
/* buffers.c */
|
||||
|
||||
#include "or.h"
|
||||
|
||||
int buf_new(char **pbuf, size_t *pbuflen, size_t *pbuf_datalen) {
|
||||
|
||||
if (!pbuf || !pbuflen || !pbuf_datalen) /* invalid parameters */
|
||||
return -1;
|
||||
|
||||
*pbuf = (char *)malloc(MAX_BUF_SIZE);
|
||||
if(!*pbuf)
|
||||
return -1;
|
||||
memset(*pbuf,0,MAX_BUF_SIZE);
|
||||
*pbuflen = MAX_BUF_SIZE;
|
||||
*pbuf_datalen = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int buf_free(char *buf) {
|
||||
|
||||
free(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_to_buf(int s, char **pbuf, size_t *pbuflen, size_t *pbuf_datalen, int *preached_eof) {
|
||||
|
||||
/* grab from s, put onto buf, return how many bytes read */
|
||||
|
||||
int read_result;
|
||||
char *buf;
|
||||
size_t buflen;
|
||||
size_t buf_datalen;
|
||||
|
||||
if (!pbuf || !pbuflen || !pbuf_datalen || !preached_eof) /* invalid parameters */
|
||||
return -1 ;
|
||||
|
||||
if(s<0) {
|
||||
log(LOG_DEBUG,"read_to_buf() received negative socket %d.",s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* this is the point where you would grow the buffer, if you want to */
|
||||
buf = *pbuf, buflen = *pbuflen, buf_datalen = *pbuf_datalen;
|
||||
|
||||
if (!buf) /* invalid parameter */
|
||||
return -1;
|
||||
|
||||
read_result = read(s, buf+buf_datalen, buflen - buf_datalen);
|
||||
if (read_result < 0) {
|
||||
if(errno!=EAGAIN) { /* it's a real error */
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
} else if (read_result == 0) {
|
||||
log(LOG_DEBUG,"read_to_buf(): Encountered eof");
|
||||
*preached_eof = 1;
|
||||
return 0;
|
||||
} else { /* we read some bytes */
|
||||
*pbuf_datalen = buf_datalen + read_result;
|
||||
log(LOG_DEBUG,"read_to_buf(): Read %d bytes. %d on inbuf.",read_result, *pbuf_datalen);
|
||||
return read_result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int flush_buf(int s, char **pbuf, size_t *pbuflen, size_t *pbuf_datalen) {
|
||||
|
||||
/* push from buf onto s
|
||||
* then memmove to front of buf
|
||||
* return -1 or how many bytes remain on the buf */
|
||||
|
||||
int write_result;
|
||||
char *buf;
|
||||
size_t buflen;
|
||||
size_t buf_datalen;
|
||||
|
||||
if (!pbuf || !pbuflen || !pbuf_datalen) /* invalid parameters */
|
||||
return -1;
|
||||
|
||||
if(s<0) {
|
||||
log(LOG_DEBUG,"flush_buf() received negative socket %d.",s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if(*pbuf_datalen == 0) /* nothing to flush */
|
||||
return 0;
|
||||
|
||||
/* this is the point where you would grow the buffer, if you want to */
|
||||
buf = *pbuf, buflen = *pbuflen, buf_datalen = *pbuf_datalen;
|
||||
|
||||
if (!buf) /* invalid parameter */
|
||||
return -1;
|
||||
|
||||
write_result = write(s, buf, buf_datalen);
|
||||
if (write_result < 0) {
|
||||
if(errno!=EAGAIN) { /* it's a real error */
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"flush_buf(): write() would block, returning.");
|
||||
return 0;
|
||||
} else {
|
||||
*pbuf_datalen -= write_result;
|
||||
memmove(buf, buf+write_result, *pbuf_datalen);
|
||||
log(LOG_DEBUG,"flush_buf(): flushed %d bytes, %d remain.",write_result,*pbuf_datalen);
|
||||
return *pbuf_datalen;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int write_to_buf(char *string, size_t string_len,
|
||||
char **pbuf, size_t *pbuflen, size_t *pbuf_datalen) {
|
||||
|
||||
/* append string to buf (growing as needed, return -1 if "too big")
|
||||
* return total number of bytes on the buf
|
||||
*/
|
||||
|
||||
char *buf;
|
||||
size_t buflen;
|
||||
size_t buf_datalen;
|
||||
|
||||
if (!string || !pbuf || !pbuflen || !pbuf_datalen) /* invalid parameters */
|
||||
return -1;
|
||||
|
||||
/* this is the point where you would grow the buffer, if you want to */
|
||||
buf = *pbuf, buflen = *pbuflen, buf_datalen = *pbuf_datalen;
|
||||
|
||||
if (!buf) /* invalid parameter */
|
||||
return -1;
|
||||
|
||||
if (string_len + buf_datalen > buflen) { /* we're out of luck */
|
||||
log(LOG_DEBUG, "write_to_buf(): buflen too small. Time to implement growing dynamic bufs.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(buf+buf_datalen, string, string_len);
|
||||
*pbuf_datalen += string_len;
|
||||
log(LOG_DEBUG,"write_to_buf(): added %d bytes to buf (now %d total).",string_len, *pbuf_datalen);
|
||||
return *pbuf_datalen;
|
||||
|
||||
}
|
||||
|
||||
int fetch_from_buf(char *string, size_t string_len,
|
||||
char **pbuf, size_t *pbuflen, size_t *pbuf_datalen) {
|
||||
|
||||
/* if there is string_len bytes in buf, write them onto string,
|
||||
* then memmove buf back (that is, remove them from buf) */
|
||||
|
||||
char *buf;
|
||||
size_t buflen;
|
||||
size_t buf_datalen;
|
||||
|
||||
if (!string || !pbuf || !pbuflen || !pbuf_datalen) /* invalid parameters */
|
||||
return -1;
|
||||
|
||||
/* this is the point where you would grow the buffer, if you want to */
|
||||
buf = *pbuf, buflen = *pbuflen, buf_datalen = *pbuf_datalen;
|
||||
|
||||
if (!buf) /* invalid parameter */
|
||||
return -1;
|
||||
|
||||
if(string_len > buf_datalen) /* we want too much. sorry. */
|
||||
return -1;
|
||||
|
||||
memcpy(string,buf,string_len);
|
||||
*pbuf_datalen -= string_len;
|
||||
memmove(buf, buf+string_len, *pbuf_datalen);
|
||||
return *pbuf_datalen;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
#include "or.h"
|
||||
|
||||
int check_sane_cell(cell_t *cell) {
|
||||
|
||||
if(!cell)
|
||||
return -1;
|
||||
|
||||
if(cell->aci == 0) {
|
||||
log(LOG_DEBUG,"check_sane_cell(): Cell has aci=0. Dropping.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 0 /* actually, the length is sometimes encrypted. so it's ok. */
|
||||
if(cell->length > 120) {
|
||||
log(LOG_DEBUG,"check_sane_cell(): Cell claims to have payload length %d. Dropping.",cell->length);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0; /* looks good */
|
||||
}
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
|
||||
#include "or.h"
|
||||
|
||||
/********* START VARIABLES **********/
|
||||
|
||||
circuit_t *global_circuitlist=NULL;
|
||||
|
||||
/********* END VARIABLES ************/
|
||||
|
||||
void circuit_add(circuit_t *circ) {
|
||||
|
||||
if(!global_circuitlist) { /* first one */
|
||||
global_circuitlist = circ;
|
||||
circ->next = NULL;
|
||||
} else {
|
||||
circ->next = global_circuitlist;
|
||||
global_circuitlist = circ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void circuit_remove(circuit_t *circ) {
|
||||
circuit_t *tmpcirc;
|
||||
|
||||
if(!circ || !global_circuitlist)
|
||||
return;
|
||||
|
||||
if(global_circuitlist == circ) {
|
||||
global_circuitlist = global_circuitlist->next;
|
||||
return;
|
||||
}
|
||||
|
||||
for(tmpcirc = global_circuitlist;tmpcirc->next;tmpcirc = tmpcirc->next) {
|
||||
if(tmpcirc->next == circ) {
|
||||
tmpcirc->next = circ->next;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
circuit_t *circuit_new(aci_t p_aci, connection_t *p_conn) {
|
||||
|
||||
circuit_t *circ;
|
||||
|
||||
circ = (circuit_t *)malloc(sizeof(circuit_t));
|
||||
if(!circ)
|
||||
return NULL;
|
||||
memset(circ,0,sizeof(circuit_t)); /* zero it out */
|
||||
|
||||
circ->p_aci = p_aci;
|
||||
circ->p_conn = p_conn;
|
||||
|
||||
circ->state = CIRCUIT_STATE_OPEN_WAIT;
|
||||
circ->onion = NULL;
|
||||
circ->onionlen=0;
|
||||
circ->recvlen=0;
|
||||
|
||||
/* ACIs */
|
||||
circ->p_aci = p_aci;
|
||||
circ->n_aci = 0; /* we need to have identified the next hop to choose a correct ACI */
|
||||
|
||||
circuit_add(circ);
|
||||
|
||||
return circ;
|
||||
}
|
||||
|
||||
void circuit_free(circuit_t *circ) {
|
||||
|
||||
EVP_CIPHER_CTX_cleanup(&circ->n_ctx);
|
||||
EVP_CIPHER_CTX_cleanup(&circ->p_ctx);
|
||||
|
||||
if(circ->onion)
|
||||
free(circ->onion);
|
||||
|
||||
free(circ);
|
||||
|
||||
}
|
||||
|
||||
aci_t get_unique_aci_by_addr_port(uint32_t addr, uint16_t port, int aci_type) {
|
||||
aci_t test_aci;
|
||||
connection_t *conn;
|
||||
|
||||
log(LOG_DEBUG,"get_unique_aci_by_addr_port() trying to get a unique aci");
|
||||
|
||||
RAND_pseudo_bytes((unsigned char *)&test_aci, 2);
|
||||
|
||||
if(aci_type == ACI_TYPE_LOWER)
|
||||
test_aci &= htons(0x00FF);
|
||||
if(aci_type == ACI_TYPE_HIGHER)
|
||||
test_aci &= htons(0xFF00);
|
||||
|
||||
if(test_aci == 0)
|
||||
return get_unique_aci_by_addr_port(addr, port, aci_type); /* try again */
|
||||
|
||||
conn = connection_get_by_addr_port(addr,port);
|
||||
if(!conn) /* there can't be a conflict -- no connection of that sort yet */
|
||||
return test_aci;
|
||||
|
||||
if(circuit_get_by_aci_conn(test_aci, conn))
|
||||
return get_unique_aci_by_addr_port(addr, port, aci_type); /* try again */
|
||||
|
||||
return test_aci;
|
||||
|
||||
}
|
||||
|
||||
int circuit_init(circuit_t *circ, int aci_type) {
|
||||
onion_layer_t *ol;
|
||||
int retval = 0;
|
||||
unsigned char digest1[20];
|
||||
unsigned char digest2[20];
|
||||
|
||||
if (!circ)
|
||||
return -1;
|
||||
|
||||
ol = (onion_layer_t *)circ->onion;
|
||||
if (!ol)
|
||||
return -1;
|
||||
|
||||
log(LOG_DEBUG,"circuit_init(): starting");
|
||||
circ->n_addr = ol->addr;
|
||||
circ->n_port = ol->port;
|
||||
log(LOG_DEBUG,"circuit_init(): Set port to %u.",ntohs(ol->port));
|
||||
circ->p_f = ol->backf;
|
||||
log(LOG_DEBUG,"circuit_init(): Set BACKF to %u.",ol->backf);
|
||||
circ->n_f = ol->forwf;
|
||||
log(LOG_DEBUG,"circuit_init(): Set FORWF to %u.",ol->forwf);
|
||||
circ->state = CIRCUIT_STATE_OPEN;
|
||||
|
||||
log(LOG_DEBUG,"circuit_init(): aci_type = %u.",aci_type);
|
||||
|
||||
circ->n_aci = get_unique_aci_by_addr_port(circ->n_addr, circ->n_port, aci_type);
|
||||
|
||||
log(LOG_DEBUG,"circuit_init(): Chosen ACI %u.",circ->n_aci);
|
||||
|
||||
/* keys */
|
||||
SHA1(ol->keyseed,16,digest1);
|
||||
SHA1(digest1,20,digest2);
|
||||
SHA1(digest2,20,digest1);
|
||||
memcpy(circ->p_key,digest2,16);
|
||||
memcpy(circ->n_key,digest1,16);
|
||||
log(LOG_DEBUG,"circuit_init(): Computed keys.");
|
||||
|
||||
/* set IVs to zero */
|
||||
memset(circ->n_iv,0,16);
|
||||
memset(circ->p_iv,0,16);
|
||||
|
||||
/* initialize cipher context */
|
||||
EVP_CIPHER_CTX_init(&circ->n_ctx);
|
||||
EVP_CIPHER_CTX_init(&circ->p_ctx);
|
||||
|
||||
/* initialize crypto engines */
|
||||
switch(circ->p_f)
|
||||
{
|
||||
case ONION_CIPHER_DES :
|
||||
retval = EVP_EncryptInit(&circ->p_ctx, EVP_des_ofb(), circ->p_key, circ->p_iv);
|
||||
break;
|
||||
case ONION_CIPHER_RC4 :
|
||||
retval = EVP_EncryptInit(&circ->p_ctx, EVP_rc4(), circ->p_key,circ->p_iv);
|
||||
break;
|
||||
case ONION_CIPHER_IDENTITY :
|
||||
retval = EVP_EncryptInit(&circ->p_ctx, EVP_enc_null(), circ->p_key, circ->p_iv);
|
||||
break;
|
||||
default :
|
||||
log(LOG_ERR,"Onion contains unrecognized cipher(%u) for ACI : %u.",circ->p_f,circ->n_aci);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!retval) /* EVP_EncryptInit() error */
|
||||
{
|
||||
log(LOG_ERR,"Cipher initialization failed (ACI %u).",circ->n_aci);
|
||||
EVP_CIPHER_CTX_cleanup(&circ->n_ctx);
|
||||
EVP_CIPHER_CTX_cleanup(&circ->p_ctx);
|
||||
return -1;
|
||||
}
|
||||
switch(circ->n_f)
|
||||
{
|
||||
case ONION_CIPHER_DES :
|
||||
retval = EVP_DecryptInit(&circ->n_ctx, EVP_des_ofb(), circ->n_key, circ->n_iv);
|
||||
break;
|
||||
case ONION_CIPHER_RC4 :
|
||||
retval = EVP_DecryptInit(&circ->n_ctx, EVP_rc4(), circ->n_key,circ->n_iv);
|
||||
break;
|
||||
case ONION_CIPHER_IDENTITY :
|
||||
retval = EVP_DecryptInit(&circ->n_ctx, EVP_enc_null(), circ->n_key, circ->n_iv);
|
||||
break;
|
||||
default :
|
||||
log(LOG_ERR,"Onion contains unrecognized cipher for ACI : %u.",circ->n_aci);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
if (!retval) /* EVP_EncryptInit() error */
|
||||
{
|
||||
log(LOG_ERR,"Cipher initialization failed (ACI %u).",circ->n_aci);
|
||||
EVP_CIPHER_CTX_cleanup(&circ->n_ctx);
|
||||
EVP_CIPHER_CTX_cleanup(&circ->p_ctx);
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"circuit_init(): Cipher initialization complete.");
|
||||
|
||||
circ->expire = ol->expire;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
circuit_t *circuit_get_by_aci_conn(aci_t aci, connection_t *conn) {
|
||||
circuit_t *circ;
|
||||
|
||||
for(circ=global_circuitlist;circ;circ = circ->next) {
|
||||
if(circ->p_conn == conn && circ->p_aci == aci)
|
||||
return circ;
|
||||
if(circ->n_conn == conn && circ->n_aci == aci)
|
||||
return circ;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
circuit_t *circuit_get_by_conn(connection_t *conn) {
|
||||
circuit_t *circ;
|
||||
|
||||
for(circ=global_circuitlist;circ;circ = circ->next) {
|
||||
if(circ->p_conn == conn)
|
||||
return circ;
|
||||
if(circ->n_conn == conn)
|
||||
return circ;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int circuit_deliver_data_cell(cell_t *cell, circuit_t *circ, connection_t *conn, int crypt_type) {
|
||||
|
||||
/* first decrypt cell->length */
|
||||
if(circuit_crypt(circ, &(cell->length), 1, crypt_type) < 0) {
|
||||
log(LOG_DEBUG,"circuit_deliver_data_cell(): length decryption failed. Dropping connection.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* then decrypt the payload */
|
||||
if(circuit_crypt(circ, (char *)&(cell->payload), CELL_PAYLOAD_SIZE, crypt_type) < 0) {
|
||||
log(LOG_DEBUG,"circuit_deliver_data_cell(): payload decryption failed. Dropping connection.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(conn->type == CONN_TYPE_APP) { /* send payload directly */
|
||||
log(LOG_DEBUG,"circuit_deliver_data_cell(): Sending to application.");
|
||||
if(connection_app_process_data_cell(cell, conn) < 0) {
|
||||
return -1;
|
||||
}
|
||||
} else { /* send it as a cell */
|
||||
log(LOG_DEBUG,"circuit_deliver_data_cell(): Sending to connection.");
|
||||
if(connection_write_cell_to_buf(cell, conn) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
int circuit_crypt(circuit_t *circ, char *in, size_t inlen, char crypt_type) {
|
||||
char *out;
|
||||
int outlen;
|
||||
|
||||
if(!circ || !in)
|
||||
return -1;
|
||||
|
||||
out = malloc(inlen);
|
||||
if(!out)
|
||||
return -1;
|
||||
|
||||
if(crypt_type == 'e') {
|
||||
log(LOG_DEBUG,"circuit_crypt(): Encrypting %d bytes.",inlen);
|
||||
if(!EVP_EncryptUpdate(&circ->p_ctx,out,&outlen,in,inlen)) {
|
||||
log(LOG_ERR,"circuit_encrypt(): Encryption failed for ACI : %u (%s).",circ->p_aci, ERR_reason_error_string(ERR_get_error()));
|
||||
return -1;
|
||||
}
|
||||
} else if(crypt_type == 'd') {
|
||||
log(LOG_DEBUG,"circuit_crypt(): Decrypting %d bytes.",inlen);
|
||||
if(!EVP_DecryptUpdate(&circ->n_ctx,out,&outlen,in,inlen)) {
|
||||
log(LOG_ERR,"circuit_crypt(): Decryption failed for ACI : %u (%s).",circ->n_aci, ERR_reason_error_string(ERR_get_error()));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(outlen != inlen) {
|
||||
log(LOG_DEBUG,"circuit_crypt(): %d bytes crypted to %d bytes. Weird.",inlen,outlen);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(in,out,inlen);
|
||||
free(out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void circuit_close(circuit_t *circ) {
|
||||
circuit_remove(circ);
|
||||
connection_send_destroy(circ->n_aci, circ->n_conn);
|
||||
connection_send_destroy(circ->p_aci, circ->p_conn);
|
||||
circuit_free(circ);
|
||||
}
|
||||
|
||||
void circuit_about_to_close_connection(connection_t *conn) {
|
||||
/* send destroys for all circuits using conn */
|
||||
/* currently, we assume it's too late to flush conn's buf here.
|
||||
* down the road, maybe we'll consider that eof doesn't mean can't-write
|
||||
*/
|
||||
|
||||
circuit_t *circ;
|
||||
|
||||
while((circ = circuit_get_by_conn(conn))) {
|
||||
circuit_remove(circ);
|
||||
if(circ->n_conn == conn) /* it's closing in front of us */
|
||||
connection_send_destroy(circ->p_aci, circ->p_conn);
|
||||
if(circ->p_conn == conn) /* it's closing behind us */
|
||||
connection_send_destroy(circ->n_aci, circ->n_conn);
|
||||
circuit_free(circ);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
|
||||
#include "or.h"
|
||||
|
||||
void command_process_cell(cell_t *cell, connection_t *conn) {
|
||||
|
||||
if(check_sane_cell(cell) < 0)
|
||||
return;
|
||||
|
||||
switch(cell->command) {
|
||||
case CELL_PADDING:
|
||||
/* do nothing */
|
||||
break;
|
||||
case CELL_CREATE:
|
||||
command_process_create_cell(cell, conn);
|
||||
break;
|
||||
case CELL_DATA:
|
||||
command_process_data_cell(cell, conn);
|
||||
break;
|
||||
case CELL_DESTROY:
|
||||
command_process_destroy_cell(cell, conn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void command_process_create_cell(cell_t *cell, connection_t *conn) {
|
||||
circuit_t *circ;
|
||||
connection_t *n_conn;
|
||||
unsigned char *cellbuf; /* array of cells */
|
||||
int cellbuflen; /* size of cellbuf in bytes */
|
||||
cell_t *tmpcell; /* pointer to an arbitrary cell */
|
||||
int retval, i;
|
||||
|
||||
circ = circuit_get_by_aci_conn(cell->aci, conn);
|
||||
|
||||
if(circ && circ->state != CIRCUIT_STATE_OPEN_WAIT) {
|
||||
log(LOG_DEBUG,"command_process_create_cell(): received CREATE cell, not in open_wait. Dropping.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!circ) { /* if it's not there, create it */
|
||||
circ = circuit_new(cell->aci, conn);
|
||||
circ->state = CIRCUIT_STATE_OPEN_WAIT;
|
||||
memcpy((void *)&circ->onionlen,(void *)cell->payload, 4);
|
||||
circ->onionlen = ntohl(circ->onionlen);
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Onion length is %u.",circ->onionlen);
|
||||
if(circ->onionlen > 50000) { /* too big */
|
||||
log(LOG_DEBUG,"That's ludicrous. Closing.");
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
circ->onion = (unsigned char *)malloc(circ->onionlen);
|
||||
if(!circ->onion) {
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Out of memory. Closing.");
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
if(circ->onionlen < cell->length-4) { /* protect from buffer overflow */
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Onion too small. Closing.");
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
memcpy((void *)circ->onion,(void *)(cell->payload+4),cell->length-4);
|
||||
circ->recvlen = cell->length-4;
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Primary create cell handled, have received %d of %d onion bytes.",
|
||||
circ->recvlen,circ->onionlen);
|
||||
|
||||
} else { /* pull over as much of the onion as we can */
|
||||
if(cell->length + circ->recvlen > circ->onionlen) { /* protect from buffer overflow */
|
||||
log(LOG_DEBUG,"command_process_create_cell(): payload too big for onion. Closing.");
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
memcpy((void *)(circ->onion+circ->recvlen),(void *)cell->payload,cell->length);
|
||||
circ->recvlen += cell->length;
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Secondary create cell handled, have received %d of %d onion bytes.",
|
||||
circ->recvlen,circ->onionlen);
|
||||
}
|
||||
|
||||
if(circ->recvlen != circ->onionlen) {
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Onion not all here yet. Ok.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* we're all ready to go now. */
|
||||
circ->state = CIRCUIT_STATE_OPEN;
|
||||
|
||||
if(process_onion(circ, conn) < 0) {
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Onion processing failed. Closing.");
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
|
||||
if(circ->n_addr && circ->n_port) { /* must send create cells to the next router */
|
||||
n_conn = connection_get_by_addr_port(circ->n_addr,circ->n_port);
|
||||
if(!n_conn || n_conn->type != CONN_TYPE_OR) {
|
||||
/* i've disabled making connections through OPs, but it's definitely
|
||||
* possible here. I'm not sure if it would be a bug or a feature. -RD
|
||||
*/
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Next router not connected. Closing.");
|
||||
circuit_close(circ);
|
||||
}
|
||||
circ->n_conn = n_conn;
|
||||
log(LOG_DEBUG,"command_process_create_cell(): n_conn is %s:%u",n_conn->address,ntohs(n_conn->port));
|
||||
|
||||
/* send the CREATE cells on to the next hop */
|
||||
pad_onion(circ->onion,circ->onionlen, sizeof(onion_layer_t));
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Padded the onion with random data.");
|
||||
|
||||
retval = pack_create(circ->n_aci, circ->onion, circ->onionlen, &cellbuf, &cellbuflen);
|
||||
free((void *)circ->onion);
|
||||
circ->onion = NULL;
|
||||
if (retval == -1) /* pack_create() error */
|
||||
{
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Could not pack the onion into CREATE cells. Closing the connection.");
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Onion packed into CREATE cells. Buffering the cells.");
|
||||
/* queue the create cells for transmission to the next hop */
|
||||
tmpcell = (cell_t *)cellbuf;
|
||||
for (i=0;i<cellbuflen/sizeof(cell_t);i++)
|
||||
{
|
||||
retval = connection_write_cell_to_buf(tmpcell, n_conn);
|
||||
if (retval == -1) /* buffering failed, drop the connection */
|
||||
{
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Could not buffer new create cells. Closing.");
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
tmpcell++;
|
||||
}
|
||||
free((void *)cellbuf);
|
||||
return;
|
||||
|
||||
} else { /* this is destined for an app */
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Creating new application connection.");
|
||||
n_conn = connection_new(CONN_TYPE_APP);
|
||||
if(!n_conn) {
|
||||
log(LOG_DEBUG,"command_process_create_cell(): connection_new failed. Closing.");
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
n_conn->state = APP_CONN_STATE_CONNECTING_WAIT;
|
||||
n_conn->s = -1; /* not yet valid */
|
||||
if(connection_add(n_conn) < 0) { /* no space, forget it */
|
||||
log(LOG_DEBUG,"command_process_create_cell(): connection_add failed. Closing.");
|
||||
connection_free(n_conn);
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
circ->n_conn = n_conn;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void command_process_data_cell(cell_t *cell, connection_t *conn) {
|
||||
circuit_t *circ;
|
||||
|
||||
/* FIXME do something with 'close' state, here */
|
||||
|
||||
circ = circuit_get_by_aci_conn(cell->aci, conn);
|
||||
|
||||
if(!circ) {
|
||||
log(LOG_DEBUG,"command_process_data_cell(): received DATA cell for unknown circuit. Dropping.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(circ->state == CIRCUIT_STATE_OPEN_WAIT) {
|
||||
log(LOG_DEBUG,"command_process_data_cell(): circuit in open_wait. Dropping data cell.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* at this point both circ->n_conn and circ->p_conn are guaranteed to be set */
|
||||
|
||||
if(cell->aci == circ->p_aci) { /* it's an outgoing cell */
|
||||
cell->aci = circ->n_aci; /* switch it */
|
||||
if(circuit_deliver_data_cell(cell, circ, circ->n_conn, 'd') < 0) {
|
||||
log(LOG_DEBUG,"command_process_data_cell(): circuit_deliver_data_cell (forward) failed. Closing.");
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
} else { /* it's an ingoing cell */
|
||||
cell->aci = circ->p_aci; /* switch it */
|
||||
if(circuit_deliver_data_cell(cell, circ, circ->p_conn, 'e') < 0) {
|
||||
log(LOG_DEBUG,"command_process_data_cell(): circuit_deliver_data_cell (backward) failed. Closing.");
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void command_process_destroy_cell(cell_t *cell, connection_t *conn) {
|
||||
circuit_t *circ;
|
||||
|
||||
circ = circuit_get_by_aci_conn(cell->aci, conn);
|
||||
|
||||
if(!circ) {
|
||||
log(LOG_DEBUG,"command_process_destroy_cell(): received DESTROY cell for unknown circuit. Dropping.");
|
||||
return;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"command_process_destroy_cell(): Received for aci %d.",cell->aci);
|
||||
circuit_remove(circ);
|
||||
if(cell->aci == circ->p_aci) /* the destroy came from behind */
|
||||
connection_send_destroy(circ->n_aci, circ->n_conn);
|
||||
if(cell->aci == circ->n_aci) /* the destroy came from ahead */
|
||||
connection_send_destroy(circ->p_aci, circ->p_conn);
|
||||
circuit_free(circ);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* config.c
|
||||
* Routines for loading the configuration file.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.3 2002/04/02 14:28:24 badbytes
|
||||
* Final finishes.
|
||||
*
|
||||
* Revision 1.2 2002/01/27 00:42:50 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO.
|
||||
*
|
||||
* Revision 1.1 2002/01/03 10:24:05 badbytes
|
||||
* COde based on that in op. Needs to be modified.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "or.h"
|
||||
|
||||
/* loads the configuration file */
|
||||
int getconfig(char *conf_filename, config_opt_t *options)
|
||||
{
|
||||
FILE *cf = NULL;
|
||||
int retval = 0;
|
||||
|
||||
if ((!conf_filename) || (!options))
|
||||
return -1;
|
||||
|
||||
/* load config file */
|
||||
cf = open_config(conf_filename);
|
||||
if (!cf)
|
||||
{
|
||||
log(LOG_ERR,"Could not open configuration file %s.",conf_filename);
|
||||
return -1;
|
||||
}
|
||||
retval = parse_config(cf,options);
|
||||
if (retval)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,362 @@
|
||||
|
||||
#include "or.h"
|
||||
|
||||
/********* START VARIABLES **********/
|
||||
|
||||
char *conn_type_to_string[] = {
|
||||
"OP listener", /* 0 */
|
||||
"OP", /* 1 */
|
||||
"OR listener", /* 2 */
|
||||
"OR", /* 3 */
|
||||
"App" /* 4 */
|
||||
};
|
||||
|
||||
char *conn_state_to_string[][10] = {
|
||||
{ "ready" }, /* op listener, 0 */
|
||||
{ "awaiting keys", /* op, 0 */
|
||||
"open", /* 1 */
|
||||
"close", /* 2 */
|
||||
"close_wait" }, /* 3 */
|
||||
{ "ready" }, /* or listener, 0 */
|
||||
{ "connecting (as client)", /* or, 0 */
|
||||
"sending auth (as client)", /* 1 */
|
||||
"waiting for auth (as client)", /* 2 */
|
||||
"sending nonce (as client)", /* 3 */
|
||||
"waiting for auth (as server)", /* 4 */
|
||||
"sending auth (as server)", /* 5 */
|
||||
"waiting for nonce (as server)",/* 6 */
|
||||
"open" }, /* 7 */
|
||||
{ "connecting", /* app, 0 */
|
||||
"open", /* 1 */
|
||||
"waiting for dest info", /* 2 */
|
||||
"flushing buffer, then will close",/* 3 */
|
||||
"close_wait" } /* 4 */
|
||||
};
|
||||
|
||||
/********* END VARIABLES ************/
|
||||
|
||||
connection_t *connection_new(int type) {
|
||||
connection_t *conn;
|
||||
|
||||
conn = (connection_t *)malloc(sizeof(connection_t));
|
||||
if(!conn)
|
||||
return NULL;
|
||||
memset(conn,0,sizeof(connection_t)); /* zero it out to start */
|
||||
|
||||
conn->type = type;
|
||||
buf_new(&conn->inbuf, &conn->inbuflen, &conn->inbuf_datalen);
|
||||
buf_new(&conn->outbuf, &conn->outbuflen, &conn->outbuf_datalen);
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
void connection_free(connection_t *conn) {
|
||||
assert(conn);
|
||||
|
||||
buf_free(conn->inbuf);
|
||||
buf_free(conn->outbuf);
|
||||
if(conn->address)
|
||||
free(conn->address);
|
||||
|
||||
/* FIXME should we do these for all connections, or just ORs, or what */
|
||||
if(conn->type == CONN_TYPE_OR ||
|
||||
conn->type == CONN_TYPE_OP) {
|
||||
// EVP_CIPHER_CTX_cleanup(&conn->f_ctx);
|
||||
// EVP_CIPHER_CTX_cleanup(&conn->b_ctx);
|
||||
}
|
||||
|
||||
if(conn->s > 0)
|
||||
close(conn->s);
|
||||
free(conn);
|
||||
}
|
||||
|
||||
int connection_create_listener(RSA *prkey, struct sockaddr_in *local, int type) {
|
||||
connection_t *conn;
|
||||
int s;
|
||||
int one=1;
|
||||
|
||||
s = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
|
||||
if (s < 0)
|
||||
{
|
||||
log(LOG_ERR,"connection_create_listener(): Socket creation failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
|
||||
|
||||
if(bind(s,(struct sockaddr *)local,sizeof(*local)) < 0) {
|
||||
perror("bind ");
|
||||
log(LOG_ERR,"Could not bind to local port %u.",ntohs(local->sin_port));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* start local server */
|
||||
if(listen(s,SOMAXCONN) < 0) {
|
||||
log(LOG_ERR,"Could not listen on local port %u.",ntohs(local->sin_port));
|
||||
return -1;
|
||||
}
|
||||
|
||||
fcntl(s, F_SETFL, O_NONBLOCK); /* set s to non-blocking */
|
||||
|
||||
conn = connection_new(type);
|
||||
conn->s = s;
|
||||
|
||||
if(connection_add(conn) < 0) { /* no space, forget it */
|
||||
connection_free(conn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* remember things so you can tell the baby sockets */
|
||||
memcpy(&conn->local,local,sizeof(struct sockaddr_in));
|
||||
conn->prkey = prkey;
|
||||
|
||||
log(LOG_DEBUG,"connection_create_listener(): Listening on local port %u.",ntohs(local->sin_port));
|
||||
|
||||
conn->state = LISTENER_STATE_READY;
|
||||
connection_watch_events(conn, POLLIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int connection_handle_listener_read(connection_t *conn, int new_type, int new_state) {
|
||||
|
||||
int news; /* the new socket */
|
||||
connection_t *newconn;
|
||||
struct sockaddr_in remote; /* information about the remote peer when connecting to other routers */
|
||||
int remotelen = sizeof(struct sockaddr_in); /* length of the remote address */
|
||||
|
||||
news = accept(conn->s,(struct sockaddr *)&remote,&remotelen);
|
||||
if (news == -1) { /* accept() error */
|
||||
if(errno==EAGAIN)
|
||||
return 0; /* he hung up before we could accept(). that's fine. */
|
||||
/* else there was a real error. */
|
||||
log(LOG_ERR,"connection_handle_listener_read(): accept() failed. Closing.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"Connection accepted on socket %d.",news);
|
||||
|
||||
newconn = connection_new(new_type);
|
||||
newconn->s = news;
|
||||
|
||||
/* learn things from parent, so we can perform auth */
|
||||
memcpy(&newconn->local,&conn->local,sizeof(struct sockaddr_in));
|
||||
newconn->prkey = conn->prkey;
|
||||
// newconn->address = strdup(get_string_from_remote()) FIXME ;
|
||||
|
||||
if(connection_add(newconn) < 0) { /* no space, forget it */
|
||||
connection_free(newconn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"connection_handle_listener_read(): socket %d entered state %d.",newconn->s, new_state);
|
||||
newconn->state = new_state;
|
||||
connection_watch_events(newconn, POLLIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int retry_all_connections(routerinfo_t **router_array, int rarray_len,
|
||||
RSA *prkey, uint16_t or_port, uint16_t op_port) {
|
||||
|
||||
/* start all connections that should be up but aren't */
|
||||
|
||||
routerinfo_t *router;
|
||||
int i;
|
||||
|
||||
/* local host information */
|
||||
char localhostname[512];
|
||||
struct hostent *localhost;
|
||||
struct sockaddr_in local; /* local address */
|
||||
|
||||
/* obtain local host information */
|
||||
if(gethostname(localhostname,512) < 0) {
|
||||
log(LOG_ERR,"Error obtaining local hostname.");
|
||||
return -1;
|
||||
}
|
||||
localhost = gethostbyname(localhostname);
|
||||
if (!localhost) {
|
||||
log(LOG_ERR,"Error obtaining local host info.");
|
||||
return -1;
|
||||
}
|
||||
memset((void *)&local,0,sizeof(local));
|
||||
local.sin_family = AF_INET;
|
||||
local.sin_addr.s_addr = INADDR_ANY;
|
||||
local.sin_port = htons(or_port);
|
||||
memcpy((void *)&local.sin_addr,(void *)localhost->h_addr,sizeof(struct in_addr));
|
||||
|
||||
for (i=0;i<rarray_len;i++) {
|
||||
router = router_array[i];
|
||||
if(!connection_get_by_addr_port(router->addr,router->port)) { /* not in the list */
|
||||
connect_to_router(router, prkey, &local);
|
||||
}
|
||||
}
|
||||
|
||||
if(!connection_get_by_type(CONN_TYPE_OR_LISTENER)) {
|
||||
connection_or_create_listener(prkey, &local);
|
||||
}
|
||||
|
||||
local.sin_port = htons(op_port);
|
||||
if(!connection_get_by_type(CONN_TYPE_OP_LISTENER)) {
|
||||
connection_op_create_listener(prkey, &local);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int connection_read_to_buf(connection_t *conn) {
|
||||
return read_to_buf(conn->s, &conn->inbuf, &conn->inbuflen, &conn->inbuf_datalen, &conn->inbuf_reached_eof);
|
||||
}
|
||||
|
||||
int connection_fetch_from_buf(char *string, int len, connection_t *conn) {
|
||||
return fetch_from_buf(string, len, &conn->inbuf, &conn->inbuflen, &conn->inbuf_datalen);
|
||||
}
|
||||
|
||||
int connection_flush_buf(connection_t *conn) {
|
||||
return flush_buf(conn->s, &conn->outbuf, &conn->outbuflen, &conn->outbuf_datalen);
|
||||
}
|
||||
|
||||
int connection_write_to_buf(char *string, int len, connection_t *conn) {
|
||||
if(!len)
|
||||
return 0;
|
||||
connection_watch_events(conn, POLLOUT | POLLIN);
|
||||
return write_to_buf(string, len, &conn->outbuf, &conn->outbuflen, &conn->outbuf_datalen);
|
||||
}
|
||||
|
||||
int connection_send_destroy(aci_t aci, connection_t *conn) {
|
||||
cell_t cell;
|
||||
|
||||
if(!conn)
|
||||
return -1;
|
||||
|
||||
if(conn->type == CONN_TYPE_OP ||
|
||||
conn->type == CONN_TYPE_APP) {
|
||||
log(LOG_DEBUG,"connection_send_destroy(): At an edge. Marking connection for close.");
|
||||
conn->marked_for_close = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell.aci = aci;
|
||||
cell.command = CELL_DESTROY;
|
||||
log(LOG_DEBUG,"connection_send_destroy(): Sending destroy (aci %d).",aci);
|
||||
return connection_write_cell_to_buf(&cell, conn);
|
||||
|
||||
}
|
||||
|
||||
int connection_write_cell_to_buf(cell_t *cellp, connection_t *conn) {
|
||||
/* FIXME in the future, we should modify windows, etc, here */
|
||||
|
||||
if(connection_encrypt_cell_header(cellp,conn)<0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return connection_write_to_buf((char *)cellp, sizeof(cell_t), conn);
|
||||
|
||||
}
|
||||
|
||||
int connection_encrypt_cell_header(cell_t *cellp, connection_t *conn) {
|
||||
char newheader[8];
|
||||
int newsize;
|
||||
int x;
|
||||
char *px;
|
||||
|
||||
printf("Sending: Cell header plaintext: ");
|
||||
px = (char *)cellp;
|
||||
for(x=0;x<8;x++) {
|
||||
printf("%u ",px[x]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if(!EVP_EncryptUpdate(&conn->f_ctx, newheader, &newsize, (char *)cellp, 8)) {
|
||||
log(LOG_ERR,"Could not encrypt data for connection %s:%u.",conn->address,ntohs(conn->port));
|
||||
return -1;
|
||||
}
|
||||
printf("Sending: Cell header crypttext: ");
|
||||
for(x=0;x<8;x++) {
|
||||
printf("%u ",newheader[x]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
memcpy(cellp,newheader,8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int connection_process_inbuf(connection_t *conn) {
|
||||
|
||||
assert(conn);
|
||||
|
||||
switch(conn->type) {
|
||||
case CONN_TYPE_OP:
|
||||
return connection_op_process_inbuf(conn);
|
||||
case CONN_TYPE_OR:
|
||||
return connection_or_process_inbuf(conn);
|
||||
case CONN_TYPE_APP:
|
||||
return connection_app_process_inbuf(conn);
|
||||
default:
|
||||
log(LOG_DEBUG,"connection_process_inbuf() got unexpected conn->type.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int connection_finished_flushing(connection_t *conn) {
|
||||
|
||||
assert(conn);
|
||||
|
||||
log(LOG_DEBUG,"connection_finished_flushing() entered. Socket %u.", conn->s);
|
||||
|
||||
switch(conn->type) {
|
||||
case CONN_TYPE_OP:
|
||||
return connection_op_finished_flushing(conn);
|
||||
case CONN_TYPE_OR:
|
||||
return connection_or_finished_flushing(conn);
|
||||
case CONN_TYPE_APP:
|
||||
return connection_app_finished_flushing(conn);
|
||||
default:
|
||||
log(LOG_DEBUG,"connection_finished_flushing() got unexpected conn->type.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int connection_process_cell_from_inbuf(connection_t *conn) {
|
||||
/* check if there's a whole cell there.
|
||||
* if yes, pull it off, decrypt it, and process it.
|
||||
*/
|
||||
char crypted[128];
|
||||
char outbuf[1024];
|
||||
int outlen;
|
||||
int x;
|
||||
cell_t *cellp;
|
||||
|
||||
if(conn->inbuf_datalen < 128) /* entire response available? */
|
||||
return 0; /* not yet */
|
||||
|
||||
if(connection_fetch_from_buf(crypted,128,conn) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Cell header crypttext: ");
|
||||
for(x=0;x<8;x++) {
|
||||
printf("%u ",crypted[x]);
|
||||
}
|
||||
printf("\n");
|
||||
/* decrypt */
|
||||
if(!EVP_DecryptUpdate(&conn->b_ctx,(unsigned char *)outbuf,&outlen,crypted,8)) {
|
||||
log(LOG_ERR,"connection_process_cell_from_inbuf(): Decryption failed, dropping.");
|
||||
return connection_process_inbuf(conn); /* process the remainder of the buffer */
|
||||
}
|
||||
log(LOG_DEBUG,"connection_process_cell_from_inbuf(): Cell decrypted (%d bytes).",outlen);
|
||||
printf("Cell header plaintext: ");
|
||||
for(x=0;x<8;x++) {
|
||||
printf("%u ",outbuf[x]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* copy the rest of the cell */
|
||||
memcpy((char *)outbuf+8, (char *)crypted+8, sizeof(cell_t)-8);
|
||||
cellp = (cell_t *)outbuf;
|
||||
log(LOG_DEBUG,"connection_process_cell_from_inbuf(): Decrypted cell is of type %u (ACI %u).",cellp->command,cellp->aci);
|
||||
command_process_cell(cellp, conn);
|
||||
|
||||
return connection_process_inbuf(conn); /* process the remainder of the buffer */
|
||||
}
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
|
||||
#include "or.h"
|
||||
|
||||
connection_t *connection_app_new(void) {
|
||||
return connection_new(CONN_TYPE_APP);
|
||||
}
|
||||
|
||||
int connection_app_process_inbuf(connection_t *conn) {
|
||||
|
||||
assert(conn && conn->type == CONN_TYPE_APP);
|
||||
|
||||
if(conn->inbuf_reached_eof) {
|
||||
/* eof reached, kill it. */
|
||||
log(LOG_DEBUG,"connection_app_process_inbuf(): conn reached eof. Closing.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"connection_app_process_inbuf(): state %d.",conn->state);
|
||||
|
||||
switch(conn->state) {
|
||||
case APP_CONN_STATE_CONNECTING:
|
||||
log(LOG_DEBUG,"connection_app_process_inbuf(): text from app server while in 'connecting' state. Leaving it on buffer.");
|
||||
return 0;
|
||||
case APP_CONN_STATE_OPEN:
|
||||
return connection_app_package_inbuf(conn);
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int connection_app_package_inbuf(connection_t *conn) {
|
||||
int amount_to_process;
|
||||
cell_t cell;
|
||||
circuit_t *circ;
|
||||
|
||||
assert(conn && conn->type == CONN_TYPE_APP);
|
||||
|
||||
amount_to_process = conn->inbuf_datalen;
|
||||
|
||||
if(!amount_to_process)
|
||||
return 0;
|
||||
|
||||
if(amount_to_process > CELL_PAYLOAD_SIZE) {
|
||||
cell.length = CELL_PAYLOAD_SIZE;
|
||||
} else {
|
||||
cell.length = amount_to_process;
|
||||
}
|
||||
|
||||
if(connection_fetch_from_buf(cell.payload,cell.length,conn) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
circ = circuit_get_by_conn(conn);
|
||||
if(!circ) {
|
||||
log(LOG_DEBUG,"connection_app_package_inbuf(): conn has no circuits!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"connection_app_package_inbuf(): Packaging %d bytes.",cell.length);
|
||||
cell.aci = circ->p_aci;
|
||||
cell.command = CELL_DATA;
|
||||
if(circuit_deliver_data_cell(&cell, circ, circ->p_conn, 'e') < 0) {
|
||||
log(LOG_DEBUG,"connection_app_package_inbuf(): circuit_deliver_data_cell (backward) failed. Closing.");
|
||||
circuit_close(circ);
|
||||
return 0;
|
||||
}
|
||||
if(amount_to_process > CELL_PAYLOAD_SIZE)
|
||||
return(connection_app_package_inbuf(conn));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int connection_app_finished_flushing(connection_t *conn) {
|
||||
int e, len=sizeof(e);
|
||||
|
||||
assert(conn && conn->type == CONN_TYPE_APP);
|
||||
|
||||
switch(conn->state) {
|
||||
case APP_CONN_STATE_CONNECTING:
|
||||
if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, &e, &len) < 0) { /* not yet */
|
||||
if(errno != EINPROGRESS){
|
||||
/* yuck. kill it. */
|
||||
log(LOG_DEBUG,"connection_app_finished_flushing(): in-progress connect failed. Removing.");
|
||||
return -1;
|
||||
} else {
|
||||
return 0; /* no change, see if next time is better */
|
||||
}
|
||||
}
|
||||
/* the connect has finished. */
|
||||
|
||||
log(LOG_DEBUG,"connection_app_finished_flushing() : Connection to %s:%u established.",
|
||||
conn->address,ntohs(conn->port));
|
||||
|
||||
conn->state = APP_CONN_STATE_OPEN;
|
||||
connection_watch_events(conn, POLLIN);
|
||||
return 0;
|
||||
case APP_CONN_STATE_OPEN:
|
||||
/* FIXME down the road, we'll clear out circuits that are pending to close */
|
||||
connection_watch_events(conn, POLLIN);
|
||||
return 0;
|
||||
default:
|
||||
log(LOG_DEBUG,"Bug: connection_app_finished_flushing() called in unexpected state.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int connection_app_process_data_cell(cell_t *cell, connection_t *conn) {
|
||||
struct hostent *rent;
|
||||
struct sockaddr_in dest_addr;
|
||||
int s;
|
||||
|
||||
/* an outgoing data cell has arrived */
|
||||
|
||||
assert(conn && conn->type == CONN_TYPE_APP);
|
||||
|
||||
switch(conn->state) {
|
||||
case APP_CONN_STATE_CONNECTING_WAIT:
|
||||
log(LOG_DEBUG,"connection_app_process_cell(): state is connecting_wait. cell length %d.", cell->length);
|
||||
if(!conn->ss_received) { /* this cell contains the ss */
|
||||
if(cell->length != sizeof(ss_t)) {
|
||||
log(LOG_DEBUG,"connection_app_process_cell(): Supposed to contain SS but wrong size. Closing.");
|
||||
return -1;
|
||||
}
|
||||
memcpy(&conn->ss, cell->payload, cell->length);
|
||||
if(conn->ss.addr_fmt != SS_ADDR_FMT_ASCII_HOST_PORT) { /* unrecognized address format */
|
||||
log(LOG_DEBUG,"connection_app_process_cell(): SS has unrecognized address format. Closing.");
|
||||
return -1;
|
||||
}
|
||||
conn->ss_received = 1;
|
||||
log(LOG_DEBUG,"connection_app_process_cell(): SS received.");
|
||||
} else if (!conn->addr) { /* this cell contains the dest addr */
|
||||
if(!memchr(cell->payload,0,cell->length)) {
|
||||
log(LOG_DEBUG,"connection_app_process_cell(): dest_addr cell has no \\0. Closing.");
|
||||
return -1;
|
||||
}
|
||||
conn->address = strdup(cell->payload);
|
||||
rent = gethostbyname(cell->payload);
|
||||
if (!rent) {
|
||||
log(LOG_ERR,"connection_app_process_cell(): Could not resolve dest addr %s.",cell->payload);
|
||||
return -1;
|
||||
}
|
||||
memcpy(&conn->addr, rent->h_addr,rent->h_length);
|
||||
log(LOG_DEBUG,"connection_app_process_cell(): addr %s resolves to %d.",cell->payload,conn->addr);
|
||||
} else if (!conn->port) { /* this cell contains the dest port */
|
||||
if(!memchr(cell->payload,'\0',cell->length)) {
|
||||
log(LOG_DEBUG,"connection_app_process_cell(): dest_port cell has no \\0. Closing.");
|
||||
return -1;
|
||||
}
|
||||
conn->port = atoi(cell->payload);
|
||||
if(!conn->port) { /* bad port */
|
||||
log(LOG_DEBUG,"connection_app_process_cell(): dest_port cell isn't a valid number. Closing.");
|
||||
return -1;
|
||||
}
|
||||
/* all the necessary info is here. Start the connect() */
|
||||
s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
|
||||
if (s < 0)
|
||||
{
|
||||
log(LOG_ERR,"connection_app_process_cell(): Error creating network socket.");
|
||||
return -1;
|
||||
}
|
||||
fcntl(s, F_SETFL, O_NONBLOCK); /* set s to non-blocking */
|
||||
|
||||
memset((void *)&dest_addr,0,sizeof(dest_addr));
|
||||
dest_addr.sin_family = AF_INET;
|
||||
dest_addr.sin_port = conn->port;
|
||||
memcpy((void *)&dest_addr.sin_addr, &conn->addr, sizeof(uint32_t));
|
||||
|
||||
log(LOG_DEBUG,"connection_app_process_cell(): Connecting to %s:%u.",conn->address,ntohs(conn->port));
|
||||
|
||||
if(connect(s,(struct sockaddr *)&dest_addr,sizeof(dest_addr)) < 0){
|
||||
if(errno != EINPROGRESS){
|
||||
/* yuck. kill it. */
|
||||
log(LOG_DEBUG,"connection_app_process_cell(): Connect failed.");
|
||||
return -1;
|
||||
} else {
|
||||
/* it's in progress. set state appropriately and return. */
|
||||
conn->s = s;
|
||||
connection_set_poll_socket(conn);
|
||||
conn->state = APP_CONN_STATE_CONNECTING;
|
||||
|
||||
/* i think only pollout is needed, but i'm curious if pollin ever gets caught -RD */
|
||||
log(LOG_DEBUG,"connection_app_process_cell(): connect in progress, socket %d.",s);
|
||||
connection_watch_events(conn, POLLOUT | POLLIN);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* it succeeded. we're connected. */
|
||||
log(LOG_DEBUG,"connection_app_process_cell(): Connection to %s:%u established.",conn->address,ntohs(conn->port));
|
||||
|
||||
conn->s = s;
|
||||
connection_set_poll_socket(conn);
|
||||
conn->state = APP_CONN_STATE_OPEN;
|
||||
connection_watch_events(conn, POLLIN);
|
||||
} else { /* i'm not sure what this would be */
|
||||
log(LOG_DEBUG,"connection_app_process_cell(): in connecting_wait, not sure why.");
|
||||
}
|
||||
return 0;
|
||||
case APP_CONN_STATE_CONNECTING:
|
||||
log(LOG_DEBUG,"connection_app_process_cell(): Data receiving while connecting. Queueing.");
|
||||
/* FIXME kludge. shouldn't call write_to_buf directly. */
|
||||
return write_to_buf(cell->payload, cell->length, &conn->outbuf, &conn->outbuflen, &conn->outbuf_datalen);
|
||||
case APP_CONN_STATE_OPEN:
|
||||
return connection_write_to_buf(cell->payload, cell->length, conn);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
|
||||
#include "or.h"
|
||||
|
||||
connection_t *connection_op_new(void) {
|
||||
return connection_new(CONN_TYPE_OP);
|
||||
}
|
||||
|
||||
connection_t *connection_op_listener_new(void) {
|
||||
return connection_new(CONN_TYPE_OP_LISTENER);
|
||||
}
|
||||
|
||||
int connection_op_process_inbuf(connection_t *conn) {
|
||||
|
||||
assert(conn && conn->type == CONN_TYPE_OP);
|
||||
|
||||
if(conn->inbuf_reached_eof) {
|
||||
/* eof reached, kill it. */
|
||||
log(LOG_DEBUG,"connection_op_process_inbuf(): conn reached eof. Closing.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"connection_op_process_inbuf(): state %d.",conn->state);
|
||||
|
||||
switch(conn->state) {
|
||||
case OP_CONN_STATE_AWAITING_KEYS:
|
||||
return op_handshake_process_keys(conn);
|
||||
case OP_CONN_STATE_OPEN:
|
||||
return connection_process_cell_from_inbuf(conn);
|
||||
default:
|
||||
log(LOG_DEBUG,"connection_op_process_inbuf() called in state where I'm writing. Ignoring buf for now.")
|
||||
;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int op_handshake_process_keys(connection_t *conn) {
|
||||
int retval;
|
||||
int x;
|
||||
|
||||
/* key exchange message */
|
||||
unsigned char auth_cipher[128];
|
||||
unsigned char auth_plain[128];
|
||||
|
||||
assert(conn);
|
||||
|
||||
log(LOG_DEBUG,"op_handshake_process_keys() entered.");
|
||||
|
||||
if(conn->inbuf_datalen < 128) /* entire response available? */
|
||||
return 0; /* not yet */
|
||||
|
||||
if(connection_fetch_from_buf(auth_cipher,128,conn) < 0) {
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"op_handshake_process_keys() : Received auth.");
|
||||
|
||||
/* decrypt response */
|
||||
retval = RSA_private_decrypt(128,auth_cipher,auth_plain,conn->prkey,RSA_PKCS1_PADDING);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Decrypting keys from new OP failed.");
|
||||
log(LOG_DEBUG,"op_handshake_process_keys() : Reason : %s.",
|
||||
ERR_reason_error_string(ERR_get_error()));
|
||||
return -1;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"Successfully decrypted keys from new OP.");
|
||||
|
||||
conn->bandwidth = ntohl(*((uint32_t *)auth_plain));
|
||||
|
||||
memcpy(conn->b_session_key, auth_plain+4, 8);
|
||||
memcpy(conn->f_session_key, auth_plain+12, 8);
|
||||
printf("f_session_key: ");
|
||||
for(x=0;x<8;x++) {
|
||||
printf("%d ",conn->f_session_key[x]);
|
||||
}
|
||||
printf("\nb_session_key: ");
|
||||
for(x=0;x<8;x++) {
|
||||
printf("%d ",conn->b_session_key[x]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
memset((void *)conn->f_session_iv, 0, 8);
|
||||
memset((void *)conn->b_session_iv, 0, 8);
|
||||
|
||||
EVP_CIPHER_CTX_init(&conn->f_ctx);
|
||||
EVP_CIPHER_CTX_init(&conn->b_ctx);
|
||||
EVP_EncryptInit(&conn->b_ctx, EVP_des_ofb(), conn->b_session_key, conn->b_session_iv);
|
||||
EVP_DecryptInit(&conn->f_ctx, EVP_des_ofb(), conn->f_session_key, conn->f_session_iv);
|
||||
|
||||
#if 0
|
||||
/* FIXME must choose conn->aci here? What does it mean for a connection to have an aci? */
|
||||
log(LOG_DEBUG,"new_entry_connection : Chosen ACI %u.",conn->aci);
|
||||
#endif
|
||||
|
||||
conn->state = OP_CONN_STATE_OPEN;
|
||||
connection_watch_events(conn, POLLIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int connection_op_finished_flushing(connection_t *conn) {
|
||||
|
||||
assert(conn && conn->type == CONN_TYPE_OP);
|
||||
|
||||
switch(conn->state) {
|
||||
case OP_CONN_STATE_OPEN:
|
||||
/* FIXME down the road, we'll clear out circuits that are pending to close */
|
||||
connection_watch_events(conn, POLLIN);
|
||||
return 0;
|
||||
default:
|
||||
log(LOG_DEBUG,"Bug: connection_op_finished_flushing() called in unexpected state.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int connection_op_create_listener(RSA *prkey, struct sockaddr_in *local) {
|
||||
log(LOG_DEBUG,"connection_create_op_listener starting");
|
||||
return connection_create_listener(prkey, local, CONN_TYPE_OP_LISTENER);
|
||||
}
|
||||
|
||||
int connection_op_handle_listener_read(connection_t *conn) {
|
||||
log(LOG_NOTICE,"OP: Received a connection request. Waiting for keys.");
|
||||
return connection_handle_listener_read(conn, CONN_TYPE_OP, OP_CONN_STATE_AWAITING_KEYS);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,580 @@
|
||||
|
||||
#include "or.h"
|
||||
|
||||
/*
|
||||
*
|
||||
* these two functions are the main ways 'in' to connection_or
|
||||
*
|
||||
*/
|
||||
|
||||
int connection_or_process_inbuf(connection_t *conn) {
|
||||
|
||||
assert(conn && conn->type == CONN_TYPE_OR);
|
||||
|
||||
if(conn->inbuf_reached_eof) {
|
||||
/* eof reached, kill it. */
|
||||
log(LOG_DEBUG,"connection_or_process_inbuf(): conn reached eof. Closing.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"connection_or_process_inbuf(): state %d.",conn->state);
|
||||
|
||||
switch(conn->state) {
|
||||
case OR_CONN_STATE_CLIENT_AUTH_WAIT:
|
||||
return or_handshake_client_process_auth(conn);
|
||||
case OR_CONN_STATE_SERVER_AUTH_WAIT:
|
||||
return or_handshake_server_process_auth(conn);
|
||||
case OR_CONN_STATE_SERVER_NONCE_WAIT:
|
||||
return or_handshake_server_process_nonce(conn);
|
||||
case OR_CONN_STATE_OPEN:
|
||||
return connection_process_cell_from_inbuf(conn);
|
||||
default:
|
||||
log(LOG_DEBUG,"connection_or_process_inbuf() called in state where I'm writing. Ignoring buf for now.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int connection_or_finished_flushing(connection_t *conn) {
|
||||
int e, len=sizeof(e);
|
||||
|
||||
assert(conn && conn->type == CONN_TYPE_OR);
|
||||
|
||||
switch(conn->state) {
|
||||
case OR_CONN_STATE_CLIENT_CONNECTING:
|
||||
if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, &e, &len) < 0) { /* not yet */
|
||||
if(errno != EINPROGRESS){
|
||||
/* yuck. kill it. */
|
||||
log(LOG_DEBUG,"connection_or_finished_flushing(): in-progress connect failed. Removing.");
|
||||
return -1;
|
||||
} else {
|
||||
return 0; /* no change, see if next time is better */
|
||||
}
|
||||
}
|
||||
/* the connect has finished. */
|
||||
|
||||
log(LOG_DEBUG,"connection_or_finished_flushing() : Connection to router %s:%u established.",
|
||||
conn->address,ntohs(conn->port));
|
||||
|
||||
return or_handshake_client_send_auth(conn);
|
||||
case OR_CONN_STATE_CLIENT_SENDING_AUTH:
|
||||
log(LOG_DEBUG,"connection_or_finished_flushing(): client finished sending auth.");
|
||||
conn->state = OR_CONN_STATE_CLIENT_AUTH_WAIT;
|
||||
connection_watch_events(conn, POLLIN);
|
||||
return 0;
|
||||
case OR_CONN_STATE_CLIENT_SENDING_NONCE:
|
||||
log(LOG_DEBUG,"connection_or_finished_flushing(): client finished sending nonce.");
|
||||
conn_or_init_crypto(conn);
|
||||
conn->state = OR_CONN_STATE_OPEN;
|
||||
connection_watch_events(conn, POLLIN);
|
||||
return 0;
|
||||
case OR_CONN_STATE_SERVER_SENDING_AUTH:
|
||||
log(LOG_DEBUG,"connection_or_finished_flushing(): server finished sending auth.");
|
||||
conn->state = OR_CONN_STATE_SERVER_NONCE_WAIT;
|
||||
connection_watch_events(conn, POLLIN);
|
||||
return 0;
|
||||
case OR_CONN_STATE_OPEN:
|
||||
/* FIXME down the road, we'll clear out circuits that are pending to close */
|
||||
connection_watch_events(conn, POLLIN);
|
||||
return 0;
|
||||
default:
|
||||
log(LOG_DEBUG,"Bug: connection_or_finished_flushing() called in unexpected state.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/*********************/
|
||||
|
||||
connection_t *connection_or_new(void) {
|
||||
return connection_new(CONN_TYPE_OR);
|
||||
}
|
||||
|
||||
connection_t *connection_or_new_listener(void) {
|
||||
return connection_new(CONN_TYPE_OR_LISTENER);
|
||||
}
|
||||
|
||||
void conn_or_init_crypto(connection_t *conn) {
|
||||
int x;
|
||||
|
||||
assert(conn);
|
||||
printf("f_session_key: ");
|
||||
for(x=0;x<8;x++) {
|
||||
printf("%d ",conn->f_session_key[x]);
|
||||
}
|
||||
printf("\nb_session_key: ");
|
||||
for(x=0;x<8;x++) {
|
||||
printf("%d ",conn->b_session_key[x]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
memset(conn->f_session_iv,0,8);
|
||||
memset(conn->b_session_iv,0,8);
|
||||
EVP_CIPHER_CTX_init(&conn->f_ctx);
|
||||
EVP_CIPHER_CTX_init(&conn->b_ctx);
|
||||
EVP_EncryptInit(&conn->f_ctx, EVP_des_ofb(), conn->f_session_key, conn->f_session_iv);
|
||||
EVP_DecryptInit(&conn->b_ctx, EVP_des_ofb(), conn->b_session_key, conn->b_session_iv);
|
||||
/* always encrypt with f, always decrypt with b */
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* auth handshake, as performed by OR *initiating* the connection
|
||||
*
|
||||
*/
|
||||
|
||||
int connect_to_router(routerinfo_t *router, RSA *prkey, struct sockaddr_in *local) {
|
||||
connection_t *conn;
|
||||
struct sockaddr_in router_addr;
|
||||
int s;
|
||||
|
||||
if ((!router) || (!prkey) || (!local))
|
||||
return -1;
|
||||
|
||||
if(router->addr == local->sin_addr.s_addr && router->port == local->sin_port) {
|
||||
/* this is me! don't connect to me. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
conn = connection_or_new();
|
||||
|
||||
/* set up conn so it's got all the data we need to remember */
|
||||
conn->addr = router->addr, conn->port = router->port;
|
||||
conn->prkey = prkey;
|
||||
conn->min = router->min, conn->max = router->max;
|
||||
conn->pkey = router->pkey;
|
||||
conn->address = strdup(router->address);
|
||||
memcpy(&conn->local,local,sizeof(struct sockaddr_in));
|
||||
|
||||
s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
|
||||
if (s < 0)
|
||||
{
|
||||
log(LOG_ERR,"Error creating network socket.");
|
||||
connection_free(conn);
|
||||
return -1;
|
||||
}
|
||||
fcntl(s, F_SETFL, O_NONBLOCK); /* set s to non-blocking */
|
||||
|
||||
memset((void *)&router_addr,0,sizeof(router_addr));
|
||||
router_addr.sin_family = AF_INET;
|
||||
router_addr.sin_port = router->port;
|
||||
memcpy((void *)&router_addr.sin_addr, &router->addr, sizeof(uint32_t));
|
||||
|
||||
log(LOG_DEBUG,"connect_to_router() : Trying to connect to %s:%u.",inet_ntoa(*(struct in_addr *)&router->addr),ntohs(router->port));
|
||||
|
||||
if(connect(s,(struct sockaddr *)&router_addr,sizeof(router_addr)) < 0){
|
||||
if(errno != EINPROGRESS){
|
||||
/* yuck. kill it. */
|
||||
connection_free(conn);
|
||||
return -1;
|
||||
} else {
|
||||
/* it's in progress. set state appropriately and return. */
|
||||
conn->s = s;
|
||||
|
||||
conn->state = OR_CONN_STATE_CLIENT_CONNECTING;
|
||||
|
||||
if(connection_add(conn) < 0) { /* no space, forget it */
|
||||
connection_free(conn);
|
||||
return -1;
|
||||
}
|
||||
/* i think only pollout is needed, but i'm curious if pollin ever gets caught -RD */
|
||||
log(LOG_DEBUG,"connect_to_router() : connect in progress.");
|
||||
connection_watch_events(conn, POLLOUT | POLLIN);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* it succeeded. we're connected. */
|
||||
conn->s = s;
|
||||
|
||||
if(connection_add(conn) < 0) { /* no space, forget it */
|
||||
connection_free(conn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"connect_to_router() : Connection to router %s:%u established.",router->address,ntohs(router->port));
|
||||
|
||||
/* move to the next step in the handshake */
|
||||
if(or_handshake_client_send_auth(conn) < 0) {
|
||||
connection_remove(conn);
|
||||
connection_free(conn);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int or_handshake_client_send_auth(connection_t *conn) {
|
||||
int retval;
|
||||
char keys[16];
|
||||
char buf[44];
|
||||
char cipher[128];
|
||||
|
||||
if (!conn)
|
||||
return -1;
|
||||
|
||||
/* generate random keys */
|
||||
retval = RAND_bytes(keys,16);
|
||||
if (retval != 1) /* error */
|
||||
{
|
||||
log(LOG_ERR,"Cannot generate a secure DES key.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"or_handshake_client_send_auth() : Generated DES keys.");
|
||||
|
||||
/* save keys */
|
||||
memcpy(conn->f_session_key,keys,8);
|
||||
memcpy(conn->b_session_key,keys+8,8);
|
||||
|
||||
/* generate first message */
|
||||
memcpy(buf,&conn->local.sin_addr,4); /* local address */
|
||||
memcpy(buf+4,(void *)&conn->local.sin_port,2); /* local port */
|
||||
memcpy(buf+6, (void *)&conn->addr, 4); /* remote address */
|
||||
memcpy(buf+10, (void *)&conn->port, 2); /* remote port */
|
||||
memcpy(buf+12,keys,16); /* keys */
|
||||
*((uint32_t *)(buf+28)) = htonl(conn->min); /* min link utilisation */
|
||||
*((uint32_t *)(buf+32)) = htonl(conn->max); /* maximum link utilisation */
|
||||
log(LOG_DEBUG,"or_handshake_client_send_auth() : Generated first authentication message.");
|
||||
|
||||
/* encrypt message */
|
||||
retval = RSA_public_encrypt(36,buf,cipher,conn->pkey,RSA_PKCS1_PADDING);
|
||||
if (retval == -1) /* error */
|
||||
{
|
||||
log(LOG_ERR,"Public-key encryption failed during authentication to %s:%u.",conn->address,ntohs(conn->port));
|
||||
log(LOG_DEBUG,"or_handshake_client_send_auth() : Reason : %s.",ERR_reason_error_string(ERR_get_error()));
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"or_handshake_client_send_auth() : Encrypted authentication message.");
|
||||
|
||||
/* send message */
|
||||
|
||||
if(connection_write_to_buf(cipher, 128, conn) < 0) {
|
||||
log(LOG_DEBUG,"or_handshake_client_send_auth(): my outbuf is full. Oops.");
|
||||
return -1;
|
||||
}
|
||||
retval = connection_flush_buf(conn);
|
||||
if(retval < 0) {
|
||||
log(LOG_DEBUG,"or_handshake_client_send_auth(): bad socket while flushing.");
|
||||
return -1;
|
||||
}
|
||||
if(retval > 0) {
|
||||
/* still stuff on the buffer. */
|
||||
conn->state = OR_CONN_STATE_CLIENT_SENDING_AUTH;
|
||||
connection_watch_events(conn, POLLOUT | POLLIN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* it finished sending */
|
||||
log(LOG_DEBUG,"or_handshake_client_send_auth(): Finished sending authentication message.");
|
||||
conn->state = OR_CONN_STATE_CLIENT_AUTH_WAIT;
|
||||
connection_watch_events(conn, POLLIN);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int or_handshake_client_process_auth(connection_t *conn) {
|
||||
char buf[128]; /* only 44 of this is expected to be used */
|
||||
char cipher[128];
|
||||
uint32_t min,max;
|
||||
int retval;
|
||||
|
||||
assert(conn);
|
||||
|
||||
if(conn->inbuf_datalen < 128) /* entire response available? */
|
||||
return 0; /* not yet */
|
||||
|
||||
if(connection_fetch_from_buf(cipher,128,conn) < 0) {
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"or_handshake_client_process_auth() : Received auth.");
|
||||
|
||||
/* decrypt response */
|
||||
retval = RSA_private_decrypt(128,cipher,buf,conn->prkey,RSA_PKCS1_PADDING);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Public-key decryption failed during authentication to %s:%u.",
|
||||
conn->address,ntohs(conn->port));
|
||||
log(LOG_DEBUG,"or_handshake_client_process_auth() : Reason : %s.",
|
||||
ERR_reason_error_string(ERR_get_error()));
|
||||
return -1;
|
||||
}
|
||||
else if (retval != 44)
|
||||
{
|
||||
log(LOG_ERR,"Received an incorrect response from router %s:%u during authentication.",
|
||||
conn->address,ntohs(conn->port));
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"or_handshake_client_process_auth() : Decrypted response.");
|
||||
/* check validity */
|
||||
if ( (memcmp(&conn->local.sin_addr, buf, 4)) || /* local address */
|
||||
(memcmp(&conn->local.sin_port, buf+4, 2)) || /* local port */
|
||||
(memcmp(&conn->addr, buf+6, 4)) || /* remote address */
|
||||
(memcmp(&conn->port, buf+10, 2)) || /* remote port */
|
||||
(memcmp(&conn->f_session_key, buf+12, 8)) || /* keys */
|
||||
(memcmp(&conn->b_session_key, buf+20, 8)))
|
||||
{ /* incorrect response */
|
||||
log(LOG_ERR,"Router %s:%u failed to authenticate. Either the key I have is obsolete or they're doing something they're not supposed to.",conn->address,ntohs(conn->port));
|
||||
return -1;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"or_handshake_client_process_auth() : Response valid.");
|
||||
|
||||
/* update link info */
|
||||
min = *(uint32_t *)(buf+28);
|
||||
max = *(uint32_t *)(buf+32);
|
||||
min = ntohl(min);
|
||||
max = ntohl(max);
|
||||
|
||||
if (conn->min > min)
|
||||
conn->min = min;
|
||||
if (conn->max > max)
|
||||
conn->max = max;
|
||||
|
||||
/* reply is just local addr/port, remote addr/port, nonce */
|
||||
memcpy(buf+12, buf+36, 8);
|
||||
|
||||
/* encrypt reply */
|
||||
retval = RSA_public_encrypt(20,buf,cipher,conn->pkey,RSA_PKCS1_PADDING);
|
||||
if (retval == -1) /* error */
|
||||
{
|
||||
log(LOG_ERR,"Public-key encryption failed during authentication to %s:%u.",conn->address,ntohs(conn->port));
|
||||
log(LOG_DEBUG,"or_handshake_client_process_auth() : Reason : %s.",ERR_reason_error_string(ERR_get_error()));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* send the message */
|
||||
|
||||
if(connection_write_to_buf(cipher, 128, conn) < 0) {
|
||||
log(LOG_DEBUG,"or_handshake_client_process_auth(): my outbuf is full. Oops.");
|
||||
return -1;
|
||||
}
|
||||
retval = connection_flush_buf(conn);
|
||||
if(retval < 0) {
|
||||
log(LOG_DEBUG,"or_handshake_client_process_auth(): bad socket while flushing.");
|
||||
return -1;
|
||||
}
|
||||
if(retval > 0) {
|
||||
/* still stuff on the buffer. */
|
||||
conn->state = OR_CONN_STATE_CLIENT_SENDING_NONCE;
|
||||
connection_watch_events(conn, POLLOUT | POLLIN);
|
||||
/* return(connection_process_inbuf(conn)); process the rest of the inbuf */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* it finished sending */
|
||||
log(LOG_DEBUG,"or_handshake_client_process_auth(): Finished sending nonce.");
|
||||
conn_or_init_crypto(conn);
|
||||
conn->state = OR_CONN_STATE_OPEN;
|
||||
connection_watch_events(conn, POLLIN);
|
||||
return connection_process_inbuf(conn); /* process the rest of the inbuf */
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* auth handshake, as performed by OR *receiving* the connection
|
||||
*
|
||||
*/
|
||||
|
||||
int or_handshake_server_process_auth(connection_t *conn) {
|
||||
int retval;
|
||||
|
||||
char buf[128]; /* only 42 of this is expected to be used */
|
||||
char cipher[128];
|
||||
|
||||
uint32_t addr;
|
||||
uint16_t port;
|
||||
|
||||
uint32_t min,max;
|
||||
routerinfo_t *router;
|
||||
|
||||
assert(conn);
|
||||
|
||||
log(LOG_DEBUG,"or_handshake_server_process_auth() entered.");
|
||||
|
||||
if(conn->inbuf_datalen < 128) /* entire response available? */
|
||||
return 0; /* not yet */
|
||||
|
||||
if(connection_fetch_from_buf(cipher,128,conn) < 0) {
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"or_handshake_server_process_auth() : Received auth.");
|
||||
|
||||
/* decrypt response */
|
||||
retval = RSA_private_decrypt(128,cipher,buf,conn->prkey,RSA_PKCS1_PADDING);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Public-key decryption failed during authentication to %s:%u.",
|
||||
conn->address,ntohs(conn->port));
|
||||
log(LOG_DEBUG,"or_handshake_server_process_auth() : Reason : %s.",
|
||||
ERR_reason_error_string(ERR_get_error()));
|
||||
return -1;
|
||||
}
|
||||
else if (retval != 36)
|
||||
{
|
||||
log(LOG_ERR,"Received an incorrect authentication request.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"or_handshake_server_process_auth() : Decrypted authentication message.");
|
||||
|
||||
/* identify the router */
|
||||
memcpy(&addr,buf,4); /* save the IP address */
|
||||
memcpy(&port,buf+4,2); /* save the port */
|
||||
|
||||
router = router_get_by_addr_port(addr,port);
|
||||
if (!router)
|
||||
{
|
||||
log(LOG_DEBUG,"or_handshake_server_process_auth() : Received a connection from an unknown router. Will drop.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"or_handshake_server_process_auth() : Router identified as %s:%u.",
|
||||
router->address,ntohs(router->port));
|
||||
|
||||
if(connection_get_by_addr_port(addr,port)) {
|
||||
log(LOG_DEBUG,"or_handshake_server_process_auth(): That router is already connected. Dropping.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* save keys */
|
||||
memcpy(conn->b_session_key,buf+12,8);
|
||||
memcpy(conn->f_session_key,buf+20,8);
|
||||
|
||||
/* update link info */
|
||||
min = *(uint32_t *)(buf+28);
|
||||
max = *(uint32_t *)(buf+32);
|
||||
min = ntohl(min);
|
||||
max = ntohl(max);
|
||||
|
||||
conn->min = router->min;
|
||||
conn->max = router->max;
|
||||
|
||||
if (conn->min > min)
|
||||
conn->min = min;
|
||||
if (conn->max > max)
|
||||
conn->max = max;
|
||||
|
||||
/* copy all relevant info to conn */
|
||||
conn->addr = router->addr, conn->port = router->port;
|
||||
conn->pkey = router->pkey;
|
||||
conn->address = strdup(router->address);
|
||||
|
||||
/* generate a nonce */
|
||||
retval = RAND_pseudo_bytes(conn->nonce,8);
|
||||
if (retval == -1) /* error */
|
||||
{
|
||||
log(LOG_ERR,"Cannot generate a nonce.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"or_handshake_server_process_auth() : Nonce generated.");
|
||||
|
||||
/* generate message */
|
||||
memcpy(buf+36,conn->nonce,8); /* append the nonce to the end of the message */
|
||||
*(uint32_t *)(buf+28) = htonl(conn->min); /* send min link utilisation */
|
||||
*(uint32_t *)(buf+32) = htonl(conn->max); /* send max link utilisation */
|
||||
|
||||
/* encrypt message */
|
||||
retval = RSA_public_encrypt(44,buf,cipher,conn->pkey,RSA_PKCS1_PADDING);
|
||||
if (retval == -1) /* error */
|
||||
{
|
||||
log(LOG_ERR,"Public-key encryption failed during authentication to %s:%u.",conn->address,ntohs(conn->port));
|
||||
log(LOG_DEBUG,"or_handshake_server_process_auth() : Reason : %s.",ERR_reason_error_string(ERR_get_error()));
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"or_handshake_server_process_auth() : Reply encrypted.");
|
||||
|
||||
/* send message */
|
||||
|
||||
if(connection_write_to_buf(cipher, 128, conn) < 0) {
|
||||
log(LOG_DEBUG,"or_handshake_server_process_auth(): my outbuf is full. Oops.");
|
||||
return -1;
|
||||
}
|
||||
retval = connection_flush_buf(conn);
|
||||
if(retval < 0) {
|
||||
log(LOG_DEBUG,"or_handshake_server_process_auth(): bad socket while flushing.");
|
||||
return -1;
|
||||
}
|
||||
if(retval > 0) {
|
||||
/* still stuff on the buffer. */
|
||||
conn->state = OR_CONN_STATE_SERVER_SENDING_AUTH;
|
||||
connection_watch_events(conn, POLLOUT | POLLIN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* it finished sending */
|
||||
log(LOG_DEBUG,"or_handshake_server_process_auth(): Finished sending auth.");
|
||||
conn->state = OR_CONN_STATE_SERVER_NONCE_WAIT;
|
||||
connection_watch_events(conn, POLLIN);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int or_handshake_server_process_nonce(connection_t *conn) {
|
||||
|
||||
char buf[128];
|
||||
char cipher[128];
|
||||
int retval;
|
||||
|
||||
assert(conn);
|
||||
|
||||
if(conn->inbuf_datalen < 128) /* entire response available? */
|
||||
return 0; /* not yet */
|
||||
|
||||
if(connection_fetch_from_buf(cipher,128,conn) < 0) {
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"or_handshake_server_process_nonce() : Received auth.");
|
||||
|
||||
/* decrypt response */
|
||||
retval = RSA_private_decrypt(128,cipher,buf,conn->prkey,RSA_PKCS1_PADDING);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Public-key decryption failed during authentication to %s:%u.",
|
||||
conn->address,ntohs(conn->port));
|
||||
log(LOG_DEBUG,"or_handshake_server_process_nonce() : Reason : %s.",
|
||||
ERR_reason_error_string(ERR_get_error()));
|
||||
return -1;
|
||||
}
|
||||
else if (retval != 20)
|
||||
{
|
||||
log(LOG_ERR,"Received an incorrect response from router %s:%u during authentication.",
|
||||
conn->address,ntohs(conn->port));
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"or_handshake_server_process_nonce() : Response decrypted.");
|
||||
|
||||
/* check validity */
|
||||
if ((memcmp(&conn->addr,buf, 4)) || /* remote address */
|
||||
(memcmp(&conn->port,buf+4,2)) || /* remote port */
|
||||
(memcmp(&conn->local.sin_addr,buf+6,4)) || /* local address */
|
||||
(memcmp(&conn->local.sin_port,buf+10,2)) || /* local port */
|
||||
(memcmp(conn->nonce,buf+12,8))) /* nonce */
|
||||
{
|
||||
log(LOG_ERR,"Router %s:%u failed to authenticate. Either the key I have is obsolete or they're doing something they're not supposed to.",conn->address,ntohs(conn->port));
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"or_handshake_server_process_nonce() : Response valid. Authentication complete.");
|
||||
|
||||
conn_or_init_crypto(conn);
|
||||
conn->state = OR_CONN_STATE_OPEN;
|
||||
connection_watch_events(conn, POLLIN);
|
||||
return connection_process_inbuf(conn); /* process the rest of the inbuf */
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ********************************** */
|
||||
|
||||
|
||||
int connection_or_create_listener(RSA *prkey, struct sockaddr_in *local) {
|
||||
log(LOG_DEBUG,"connection_create_or_listener starting");
|
||||
return connection_create_listener(prkey, local, CONN_TYPE_OR_LISTENER);
|
||||
}
|
||||
|
||||
int connection_or_handle_listener_read(connection_t *conn) {
|
||||
log(LOG_NOTICE,"OR: Received a connection request from a router. Attempting to authenticate.");
|
||||
return connection_handle_listener_read(conn, CONN_TYPE_OR, OR_CONN_STATE_SERVER_AUTH_WAIT);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,406 @@
|
||||
|
||||
#include "or.h"
|
||||
|
||||
/********* START VARIABLES **********/
|
||||
|
||||
/* valid command-line options */
|
||||
static char *args = "hf:e:n:l:";
|
||||
|
||||
int loglevel = LOG_DEBUG;
|
||||
|
||||
/* valid config file options */
|
||||
config_opt_t options[] =
|
||||
{
|
||||
{"RouterFile", CONFIG_TYPE_STRING, {0}, 0},
|
||||
{"PrivateKeyFile", CONFIG_TYPE_STRING, {0}, 0},
|
||||
{"EntryPort", CONFIG_TYPE_INT, {0}, 0},
|
||||
{"NetworkPort", CONFIG_TYPE_INT, {0}, 0},
|
||||
{"MaxConn", CONFIG_TYPE_INT, {0}, 0},
|
||||
{"MaxConnTimeout", CONFIG_TYPE_INT, {0}, 0},
|
||||
{"TrafficShaping", CONFIG_TYPE_INT, {0}, 0},
|
||||
{0}
|
||||
};
|
||||
enum opts {
|
||||
RouterFile=0, PrivateKeyFile, EntryPort, NetworkPort, MaxConn, MaxConnTimeout, TrafficShaping
|
||||
};
|
||||
|
||||
connection_t *connection_array[MAXCONNECTIONS] =
|
||||
{ NULL };
|
||||
|
||||
struct pollfd poll_array[MAXCONNECTIONS] =
|
||||
{ [0 ... MAXCONNECTIONS-1] = { -1, 0, 0 } };
|
||||
|
||||
int nfds=0; /* number of connections currently active */
|
||||
|
||||
/* default logging threshold */
|
||||
extern int loglevel;
|
||||
|
||||
/* private key */
|
||||
RSA *prkey = NULL;
|
||||
|
||||
/* router array */
|
||||
routerinfo_t **router_array = NULL;
|
||||
int rarray_len = 0;
|
||||
|
||||
/********* END VARIABLES ************/
|
||||
|
||||
int connection_add(connection_t *conn) {
|
||||
|
||||
if(nfds >= MAXCONNECTIONS-2) { /* 2, for some breathing room. should count the fenceposts. */
|
||||
/* FIXME should use the 'max connections' option */
|
||||
log(LOG_DEBUG,"connection_add(): 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(LOG_DEBUG,"connection_add(): new conn type %d, socket %d, nfds %d.",conn->type, conn->s, nfds);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void connection_set_poll_socket(connection_t *conn) {
|
||||
poll_array[conn->poll_index].fd = conn->s;
|
||||
}
|
||||
|
||||
int connection_remove(connection_t *conn) {
|
||||
|
||||
int current_index;
|
||||
|
||||
assert(conn);
|
||||
assert(nfds>0);
|
||||
|
||||
circuit_about_to_close_connection(conn); /* flush and send destroys for all circuits on this conn */
|
||||
|
||||
current_index = conn->poll_index;
|
||||
if(current_index == nfds-1) { /* this is the end */
|
||||
// connection_free(conn);
|
||||
nfds--;
|
||||
log(LOG_DEBUG,"connection_remove(): nfds now %d.",nfds);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we replace this one with the one at the end, then free it */
|
||||
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;
|
||||
|
||||
log(LOG_DEBUG,"connection_remove(): nfds now %d.",nfds);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
connection_t *connection_get_by_addr_port(uint32_t addr, uint16_t port) {
|
||||
|
||||
int i;
|
||||
connection_t *conn;
|
||||
|
||||
for(i=0;i<nfds;i++) {
|
||||
conn = connection_array[i];
|
||||
assert(conn);
|
||||
if(conn->addr == addr && conn->port == port)
|
||||
return conn;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
connection_t *connection_get_by_type(int type) {
|
||||
|
||||
int i;
|
||||
connection_t *conn;
|
||||
|
||||
for(i=0;i<nfds;i++) {
|
||||
conn = connection_array[i];
|
||||
if(conn->type == type)
|
||||
return conn;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) {
|
||||
int i;
|
||||
routerinfo_t *router;
|
||||
|
||||
if (!router_array)
|
||||
return NULL;
|
||||
|
||||
for(i=0;i<rarray_len;i++)
|
||||
{
|
||||
router = router_array[i];
|
||||
if ((router->addr == addr) && (router->port == port))
|
||||
return router;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
void connection_watch_events(connection_t *conn, short events) {
|
||||
|
||||
assert(conn && conn->poll_index < nfds);
|
||||
|
||||
poll_array[conn->poll_index].events = events;
|
||||
}
|
||||
|
||||
void check_conn_read(int i) {
|
||||
|
||||
int retval;
|
||||
connection_t *conn;
|
||||
|
||||
if(poll_array[i].revents & POLLIN) { /* something to read */
|
||||
|
||||
conn = connection_array[i];
|
||||
assert(conn);
|
||||
log(LOG_DEBUG,"check_conn_read(): socket %d has something to read.",conn->s);
|
||||
|
||||
if (conn->type == CONN_TYPE_OP_LISTENER) {
|
||||
retval = connection_op_handle_listener_read(conn);
|
||||
} else if (conn->type == CONN_TYPE_OR_LISTENER) {
|
||||
retval = connection_or_handle_listener_read(conn);
|
||||
} else {
|
||||
/* else it's an OP, OR, or app */
|
||||
retval = connection_read_to_buf(conn);
|
||||
if (retval >= 0) { /* all still well */
|
||||
retval = connection_process_inbuf(conn);
|
||||
log(LOG_DEBUG,"check_conn_read(): connection_process_inbuf returned %d.",retval);
|
||||
}
|
||||
}
|
||||
|
||||
if(retval < 0) { /* this connection is broken. remove it */
|
||||
log(LOG_DEBUG,"check_conn_read(): Connection broken, removing.");
|
||||
connection_remove(conn);
|
||||
connection_free(conn);
|
||||
if(i<nfds) { /* we just replaced the one at i with a new one.
|
||||
process it too. */
|
||||
check_conn_read(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void check_conn_write(int i) {
|
||||
|
||||
int retval;
|
||||
connection_t *conn;
|
||||
|
||||
if(poll_array[i].revents & POLLOUT) { /* something to write */
|
||||
|
||||
conn = connection_array[i];
|
||||
log(LOG_DEBUG,"check_conn_write(): socket %d wants to write.",conn->s);
|
||||
|
||||
if(conn->type == CONN_TYPE_OP_LISTENER ||
|
||||
conn->type == CONN_TYPE_OR_LISTENER) {
|
||||
log(LOG_DEBUG,"check_conn_write(): Got a listener socket. Can't happen!");
|
||||
retval = -1;
|
||||
} else {
|
||||
/* else it's an OP, OR, or app */
|
||||
retval = connection_flush_buf(conn); /* conns in CONNECTING state will fall through... */
|
||||
if(retval == 0) { /* it's done flushing */
|
||||
retval = connection_finished_flushing(conn); /* ...and get handled here. */
|
||||
}
|
||||
}
|
||||
|
||||
if(retval < 0) { /* this connection is broken. remove it. */
|
||||
log(LOG_DEBUG,"check_conn_write(): Connection broken, removing.");
|
||||
connection_remove(conn);
|
||||
connection_free(conn);
|
||||
if(i<nfds) { /* we just replaced the one at i with a new one.
|
||||
process it too. */
|
||||
check_conn_read(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void check_conn_marked(int i) {
|
||||
connection_t *conn;
|
||||
|
||||
conn = connection_array[i];
|
||||
assert(conn);
|
||||
if(conn->marked_for_close) {
|
||||
log(LOG_DEBUG,"check_conn_marked(): Cleaning up connection.");
|
||||
connection_flush_buf(conn); /* flush it first */
|
||||
connection_remove(conn);
|
||||
connection_free(conn);
|
||||
if(i<nfds) { /* we just replaced the one at i with a new one.
|
||||
process it too. */
|
||||
check_conn_read(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void check_conn_hup(int i) {
|
||||
connection_t *conn;
|
||||
|
||||
if(poll_array[i].revents & POLLHUP) { /* they've hung up */
|
||||
conn = connection_array[i];
|
||||
log(LOG_DEBUG,"check_conn_hup(): socket %d has hung up.",conn->s);
|
||||
connection_remove(conn);
|
||||
connection_free(conn);
|
||||
|
||||
if(i<nfds) { /* we just replaced the one at i with a new one.
|
||||
process it too. */
|
||||
check_conn_hup(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int do_main_loop(void) {
|
||||
|
||||
int i;
|
||||
|
||||
/* load the routers file */
|
||||
router_array = getrouters(options[RouterFile].r.str,&rarray_len);
|
||||
if (!router_array)
|
||||
{
|
||||
log(LOG_ERR,"Error loading router list.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* load the private key */
|
||||
ERR_load_crypto_strings();
|
||||
prkey = load_prkey(options[PrivateKeyFile].r.str);
|
||||
if (!prkey)
|
||||
{
|
||||
log(LOG_ERR,"Error loading private key.");
|
||||
exit(1);
|
||||
}
|
||||
log(LOG_DEBUG,"core : Loaded private key of size %u bytes.",RSA_size(prkey));
|
||||
ERR_free_strings();
|
||||
|
||||
/* try to connect to all the other ORs, and start the listeners */
|
||||
retry_all_connections(router_array, rarray_len, prkey,
|
||||
options[NetworkPort].r.i,options[EntryPort].r.i);
|
||||
|
||||
for(;;) {
|
||||
poll(poll_array, nfds, -1); /* poll until we have an event */
|
||||
|
||||
/* do all the reads first, so we can detect closed sockets */
|
||||
for(i=0;i<nfds;i++)
|
||||
check_conn_read(i);
|
||||
|
||||
/* then do the writes */
|
||||
for(i=0;i<nfds;i++)
|
||||
check_conn_write(i);
|
||||
|
||||
/* any of the conns need to be closed now? */
|
||||
for(i=0;i<nfds;i++)
|
||||
check_conn_marked(i);
|
||||
|
||||
#if 0 /* no, check_conn_read() takes care of hups. */
|
||||
/* remove the ones that have disconnected */
|
||||
for(i=0;i<nfds;i++)
|
||||
check_conn_hup(i);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void catch ()
|
||||
{
|
||||
errno = 0; /* netcat does this. it looks fun. */
|
||||
|
||||
log(LOG_DEBUG,"Catching ^c, exiting cleanly.");
|
||||
|
||||
exit(0);
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
char *conf_filename = NULL; /* configuration file */
|
||||
signal (SIGINT, catch); /* to catch ^c so we can exit cleanly */
|
||||
|
||||
/* get command-line arguments */
|
||||
retval = getargs(argc,argv,args,&conf_filename,&loglevel);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Error processing command-line arguments.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* load config file */
|
||||
retval = getconfig(conf_filename,options);
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Error loading configuration file.");
|
||||
exit(1);
|
||||
}
|
||||
else if (options[RouterFile].err != 1)
|
||||
{
|
||||
log(LOG_ERR,"RouterFile option required, but not found.");
|
||||
exit(1);
|
||||
}
|
||||
else if (options[PrivateKeyFile].err != 1)
|
||||
{
|
||||
log(LOG_ERR,"PrivateKeyFile option required but not found.");
|
||||
exit(1);
|
||||
}
|
||||
else if (options[EntryPort].err != 1)
|
||||
{
|
||||
log(LOG_ERR,"EntryPort option required but not found.");
|
||||
exit(1);
|
||||
}
|
||||
else if (options[NetworkPort].err != 1)
|
||||
{
|
||||
log(LOG_ERR,"NetworkPort option required but not found.");
|
||||
exit(1);
|
||||
}
|
||||
else if (options[MaxConn].err != 1)
|
||||
{
|
||||
log(LOG_ERR,"MaxConn option required but not found.");
|
||||
exit(1);
|
||||
}
|
||||
#if 0
|
||||
else if (options[MaxConnTimeout].err != 1)
|
||||
{
|
||||
conn_tout.tv_sec = OR_DEFAULT_CONN_TIMEOUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!options[MaxConnTimeout].r.i)
|
||||
conn_toutp = NULL;
|
||||
else
|
||||
conn_tout.tv_sec = options[MaxConnTimeout].r.i;
|
||||
}
|
||||
conn_tout.tv_usec = 0;
|
||||
|
||||
if (!options[TrafficShaping].err)
|
||||
{
|
||||
options[TrafficShaping].r.i = DEFAULT_POLICY;
|
||||
}
|
||||
else if ((options[TrafficShaping].r.i < 0) || (options[TrafficShaping].r.i > 1))
|
||||
{
|
||||
log(LOG_ERR,"Invalid value for the TrafficShaping option.");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
ERR_load_crypto_strings();
|
||||
retval = do_main_loop();
|
||||
ERR_free_strings();
|
||||
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
|
||||
#include "or.h"
|
||||
|
||||
/********* START VARIABLES **********/
|
||||
|
||||
tracked_onion_t *tracked_onions = NULL; /* linked list of tracked onions */
|
||||
tracked_onion_t *last_tracked_onion = NULL;
|
||||
|
||||
/********* END VARIABLES ************/
|
||||
|
||||
|
||||
int decide_aci_type(uint32_t local_addr, uint16_t local_port,
|
||||
uint32_t remote_addr, uint16_t remote_port) {
|
||||
|
||||
if(local_addr > remote_addr)
|
||||
return ACI_TYPE_HIGHER;
|
||||
if(local_addr < remote_addr)
|
||||
return ACI_TYPE_LOWER;
|
||||
if(local_port > remote_port)
|
||||
return ACI_TYPE_HIGHER;
|
||||
/* else */
|
||||
return ACI_TYPE_LOWER;
|
||||
}
|
||||
|
||||
int process_onion(circuit_t *circ, connection_t *conn) {
|
||||
aci_t aci_type;
|
||||
|
||||
if(!decrypt_onion((onion_layer_t *)circ->onion,circ->onionlen,conn->prkey)) {
|
||||
log(LOG_DEBUG,"command_process_create_cell(): decrypt_onion() failed, closing circuit.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Onion decrypted.");
|
||||
|
||||
/* check freshness */
|
||||
if (((onion_layer_t *)circ->onion)->expire < time(NULL)) /* expired onion */
|
||||
{
|
||||
log(LOG_NOTICE,"I have just received an expired onion. This could be a replay attack.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
aci_type = decide_aci_type(conn->local.sin_addr.s_addr, conn->local.sin_port,
|
||||
((onion_layer_t *)circ->onion)->addr,((onion_layer_t *)circ->onion)->port);
|
||||
|
||||
if(circuit_init(circ, aci_type) < 0) {
|
||||
log(LOG_ERR,"process_onion(): init_circuit() failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check for replay */
|
||||
if(id_tracked_onion(circ->onion, circ->onionlen, tracked_onions)) {
|
||||
log(LOG_NOTICE,"process_onion(): I have just received a replayed onion. This could be a replay attack.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* track the new onion */
|
||||
if(!new_tracked_onion(circ->onion,circ->onionlen, &tracked_onions, &last_tracked_onion)) {
|
||||
log(LOG_DEBUG,"process_onion(): Onion tracking failed. Will ignore.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,411 @@
|
||||
/* Copyright (c) 2002 Roger Dingledine. See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef __OR_H
|
||||
#define __OR_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <netdb.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "../common/cell.h"
|
||||
#include "../common/config.h"
|
||||
#include "../common/key.h"
|
||||
#include "../common/log.h"
|
||||
#include "../common/onion.h"
|
||||
#include "../common/ss.h"
|
||||
|
||||
#define MAXCONNECTIONS 200 /* upper bound on max connections.
|
||||
can be overridden by config file */
|
||||
|
||||
#define MAX_BUF_SIZE (64*1024)
|
||||
|
||||
#define ACI_TYPE_LOWER 0
|
||||
#define ACI_TYPE_HIGHER 1
|
||||
|
||||
#define CONN_TYPE_OP_LISTENER 1
|
||||
#define CONN_TYPE_OP 2
|
||||
#define CONN_TYPE_OR_LISTENER 3
|
||||
#define CONN_TYPE_OR 4
|
||||
#define CONN_TYPE_APP 5
|
||||
|
||||
#define LISTENER_STATE_READY 0
|
||||
|
||||
#define OP_CONN_STATE_AWAITING_KEYS 0
|
||||
#define OP_CONN_STATE_OPEN 1
|
||||
#if 0
|
||||
#define OP_CONN_STATE_CLOSE 2 /* flushing the buffer, then will close */
|
||||
#define OP_CONN_STATE_CLOSE_WAIT 3 /* have sent a destroy, awaiting a confirmation */
|
||||
#endif
|
||||
|
||||
#define OR_CONN_STATE_CLIENT_CONNECTING 0
|
||||
#define OR_CONN_STATE_CLIENT_SENDING_AUTH 1 /* sending address and info */
|
||||
#define OR_CONN_STATE_CLIENT_AUTH_WAIT 2 /* have sent address and info, waiting */
|
||||
#define OR_CONN_STATE_CLIENT_SENDING_NONCE 3 /* sending nonce, last piece of handshake */
|
||||
#define OR_CONN_STATE_SERVER_AUTH_WAIT 4 /* waiting for address and info */
|
||||
#define OR_CONN_STATE_SERVER_SENDING_AUTH 5 /* writing auth and nonce */
|
||||
#define OR_CONN_STATE_SERVER_NONCE_WAIT 6 /* waiting for confirmation of nonce */
|
||||
#define OR_CONN_STATE_OPEN 7 /* ready to send/receive cells. */
|
||||
|
||||
#define APP_CONN_STATE_CONNECTING_WAIT 0 /* waiting for standard structure or dest info */
|
||||
#define APP_CONN_STATE_CONNECTING 1
|
||||
#define APP_CONN_STATE_OPEN 2
|
||||
#if 0
|
||||
#define APP_CONN_STATE_CLOSE 3 /* flushing the buffer, then will close */
|
||||
#define APP_CONN_STATE_CLOSE_WAIT 4 /* have sent a destroy, awaiting a confirmation */
|
||||
#endif
|
||||
|
||||
#define CIRCUIT_STATE_OPEN_WAIT 0 /* receiving/processing the onion */
|
||||
#define CIRCUIT_STATE_OPEN 1 /* onion processed, ready to send data along the connection */
|
||||
#define CIRCUIT_STATE_CLOSE_WAIT1 2 /* sent two "destroy" signals, waiting for acks */
|
||||
#define CIRCUIT_STATE_CLOSE_WAIT2 3 /* received one ack, waiting for one more
|
||||
(or if just one was sent, waiting for that one */
|
||||
//#define CIRCUIT_STATE_CLOSE 4 /* both acks received, connection is dead */ /* NOT USED */
|
||||
|
||||
typedef uint16_t aci_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
/* Used by all types: */
|
||||
|
||||
unsigned char type;
|
||||
int state;
|
||||
int s; /* our socket */
|
||||
int poll_index;
|
||||
int marked_for_close;
|
||||
|
||||
char *inbuf;
|
||||
size_t inbuflen;
|
||||
size_t inbuf_datalen;
|
||||
int inbuf_reached_eof;
|
||||
|
||||
char *outbuf;
|
||||
size_t outbuflen;
|
||||
size_t outbuf_datalen;
|
||||
|
||||
/* used by OP and App: */
|
||||
|
||||
uint16_t aci; /* anonymous connection identifier */
|
||||
|
||||
/* used by OR and OP: */
|
||||
|
||||
uint32_t bandwidth; /* connection bandwidth */
|
||||
int window_sent; /* how many cells can i still send? */
|
||||
int window_received; /* how many cells do i still expect to receive? */
|
||||
|
||||
/* link encryption */
|
||||
unsigned char f_session_key[8];
|
||||
unsigned char b_session_key[8];
|
||||
unsigned char f_session_iv[8];
|
||||
unsigned char b_session_iv[8];
|
||||
EVP_CIPHER_CTX f_ctx;
|
||||
EVP_CIPHER_CTX b_ctx;
|
||||
|
||||
// struct timeval lastsend; /* time of last transmission to the client */
|
||||
// struct timeval interval; /* transmission interval */
|
||||
|
||||
uint32_t addr; /* these two uniquely identify a router */
|
||||
uint16_t port;
|
||||
|
||||
/* used by app: */
|
||||
|
||||
ss_t ss; /* standard structure */
|
||||
int ss_received; /* size of ss, received so far */
|
||||
|
||||
/* used by OR, to keep state while connect()ing: Kludge. */
|
||||
|
||||
RSA *prkey;
|
||||
struct sockaddr_in local;
|
||||
|
||||
/* link info */
|
||||
uint32_t min;
|
||||
uint32_t max;
|
||||
|
||||
char *address; /* strdup into this, gets free_connection frees it */
|
||||
RSA *pkey; /* public RSA key for the other side */
|
||||
|
||||
char nonce[8];
|
||||
|
||||
} connection_t;
|
||||
|
||||
/* config stuff we know about the other ORs in the network */
|
||||
typedef struct
|
||||
{
|
||||
char *address;
|
||||
|
||||
uint32_t addr;
|
||||
uint16_t port;
|
||||
|
||||
RSA *pkey; /* public RSA key */
|
||||
|
||||
/* link info */
|
||||
uint32_t min;
|
||||
uint32_t max;
|
||||
// struct timeval min_interval;
|
||||
|
||||
/* time when last data was sent to that router */
|
||||
// struct timeval lastsend;
|
||||
|
||||
/* socket */
|
||||
// int s;
|
||||
|
||||
void *next;
|
||||
} routerinfo_t;
|
||||
|
||||
/* per-anonymous-connection struct */
|
||||
typedef struct
|
||||
{
|
||||
#if 0
|
||||
uint32_t p_addr; /* all in network order */
|
||||
uint16_t p_port;
|
||||
#endif
|
||||
uint32_t n_addr;
|
||||
uint16_t n_port;
|
||||
connection_t *p_conn;
|
||||
connection_t *n_conn;
|
||||
|
||||
aci_t p_aci; /* connection identifiers */
|
||||
aci_t n_aci;
|
||||
|
||||
unsigned char p_f; /* crypto functions */
|
||||
unsigned char n_f;
|
||||
|
||||
unsigned char p_key[128]; /* crypto keys */
|
||||
unsigned char n_key[128];
|
||||
|
||||
unsigned char p_iv[16]; /* initialization vectors */
|
||||
unsigned char n_iv[16];
|
||||
|
||||
EVP_CIPHER_CTX p_ctx; /* cipher context */
|
||||
EVP_CIPHER_CTX n_ctx;
|
||||
|
||||
uint32_t expire; /* expiration time for the corresponding onion */
|
||||
|
||||
int state;
|
||||
|
||||
unsigned char *onion; /* stores the onion when state is CONN_STATE_OPEN_WAIT */
|
||||
uint32_t onionlen; /* total onion length */
|
||||
uint32_t recvlen; /* length of the onion so far */
|
||||
|
||||
void *next;
|
||||
} circuit_t;
|
||||
|
||||
|
||||
|
||||
|
||||
/* all the function prototypes go here */
|
||||
|
||||
|
||||
/********************************* args.c ***************************/
|
||||
|
||||
/* print help*/
|
||||
void print_usage();
|
||||
|
||||
/* get command-line arguments */
|
||||
int getargs(int argc,char *argv[], char *args,char **conf_filename, int *loglevel);
|
||||
|
||||
/********************************* buffers.c ***************************/
|
||||
|
||||
int buf_new(char **pbuf, size_t *pbuflen, size_t *pbuf_datalen);
|
||||
|
||||
int buf_free(char *buf);
|
||||
|
||||
int read_to_buf(int s, char **pbuf, size_t *pbuflen, size_t *pbuf_datalen, int *preached_eof);
|
||||
/* grab from s, put onto buf, return how many bytes read */
|
||||
|
||||
int flush_buf(int s, char **pbuf, size_t *pbuflen, size_t *pbuf_datalen);
|
||||
/* push from buf onto s
|
||||
* then memmove to front of buf
|
||||
* return -1 or how many bytes remain on the buf */
|
||||
|
||||
int write_to_buf(char *string, size_t string_len,
|
||||
char **pbuf, size_t *pbuflen, size_t *pbuf_datalen);
|
||||
/* append string to buf (growing as needed, return -1 if "too big")
|
||||
* return total number of bytes on the buf
|
||||
*/
|
||||
|
||||
int fetch_from_buf(char *string, size_t string_len,
|
||||
char **pbuf, size_t *pbuflen, size_t *pbuf_datalen);
|
||||
/* if there is string_len bytes in buf, write them onto string,
|
||||
* * then memmove buf back (that is, remove them from buf) */
|
||||
|
||||
/********************************* cell.c ***************************/
|
||||
|
||||
int check_sane_cell(cell_t *cell);
|
||||
|
||||
/********************************* circuit.c ***************************/
|
||||
|
||||
void circuit_add(circuit_t *circ);
|
||||
void circuit_remove(circuit_t *circ);
|
||||
|
||||
circuit_t *circuit_new(aci_t p_aci, connection_t *p_conn);
|
||||
|
||||
/* internal */
|
||||
aci_t get_unique_aci_by_addr_port(uint32_t addr, uint16_t port, int aci_type);
|
||||
|
||||
circuit_t *circuit_get_by_aci_conn(aci_t aci, connection_t *conn);
|
||||
circuit_t *circuit_get_by_conn(connection_t *conn);
|
||||
|
||||
int circuit_deliver_data_cell(cell_t *cell, circuit_t *circ, connection_t *conn, int crypt_type);
|
||||
int circuit_crypt(circuit_t *circ, char *in, size_t inlen, char crypt_type);
|
||||
|
||||
int circuit_init(circuit_t *circ, int aci_type);
|
||||
void circuit_free(circuit_t *circ);
|
||||
|
||||
void circuit_close(circuit_t *circ);
|
||||
|
||||
void circuit_about_to_close_connection(connection_t *conn);
|
||||
/* flush and send destroys for all circuits using conn */
|
||||
|
||||
/********************************* command.c ***************************/
|
||||
|
||||
void command_process_cell(cell_t *cell, connection_t *conn);
|
||||
|
||||
void command_process_create_cell(cell_t *cell, connection_t *conn);
|
||||
void command_process_data_cell(cell_t *cell, connection_t *conn);
|
||||
void command_process_destroy_cell(cell_t *cell, connection_t *conn);
|
||||
|
||||
/********************************* config.c ***************************/
|
||||
|
||||
/* loads the configuration file */
|
||||
int getconfig(char *filename, config_opt_t *options);
|
||||
|
||||
/********************************* connection.c ***************************/
|
||||
|
||||
connection_t *connection_new(int type);
|
||||
|
||||
void connection_free(connection_t *conn);
|
||||
|
||||
int connection_create_listener(RSA *prkey, struct sockaddr_in *local, int type);
|
||||
|
||||
int connection_handle_listener_read(connection_t *conn, int new_type, int new_state);
|
||||
|
||||
/* start all connections that should be up but aren't */
|
||||
int retry_all_connections(routerinfo_t **router_array, int rarray_len,
|
||||
RSA *prkey, uint16_t or_port, uint16_t op_port);
|
||||
|
||||
int connection_read_to_buf(connection_t *conn);
|
||||
|
||||
int connection_fetch_from_buf(char *string, int len, connection_t *conn);
|
||||
|
||||
int connection_flush_buf(connection_t *conn);
|
||||
|
||||
int connection_write_to_buf(char *string, int len, connection_t *conn);
|
||||
int connection_send_destroy(aci_t aci, connection_t *conn);
|
||||
int connection_encrypt_cell_header(cell_t *cellp, connection_t *conn);
|
||||
int connection_write_cell_to_buf(cell_t *cellp, connection_t *conn);
|
||||
|
||||
int connection_process_inbuf(connection_t *conn);
|
||||
int connection_process_cell_from_inbuf(connection_t *conn);
|
||||
|
||||
int connection_finished_flushing(connection_t *conn);
|
||||
|
||||
/********************************* connection_or.c ***************************/
|
||||
|
||||
int connection_or_process_inbuf(connection_t *conn);
|
||||
int connection_or_finished_flushing(connection_t *conn);
|
||||
|
||||
connection_t *connection_or_new(void);
|
||||
connection_t *connection_or_listener_new(void);
|
||||
|
||||
void conn_or_init_crypto(connection_t *conn);
|
||||
|
||||
int or_handshake_client_process_auth(connection_t *conn);
|
||||
int or_handshake_client_send_auth(connection_t *conn);
|
||||
|
||||
int or_handshake_server_process_auth(connection_t *conn);
|
||||
int or_handshake_server_process_nonce(connection_t *conn);
|
||||
|
||||
int connect_to_router(routerinfo_t *router, RSA *prkey, struct sockaddr_in *local);
|
||||
|
||||
int connection_or_create_listener(RSA *prkey, struct sockaddr_in *local);
|
||||
int connection_or_handle_listener_read(connection_t *conn);
|
||||
|
||||
/********************************* connection_op.c ***************************/
|
||||
|
||||
connection_t *connection_op_new(void);
|
||||
connection_t *connection_op_listener_new(void);
|
||||
|
||||
int op_handshake_process_keys(connection_t *conn);
|
||||
|
||||
int connection_op_process_inbuf(connection_t *conn);
|
||||
|
||||
int connection_op_finished_flushing(connection_t *conn);
|
||||
|
||||
int connection_op_create_listener(RSA *prkey, struct sockaddr_in *local);
|
||||
|
||||
int connection_op_handle_listener_read(connection_t *conn);
|
||||
|
||||
/********************************* connection_app.c ***************************/
|
||||
|
||||
connection_t *connection_app_new(void);
|
||||
|
||||
int connection_app_process_inbuf(connection_t *conn);
|
||||
int connection_app_package_inbuf(connection_t *conn);
|
||||
int connection_app_process_data_cell(cell_t *cell, connection_t *conn);
|
||||
|
||||
int connection_app_finished_flushing(connection_t *conn);
|
||||
|
||||
/********************************* main.c ***************************/
|
||||
|
||||
int connection_add(connection_t *conn);
|
||||
int connection_remove(connection_t *conn);
|
||||
void connection_set_poll_socket(connection_t *conn);
|
||||
|
||||
connection_t *connection_get_by_addr_port(uint32_t addr, uint16_t port);
|
||||
|
||||
connection_t *connection_get_by_type(int type);
|
||||
|
||||
routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port);
|
||||
|
||||
void connection_watch_events(connection_t *conn, short events);
|
||||
|
||||
void check_conn_read(int i);
|
||||
void check_conn_marked(int i);
|
||||
void check_conn_write(int i);
|
||||
|
||||
void check_conn_hup(int i);
|
||||
|
||||
int do_main_loop(void);
|
||||
|
||||
int main(int argc, char *argv[]);
|
||||
|
||||
/********************************* onion.c ***************************/
|
||||
|
||||
int decide_aci_type(uint32_t local_addr, uint16_t local_port,
|
||||
uint32_t remote_addr, uint16_t remote_port);
|
||||
|
||||
int process_onion(circuit_t *circ, connection_t *conn);
|
||||
|
||||
/********************************* routers.c ***************************/
|
||||
|
||||
routerinfo_t **getrouters(char *routerfile, size_t *listlenp);
|
||||
void delete_routerlist(routerinfo_t *list);
|
||||
/* create an NULL-terminated array of pointers pointing to elements of a router list */
|
||||
routerinfo_t **make_rarray(routerinfo_t* list, size_t *listlenp);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,365 @@
|
||||
/**
|
||||
* routers.c
|
||||
* Routines for loading the list of routers and their public RSA keys.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
#define OR_ROUTERLIST_SEPCHARS " \t\n"
|
||||
#define OR_PUBLICKEY_BEGIN_TAG "-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
|
||||
#include "or.h"
|
||||
|
||||
/* delete a list of routers from memory */
|
||||
void delete_routerlist(routerinfo_t *list)
|
||||
{
|
||||
routerinfo_t *tmp = NULL;
|
||||
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
do
|
||||
{
|
||||
tmp=list->next;
|
||||
free((void *)list->address);
|
||||
RSA_free(list->pkey);
|
||||
free((void *)list);
|
||||
list = tmp;
|
||||
}
|
||||
while (list != NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* create an NULL-terminated array of pointers pointing to elements of a router list */
|
||||
/* this is done in two passes through the list - inefficient but irrelevant as this is
|
||||
* only done once when op/or start up */
|
||||
routerinfo_t **make_rarray(routerinfo_t* list, size_t *len)
|
||||
{
|
||||
routerinfo_t *tmp=NULL;
|
||||
int listlen = 0;
|
||||
routerinfo_t **array=NULL;
|
||||
routerinfo_t **p=NULL;
|
||||
|
||||
if ((!list) || (!len))
|
||||
return NULL;
|
||||
|
||||
/* get the length of the list */
|
||||
tmp = list;
|
||||
do
|
||||
{
|
||||
listlen++;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
while (tmp != NULL);
|
||||
|
||||
array = malloc((listlen+1)*sizeof(routerinfo_t *));
|
||||
if (!array)
|
||||
{
|
||||
log(LOG_ERR,"Error allocating memory.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tmp=list;
|
||||
p = array;
|
||||
do
|
||||
{
|
||||
*p = tmp;
|
||||
p++;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
while(tmp != NULL);
|
||||
*p=NULL;
|
||||
|
||||
*len = listlen;
|
||||
return array;
|
||||
}
|
||||
|
||||
/* load the router list */
|
||||
routerinfo_t **getrouters(char *routerfile, size_t *lenp)
|
||||
{
|
||||
int retval = 0;
|
||||
char *retp = NULL;
|
||||
routerinfo_t *router=NULL, *routerlist=NULL, *lastrouter=NULL;
|
||||
FILE *rf; /* router file */
|
||||
fpos_t fpos;
|
||||
char line[512];
|
||||
char *token;
|
||||
char *errtest; /* detecting errors in strtoul() calls */
|
||||
struct hostent *rent;
|
||||
|
||||
if ((!routerfile) || (!lenp))
|
||||
return NULL;
|
||||
|
||||
if (strcspn(routerfile,CONFIG_LEGAL_FILENAME_CHARACTERS) != 0)
|
||||
{
|
||||
log(LOG_ERR,"Filename %s contains illegal characters.",routerfile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* open the router list */
|
||||
rf = fopen(routerfile,"r");
|
||||
if (!rf)
|
||||
{
|
||||
log(LOG_ERR,"Could not open %s.",routerfile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retp= fgets(line,512,rf);
|
||||
while (retp)
|
||||
{
|
||||
log(LOG_DEBUG,"getrouters():Line :%s",line);
|
||||
token = (char *)strtok(line,OR_ROUTERLIST_SEPCHARS);
|
||||
if (token)
|
||||
{
|
||||
log(LOG_DEBUG,"getrouters():Token : %s",token);
|
||||
if (token[0] != '#') /* ignore comment lines */
|
||||
{
|
||||
router = malloc(sizeof(routerinfo_t));
|
||||
if (!router)
|
||||
{
|
||||
log(LOG_ERR,"Could not allocate memory.");
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
router->conn_bufs = NULL; /* no output buffers */
|
||||
router->last_conn_buf = NULL;
|
||||
router->next_to_service = 0;
|
||||
|
||||
router->s = -1; /* to signify this router is as yet unconnected */
|
||||
router->celllen = 0; /* cell buffer is empty */
|
||||
#endif
|
||||
|
||||
/* read the address */
|
||||
router->address = malloc(strlen(token)+1);
|
||||
if (!router->address)
|
||||
{
|
||||
log(LOG_ERR,"Could not allocate memory.");
|
||||
fclose(rf);
|
||||
free((void *)router);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
strcpy(router->address,token);
|
||||
|
||||
rent = (struct hostent *)gethostbyname(router->address);
|
||||
if (!rent)
|
||||
{
|
||||
log(LOG_ERR,"Could not get address for router %s.",router->address);
|
||||
fclose(rf);
|
||||
free((void *)router->address);
|
||||
free((void *)router);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(&router->addr, rent->h_addr,rent->h_length);
|
||||
|
||||
/* read the port */
|
||||
token = (char *)strtok(NULL,OR_ROUTERLIST_SEPCHARS);
|
||||
if (token)
|
||||
{
|
||||
log(LOG_DEBUG,"getrouters():Token :%s",token);
|
||||
router->port = (uint16_t)strtoul(token,&errtest,0);
|
||||
if ((*token != '\0') && (*errtest == '\0')) /* conversion was successful */
|
||||
{
|
||||
/* convert port to network format */
|
||||
router->port = htons(router->port);
|
||||
|
||||
/* read min bandwidth */
|
||||
token = (char *)strtok(NULL,OR_ROUTERLIST_SEPCHARS);
|
||||
if (token) /* min bandwidth */
|
||||
{
|
||||
router->min = (uint32_t)strtoul(token,&errtest,0);
|
||||
if ((*token != '\0') && (*errtest == '\0')) /* conversion was successful */
|
||||
{
|
||||
if (router->min) /* must not be zero */
|
||||
{
|
||||
/* read max bandwidth */
|
||||
token = (char *)strtok(NULL,OR_ROUTERLIST_SEPCHARS);
|
||||
if (token) /* max bandwidth */
|
||||
{
|
||||
router->max = (uint32_t)strtoul(token,&errtest,0);
|
||||
if ((*token != '\0') && (*errtest == '\0')) /* conversion was successful */
|
||||
{
|
||||
if (router->max) /* must not be zero */
|
||||
{
|
||||
/* check that there is a public key entry for that router */
|
||||
retval = fgetpos(rf, &fpos); /* save the current file position
|
||||
* we wil return to it later if we find a public key */
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Could not save position in %s.",routerfile);
|
||||
free((void *)router->address);
|
||||
free((void *)router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
do /* read through to the next non-empty line */
|
||||
{
|
||||
retp=fgets(line,512,rf);
|
||||
if (!retp)
|
||||
{
|
||||
log(LOG_ERR,"Could not find a public key entry for router %s:%u.",router->address,router->port);
|
||||
free((void *)router->address);
|
||||
free((void *)router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
log(LOG_DEBUG,"getrouters():Line:%s",line);
|
||||
if ((*line != '#') && ( strspn(line,OR_ROUTERLIST_SEPCHARS) != strlen(line) ))
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
if (!strcmp(line,OR_PUBLICKEY_BEGIN_TAG)) /* we've got the public key */
|
||||
{
|
||||
retval = fsetpos(rf,&fpos); /* get us back to where we were otherwise crypto lib won't find the key */
|
||||
if (retval == -1)
|
||||
{
|
||||
log(LOG_ERR,"Could not set position in %s.",routerfile);
|
||||
free((void *)router->address);
|
||||
free((void *)router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else /* we found something else; this isn't right */
|
||||
{
|
||||
log(LOG_ERR,"Could not find a public key entry for router %s:%u.",router->address,router->port);
|
||||
free((void *)router->address);
|
||||
free((void *)router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"getrouters():Reading the key ...");
|
||||
/* read the public key into router->pkey */
|
||||
router->pkey=NULL;
|
||||
router->pkey = PEM_read_RSAPublicKey(rf,&router->pkey,NULL,NULL);
|
||||
if (!router->pkey) /* something went wrong */
|
||||
{
|
||||
log(LOG_ERR,"Could not read public key for router %s:%u.",router->address,router->port);
|
||||
free((void *)router->address);
|
||||
free((void *)router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
else /* read the key */
|
||||
{
|
||||
log(LOG_DEBUG,"getrouters():Public key size = %u.", RSA_size(router->pkey));
|
||||
if (RSA_size(router->pkey) != 128) /* keys MUST be 1024 bits in size */
|
||||
{
|
||||
log(LOG_ERR,"Key for router %s:%u is not 1024 bits. All keys must be exactly 1024 bits long.",router->address,router->port);
|
||||
free((void *)router->address);
|
||||
RSA_free(router->pkey);
|
||||
free((void *)router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
router->next = NULL;
|
||||
/* save the entry into the routerlist linked list */
|
||||
if (!routerlist) /* this is the first entry */
|
||||
routerlist = router;
|
||||
else
|
||||
lastrouter->next = (void *)router;
|
||||
lastrouter = router;
|
||||
}
|
||||
}
|
||||
else /* maximum link utilisation is zero */
|
||||
{
|
||||
log(LOG_ERR,"Entry for router %s doesn't contain a valid maximum bandwidth entry (must be > 0).",router->address);
|
||||
free((void *)router->address);
|
||||
free((void *)router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log(LOG_ERR,"Entry for router %s doesn't seem to contain a valid maximum bandwidth entry.",router->address);
|
||||
free((void *)router->address);
|
||||
free((void *)router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log(LOG_ERR,"Entry for router %s doesn't seem to contain a maximum bandwidth entry.",router->address);
|
||||
free((void *)router->address);
|
||||
free((void *)router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log(LOG_ERR,"Entry for router %s doesn't contain a valid minimum bandwidth entry (must be > 0).",router->address);
|
||||
free((void *)router->address);
|
||||
free((void *)router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log(LOG_ERR,"Entry for router %s doesn't seem to contain a valid minimum bandwidth entry.",router->address);
|
||||
free((void *)router->address);
|
||||
free((void *)router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log(LOG_ERR,"Entry for router %s doesn't seem to contain a minimum bandwidth entry.",router->address);
|
||||
free((void *)router->address);
|
||||
free((void *)router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log(LOG_ERR,"Entry for router %s doesn't seem to contain a valid port number.",router->address);
|
||||
free((void *)router->address);
|
||||
free((void *)router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log(LOG_ERR,"Entry for router %s doesn't seem to contain a port number.",router->address);
|
||||
free((void *)router->address);
|
||||
free((void *)router);
|
||||
fclose(rf);
|
||||
delete_routerlist(routerlist);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
retp=fgets(line,512,rf);
|
||||
}
|
||||
|
||||
fclose(rf);
|
||||
return make_rarray(routerlist, lenp);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
SRC=orkeygen.c
|
||||
OBJ=${SRC:.c=.o}
|
||||
PROGS=orkeygen
|
||||
LIB=-L/usr/local/ssl/lib
|
||||
LIBS=-lcrypto
|
||||
INCLUDE=-I/usr/local/ssl/include
|
||||
|
||||
CFLAGS= $(INCLUDE)
|
||||
LDFLAGS = $(LIB) ${LIBS}
|
||||
|
||||
all: ${PROGS}
|
||||
|
||||
clean:
|
||||
rm -f *.o ${PROGS}
|
||||
|
||||
depend:
|
||||
makedepend -- ${CFLAGS} -- ${SRC}
|
||||
|
||||
${PROGS}: ${OBJ}
|
||||
$(LINK.c) -o $@ $(OBJ)
|
||||
|
||||
# DO NOT DELETE
|
||||
|
||||
|
||||
orkeygen.o: /usr/include/alloca.h /usr/include/asm/errno.h
|
||||
orkeygen.o: /usr/include/bits/endian.h /usr/include/bits/errno.h
|
||||
orkeygen.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
|
||||
orkeygen.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
|
||||
orkeygen.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
|
||||
orkeygen.o: /usr/include/bits/types.h /usr/include/bits/waitflags.h
|
||||
orkeygen.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
|
||||
orkeygen.o: /usr/include/endian.h /usr/include/errno.h /usr/include/features.h
|
||||
orkeygen.o: /usr/include/_G_config.h /usr/include/gconv.h
|
||||
orkeygen.o: /usr/include/gnu/stubs.h /usr/include/libio.h
|
||||
orkeygen.o: /usr/include/linux/errno.h /usr/include/openssl/asn1.h
|
||||
orkeygen.o: /usr/include/openssl/bio.h /usr/include/openssl/blowfish.h
|
||||
orkeygen.o: /usr/include/openssl/bn.h /usr/include/openssl/buffer.h
|
||||
orkeygen.o: /usr/include/openssl/cast.h /usr/include/openssl/crypto.h
|
||||
orkeygen.o: /usr/include/openssl/des.h /usr/include/openssl/dh.h
|
||||
orkeygen.o: /usr/include/openssl/dsa.h /usr/include/openssl/e_os2.h
|
||||
orkeygen.o: /usr/include/openssl/err.h /usr/include/openssl/evp.h
|
||||
orkeygen.o: /usr/include/openssl/lhash.h /usr/include/openssl/md2.h
|
||||
orkeygen.o: /usr/include/openssl/md4.h /usr/include/openssl/md5.h
|
||||
orkeygen.o: /usr/include/openssl/objects.h /usr/include/openssl/obj_mac.h
|
||||
orkeygen.o: /usr/include/openssl/opensslconf.h /usr/include/openssl/opensslv.h
|
||||
orkeygen.o: /usr/include/openssl/pem2.h /usr/include/openssl/pem.h
|
||||
orkeygen.o: /usr/include/openssl/pkcs7.h /usr/include/openssl/rc2.h
|
||||
orkeygen.o: /usr/include/openssl/rc4.h /usr/include/openssl/ripemd.h
|
||||
orkeygen.o: /usr/include/openssl/rsa.h /usr/include/openssl/safestack.h
|
||||
orkeygen.o: /usr/include/openssl/sha.h /usr/include/openssl/stack.h
|
||||
orkeygen.o: /usr/include/openssl/symhacks.h /usr/include/openssl/x509.h
|
||||
orkeygen.o: /usr/include/openssl/x509_vfy.h /usr/include/stdio.h
|
||||
orkeygen.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
|
||||
orkeygen.o: /usr/include/sys/select.h /usr/include/sys/sysmacros.h
|
||||
orkeygen.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/wchar.h
|
||||
orkeygen.o: /usr/include/xlocale.h
|
||||
orkeygen.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
orkeygen.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* orkeygen.c
|
||||
* Key generation utility.
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.1 2002/01/04 07:19:27 badbytes
|
||||
* Key generation utility.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
char *file_pr = argv[1];
|
||||
char *file_pu = argv[2];
|
||||
|
||||
FILE *f_pr = NULL;
|
||||
FILE *f_pu = NULL;
|
||||
|
||||
RSA *rsa_key = NULL;
|
||||
|
||||
int retval = 0;
|
||||
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
printf("Need two files, for private and public key in that order.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* generate the key */
|
||||
rsa_key = RSA_generate_key(1024,65535,NULL,NULL);
|
||||
if (!rsa_key) /* error has occured */
|
||||
{
|
||||
printf("%s",ERR_reason_error_string(ERR_get_error()));
|
||||
exit(1);
|
||||
}
|
||||
else /* keys generated */
|
||||
{
|
||||
retval = RSA_check_key(rsa_key);
|
||||
if (retval == 1)
|
||||
{
|
||||
printf("Generated key seems to be valid.\n");
|
||||
/* open the output files */
|
||||
f_pr = fopen(file_pr,"w");
|
||||
if (!f_pr)
|
||||
{
|
||||
perror("fopen");
|
||||
RSA_free(rsa_key);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
f_pu = fopen(file_pu,"w");
|
||||
if (!f_pu)
|
||||
{
|
||||
perror("fopen");
|
||||
RSA_free(rsa_key);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* write the private key */
|
||||
retval = PEM_write_RSAPrivateKey(f_pr,rsa_key,NULL,NULL,0,0,NULL);
|
||||
if (retval == 0)
|
||||
{
|
||||
printf("%s",ERR_reason_error_string(ERR_get_error()));
|
||||
fclose(f_pr);
|
||||
fclose(f_pu);
|
||||
RSA_free(rsa_key);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* write the public key */
|
||||
retval = PEM_write_RSAPublicKey(f_pu,rsa_key);
|
||||
if (retval == 0)
|
||||
{
|
||||
printf("%s",ERR_reason_error_string(ERR_get_error()));
|
||||
fclose(f_pr);
|
||||
fclose(f_pu);
|
||||
RSA_free(rsa_key);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Keys written to files %s (public) and %s (private).\n",file_pu,file_pr);
|
||||
}
|
||||
else if (retval == 0)
|
||||
{
|
||||
printf("Generated key seems to be invalid. Exiting.\n");
|
||||
RSA_free(rsa_key);
|
||||
exit(1);
|
||||
}
|
||||
else if (retval == -1)
|
||||
{
|
||||
printf("%s",ERR_reason_error_string(ERR_get_error()));
|
||||
RSA_free(rsa_key);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
RSA_free(rsa_key);
|
||||
fclose(f_pu);
|
||||
fclose(f_pr);
|
||||
exit(0);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
SRC=smtpap.c io.c
|
||||
OBJ=${SRC:.c=.o}
|
||||
PROGS=smtpap
|
||||
LIB=
|
||||
LIBS=
|
||||
INCLUDE =
|
||||
|
||||
CFLAGS= $(INCLUDE) -Wall -Wpointer-arith -O2 -ggdb
|
||||
LDFLAGS = $(LIB) $(LIBS)
|
||||
|
||||
all: ${PROGS}
|
||||
|
||||
clean:
|
||||
rm -f *.o ${PROGS}
|
||||
|
||||
depend:
|
||||
makedepend -- ${CFLAGS} -- ${SRC}
|
||||
|
||||
${PROGS}: ${OBJ}
|
||||
$(LINK.c) -o $@ $(OBJ) ../common/log.o ../common/config.o ../common/utils.o
|
||||
|
||||
# DO NOT DELETE
|
||||
|
||||
|
||||
io.o: ../common/log.h ../common/utils.h io.h smtpap.h
|
||||
io.o: /usr/include/bits/endian.h /usr/include/bits/pthreadtypes.h
|
||||
io.o: /usr/include/bits/sched.h /usr/include/bits/select.h
|
||||
io.o: /usr/include/bits/sigset.h /usr/include/bits/sockaddr.h
|
||||
io.o: /usr/include/bits/stdio_lim.h /usr/include/bits/time.h
|
||||
io.o: /usr/include/bits/types.h /usr/include/bits/wchar.h
|
||||
io.o: /usr/include/endian.h /usr/include/features.h /usr/include/_G_config.h
|
||||
io.o: /usr/include/gconv.h /usr/include/gnu/stubs.h /usr/include/libio.h
|
||||
io.o: /usr/include/malloc.h /usr/include/stdio.h /usr/include/string.h
|
||||
io.o: /usr/include/sys/cdefs.h /usr/include/syslog.h /usr/include/sys/select.h
|
||||
io.o: /usr/include/sys/syslog.h /usr/include/sys/sysmacros.h
|
||||
io.o: /usr/include/sys/time.h /usr/include/sys/types.h /usr/include/sys/un.h
|
||||
io.o: /usr/include/time.h /usr/include/wchar.h /usr/include/xlocale.h
|
||||
io.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
io.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
smtpap.o: ../common/config.h ../common/log.h ../common/ss.h ../common/utils.h
|
||||
smtpap.o: ../common/version.h io.h smtpap.h /usr/include/alloca.h
|
||||
smtpap.o: /usr/include/arpa/inet.h /usr/include/asm/errno.h
|
||||
smtpap.o: /usr/include/asm/sigcontext.h /usr/include/asm/socket.h
|
||||
smtpap.o: /usr/include/asm/sockios.h /usr/include/bits/byteswap.h
|
||||
smtpap.o: /usr/include/bits/confname.h /usr/include/bits/endian.h
|
||||
smtpap.o: /usr/include/bits/environments.h /usr/include/bits/errno.h
|
||||
smtpap.o: /usr/include/bits/in.h /usr/include/bits/local_lim.h
|
||||
smtpap.o: /usr/include/bits/netdb.h /usr/include/bits/posix1_lim.h
|
||||
smtpap.o: /usr/include/bits/posix2_lim.h /usr/include/bits/posix_opt.h
|
||||
smtpap.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/resource.h
|
||||
smtpap.o: /usr/include/bits/sched.h /usr/include/bits/select.h
|
||||
smtpap.o: /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h
|
||||
smtpap.o: /usr/include/bits/siginfo.h /usr/include/bits/signum.h
|
||||
smtpap.o: /usr/include/bits/sigset.h /usr/include/bits/sigstack.h
|
||||
smtpap.o: /usr/include/bits/sigthread.h /usr/include/bits/sockaddr.h
|
||||
smtpap.o: /usr/include/bits/socket.h /usr/include/bits/stdio_lim.h
|
||||
smtpap.o: /usr/include/bits/time.h /usr/include/bits/types.h
|
||||
smtpap.o: /usr/include/bits/uio.h /usr/include/bits/waitflags.h
|
||||
smtpap.o: /usr/include/bits/waitstatus.h /usr/include/bits/wchar.h
|
||||
smtpap.o: /usr/include/bits/wordsize.h /usr/include/bits/xopen_lim.h
|
||||
smtpap.o: /usr/include/ctype.h /usr/include/endian.h /usr/include/errno.h
|
||||
smtpap.o: /usr/include/features.h /usr/include/_G_config.h
|
||||
smtpap.o: /usr/include/gconv.h /usr/include/getopt.h /usr/include/gnu/stubs.h
|
||||
smtpap.o: /usr/include/libio.h /usr/include/limits.h
|
||||
smtpap.o: /usr/include/linux/errno.h /usr/include/linux/limits.h
|
||||
smtpap.o: /usr/include/netdb.h /usr/include/netinet/in.h
|
||||
smtpap.o: /usr/include/rpc/netdb.h /usr/include/signal.h /usr/include/stdint.h
|
||||
smtpap.o: /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h
|
||||
smtpap.o: /usr/include/sys/cdefs.h /usr/include/syslog.h
|
||||
smtpap.o: /usr/include/sys/resource.h /usr/include/sys/select.h
|
||||
smtpap.o: /usr/include/sys/socket.h /usr/include/sys/syslog.h
|
||||
smtpap.o: /usr/include/sys/sysmacros.h /usr/include/sys/time.h
|
||||
smtpap.o: /usr/include/sys/types.h /usr/include/sys/ucontext.h
|
||||
smtpap.o: /usr/include/sys/uio.h /usr/include/sys/un.h /usr/include/sys/wait.h
|
||||
smtpap.o: /usr/include/time.h /usr/include/ucontext.h /usr/include/unistd.h
|
||||
smtpap.o: /usr/include/wait.h /usr/include/wchar.h /usr/include/xlocale.h
|
||||
smtpap.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/limits.h
|
||||
smtpap.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h
|
||||
smtpap.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h
|
||||
smtpap.o: /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/syslimits.h
|
||||
@@ -0,0 +1,133 @@
|
||||
#include <sys/time.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "../common/log.h"
|
||||
#include "../common/utils.h"
|
||||
|
||||
#include "smtpap.h"
|
||||
#include "io.h"
|
||||
|
||||
/* connection timeout */
|
||||
extern struct timeval *conn_toutp;
|
||||
|
||||
/* printf-like function used to send messages to a socket */
|
||||
int sendmessage(int s, char *buf, size_t buflen, const char *format, ...)
|
||||
{
|
||||
int retval = 0;
|
||||
va_list ap;
|
||||
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
va_start(ap,format);
|
||||
retval = vsnprintf(buf,buflen, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (retval < 0)
|
||||
{
|
||||
log(LOG_DEBUG,"sendmessage() : could not print to buffer");
|
||||
return -1;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"sendmessage() : printed this to buffer : %s",buf);
|
||||
|
||||
retval = write_tout(s,buf,(size_t)retval, conn_toutp);
|
||||
if (retval < 0)
|
||||
{
|
||||
log(LOG_DEBUG,"sendmessage() : could not send");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* receive a response from the recipient SMTP server into *op_in
|
||||
* Can handle multi-line responses. */
|
||||
int receive(int s, char **inbuf,size_t *inbuflen, int flags)
|
||||
{
|
||||
int inputlen = 0; /* running total length of the input */
|
||||
int inputerror = 0; /* has an error occured? */
|
||||
int retval = 0; /* used for saving function return values */
|
||||
|
||||
/* for processing multi-line responses */
|
||||
int i=0;
|
||||
|
||||
/* storing old values of *inbuf and *inbuflen */
|
||||
char *inbuf_old = NULL;
|
||||
size_t inbuflen_old=0;
|
||||
|
||||
if ((!inbuf) || (!*inbuf) || (!inbuflen))
|
||||
return -1;
|
||||
|
||||
/* saving old values in case we need to restore them */
|
||||
inbuf_old = *inbuf;
|
||||
inbuflen_old = *inbuflen;
|
||||
|
||||
do
|
||||
{
|
||||
if (inputlen == *inbuflen-1) /* we need to increase the buffer size */
|
||||
{
|
||||
/* increase the size of the buffer */
|
||||
*inbuflen += 512;
|
||||
|
||||
*inbuf = (char *)realloc(*inbuf,(size_t)*inbuflen);
|
||||
if (!*inbuf)
|
||||
{
|
||||
log(LOG_ERR,"Could not allocate memory.");
|
||||
*inbuf = inbuf_old;
|
||||
*inbuflen = inbuflen_old;
|
||||
inputerror = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
retval=read_tout(s,*inbuf+inputlen,(size_t)(*inbuflen-inputlen-1),flags, conn_toutp); /* subtract 1 from inbuflen to leave space for \0 */
|
||||
if (retval <= 0)
|
||||
{
|
||||
log(LOG_ERR,"Error occured while receiving data.");
|
||||
inputerror = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
inputerror = 0;
|
||||
inputlen += retval;
|
||||
|
||||
/* exit clause if we have received CRLF, otherwise we need to keep reading*/
|
||||
/* also keep on reading if it's a multi-line response */
|
||||
if (inputlen >= SMTPAP_CRLF_LEN)
|
||||
{
|
||||
if (!strncmp(*inbuf+inputlen-SMTPAP_CRLF_LEN,SMTPAP_CRLF,SMTPAP_CRLF_LEN)) /* entire line received */
|
||||
{
|
||||
/* now check wether we should expect more lines */
|
||||
/* find the <CRLF> sequence which occurs one before last */
|
||||
for(i=inputlen-SMTPAP_CRLF_LEN-1; i > 0; i--) /* move backwards, start just before the final CRLF */
|
||||
{
|
||||
if ((*inbuf)[i] == SMTPAP_LF) /* got a LF */
|
||||
{
|
||||
/* check for a CR preceding it */
|
||||
if ((*inbuf)[i-1] == SMTPAP_CR) /* got a CR */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i==0) /* correct the offset if no CRLF found */
|
||||
i=-1;
|
||||
|
||||
/* check the 4th character after the <CRLF> to see if it is - or <SP> */
|
||||
if ((*inbuf)[i+4] != '-') /* no more lines */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(1);
|
||||
|
||||
if (!inputerror)
|
||||
{
|
||||
(*inbuf)[inputlen]=0; /* add the terminating NULL character */
|
||||
return inputlen;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
int sendmessage(int s, char *buf, size_t buflen, const char *format, ...);
|
||||
int receive(int s, char **inbuf,size_t *inbuflen, int flags);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* smtpap.h
|
||||
* SMTP Application Proxy for Onion Routing
|
||||
*
|
||||
* Matej Pfajfar <mp292@cam.ac.uk>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
* $Log$
|
||||
* Revision 1.1 2002/06/26 22:45:50 arma
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.12 2002/01/29 01:00:10 mp292
|
||||
* All network operations are now timeoutable.
|
||||
*
|
||||
* Revision 1.11 2002/01/26 21:50:17 mp292
|
||||
* Reviewed according to Secure-Programs-HOWTO. Still need to deal with network
|
||||
* timeouts.
|
||||
*
|
||||
* Revision 1.10 2001/12/18 14:56:29 badbytes
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.9 2001/12/18 14:43:19 badbytes
|
||||
* Added DEFAULT_SMTP_PORT.
|
||||
*
|
||||
* Revision 1.8 2001/12/12 16:02:29 badbytes
|
||||
* Testing completed.
|
||||
*
|
||||
* Revision 1.7 2001/12/11 10:43:21 badbytes
|
||||
* MAIL and RCPT handling completed. Still coding connection to Onion Proxy.
|
||||
*
|
||||
* Revision 1.6 2001/12/10 16:10:35 badbytes
|
||||
* Wrote a tokenize() function to help with parsing input from SMTP clients.
|
||||
*
|
||||
* Revision 1.5 2001/12/07 15:02:43 badbytes
|
||||
* Server setup code completed.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SMTPAP_H
|
||||
|
||||
#define __SMTPAP_H
|
||||
|
||||
#define SMTPAP_CRLF "\015\012"
|
||||
#define SMTPAP_CRLF_LEN 2
|
||||
|
||||
#define SMTPAP_CR '\015'
|
||||
#define SMTPAP_LF '\012'
|
||||
|
||||
/* terminator for DATA input */
|
||||
#define SMTPAP_ENDDATA "\015\012.\015\012"
|
||||
#define SMTPAP_ENDDATA_LEN 5
|
||||
|
||||
/* characters that separate tokens in SMTPAP commands */
|
||||
#define SMTPAP_SEPCHARS " \t\015\012" /* for general commands */
|
||||
#define SMTPAP_PATH_SEPCHARS " \t\015\012<>" /* for forward and reverse path */
|
||||
|
||||
/* default listening port */
|
||||
#define SMTPAP_LISTEN_PORT 25
|
||||
|
||||
/* default SMTP port */
|
||||
#define SMTPAP_DEFAULT_SMTP_PORT 25
|
||||
|
||||
/* default connection timeout */
|
||||
#define SMTPAP_DEFAULT_CONN_TIMEOUT 120; /* 120s */
|
||||
|
||||
/* SMTP commands and their lengths */
|
||||
#define SMTPAP_QUIT "quit"
|
||||
#define SMTPAP_QUIT_LEN 4
|
||||
|
||||
#define SMTPAP_HELO "helo"
|
||||
#define SMTPAP_HELO_LEN 4
|
||||
#define SMTPAP_EHLO "ehlo"
|
||||
#define SMTPAP_EHLO_LEN 4
|
||||
|
||||
#define SMTPAP_MAIL "mail"
|
||||
#define SMTPAP_MAIL_LEN 4
|
||||
|
||||
#define SMTPAP_RSET "rset"
|
||||
#define SMTPAP_RSET_LEN 4
|
||||
|
||||
#define SMTPAP_RCPT "rcpt"
|
||||
#define SMTPAP_RCPT_LEN 4
|
||||
|
||||
#define SMTPAP_DATA "data"
|
||||
#define SMTPAP_DATA_LEN 4
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user