This commit was manufactured by cvs2svn to create tag 'src'.

svn:r6
This commit is contained in:
(no author)
2002-06-26 22:45:50 +00:00
parent daf83b0be3
commit c5006f9683
67 changed files with 12287 additions and 0 deletions
+124
View File
@@ -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.
+228
View File
@@ -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
+355
View File
@@ -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;
}
+95
View File
@@ -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
+347
View File
@@ -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;
}
+88
View File
@@ -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
+89
View File
@@ -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 */
}
+32
View File
@@ -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
+74
View File
@@ -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);
}
+40
View File
@@ -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
+633
View File
@@ -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;
}
+156
View File
@@ -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
+77
View File
@@ -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;
}
+44
View File
@@ -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
+39
View File
@@ -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 */
+147
View File
@@ -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;
}
+189
View File
@@ -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
+260
View File
@@ -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;
}
+57
View File
@@ -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
+63
View File
@@ -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
+150
View File
@@ -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;
}
}
+53
View File
@@ -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
+28
View File
@@ -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
+99
View File
@@ -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
+194
View File
@@ -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;
}
+46
View File
@@ -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);
+702
View File
@@ -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;
}
+33
View File
@@ -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
+285
View File
@@ -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
+121
View File
@@ -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;
}
+41
View File
@@ -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
+85
View File
@@ -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;
}
+23
View File
@@ -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);
+146
View File
@@ -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;
}
+25
View File
@@ -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);
+49
View File
@@ -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;
}
+30
View File
@@ -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);
+104
View File
@@ -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;
}
+23
View File
@@ -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);
+916
View File
@@ -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;
}
+54
View File
@@ -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
+364
View File
@@ -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);
}
+66
View File
@@ -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
+194
View File
@@ -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;
}
+22
View File
@@ -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);
+18
View File
@@ -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}
+99
View File
@@ -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;
}
+174
View File
@@ -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;
}
+23
View File
@@ -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 */
}
+319
View File
@@ -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);
}
}
+212
View File
@@ -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);
}
+49
View File
@@ -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;
}
+362
View File
@@ -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 */
}
+212
View File
@@ -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;
}
+130
View File
@@ -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);
}
+580
View File
@@ -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);
}
+406
View File
@@ -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;
}
+62
View File
@@ -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;
}
+411
View File
@@ -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
+365
View File
@@ -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);
}
+58
View File
@@ -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
+119
View File
@@ -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);
}
+80
View File
@@ -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
+133
View File
@@ -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;
}
+2
View File
@@ -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
+90
View File
@@ -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