Skip to content
This repository was archived by the owner on Apr 16, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ jobs:
- name: Build
run: go build -v .

# - name: Test
# run: go test -v .
- name: Test
run: go test -v ./...
2 changes: 1 addition & 1 deletion client/client_names.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (client *FTLClient) GetClientNames() (*[]Client, error) {
var clients []Client
for {
name, err := readString(conn)
if err == EOF {
if err == errEndOfInput {
break
}
if err != nil {
Expand Down
25 changes: 12 additions & 13 deletions client/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,22 @@
package client

import (
"encoding/binary"
"net"
)

// GetTopClients retrieves the list of clients together with amount of queries
// made by each client from response of `>top-clients` command
func (client *FTLClient) GetTopClients() (*Entries, error) {
func (client *FTLClient) GetTopClients() (*TopEntries, error) {
return topClientsFor(">top-clients", client)
}

// GetTopBlockedClients retrieves the list of clients together with amount of blocked
// queries made by each client from response of `>top-clients` command
func (client *FTLClient) GetTopBlockedClients() (*Entries, error) {
func (client *FTLClient) GetTopBlockedClients() (*TopEntries, error) {
return topClientsFor(">top-clients blocked", client)
}

func topClientsFor(command string, client *FTLClient) (*Entries, error) {
func topClientsFor(command string, client *FTLClient) (*TopEntries, error) {
conn, err := net.DialUnix("unix", nil, client.addr)
if err != nil {
return nil, err
Expand All @@ -41,15 +40,18 @@ func topClientsFor(command string, client *FTLClient) (*Entries, error) {
return nil, err
}

var result Entries

if err := binary.Read(conn, binary.BigEndian, &result.Total); err != nil {
total, err := readInt32(conn)
if err != nil {
return nil, err
}

result := TopEntries{
Total: total,
}

for {
_, err := readString(conn)
if err == EOF {
if err == errEndOfInput {
break
}
if err != nil {
Expand All @@ -61,15 +63,12 @@ func topClientsFor(command string, client *FTLClient) (*Entries, error) {
return nil, err
}

count, err := readUint32(conn)
count, err := readInt32(conn)
if err != nil {
return nil, err
}

result.List = append(result.List, struct {
Entry string
Count uint32
}{Entry: address, Count: count})
result.Entries = append(result.Entries, entry{Label: address, Count: count})
}

return &result, nil
Expand Down
22 changes: 7 additions & 15 deletions client/clients_over_time.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@
package client

import (
"encoding/binary"
"io"
"net"
)

// GetQueriesOverTime retrieves amount of queries grouped by client
// GetClientsOverTime retrieves amount of queries grouped by client
// for the last 24 hours aggregated over 10 minute intervals
// from response of `>ClientsoverTime` command
// Warning: API might be not public
Expand All @@ -36,29 +34,23 @@ func (client *FTLClient) GetClientsOverTime() (*[]TimestampClients, error) {

var timestamps []TimestampClients
for {
var format uint8
err := binary.Read(conn, binary.BigEndian, &format)

if err == io.EOF || format == formatEOF {
timestamp, err := readInt32(conn)
if err == errEndOfInput {
break
}

var clients []Int32Block

var timestamp uint32
err = binary.Read(conn, binary.BigEndian, &timestamp)
if err != nil {
return nil, err
}

var clients []int

for {
var clientQueryCount Int32Block
err := binary.Read(conn, binary.BigEndian, &clientQueryCount)
clientQueryCount, err := readInt32(conn)
if err != nil {
return nil, err
}

if clientQueryCount.Value == -1 {
if clientQueryCount == -1 {
break
}

Expand Down
15 changes: 11 additions & 4 deletions client/db_stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
package client

import (
"encoding/binary"
"net"
)

Expand All @@ -30,10 +29,18 @@ func (client *FTLClient) GetDBStats() (*DBStats, error) {
return nil, err
}

var stats DBStats
if err := binary.Read(conn, binary.BigEndian, &stats); err != nil {
rows, err := readInt32(conn)
if err != nil {
return nil, err
}

size, err := readInt64(conn)
if err != nil {
return nil, err
}

return &stats, nil
return &DBStats{
RowsCount: rows,
FileSize: size,
}, nil
}
24 changes: 12 additions & 12 deletions client/domains.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,22 @@
package client

import (
"encoding/binary"
"net"
)

// GetTopDomains retrieves the list of domains together with amount of queries
// made for each domain from response of `>top-domains` command
func (client *FTLClient) GetTopDomains() (*Entries, error) {
func (client *FTLClient) GetTopDomains() (*TopEntries, error) {
return topQueriesFor(">top-domains", client)
}

// GetTopAds retrieves the list of ad domains together with amount of queries
// made for each domain from response of `>top-ads` command
func (client *FTLClient) GetTopAds() (*Entries, error) {
func (client *FTLClient) GetTopAds() (*TopEntries, error) {
return topQueriesFor(">top-ads", client)
}

func topQueriesFor(command string, client *FTLClient) (*Entries, error) {
func topQueriesFor(command string, client *FTLClient) (*TopEntries, error) {
conn, err := net.DialUnix("unix", nil, client.addr)
if err != nil {
return nil, err
Expand All @@ -41,29 +40,30 @@ func topQueriesFor(command string, client *FTLClient) (*Entries, error) {
return nil, err
}

var result Entries
if err := binary.Read(conn, binary.BigEndian, &result.Total); err != nil {
total, err := readInt32(conn)
if err != nil {
return nil, err
}

result := TopEntries{
Total: int(total),
}

for {
domainName, err := readString(conn)
if err == EOF {
if err == errEndOfInput {
break
}
if err != nil {
return nil, err
}

domainCount, err := readUint32(conn)
domainCount, err := readInt32(conn)
if err != nil {
return nil, err
}

result.List = append(result.List, struct {
Entry string
Count uint32
}{Entry: domainName, Count: domainCount})
result.Entries = append(result.Entries, entry{Label: domainName, Count: domainCount})
}

return &result, nil
Expand Down
2 changes: 1 addition & 1 deletion client/forward_destinations.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (client *FTLClient) GetForwardDestinations() (*[]UpstreamDestination, error
var destinations []UpstreamDestination
for {
name, err := readString(conn)
if err == EOF {
if err == errEndOfInput {
break
}
if err != nil {
Expand Down
85 changes: 69 additions & 16 deletions client/ftl_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import (
)

const (
formatUint32 uint8 = 0xd2 // 210
formatInt32 uint8 = 0xd2 // 210
formatInt64 uint8 = 0xd3 // 211
formatFloat32 uint8 = 0xca // 202
formatUInt8 uint8 = 0xcc // 204
formatString uint8 = 0xdb // 219
Expand All @@ -31,8 +32,8 @@ const (
formatEOF uint8 = 0xc1 // 193
)

var EOF = errors.New("EOF")
var invalidFormat = errors.New("unexpected format")
var errEndOfInput = errors.New("end of the input")
var errInvalidFormat = errors.New("unexpected format")

// FTLClient for Pi-holes's FTL daemon. Contains address to a unix socket
type FTLClient struct {
Expand Down Expand Up @@ -66,18 +67,18 @@ func readString(conn *net.UnixConn) (string, error) {
var format uint8
if err := binary.Read(conn, binary.BigEndian, &format); err != nil {
if err == io.EOF {
return "", EOF
return "", errEndOfInput
}

return "", err
}

if format == formatEOF {
return "", EOF
return "", errEndOfInput
}

if format != formatString {
return "", invalidFormat
return "", errInvalidFormat
}

var length uint32
Expand All @@ -98,18 +99,18 @@ func readFloat32(conn *net.UnixConn) (float32, error) {
var format uint8
if err := binary.Read(conn, binary.BigEndian, &format); err != nil {
if err == io.EOF {
return 0.0, EOF
return 0.0, errEndOfInput
}

return 0.0, err
}

if format == formatEOF {
return 0.0, EOF
return 0.0, errEndOfInput
}

if format != formatFloat32 {
return 0.0, invalidFormat
return 0.0, errInvalidFormat
}

var value float32
Expand All @@ -120,30 +121,82 @@ func readFloat32(conn *net.UnixConn) (float32, error) {
return value, nil
}

func readUint32(conn *net.UnixConn) (uint32, error) {
func readInt32(conn *net.UnixConn) (int, error) {
var format uint8
if err := binary.Read(conn, binary.BigEndian, &format); err != nil {
if err == io.EOF {
return 0, EOF
return 0, errEndOfInput
}

return 0, err
}

if format == formatEOF {
return 0, EOF
return 0, errEndOfInput
}

if format != formatUint32 {
return 0, invalidFormat
if format != formatInt32 {
return 0, errInvalidFormat
}

var value uint32
var value int32
if err := binary.Read(conn, binary.BigEndian, &value); err != nil {
return 0, err
}

return value, nil
return int(value), nil
}

func readInt64(conn *net.UnixConn) (int, error) {
var format uint8
if err := binary.Read(conn, binary.BigEndian, &format); err != nil {
if err == io.EOF {
return 0, errEndOfInput
}

return 0, err
}

if format == formatEOF {
return 0, errEndOfInput
}

if format != formatInt64 {
return 0, errInvalidFormat
}

var value int64
if err := binary.Read(conn, binary.BigEndian, &value); err != nil {
return 0, err
}

return int(value), nil
}

func readMapCount(conn *net.UnixConn) (int, error) {
var format uint8
if err := binary.Read(conn, binary.BigEndian, &format); err != nil {
if err == io.EOF {
return 0, errEndOfInput
}

return 0, err
}

if format == formatEOF {
return 0, errEndOfInput
}

if format != formatMap16 {
return 0, errInvalidFormat
}

var value int16
if err := binary.Read(conn, binary.BigEndian, &value); err != nil {
return 0, err
}

return int(value), nil
}

func sendCommand(conn *net.UnixConn, command string) error {
Expand Down
Loading