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 }