support for sending commands over socket
Add support for sending a ping command to the fail2ban server over the socket file. This includes encoding the command data using og-rek and decoding the response using `gopickle`.
This commit is contained in:
parent
073ec89cb3
commit
86f8fd2c07
@ -3,6 +3,8 @@ module fail2ban-prometheus-exporter
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/kisielk/og-rek v1.1.0
|
||||
github.com/mattn/go-sqlite3 v1.14.6
|
||||
github.com/nlpodyssey/gopickle v0.1.0
|
||||
github.com/prometheus/client_golang v1.9.0
|
||||
)
|
||||
|
@ -137,6 +137,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kisielk/og-rek v1.1.0 h1:u10TvQbPtrlY/6H4+BiFsBywwSVTGFsx0YOVtpx3IbI=
|
||||
github.com/kisielk/og-rek v1.1.0/go.mod h1:6ihsOSzSAxR/65S3Bn9zNihoEqRquhDQZ2c6I2+MG3c=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
@ -175,6 +177,8 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE
|
||||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/nlpodyssey/gopickle v0.1.0 h1:9wjwRqXsOSYWZl4c4ko472b6RW+VB1I441ZcfFg1r5g=
|
||||
github.com/nlpodyssey/gopickle v0.1.0/go.mod h1:YIUwjJ2O7+vnBsxUN+MHAAI3N+adqEGiw+nDpwW95bY=
|
||||
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
|
8
src/socket/decoder.go
Normal file
8
src/socket/decoder.go
Normal file
@ -0,0 +1,8 @@
|
||||
package socket
|
||||
|
||||
// Py_builtins_str is used by the pickle decoder to parse the server response into a format Go can understand
|
||||
type Py_builtins_str struct{}
|
||||
|
||||
func (c Py_builtins_str) Call(args ...interface{}) (interface{}, error) {
|
||||
return args[0], nil
|
||||
}
|
38
src/socket/fail2banSocket.go
Normal file
38
src/socket/fail2banSocket.go
Normal file
@ -0,0 +1,38 @@
|
||||
package socket
|
||||
|
||||
import (
|
||||
"github.com/kisielk/og-rek"
|
||||
"log"
|
||||
"net"
|
||||
)
|
||||
|
||||
type Fail2BanSocket struct {
|
||||
socket net.Conn
|
||||
encoder *ogórek.Encoder
|
||||
}
|
||||
|
||||
func MustConnectToSocket(path string) *Fail2BanSocket {
|
||||
c, err := net.Dial("unix", path)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to open fail2ban socket: %v", err)
|
||||
}
|
||||
return &Fail2BanSocket{
|
||||
socket: c,
|
||||
encoder: ogórek.NewEncoderWithConfig(c, &ogórek.EncoderConfig{
|
||||
Protocol: 5,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Fail2BanSocket) Ping() bool {
|
||||
response, err := s.sendCommand([]string{pingCommand, "100"})
|
||||
if err != nil {
|
||||
log.Printf("server ping failed: %v", err)
|
||||
return false
|
||||
}
|
||||
if v, ok := response.([]string); ok && v[1] == "pong" {
|
||||
return true
|
||||
}
|
||||
log.Printf("unexpected response from server: %v", response)
|
||||
return false
|
||||
}
|
55
src/socket/protocol.go
Normal file
55
src/socket/protocol.go
Normal file
@ -0,0 +1,55 @@
|
||||
package socket
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/kisielk/og-rek"
|
||||
"github.com/nlpodyssey/gopickle/pickle"
|
||||
"net"
|
||||
)
|
||||
|
||||
const (
|
||||
commandTerminator = "<F2B_END_COMMAND>"
|
||||
pingCommand = "ping"
|
||||
socketReadBufferSize = 10000
|
||||
)
|
||||
|
||||
func (s *Fail2BanSocket) sendCommand(command []string) (interface{}, error) {
|
||||
err := write(s.encoder, command)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return read(&s.socket)
|
||||
}
|
||||
|
||||
func write(encoder *ogórek.Encoder, command []string) error {
|
||||
err := encoder.Encode(command)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = encoder.Encode(commandTerminator)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func read(s *net.Conn) (interface{}, error) {
|
||||
buf := make([]byte, socketReadBufferSize)
|
||||
_, err := (*s).Read(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bufReader := bytes.NewReader(buf)
|
||||
unpickler := pickle.NewUnpickler(bufReader)
|
||||
|
||||
unpickler.FindClass = func(module, name string) (interface{}, error) {
|
||||
if module == "builtins" && name == "str" {
|
||||
return &Py_builtins_str{}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("class not found: " + module + " : " + name)
|
||||
}
|
||||
|
||||
return unpickler.Load()
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user