badguardhome/internal/storage/logs/logfile.go

132 lines
2.5 KiB
Go

package logfile
import (
"encoding/binary"
"net"
"sync"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
"github.com/AdguardTeam/AdGuardHome/internal/querylog"
"github.com/cockroachdb/pebble"
)
var magic = [8]byte{0xfe, 0xed, 0xbe, 0xef, 0x69, 0x00, 0x00, 0x00}
const BLOCK_SIZE = 1600
const BLOOM_SIZE_BITS = 500 * 64
const BLOOM_SIZE_BYTES = BLOOM_SIZE_BITS / 8
const BLOOM_SIZE_TOTAL = 8 + 8 + 8 + BLOOM_SIZE_BYTES
type LogStorage struct {
}
type LogBlock struct {
}
type ShapeStorage struct {
blocks []ShapeBlock
shapeCache map[string][8]byte
}
func (s *ShapeStorage) FindOrAdd(k []byte) [8]byte {
if len(k) <= 8 {
o := [8]byte{}
for i, v := range k {
o[i] = v
}
return o
}
return [8]byte{}
}
type ShapeBlock struct {
db *pebble.DB
sync.RWMutex
}
func (b *ShapeBlock) Open(name string) (err error) {
b.db, err = pebble.Open(name, &pebble.Options{})
if err != nil {
return nil
}
return nil
}
func (b *ShapeBlock) Add(k []byte) ([]byte, error) {
h := hash(k)
_, c, err := b.db.Get(h)
if err == pebble.ErrNotFound {
err = b.db.Set(h, k, pebble.Sync)
if err != nil {
return nil, err
}
return h, nil
} else if err != nil {
return nil, err
}
c.Close()
return h, nil
}
func (b *ShapeBlock) Get(h [4]byte) ([]byte, error) {
ans, c, err := b.db.Get(h[:])
if err != nil {
return nil, err
}
defer c.Close()
ansCopy := make([]byte, len(ans))
copy(ansCopy, ans)
return ansCopy, nil
}
// represents a single log entry in storage
type LogEntry struct {
IP net.IP `json:"IP"` // Client IP
Time time.Time `json:"T"`
QHost string `json:"QH"`
QType string `json:"QT"`
QClass string `json:"QC"`
ClientID string `json:"CID,omitempty"`
ClientProto querylog.ClientProto `json:"CP"`
Answer []byte `json:",omitempty"` // sometimes empty answers happen like binerdunt.top or rev2.globalrootservers.net
OrigAnswer []byte `json:",omitempty"`
Result filtering.Result
Elapsed time.Duration
Upstream string `json:",omitempty"` // if empty, means it was cached
}
func hash(b []byte) []byte {
const (
seed = 0xbc9f1d34
m = 0xc6a4a793
)
h := uint32(seed) ^ uint32(uint64(uint32(len(b))*m))
for ; len(b) >= 4; b = b[4:] {
h += uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
h *= m
h ^= h >> 16
}
switch len(b) {
case 3:
h += uint32(int8(b[2])) << 16
fallthrough
case 2:
h += uint32(int8(b[1])) << 8
fallthrough
case 1:
h += uint32(int8(b[0]))
h *= m
h ^= h >> 24
}
o := [4]byte{}
binary.LittleEndian.PutUint32(o[:], h)
return o[:]
}