Contributing to SSHGuard

Contents

For Users

Your feedback on how you use SSHGuard, what you like, and what annoys you, helps us improve SSHGuard.

For Contributors

Architecture

SSHGuard consists of a pipeline of programs that work together, depicted in doc/sshguard.dot.

In this diagram, processes shown with a dashed border are sandboxed, if sandboxing support is implemented for the OS in sandbox_init(). Currently, sandboxing is only implemented on FreeBSD with Capsicum and on OpenBSD with pledge().

sshguard reads the configuration file and spawns a pipeline.

sshg-logtail monitors one or more log files, aggregates them, and pipes their contents to the next stage.

sshg-parser reads its input and looks for attacks. If it finds an attack, it reports the service, remote address, address type (IPv4 or IPv6), and score ("dangerousness") to the next stage. The format is defined in print_attack() (src/parser/parser.c). This is the only program you need to change to add new signatures.

sshg-blocker maintains a list of recent attackers. If there are enough attacks from an attacker in a given time interval, it commands the firewall backend to block the attacker's address. After a certain amount of time, sshg-blocker is also responsible for unblocking an attacker, or blacklisting if configured to do so.

sshg-fw-* is one of several firewall backends. It reads firewall commands from its input and runs the appropriate system commands to do the firewall.

Add New Signatures

Files to change:

If you are adding a new service, changes are also needed in:

  1. Obtain several samples of the log message you want to match. Add these attacks, along with the expected parse result, to tests.txt.
  2. Run make check, to make sure your new tests fail.
  3. Create new tokens for parts of the string you want to match at the top of attack_parser.y, where the %token lines are.
  4. Add regular expressions for matching your new tokens in attack_scanner.l.
  5. Add grammar rules for your attack in attack_parser.y. A good starting point is to look at how the existing signatures are matached from the msg_single rule.
  6. Check that your new tests pass, and that you haven't broken existing tests. To help debug your rule, you can run sshg-parser directly with the -d flag.

Firewall Backend Interface

sshg-blocker sends line-delimited commands to a firewall backend through a pipe, which does the actual work of blocking and releasing addresses using the underlying firewall. The firewall backend must support these commands:

  • block ADDR KIND SUBNET_SIZE (fw_block() in blocklist.c). This command blocks an IP address block given in CIDR notation as ADDR/SUBNET_SIZE which is either IPv4 if KIND is '4' or IPv6 if KIND is '6'. As is the case with CIDR notation, a SUBNET_SIZE of 32 indicates that only one IP address must be blocked.

    Since the firewall backend likely runs with elevated permissions, implementations should validate their inputs.

    At its option, an implementation may gather several block commands to issue to the underlying backend at once to reduce overhead.

  • release ADDR KIND SUBNET_SIZE (fw_release() in blocklist.c). This command undoes the block command, taking the same arguments. The backend may assume that a release command is never issued without a corresponding block command.

    If block addresses overlap, it is up to the implementation to decide when to allow access through the firewall. For example, if both 1.2.3.4/32 and 1.2.3.0/24 were blocked, in that order, and 1.2.3.4/32 was released, the firewall backend may continue to block 1.2.3.4 until both are released, or may unblock it immediately.

  • flushonexit (main() in blocker.c). This command instructs the backend to release all blocked addresses when the backend exits. sshg-blocker will usually issue this command before any others. Implementations should release all blocked addresses, including those that do not have a corresponding block command (for example, blocks from a previous invocation).

Submitting Your Patches

We welcome your patches through:

For Committers

Commit Guidelines

  • Merge via fast-forward and rebase. Where possible, merge pull requests and branches by rebasing on top of master and fast-forwarding, without creating a separate merge commit. Linear history makes it possible for us to bisect regressions.
  • 50 character subject line, followed by a blank and more details in the body if needed, in the commit message.
  • Work in topic branches as needed. For changes big or small, feel free to use public topic branches in the SSHGuard repository. After review, they go in by rebasing master. Topic branches are usually deleted after merging. Force pushes are welcome in topic branches but not allowed in master.

Issue Tracker Workflow

An explanation of workflow states that aren't self-explanatory:

Open
Issue analyzed, fair game for someone to fix
On hold
Issue analyzed, fix deferred (e.g. due to coming architectural changes)
Resolved
Action taken, issue resolved
Invalid
Not an issue (e.g. external bugs, spam)
Wontfix
Intentional behavior or rejected feature requests
Closed
No action taken, issue resolved (e.g. already fixed in master)

Release Checklist

Before release, make sure that:

  1. Change log and documentation are up-to-date
  2. Version number is consistent in configure.ac and man pages
  3. Regenerate autotools: autoreconf -i
  4. Building and installing work from source tarball: make distcheck

Then:

  1. Tag release: git tag -s -m "Tag <version> release" v<version>
  2. Source tarball should have been generated from make distcheck already
  3. Sign source tarball ./distsign <tarball>
  4. Push tags: git push --tags
  5. Upload release files to SourceForge.
  6. Send release announcement to mailing lists.
  7. Announce release on website.