"Fossies" - the Fresh Open Source Software Archive

Member "openssl-1.0.2q/demos/tunala/README" (20 Nov 2018, 11621 Bytes) of package /linux/misc/openssl-1.0.2q.tar.gz:


As a special service "Fossies" has tried to format the requested text file into HTML format (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 This is intended to be an example of a state-machine driven SSL application. It
    2 acts as an SSL tunneler (functioning as either the server or client half,
    3 depending on command-line arguments). *PLEASE* read the comments in tunala.h
    4 before you treat this stuff as anything more than a curiosity - YOU HAVE BEEN
    5 WARNED!! There, that's the draconian bit out of the way ...
    6 
    7 
    8 Why "tunala"??
    9 --------------
   10 
   11 I thought I asked you to read tunala.h?? :-)
   12 
   13 
   14 Show me
   15 -------
   16 
   17 If you want to simply see it running, skip to the end and see some example
   18 command-line arguments to demonstrate with.
   19 
   20 
   21 Where to look and what to do?
   22 -----------------------------
   23 
   24 The code is split up roughly coinciding with the detaching of an "abstract" SSL
   25 state machine (which is the purpose of all this) and its surrounding application
   26 specifics. This is primarily to make it possible for me to know when I could cut
   27 corners and when I needed to be rigorous (or at least maintain the pretense as
   28 such :-).
   29 
   30 Network stuff:
   31 
   32 Basically, the network part of all this is what is supposed to be abstracted out
   33 of the way. The intention is to illustrate one way to stick OpenSSL's mechanisms
   34 inside a little memory-driven sandbox and operate it like a pure state-machine.
   35 So, the network code is inside both ip.c (general utility functions and gory
   36 IPv4 details) and tunala.c itself, which takes care of application specifics
   37 like the main select() loop. The connectivity between the specifics of this
   38 application (TCP/IP tunneling and the associated network code) and the
   39 underlying abstract SSL state machine stuff is through the use of the "buffer_t"
   40 type, declared in tunala.h and implemented in buffer.c.
   41 
   42 State machine:
   43 
   44 Which leaves us, generally speaking, with the abstract "state machine" code left
   45 over and this is sitting inside sm.c, with declarations inside tunala.h. As can
   46 be seen by the definition of the state_machine_t structure and the associated
   47 functions to manipulate it, there are the 3 OpenSSL "handles" plus 4 buffer_t
   48 structures dealing with IO on both the encrypted and unencrypted sides ("dirty"
   49 and "clean" respectively). The "SSL" handle is what facilitates the reading and
   50 writing of the unencrypted (tunneled) data. The two "BIO" handles act as the
   51 read and write channels for encrypted tunnel traffic - in other applications
   52 these are often socket BIOs so that the OpenSSL framework operates with the
   53 network layer directly. In this example, those two BIOs are memory BIOs
   54 (BIO_s_mem()) so that the sending and receiving of the tunnel traffic stays
   55 within the state-machine, and we can handle where this gets send to (or read
   56 from) ourselves.
   57 
   58 
   59 Why?
   60 ----
   61 
   62 If you take a look at the "state_machine_t" section of tunala.h and the code in
   63 sm.c, you will notice that nothing related to the concept of 'transport' is
   64 involved. The binding to TCP/IP networking occurs in tunala.c, specifically
   65 within the "tunala_item_t" structure that associates a state_machine_t object
   66 with 4 file-descriptors. The way to best see where the bridge between the
   67 outside world (TCP/IP reads, writes, select()s, file-descriptors, etc) and the
   68 state machine is, is to examine the "tunala_item_io()" function in tunala.c.
   69 This is currently around lines 641-732 but of course could be subject to change.
   70 
   71 
   72 And...?
   73 -------
   74 
   75 Well, although that function is around 90 lines of code, it could easily have
   76 been a lot less only I was trying to address an easily missed "gotcha" (item (2)
   77 below). The main() code that drives the select/accept/IO loop initialises new
   78 tunala_item_t structures when connections arrive, and works out which
   79 file-descriptors go where depending on whether we're an SSL client or server
   80 (client --> accepted connection is clean and proxied is dirty, server -->
   81 accepted connection is dirty and proxied is clean). What that tunala_item_io()
   82 function is attempting to do is 2 things;
   83 
   84   (1) Perform all reads and writes on the network directly into the
   85       state_machine_t's buffers (based on a previous select() result), and only
   86       then allow the abstact state_machine_t to "churn()" using those buffers.
   87       This will cause the SSL machine to consume as much input data from the two
   88       "IN" buffers as possible, and generate as much output data into the two
   89       "OUT" buffers as possible. Back up in the main() function, the next main
   90       loop loop will examine these output buffers and select() for writability
   91       on the corresponding sockets if the buffers are non-empty.
   92 
   93   (2) Handle the complicated tunneling-specific issue of cascading "close"s.
   94       This is the reason for most of the complexity in the logic - if one side
   95       of the tunnel is closed, you can't simply close the other side and throw
   96       away the whole thing - (a) there may still be outgoing data on the other
   97       side of the tunnel that hasn't been sent yet, (b) the close (or things
   98       happening during the close) may cause more data to be generated that needs
   99       sending on the other side. Of course, this logic is complicated yet futher
  100       by the fact that it's different depending on which side closes first :-)
  101       state_machine_close_clean() will indicate to the state machine that the
  102       unencrypted side of the tunnel has closed, so any existing outgoing data
  103       needs to be flushed, and the SSL stream needs to be closed down using the
  104       appropriate shutdown sequence. state_machine_close_dirty() is simpler
  105       because it indicates that the SSL stream has been disconnected, so all
  106       that remains before closing the other side is to flush out anything that
  107       remains and wait for it to all be sent.
  108 
  109 Anyway, with those things in mind, the code should be a little easier to follow
  110 in terms of "what is *this* bit supposed to achieve??!!".
  111 
  112 
  113 How might this help?
  114 --------------------
  115 
  116 Well, the reason I wrote this is that there seemed to be rather a flood of
  117 questions of late on the openssl-dev and openssl-users lists about getting this
  118 whole IO logic thing sorted out, particularly by those who were trying to either
  119 use non-blocking IO, or wanted SSL in an environment where "something else" was
  120 handling the network already and they needed to operate in memory only. This
  121 code is loosely based on some other stuff I've been working on, although that
  122 stuff is far more complete, far more dependant on a whole slew of other
  123 network/framework code I don't want to incorporate here, and far harder to look
  124 at for 5 minutes and follow where everything is going. I will be trying over
  125 time to suck in a few things from that into this demo in the hopes it might be
  126 more useful, and maybe to even make this demo usable as a utility of its own.
  127 Possible things include:
  128 
  129   * controlling multiple processes/threads - this can be used to combat
  130     latencies and get passed file-descriptor limits on some systems, and it uses
  131     a "controller" process/thread that maintains IPC links with the
  132     processes/threads doing the real work.
  133 
  134   * cert verification rules - having some say over which certs get in or out :-)
  135 
  136   * control over SSL protocols and cipher suites
  137 
  138   * A few other things you can already do in s_client and s_server :-)
  139 
  140   * Support (and control over) session resuming, particularly when functioning
  141     as an SSL client.
  142 
  143 If you have a particular environment where this model might work to let you "do
  144 SSL" without having OpenSSL be aware of the transport, then you should find you
  145 could use the state_machine_t structure (or your own variant thereof) and hook
  146 it up to your transport stuff in much the way tunala.c matches it up with those
  147 4 file-descriptors. The state_machine_churn(), state_machine_close_clean(), and
  148 state_machine_close_dirty() functions are the main things to understand - after
  149 that's done, you just have to ensure you're feeding and bleeding the 4
  150 state_machine buffers in a logical fashion. This state_machine loop handles not
  151 only handshakes and normal streaming, but also renegotiates - there's no special
  152 handling required beyond keeping an eye on those 4 buffers and keeping them in
  153 sync with your outer "loop" logic. Ie. if one of the OUT buffers is not empty,
  154 you need to find an opportunity to try and forward its data on. If one of the IN
  155 buffers is not full, you should keep an eye out for data arriving that should be
  156 placed there.
  157 
  158 This approach could hopefully also allow you to run the SSL protocol in very
  159 different environments. As an example, you could support encrypted event-driven
  160 IPC where threads/processes pass messages to each other inside an SSL layer;
  161 each IPC-message's payload would be in fact the "dirty" content, and the "clean"
  162 payload coming out of the tunnel at each end would be the real intended message.
  163 Likewise, this could *easily* be made to work across unix domain sockets, or
  164 even entirely different network/comms protocols.
  165 
  166 This is also a quick and easy way to do VPN if you (and the remote network's
  167 gateway) support virtual network devices that are encapsulted in a single
  168 network connection, perhaps PPP going through an SSL tunnel?
  169 
  170 
  171 Suggestions
  172 -----------
  173 
  174 Please let me know if you find this useful, or if there's anything wrong or
  175 simply too confusing about it. Patches are also welcome, but please attach a
  176 description of what it changes and why, and "diff -urN" format is preferred.
  177 Mail to geoff@openssl.org should do the trick.
  178 
  179 
  180 Example
  181 -------
  182 
  183 Here is an example of how to use "tunala" ...
  184 
  185 First, it's assumed that OpenSSL has already built, and that you are building
  186 inside the ./demos/tunala/ directory. If not - please correct the paths and
  187 flags inside the Makefile. Likewise, if you want to tweak the building, it's
  188 best to try and do so in the makefile (eg. removing the debug flags and adding
  189 optimisation flags).
  190 
  191 Secondly, this code has mostly only been tested on Linux. However, some
  192 autoconf/etc support has been added and the code has been compiled on openbsd
  193 and solaris using that.
  194 
  195 Thirdly, if you are Win32, you probably need to do some *major* rewriting of
  196 ip.c to stand a hope in hell. Good luck, and please mail me the diff if you do
  197 this, otherwise I will take a look at another time. It can certainly be done,
  198 but it's very non-POSIXy.
  199 
  200 See the INSTALL document for details on building.
  201 
  202 Now, if you don't have an executable "tunala" compiled, go back to "First,...".
  203 Rinse and repeat.
  204 
  205 Inside one console, try typing;
  206 
  207 (i)  ./tunala -listen localhost:8080 -proxy localhost:8081 -cacert CA.pem \
  208               -cert A-client.pem -out_totals -v_peer -v_strict
  209 
  210 In another console, type;
  211 
  212 (ii) ./tunala -listen localhost:8081 -proxy localhost:23 -cacert CA.pem \
  213               -cert A-server.pem -server 1 -out_totals -v_peer -v_strict
  214 
  215 Now if you open another console and "telnet localhost 8080", you should be
  216 tunneled through to the telnet service on your local machine (if it's running -
  217 you could change it to port "22" and tunnel ssh instead if you so desired). When
  218 you logout of the telnet session, the tunnel should cleanly shutdown and show
  219 you some traffic stats in both consoles. Feel free to experiment. :-)
  220 
  221 Notes:
  222 
  223  - the format for the "-listen" argument can skip the host part (eg. "-listen
  224    8080" is fine). If you do, the listening socket will listen on all interfaces
  225    so you can connect from other machines for example. Using the "localhost"
  226    form listens only on 127.0.0.1 so you can only connect locally (unless, of
  227    course, you've set up weird stuff with your networking in which case probably
  228    none of the above applies).
  229 
  230  - ./tunala -? gives you a list of other command-line options, but tunala.c is
  231    also a good place to look :-)
  232 
  233