summaryrefslogtreecommitdiffstats
path: root/src/go/collectors/go.d.plugin/modules/freeradius/api/client.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/go/collectors/go.d.plugin/modules/freeradius/api/client.go174
1 files changed, 174 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/freeradius/api/client.go b/src/go/collectors/go.d.plugin/modules/freeradius/api/client.go
new file mode 100644
index 000000000..01f784c17
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/freeradius/api/client.go
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package api
+
+import (
+ "context"
+ "crypto/hmac"
+ "crypto/md5"
+ "fmt"
+ "net"
+ "strconv"
+ "time"
+
+ "layeh.com/radius"
+ "layeh.com/radius/rfc2869"
+)
+
+type Status struct {
+ AccessRequests int64 `stm:"access-requests"`
+ AccessAccepts int64 `stm:"access-accepts"`
+ AccessRejects int64 `stm:"access-rejects"`
+ AccessChallenges int64 `stm:"access-challenges"`
+ AuthResponses int64 `stm:"auth-responses"`
+ AuthDuplicateRequests int64 `stm:"auth-duplicate-requests"`
+ AuthMalformedRequests int64 `stm:"auth-malformed-requests"`
+ AuthInvalidRequests int64 `stm:"auth-invalid-requests"`
+ AuthDroppedRequests int64 `stm:"auth-dropped-requests"`
+ AuthUnknownTypes int64 `stm:"auth-unknown-types"`
+
+ AccountingRequests int64 `stm:"accounting-requests"`
+ AccountingResponses int64 `stm:"accounting-responses"`
+ AcctDuplicateRequests int64 `stm:"acct-duplicate-requests"`
+ AcctMalformedRequests int64 `stm:"acct-malformed-requests"`
+ AcctInvalidRequests int64 `stm:"acct-invalid-requests"`
+ AcctDroppedRequests int64 `stm:"acct-dropped-requests"`
+ AcctUnknownTypes int64 `stm:"acct-unknown-types"`
+
+ ProxyAccessRequests int64 `stm:"proxy-access-requests"`
+ ProxyAccessAccepts int64 `stm:"proxy-access-accepts"`
+ ProxyAccessRejects int64 `stm:"proxy-access-rejects"`
+ ProxyAccessChallenges int64 `stm:"proxy-access-challenges"`
+ ProxyAuthResponses int64 `stm:"proxy-auth-responses"`
+ ProxyAuthDuplicateRequests int64 `stm:"proxy-auth-duplicate-requests"`
+ ProxyAuthMalformedRequests int64 `stm:"proxy-auth-malformed-requests"`
+ ProxyAuthInvalidRequests int64 `stm:"proxy-auth-invalid-requests"`
+ ProxyAuthDroppedRequests int64 `stm:"proxy-auth-dropped-requests"`
+ ProxyAuthUnknownTypes int64 `stm:"proxy-auth-unknown-types"`
+
+ ProxyAccountingRequests int64 `stm:"proxy-accounting-requests"`
+ ProxyAccountingResponses int64 `stm:"proxy-accounting-responses"`
+ ProxyAcctDuplicateRequests int64 `stm:"proxy-acct-duplicate-requests"`
+ ProxyAcctMalformedRequests int64 `stm:"proxy-acct-malformed-requests"`
+ ProxyAcctInvalidRequests int64 `stm:"proxy-acct-invalid-requests"`
+ ProxyAcctDroppedRequests int64 `stm:"proxy-acct-dropped-requests"`
+ ProxyAcctUnknownTypes int64 `stm:"proxy-acct-unknown-types"`
+}
+
+type (
+ radiusClient interface {
+ Exchange(ctx context.Context, packet *radius.Packet, address string) (*radius.Packet, error)
+ }
+ Config struct {
+ Address string
+ Port int
+ Secret string
+ Timeout time.Duration
+ }
+ Client struct {
+ address string
+ secret string
+ timeout time.Duration
+ radiusClient
+ }
+)
+
+func New(conf Config) *Client {
+ return &Client{
+ address: net.JoinHostPort(conf.Address, strconv.Itoa(conf.Port)),
+ secret: conf.Secret,
+ timeout: conf.Timeout,
+ radiusClient: &radius.Client{Retry: time.Second, MaxPacketErrors: 10},
+ }
+}
+
+func (c Client) Status() (*Status, error) {
+ packet, err := newStatusServerPacket(c.secret)
+ if err != nil {
+ return nil, fmt.Errorf("error on creating StatusServer packet: %v", err)
+ }
+
+ resp, err := c.queryServer(packet)
+ if err != nil {
+ return nil, fmt.Errorf("error on request to '%s': %v", c.address, err)
+ }
+
+ return decodeResponse(resp), nil
+}
+
+func (c Client) queryServer(packet *radius.Packet) (*radius.Packet, error) {
+ ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
+ defer cancel()
+
+ resp, err := c.Exchange(ctx, packet, c.address)
+ if err != nil {
+ return nil, err
+ }
+
+ if resp.Code != radius.CodeAccessAccept {
+ return nil, fmt.Errorf("'%s' returned response code %d", c.address, resp.Code)
+ }
+ return resp, nil
+}
+
+func newStatusServerPacket(secret string) (*radius.Packet, error) {
+ // https://wiki.freeradius.org/config/Status#status-of-freeradius-server
+ packet := radius.New(radius.CodeStatusServer, []byte(secret))
+ if err := FreeRADIUSStatisticsType_Set(packet, FreeRADIUSStatisticsType_Value_All); err != nil {
+ return nil, err
+ }
+ if err := rfc2869.MessageAuthenticator_Set(packet, make([]byte, 16)); err != nil {
+ return nil, err
+ }
+ hash := hmac.New(md5.New, packet.Secret)
+ encode, err := packet.Encode()
+ if err != nil {
+ return nil, err
+ }
+ if _, err := hash.Write(encode); err != nil {
+ return nil, err
+ }
+ if err := rfc2869.MessageAuthenticator_Set(packet, hash.Sum(nil)); err != nil {
+ return nil, err
+ }
+ return packet, nil
+}
+
+func decodeResponse(resp *radius.Packet) *Status {
+ return &Status{
+ AccessRequests: int64(FreeRADIUSTotalAccessRequests_Get(resp)),
+ AccessAccepts: int64(FreeRADIUSTotalAccessAccepts_Get(resp)),
+ AccessRejects: int64(FreeRADIUSTotalAccessRejects_Get(resp)),
+ AccessChallenges: int64(FreeRADIUSTotalAccessChallenges_Get(resp)),
+ AuthResponses: int64(FreeRADIUSTotalAuthResponses_Get(resp)),
+ AuthDuplicateRequests: int64(FreeRADIUSTotalAuthDuplicateRequests_Get(resp)),
+ AuthMalformedRequests: int64(FreeRADIUSTotalAuthMalformedRequests_Get(resp)),
+ AuthInvalidRequests: int64(FreeRADIUSTotalAuthInvalidRequests_Get(resp)),
+ AuthDroppedRequests: int64(FreeRADIUSTotalAuthDroppedRequests_Get(resp)),
+ AuthUnknownTypes: int64(FreeRADIUSTotalAuthUnknownTypes_Get(resp)),
+ AccountingRequests: int64(FreeRADIUSTotalAccountingRequests_Get(resp)),
+ AccountingResponses: int64(FreeRADIUSTotalAccountingResponses_Get(resp)),
+ AcctDuplicateRequests: int64(FreeRADIUSTotalAcctDuplicateRequests_Get(resp)),
+ AcctMalformedRequests: int64(FreeRADIUSTotalAcctMalformedRequests_Get(resp)),
+ AcctInvalidRequests: int64(FreeRADIUSTotalAcctInvalidRequests_Get(resp)),
+ AcctDroppedRequests: int64(FreeRADIUSTotalAcctDroppedRequests_Get(resp)),
+ AcctUnknownTypes: int64(FreeRADIUSTotalAcctUnknownTypes_Get(resp)),
+ ProxyAccessRequests: int64(FreeRADIUSTotalProxyAccessRequests_Get(resp)),
+ ProxyAccessAccepts: int64(FreeRADIUSTotalProxyAccessAccepts_Get(resp)),
+ ProxyAccessRejects: int64(FreeRADIUSTotalProxyAccessRejects_Get(resp)),
+ ProxyAccessChallenges: int64(FreeRADIUSTotalProxyAccessChallenges_Get(resp)),
+ ProxyAuthResponses: int64(FreeRADIUSTotalProxyAuthResponses_Get(resp)),
+ ProxyAuthDuplicateRequests: int64(FreeRADIUSTotalProxyAuthDuplicateRequests_Get(resp)),
+ ProxyAuthMalformedRequests: int64(FreeRADIUSTotalProxyAuthMalformedRequests_Get(resp)),
+ ProxyAuthInvalidRequests: int64(FreeRADIUSTotalProxyAuthInvalidRequests_Get(resp)),
+ ProxyAuthDroppedRequests: int64(FreeRADIUSTotalProxyAuthDroppedRequests_Get(resp)),
+ ProxyAuthUnknownTypes: int64(FreeRADIUSTotalProxyAuthUnknownTypes_Get(resp)),
+ ProxyAccountingRequests: int64(FreeRADIUSTotalProxyAccountingRequests_Get(resp)),
+ ProxyAccountingResponses: int64(FreeRADIUSTotalProxyAccountingResponses_Get(resp)),
+ ProxyAcctDuplicateRequests: int64(FreeRADIUSTotalProxyAcctDuplicateRequests_Get(resp)),
+ ProxyAcctMalformedRequests: int64(FreeRADIUSTotalProxyAcctMalformedRequests_Get(resp)),
+ ProxyAcctInvalidRequests: int64(FreeRADIUSTotalProxyAcctInvalidRequests_Get(resp)),
+ ProxyAcctDroppedRequests: int64(FreeRADIUSTotalProxyAcctDroppedRequests_Get(resp)),
+ ProxyAcctUnknownTypes: int64(FreeRADIUSTotalProxyAcctUnknownTypes_Get(resp)),
+ }
+}