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[:] }