/librepsheet

The Repsheet core logic extracted to a separate library

Primary LanguageCApache License 2.0Apache-2.0

librepsheet Build Status Coverity Status

Purpose

This is the core logic library for Repsheet. It provides the Redis database operations, and X-Forwarded-For parsing code. This library will supply everything needed to implement Repsheet in any program. The current targets are the Apache and NGINX web servers.

Dependencies

To install librepsheet from source, you will need:

  • automake
  • autoconf
  • libtool

And in order to run the tests, you will need the check library.

Installation

You can install librepsheet using the Debian and RedHat packages provided with the official release. To use the library you will need a Redis server available. Once you have the dependencies installed, you can run the following to build and install librepsheet:

$ ./autogen.sh
$ ./configure
$ make
$ make check # all tests should pass
$ <sudo> make install

To verify that the installation completed successfully, check pkg-config:

$ pkg-config --list-all | grep repsheet
repsheet                  repsheet - The Repsheet core logic library

Examples

Connecting

librepsheet provides a connection function for Redis along with a number of operations against Redis that are used in building Repsheet. To get a connection use repsheet_connect. The arguments are host, port, connect_timeout, and read_timeout. Each timeout argument is considered to be in milliseconds. If the connect or read timeouts are exceeded and error is set on the connection and it is no longer usable.

redisContext *context = repsheet_connect("localhost", 6379, 5, 10);

You can check the connection to ensure it is in tact before issuing a command using the check_connection function:

int status = check_connection(context);

If your connection is broken or has an error, you can attempt a reconnect with the repsheet_reconnect function:

int status = repsheet_reconnect(context);

Obtaining the status of an actor

Actors can be looked up by IP or by user. After establishing a connection, you can ask for the status of an actor using the actor_status function. You will need to provide a variable to hold the response of the lookup if the actor is found. The response contains the reason why the actor is present.

char reason[MAX_REASON_LENGTH];
int status = actor_status(context, "1.1.1.1", IP, reason);
char reason[MAX_REASON_LENGTH];
int status = actor_status(context, "d93c2e4e-40f5-4463-ac79-7a40e51eeae0", USER, reason);

The following are the possible status results for actor_status:

BLACKLISTED
WHITELISTED
MARKED
LIBREPSHEET_OK
UNSUPPORTED
DISCONNECTED

Under normal circumstances you will only see the first four statuses. The last two are due to passing in an unsupported type to the lookup, or the connection has either been terminated or it has timed out. The result of actor_status should be used to determine if the actor should be able to continue what it is doing.

The following example shows a the code for a complete status check:

#include <stdio.h>
#include <repsheet.h>

int main(void)
{
  redisContext *context = repsheet_connect("localhost", 6379, 5, 10);
  char reason[MAX_REASON_LENGTH];
  int status = actor_status(context, "127.0.0.1", IP, reason);

  if (status == DISCONNECTED) {
    printf("Redis connection unavailable\n");
  } else if (status == WHITELISTED) {
    printf("IP is whitelisted: %s\n", reason);
  } else if (status == BLACKLISTED) {
    printf("IP is blacklisted: %s\n", reason);
  } else if (status == MARKED) {
    printf("IP is marked: %s\n", reason);
  } else if (status == LIBREPSHEET_OK) {
    printf("IP is considered ok\n");
  }

  redisFree(context);
  return 0;
}

Processing the X-Forwarded-For Header

This library is commonly used inside of web servers. The most common webservers (Apache and NGINX) do not have functions to process the X-Forwarded-For header and extract the IP address of the actor. The remote_address function can do this for you:

char address[INET6_ADDRSTRLEN];
int result = remote_address("10.0.1.15", "1.1.1.1, 8.8.8.8, 2.2.2.2", address);

You must pass in a variable that is used to hold the result of the processing. The possible return values are:

BLACKLISTED
LIBREPSHEET_OK
NIL

If the processing is successful, LIBREPSHEET_OK is returned. If the value is not a valid IPv4 or IPv6 address, BLACKLISTED is returned. It is common to reject any request that does not have a valid address in the XFF header because it is likely malicious in nature. NIL is returned if improper values are provided to remote_address.

Redis Keyspace

Although librepsheet abstracts the Redis keyspace away, it is still useful to understand how to compose values that librepsheet can lookup if another system is writing values to Redis after processing attack signals. The following scheme is used:

Blacklist

Key Value
<ip>:repsheet:ip:blacklisted <reason>
<user>:repsheet:user:blacklisted <reason>
<cidr>:repsheet:cidr:blacklisted <reason>
repsheet:cidr:blacklisted <cidr>

Whitelist

Key Value
<ip>:repsheet:ip:whitelisted <reason>
<user>:repsheet:user:whitelisted <reason>
<cidr>:repsheet:cidr:whitelisted <reason>
repsheet:cidr:whitelisted <cidr>

Marked

Key Value
<ip>:repsheet:ip:marked <reason>
<user>:repsheet:user:marked <reason>
<cidr>:repsheet:cidr:marked <reason>
repsheet:cidr:marked <cidr>

To view all of the functions provided by librepsheet you can visit the documentation page. To see a complete example of librepsheet used in a webserver module, see the Apache or NGINX modules.