132 lines
2.5 KiB
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[:]
|
|
}
|