163 lines
3.0 KiB
Go
163 lines
3.0 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"crypto/sha512"
|
|
"encoding/base64"
|
|
"errors"
|
|
"github.com/miekg/dns"
|
|
log "github.com/sirupsen/logrus"
|
|
"github.com/syndtr/goleveldb/leveldb"
|
|
"github.com/syndtr/goleveldb/leveldb/util"
|
|
"math"
|
|
"math/big"
|
|
"os"
|
|
"path"
|
|
"strings"
|
|
"time"
|
|
"github.com/patrickmn/go-cache"
|
|
)
|
|
|
|
type Database struct {
|
|
_db *leveldb.DB
|
|
_cache *cache.Cache
|
|
_zone string
|
|
}
|
|
|
|
func (d *Database) ExistHost(host string) bool {
|
|
ret, err := d._db.Has([]byte("hosts/" + host), nil)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func (d *Database) DeleteHost(host string) bool {
|
|
err := d._db.Delete([]byte("hosts/" + host), nil)
|
|
return err == nil
|
|
}
|
|
|
|
func (d *Database) GetExistingHosts(match string) map[string]string {
|
|
iter := d._db.NewIterator(util.BytesPrefix([]byte("hosts/" + match)), nil)
|
|
ret := make(map[string]string)
|
|
for iter.Next() {
|
|
hostname := strings.TrimPrefix(string(iter.Key()), "hosts/")
|
|
ret[hostname] = string(iter.Value())
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func (d *Database) Authorize(host string, token_user string) bool {
|
|
|
|
token, err := d._db.Get([]byte("hosts/" + host), nil)
|
|
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
if len(token) < sha512.Size {
|
|
return false
|
|
}
|
|
|
|
if len(token_user) < sha512.Size {
|
|
return false
|
|
}
|
|
|
|
if string(token) == token_user {
|
|
return true
|
|
}
|
|
|
|
log.Error(string(token), "!=", token_user)
|
|
|
|
return false
|
|
}
|
|
|
|
func generateToken() string {
|
|
maxInt := big.NewInt(math.MaxInt64)
|
|
randInt, err := rand.Int(rand.Reader, maxInt)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
h_plain := []byte(randInt.String() + time.Now().String())
|
|
|
|
h:= sha256.Sum256(h_plain)
|
|
|
|
for i:=0;i<10000; i++ {
|
|
h = sha256.Sum256(h[:])
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
base64.NewEncoder(base64.URLEncoding, &buf).Write(h[:])
|
|
return buf.String()
|
|
}
|
|
|
|
func (d *Database) IsBannedHost(host string) bool {
|
|
val, ok := d._cache.Get(host)
|
|
var counter int
|
|
if ok {
|
|
counter = val.(int)
|
|
if counter > 3 {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
|
|
func (d *Database) IncrementBanHost(host string) {
|
|
_, ok := d._cache.Get(host)
|
|
if ok {
|
|
d._cache.IncrementInt(host,1)
|
|
} else {
|
|
d._cache.Add(host, 1, cache.DefaultExpiration)
|
|
}
|
|
}
|
|
|
|
|
|
func (d *Database) CreateHost(host string) (string, error) {
|
|
if d.ExistHost(host) {
|
|
return "", errors.New("host already existent")
|
|
}
|
|
|
|
if host == "" {
|
|
return "", errors.New("given hostname is empty")
|
|
}
|
|
|
|
if _, ok := dns.IsDomainName(host + "." + d._zone); !ok {
|
|
return "", errors.New("given hostname is invalid")
|
|
}
|
|
|
|
|
|
token := generateToken()
|
|
d._db.Put([]byte("hosts/" + host), []byte(token), nil)
|
|
|
|
return token, nil
|
|
}
|
|
|
|
|
|
func CreateDatabase(config *Config) (*Database, error){
|
|
_, err := os.Stat(config.DataDir)
|
|
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
os.MkdirAll(config.DataDir, os.ModeDir)
|
|
}
|
|
}
|
|
|
|
file := path.Join(config.DataDir, "ddnsService.db")
|
|
store, err := leveldb.OpenFile(file, nil)
|
|
db := cache.New(5*time.Minute, 10*time.Minute)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Database{_db: store, _cache: db}, nil
|
|
|
|
}
|