-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #37 from sbz/add_pf_support
Add pf support
- Loading branch information
Showing
9 changed files
with
281 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
// +build linux | ||
|
||
package main | ||
|
||
import ( | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
// +build linux | ||
|
||
package main | ||
|
||
import ( | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// +build !linux | ||
|
||
package main | ||
|
||
func newIPTables(config *bouncerConfig) (interface{}, error) { | ||
return nil, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
// +build linux | ||
|
||
package main | ||
|
||
import ( | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// +build !linux | ||
|
||
package main | ||
|
||
func newNFTables(config *bouncerConfig) (interface{}, error) { | ||
return nil, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
// +build openbsd freebsd | ||
|
||
package main | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"os/exec" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
"github.com/crowdsecurity/crowdsec/pkg/models" | ||
"github.com/pkg/errors" | ||
|
||
log "github.com/sirupsen/logrus" | ||
) | ||
|
||
type pfContext struct { | ||
proto string | ||
table string | ||
version string | ||
} | ||
|
||
type pf struct { | ||
inet *pfContext | ||
inet6 *pfContext | ||
} | ||
|
||
const ( | ||
backendName = "pf" | ||
|
||
pfinetTable = "crowdsec-blacklists" | ||
pfinet6Table = "crowdsec6-blacklists" | ||
|
||
pfctlCmd = "/sbin/pfctl" | ||
pfDevice = "/dev/pf" | ||
|
||
addBanFormat = "%s: add ban on %s for %s sec (%s)" | ||
delBanFormat = "%s: del ban on %s for %s sec (%s)" | ||
) | ||
|
||
func newPF(config *bouncerConfig) (interface{}, error) { | ||
ret := &pf{} | ||
|
||
inetCtx := &pfContext{ | ||
table: pfinetTable, | ||
proto: "inet", | ||
version: "ipv4", | ||
} | ||
|
||
inet6Ctx := &pfContext{ | ||
table: pfinet6Table, | ||
proto: "inet6", | ||
version: "ipv6", | ||
} | ||
|
||
ret.inet = inetCtx | ||
|
||
if config.DisableIPV6 { | ||
return ret, nil | ||
} | ||
|
||
ret.inet6 = inet6Ctx | ||
|
||
return ret, nil | ||
} | ||
|
||
func (ctx *pfContext) checkTable() error { | ||
log.Infof("Checking pf table: %s", ctx.table) | ||
|
||
cmd := exec.Command(pfctlCmd, "-s", "Tables") | ||
out, err := cmd.CombinedOutput() | ||
|
||
if err != nil { | ||
return errors.Wrapf(err, "pfctl error : %v - %s", err, string(out)) | ||
} else if !strings.Contains(string(out), ctx.table) { | ||
return errors.Errorf("table %s doesn't exist", ctx.table) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (ctx *pfContext) shutDown() error { | ||
cmd := exec.Command(pfctlCmd, "-t", ctx.table, "-T", "flush") | ||
log.Infof("pf table clean-up : %s", cmd.String()) | ||
if out, err := cmd.CombinedOutput(); err != nil { | ||
log.Errorf("Error while flushing table (%s): %v - %s", err, string(out)) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (ctx *pfContext) Add(decision *models.Decision) error { | ||
banDuration, err := time.ParseDuration(*decision.Duration) | ||
if err != nil { | ||
return err | ||
} | ||
log.Debugf(addBanFormat, backendName, *decision.Value, strconv.Itoa(int(banDuration.Seconds())), *decision.Scenario) | ||
cmd := exec.Command(pfctlCmd, "-t", ctx.table, "-T", "add", *decision.Value) | ||
log.Debugf("pfctl add : %s", cmd.String()) | ||
if out, err := cmd.CombinedOutput(); err != nil { | ||
log.Infof("Error while adding to table (%s): %v --> %s", cmd.String(), err, string(out)) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (ctx *pfContext) Delete(decision *models.Decision) error { | ||
banDuration, err := time.ParseDuration(*decision.Duration) | ||
if err != nil { | ||
return err | ||
} | ||
log.Debugf(delBanFormat, backendName, *decision.Value, strconv.Itoa(int(banDuration.Seconds())), *decision.Scenario) | ||
cmd := exec.Command(pfctlCmd, "-t", ctx.table, "-T", "delete", *decision.Value) | ||
log.Debugf("pfctl del : %s", cmd.String()) | ||
if out, err := cmd.CombinedOutput(); err != nil { | ||
log.Infof("Error while deleting from table (%s): %v --> %s", cmd.String(), err, string(out)) | ||
} | ||
return nil | ||
} | ||
|
||
func initPF(ctx *pfContext) error { | ||
|
||
if err := ctx.shutDown(); err != nil { | ||
return fmt.Errorf("pf table flush failed: %s", err.Error()) | ||
} | ||
if err := ctx.checkTable(); err != nil { | ||
return fmt.Errorf("pf init failed: %s", err.Error()) | ||
} | ||
log.Infof("%s initiated for %s", backendName, ctx.version) | ||
|
||
return nil | ||
} | ||
|
||
func (pf *pf) Init() error { | ||
|
||
if _, err := os.Stat(pfDevice); err != nil { | ||
return fmt.Errorf("%s device not found: %s", pfDevice, err.Error()) | ||
} | ||
|
||
if _, err := exec.LookPath(pfctlCmd); err != nil { | ||
return fmt.Errorf("%s command not found: %s", pfctlCmd, err.Error()) | ||
} | ||
|
||
if err := initPF(pf.inet); err != nil { | ||
return err | ||
} | ||
|
||
if pf.inet6 != nil { | ||
if err := initPF(pf.inet6); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (pf *pf) Add(decision *models.Decision) error { | ||
if strings.Contains(*decision.Value, ":") && pf.inet6 != nil { // inet6 | ||
if pf.inet6 != nil { | ||
if err := pf.inet6.Add(decision); err != nil { | ||
return fmt.Errorf("failed to add ban ip '%s' to inet6 table", *decision.Value) | ||
} | ||
} else { | ||
log.Debugf("not adding '%s' because ipv6 is disabled", *decision.Value) | ||
return nil | ||
} | ||
} else { // inet | ||
if err := pf.inet.Add(decision); err != nil { | ||
return fmt.Errorf("failed adding ban ip '%s' to inet table", *decision.Value) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (pf *pf) Delete(decision *models.Decision) error { | ||
if strings.Contains(*decision.Value, ":") { // ipv6 | ||
if pf.inet6 != nil { | ||
if err := pf.inet6.Delete(decision); err != nil { | ||
return fmt.Errorf("failed to remove ban ip '%s' from inet6 table", *decision.Value) | ||
} | ||
} else { | ||
log.Debugf("not removing '%s' because ipv6 is disabled", *decision.Value) | ||
return nil | ||
} | ||
} else { // ipv4 | ||
if err := pf.inet.Delete(decision); err != nil { | ||
return fmt.Errorf("failed to remove ban ip '%s' from inet6 table", *decision.Value) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (pf *pf) ShutDown() error { | ||
log.Infof("flushing 'crowdsec' table(s)") | ||
|
||
if err := pf.inet.shutDown(); err != nil { | ||
return fmt.Errorf("unable to flush %s table (%s): ", pf.inet.version, pf.inet.table) | ||
} | ||
|
||
if pf.inet6 != nil { | ||
if err := pf.inet6.shutDown(); err != nil { | ||
return fmt.Errorf("unable to flush %s table (%s): ", pf.inet6.version, pf.inet6.table) | ||
} | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// +build !openbsd,!freebsd | ||
|
||
package main | ||
|
||
func newPF(config *bouncerConfig) (interface{}, error) { | ||
return nil, nil | ||
} |