HTTPS SSH

Elderberries

A primarly command-line based debugging proxy.

Why Elderberries? Because your mother was a hamster... No but seriously? We named this project after a famous and not so famous Monty Python reference.

License

This software is licensed under the Mozilla Public License v2, bundled with this program.

Requirements

The official requirements are:

  • C99 compiler
  • Standard UNIX header files

Our normal build process uses GCC 4.8.2 with glibc 2.8. Cygwin builds may work (disabling -Werror may be necessary) but they aren't officially supported (yet).

Building

Elderberries uses GNU make as its build system, for the simple reason that make (or any compatible alternative) is free and available on virtually all platforms.

Building an executable

To build a native executable for your platform from the sources, navigate to the root path of where you cloned the repository and run:

make

This will build the object files and link them together in an executable, that will be put in the dist/ subdirectory created by the build process.

If you want to create a debug build, run:

make DEBUG=1

A debug build enables your compiler's debug flags, as well as extra logging and debugging features within the application itself.

Running

Once compiled, you can run the proxy using the command-line:

./elderberries -d www.github.com:80

The above with proxy all requests from the current machine on port 80 to the address www.github.com on port 80.

It's also possible to listen on a specific interface only. Per example, your local network address:

./elderberries -i 192.168.1.10 -d www.github.com:80

You can also proxy from a port to a different port:

./elderberries -i 192.168.1.10:8080 -d www.github.com:80

Documentation

What is Elderberries?

Elderberries is a primarily command-line based debugging proxy built for Linux. It allows one to intercept network transfers for ulterior consultation, then forward them to their original intended destination.

Why are debugging proxies useful?

Debugging proxies are useful when developing software that transfers data over a network, such as network programming or web applications. When creating such software, a proxy allows the developer to examine the data sent and received by his program without having to add extra debugging routines, recompile, etc.

Aren't there any debugging proxies already available out there?

There is, are like Charles, Zaproxy or Paros, but most of them are proprietary, GUI-oriented, complex to configure and run or have large footprints and dependencies.

Elderberries is small, fast, oriented towards the command-line, very easy to run and requires nothing more than the standard Linux headers and libc.

How does it work?

Whenever Elderberries is started, you will need to provide it with a destination IP address and port, as well as a listening interface and port (if they are omitted, they are assumed to be all interfaces and the same port as the destination).

The next step would be to configure your application to connect on the listening interface and port, rather than the destination interface.

Whenever something (or someone) connects to the listening port, Elderberries logs the incoming data in a segment, then forwards it to the destination interface as if it wasn't there. If the destination replies with some data, that data is logged in another segment and forwarded back to the connected client as if it wasn't there.

This allows you to see what the client asked, and what the server responded without having to modify either.

What is a segment?

A data segment is a structure that holds the data transferred by a peer (client or server). It has a timestamp, a length and content.

Elderberries automatically creates data segments based on input and output. Per example, if client A sends data to the server B, an "output" data segment is created to hold that data. If B replies, an "input" data segment is created to hold that data, so on and so forth.

If A sends data to B but B doesn't respond, and then A sends more data, both transfers will be stored in the same data segment as "output".

Data segments always follow the pattern "output", "input", "output", "input", etc.

Proxy options reference

Basic options

-d Destination address and port

Sets the address and port where incoming requests will be routed to.

This is a mandatory argument.

Usage:

./elderberries -d ADDR:PORT
  • ADDR, mandatory: is an IP address or hostname to which to connect to and forward requests.
  • PORT, mandatory: is a valid port number (0-65535) to which to forward the requests on the destination address.
-i Listening interface and port

Sets the interface to use when listening to incoming connections.

Default: 0.0.0.0

Usage:

./elderberries -i [ADDR][:PORT]
  • ADDR, optional: is an IP address to listen on. It must match an available network interface address. If the address 0.0.0.0 is specified, the listener will accept connections on all interfaces. If omitted, 0.0.0.0 is assumed.
  • PORT, optional: is a valid port number (0-65535) on which to listen to. If omitted, the same port as the destination address will be used.

Transfer options

-k Block size

Sets the size of blocks (or chunks) that are read from the source then written to the destination at once.

Whenever a client requests comes in the proxy, it will try to read at most the length defined by the block size, then send it to the destination socket, and vice versa. This controls the I/O of both sockets. A small value will transfer data faster between hosts, will use less memory, but will cost most I/O operations on the system.

Default: 2048

Usage:

./elderberries -k NUM_BYTES
  • NUM_BYTES, mandatory: is the size of the block, in bytes, after which it is transferred from the source to the destination.

Logging options

-s Stack size

Sets the number of connections to backlog in memory.

A higher value means you can see more past connections when querying, at the cost of additional memory allocation. When the limit is reached, older logs will be replaced by newer ones.

Default: 128

Usage:

./elderberries -s NUM_CONN
  • NUM_CONN, mandatory: the maximum number of connections to keep logs for.

Client options reference

Querying the logs

-q Obtain the list of connections

Activates query mode and list the current and past connections along with some information about them.

Usage:

./elderberries -q

Output:

     UID  TIMESTAMP
       0  2013-11-25 09:48:52         3 segments      1436 bytes     closed
       1  2013-11-25 09:49:02         6 segments      3063 bytes     open
  • UID: a unique identifier for the connection, used when querying a specific connection.
  • TIMESTAMP: is the time and date when the connection happened (not the time where the first segment was received).
  • 3 segments: is the number of segments transferred in the connection.
  • 1436 bytes: is the number of bytes sent transferred for all segments.
  • The last column is the state of the connection:
  • open: means that the connection is still active on both sides.
  • closed: means that either the server or the client ended the connection.
-u Details of a connection and its segments

Obtain details about a connection and list all segments transferred during it.

Usage:

./elderberries -q -u UID
  • UID, mandatory: is the unique identifier (see above) of the connection to obtain details for.

Output:

Data stack UID:           0
Stack timestamp:          2013-11-25 09:48:52
Number of data segments:  3 segments
Total length:             1436 bytes
Connection status:        closed

       #  TIMESTAMP
       0  2013-11-25 09:48:54        35 bytes     output
       1  2013-11-25 09:48:56      1401 bytes     input
       2  2013-11-25 09:49:01         0 bytes     server disconnect
  • The top section displays the same information from the connections list.
  • #: is the identifier for the data segment within the connection.
  • TIMESTAMP: is the time and date when transfer for this segment started.
  • 35 bytes: is the number of bytes transferred during the segment.
  • The last column is the type of segment, chosen from:
  • output: Data was sent from the listening interface to the destination address.
  • input: The destination address sent back data to the connected client.
  • client disconnect: The connected client has closed the connection.
  • server disconnect: The destination address has closed the connection.
-p Output data from segments

Usage:

./elderberries -q -u UID -p SEGNUM ...
  • UID, mandatory: is the unique identifier (see above) of the connection to fetch the segment from.
  • SEGNUM, mandatory: is the identifier of the segment (obtained from the details of a connection)

The output is the data contained in the specified segment(s), as is.

It is possible to output multiple segments at once by supplying the argument multiple times. Per example, to print segments 0, 1 and 4:

./elderberries -q -u0 -p0 -p1 -p4

Since v0.2.2: It is also possible to output multiple segments at once by supplying a range as the argument. Per example, to print segments 0, 1, 2, 3 and 4:

./elderberries -q -u0 -p0-4

Contributing

Anybody is welcome to contribute to this project. If you want to do so, please follow the following guidelines:

  • Fork the project on github.
  • Make sure you follow the code style already in place.
  • Make sure you run make all (without debug flags) before requesting a pull, to make sure the code is error free.