Contributing to SSHGuard
Your feedback on how you use SSHGuard, what you like, and what annoys you, helps us improve SSHGuard.
- Subscribe to the users mailing list and contribute to discussions on issues you care about.
- Vote for issues on the issue tracker.
- Report log messages that should or should not be identified as attacks on the issue tracker.
- Consider maintaining a package for SSHGuard on your operating system.
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:
- Obtain several samples of the log message you want to match. Add these attacks, along with the expected parse result, to tests.txt.
make check, to make sure your new tests fail.
- Create new tokens for parts of the string you want to match at the top of attack_parser.y, where the
- Add regular expressions for matching your new tokens in attack_scanner.l.
- 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
- 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
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
blockcommands 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
blockcommand, taking the same arguments. The backend may assume that a
releasecommand is never issued without a corresponding
If block addresses overlap, it is up to the implementation to decide when to allow access through the firewall. For example, if both 18.104.22.168/32 and 22.214.171.124/24 were blocked, in that order, and 126.96.36.199/32 was released, the firewall backend may continue to block 188.8.131.52 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-blockerwill usually issue this command before any others. Implementations should release all blocked addresses, including those that do not have a corresponding
blockcommand (for example, blocks from a previous invocation).
Submitting Your Patches
We welcome your patches through:
- Email submission in
git format-patchform or as a unified diff to the SSHGuard Users' Mailing List <email@example.com>
- A BitBucket pull request
- 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:
Issue analyzed, fair game for someone to fix
- On hold
Issue analyzed, fix deferred (e.g. due to coming architectural changes)
Action taken, issue resolved
Not an issue (e.g. external bugs, spam)
Intentional behavior or rejected feature requests
No action taken, issue resolved (e.g. already fixed in
Before release, make sure that:
- Change log and documentation are up-to-date
- Version number is consistent in configure.ac and man pages
- Regenerate autotools:
- Building and installing work from source tarball:
- Tag release:
git tag -s -m "Tag <version> release" v<version>
- Source tarball should have been generated from
- Sign source tarball
- Push tags:
git push --tags
- Upload release files to SourceForge.
- Send release announcement to mailing lists.
- Announce release on website.