base ping audit impl (SSH handshake)
parent
df48ee3ce6
commit
8c0bbe8eb4
|
@ -13,6 +13,7 @@ This repository contains the base chain implementation that Colinear's compute m
|
|||
| :-------- | :-------- |
|
||||
| Leasing & settlement module | [x/colinearcore](./x/colinearcore/README.md) |
|
||||
| In-memory bid database | [x/colinearcore/memdb](./x/colinearcore/memdb/README.md) |
|
||||
| Hardware provider auditing | [x/colinearcore/audit](./x/colinearcore/audit/README.md) |
|
||||
|
||||
## Validators
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
# Peer Auditing
|
||||
|
||||
The auditing mechanism contained in this folder ensures that hardware providers are running the hardware they say they are. The basic requirements will be as follows:
|
||||
|
||||
| Requirement | Punishment |
|
||||
| :-- | :-- |
|
||||
| Must stake a set amount of CLR. | N/A |
|
||||
| Must complete a GPU puzzle for each declared GPU. | N/A |
|
||||
| Must be online for validator pings | Staked funds slashed |
|
||||
|
||||
## GPU Puzzle
|
||||
|
||||
Work in progress.
|
||||
|
||||
## Validator Pings
|
||||
|
||||
Attempts to perform an SSH handshake using Go's builtin `crypto/ssh`. If the handshake times out, this means that practically speaking, the provider is offline.
|
|
@ -0,0 +1,109 @@
|
|||
package audit
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/dgraph-io/badger/v2"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// Maps SSH ping result channel to address that is being pinged
|
||||
var pingDB *badger.DB
|
||||
|
||||
func MountPingDB() {
|
||||
var err error
|
||||
pingDB, err = badger.Open(badger.DefaultOptions("").WithInMemory(true))
|
||||
if err != nil {
|
||||
// must force crash here, since ping db is absolutely required
|
||||
log.Fatalf("Failed to mount in-memory db: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Begin ping to check if SSH is running on an open port on a host.
|
||||
//
|
||||
// NOTE: host should include a port number.
|
||||
func BeginSshPing(host string) error {
|
||||
|
||||
k := []byte(host)
|
||||
|
||||
err := pingDB.Update(func(txn *badger.Txn) error {
|
||||
_, err := txn.Get(k)
|
||||
if err != nil {
|
||||
if !errors.Is(err, badger.ErrKeyNotFound) {
|
||||
// key-not-found condition required to write
|
||||
return err
|
||||
} else {
|
||||
goto writePing
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("already pinging host %s", host)
|
||||
|
||||
writePing:
|
||||
if err := txn.Set(k, []byte(strconv.FormatBool(false))); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sshConfig := &ssh.ClientConfig{
|
||||
User: "user",
|
||||
Auth: []ssh.AuthMethod{ssh.Password("pass")},
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
Timeout: 100 * time.Second,
|
||||
}
|
||||
|
||||
go dialSshAsync(host, sshConfig)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check on ongoing SSH ping
|
||||
func CheckSshPing(host string) (bool, error) {
|
||||
k := []byte(host)
|
||||
|
||||
var pingStatus bool
|
||||
|
||||
err := pingDB.View(func(txn *badger.Txn) error {
|
||||
resVal, err := txn.Get(k)
|
||||
if err != nil {
|
||||
if !errors.Is(err, badger.ErrKeyNotFound) {
|
||||
return err
|
||||
} else {
|
||||
return fmt.Errorf("not pinging host %s", host)
|
||||
}
|
||||
}
|
||||
|
||||
err = resVal.Value(func(val []byte) error {
|
||||
pingStatus, err = strconv.ParseBool(string(val))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode ping status for host %s: %s", host, string(val))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return pingStatus, nil
|
||||
}
|
||||
|
||||
func dialSshAsync(host string, conf *ssh.ClientConfig) {
|
||||
ssh.Dial("tcp", host, conf)
|
||||
pingDB.Update(func(txn *badger.Txn) error {
|
||||
k := []byte(host)
|
||||
return txn.Set(k, []byte(strconv.FormatBool(true)))
|
||||
})
|
||||
// any potential resulting error is swallowed since this is run asynchronously
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package audit
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestCheckSSH(t *testing.T) {
|
||||
|
||||
MountPingDB()
|
||||
|
||||
host1 := "102.1.41.3:22" // should evaluate to false
|
||||
host2 := "127.0.0.1:22" // should evaluate to true
|
||||
|
||||
if err := BeginSshPing(host1); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := BeginSshPing(host2); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
res, err := CheckSshPing(host1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if res {
|
||||
panic("check host 1 - res should be false")
|
||||
}
|
||||
|
||||
res2, err := CheckSshPing(host2)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !res2 {
|
||||
panic("check host 2 - res should be true")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue