Draw the actual rest of the fucking owl.
Change-Id: Ia04fb49ebbe3a5afccc57e62f6335e35b45192fe
diff --git a/bgpwtf/cccampix/verifier/model/config.go b/bgpwtf/cccampix/verifier/model/config.go
index bafd46f..1cbd2d7 100644
--- a/bgpwtf/cccampix/verifier/model/config.go
+++ b/bgpwtf/cccampix/verifier/model/config.go
@@ -4,6 +4,8 @@
"context"
"database/sql"
"fmt"
+ "net"
+ "strconv"
)
func (m *sqlModel) ConfigureMissingSessions(ctx context.Context, gen func() SessionConfig) error {
@@ -49,3 +51,75 @@
return tx.Commit()
}
+
+func (m *sqlModel) GetPeerConfiguration(ctx context.Context) ([]*PeerConfiguration, error) {
+ q := `
+ SELECT
+ peers.asn "asn",
+ peer_pgp_keys.fingerprint "peer_pgp_keys.fingerprint",
+ peer_routers.v6 "peer_routers.v6", peer_routers.v4 "peer_routers.v4",
+ session_configs.bgp_secret "session_configs.bgp_secret"
+ FROM session_configs
+ LEFT JOIN peer_routers
+ ON peer_routers.id = session_configs.peer_router_id
+ INNER JOIN peer_pgp_keys
+ ON peer_pgp_keys.peer_id = session_configs.peer_id
+ LEFT JOIN peers
+ on peers.id = session_configs.peer_id
+ `
+
+ data := []struct {
+ PGP sqlPeerPGPKey `db:"peer_pgp_keys"`
+ Config sqlSessionConfig `db:"session_configs"`
+ Router sqlPeerRouter `db:"peer_routers"`
+ ASN string `db:"asn"`
+ }{}
+
+ if err := m.db.SelectContext(ctx, &data, q); err != nil {
+ return nil, fmt.Errorf("SELECT peers/peer_pgp_keys/session_configs: %v", err)
+ }
+
+ resM := make(map[string]*PeerConfiguration)
+
+ for _, d := range data {
+ k := fmt.Sprintf("%s", d.ASN)
+ r, ok := resM[k]
+ if !ok {
+ asn, err := strconv.ParseInt(d.ASN, 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("data corruption: invalid ASN %q", d.ASN)
+ }
+ r = &PeerConfiguration{
+ Peer: Peer{
+ ASN: asn,
+ Routers: []*Router{},
+ },
+ Key: PeerPGPKey{
+ PeerASN: asn,
+ Fingerprint: d.PGP.Fingerprint,
+ },
+ }
+ resM[k] = r
+ }
+
+ v6 := net.ParseIP(d.Router.V6.String)
+ v4 := net.ParseIP(d.Router.V4.String)
+ secret := d.Config.BGPSecret
+ r.Peer.Routers = append(r.Peer.Routers, &Router{
+ V6: v6,
+ V4: v4,
+ Config: &SessionConfig{
+ BGPSecret: secret,
+ },
+ })
+ }
+
+ res := make([]*PeerConfiguration, len(resM))
+ i := 0
+ for _, pc := range resM {
+ res[i] = pc
+ i += 1
+ }
+
+ return res, nil
+}
diff --git a/bgpwtf/cccampix/verifier/model/migrations/1565806867_pgp_key_state.down.sql b/bgpwtf/cccampix/verifier/model/migrations/1565806867_pgp_key_state.down.sql
new file mode 100644
index 0000000..a768e04
--- /dev/null
+++ b/bgpwtf/cccampix/verifier/model/migrations/1565806867_pgp_key_state.down.sql
@@ -0,0 +1,3 @@
+set sql_safe_updates=false;
+ALTER TABLE peer_pgp_keys DROP COLUMN state;
+set sql_safe_updates=true;
diff --git a/bgpwtf/cccampix/verifier/model/migrations/1565806867_pgp_key_state.up.sql b/bgpwtf/cccampix/verifier/model/migrations/1565806867_pgp_key_state.up.sql
new file mode 100644
index 0000000..e7d7fd4
--- /dev/null
+++ b/bgpwtf/cccampix/verifier/model/migrations/1565806867_pgp_key_state.up.sql
@@ -0,0 +1,2 @@
+ALTER TABLE peer_pgp_keys ADD COLUMN state STRING check ( state = 'unchecked' or state = 'unknown' or state = 'known' ) NOT NULL DEFAULT 'unchecked';
+ALTER TABLE peer_pgp_keys ALTER COLUMN state DROP DEFAULT;
diff --git a/bgpwtf/cccampix/verifier/model/model.go b/bgpwtf/cccampix/verifier/model/model.go
index b9b81c9..53294dd 100644
--- a/bgpwtf/cccampix/verifier/model/model.go
+++ b/bgpwtf/cccampix/verifier/model/model.go
@@ -23,40 +23,48 @@
GetPeeringDBPeer(ctx context.Context, asn int64) (*pb.PeeringDBMember, error)
GetCheckablePeers(ctx context.Context) ([]*Peer, error)
- SubmitPeerCheckResults(ctx context.Context, res []*PeerCheckResult) error
+ SubmitPeerCheckResults(ctx context.Context, checkName string, res []*PeerCheckResult) error
GetPeerCheckResults(ctx context.Context, asn []int64) ([]*PeerCheckResult, error)
UpdatePGPKey(ctx context.Context, key *PeerPGPKey) error
+ GetPGPKeysRequiringAttention(ctx context.Context) ([]*PeerPGPKey, error)
+ ValidatePGPKeys(ctx context.Context, positive, negative []string) error
+ GetPeerPGPKey(ctx context.Context, asn int64) (*PeerPGPKey, error)
ConfigureMissingSessions(ctx context.Context, gen func() SessionConfig) error
+ GetPeerConfiguration(ctx context.Context) ([]*PeerConfiguration, error)
+
UpdateAllowedPrefixes(ctx context.Context, asn int64, prefixes []*AllowedPrefix) error
GetAllowedPrefixes(ctx context.Context, asn int64) ([]*AllowedPrefix, error)
}
-type stringer struct {
+type Router struct {
+ V6 net.IP
+ V4 net.IP
+ Config *SessionConfig
}
-func (s *stringer) String() string {
- if s == nil {
+func (p *Router) String() string {
+ if p == nil {
return "<nil>"
}
- return fmt.Sprintf("%+v", *s)
-}
-
-type Router struct {
- stringer
- V6 net.IP
- V4 net.IP
+ return fmt.Sprintf("%+v", *p)
}
type Peer struct {
- stringer
ASN int64
Name string
Routers []*Router
}
+func (p *Peer) String() string {
+ if p == nil {
+ return "<nil>"
+ }
+ return fmt.Sprintf("%+v", *p)
+}
+
type PeerCheckStatus int
const (
@@ -82,15 +90,41 @@
}
type PeerPGPKey struct {
- stringer
PeerASN int64
Fingerprint string
+ State string
+}
+
+func (p *PeerPGPKey) String() string {
+ if p == nil {
+ return "<nil>"
+ }
+ return fmt.Sprintf("%+v", *p)
}
type SessionConfig struct {
BGPSecret string
}
+func (p *SessionConfig) String() string {
+ if p == nil {
+ return "<nil>"
+ }
+ return fmt.Sprintf("%+v", *p)
+}
+
+type PeerConfiguration struct {
+ Peer Peer
+ Key PeerPGPKey
+}
+
+func (p *PeerConfiguration) String() string {
+ if p == nil {
+ return "<nil>"
+ }
+ return fmt.Sprintf("%+v", *p)
+}
+
type AllowedPrefix struct {
Prefix net.IPNet
MaxLength int64
diff --git a/bgpwtf/cccampix/verifier/model/pgp.go b/bgpwtf/cccampix/verifier/model/pgp.go
index a76186e..9292c45 100644
--- a/bgpwtf/cccampix/verifier/model/pgp.go
+++ b/bgpwtf/cccampix/verifier/model/pgp.go
@@ -2,22 +2,26 @@
import (
"context"
+ "database/sql"
"fmt"
+ "strconv"
"time"
)
func (s *sqlModel) UpdatePGPKey(ctx context.Context, key *PeerPGPKey) error {
q := `
INSERT INTO peer_pgp_keys
- (peer_id, fingerprint, time_created)
+ (peer_id, fingerprint, time_created, state)
SELECT
- peers.id, :fingerprint, :time_created
+ peers.id, :fingerprint, :time_created, 'unchecked'
FROM peers
WHERE peers.asn = :asn
ON CONFLICT (peer_id)
DO UPDATE SET
fingerprint = :fingerprint,
- time_created = :time_created
+ time_created = :time_created,
+ state = 'unchecked'
+ WHERE peer_pgp_keys.fingerprint != excluded.fingerprint
`
data := &sqlPeerPGPKey{
Fingerprint: key.Fingerprint,
@@ -29,3 +33,105 @@
}
return nil
}
+
+func (s *sqlModel) GetPGPKeysRequiringAttention(ctx context.Context) ([]*PeerPGPKey, error) {
+ q := `
+ SELECT
+ peer_pgp_keys.fingerprint "fingerprint",
+ peer_pgp_keys.state "state",
+ peers.asn "asn"
+ FROM peer_pgp_keys
+ LEFT JOIN peers
+ ON peers.id = peer_pgp_keys.peer_id
+ WHERE
+ peer_pgp_keys.state = 'unchecked'
+ OR
+ peer_pgp_keys.state = 'known'
+ OR (
+ peer_pgp_keys.state = 'unknown' AND
+ peer_pgp_keys.time_created > $1
+ )
+ `
+
+ data := []sqlPeerPGPKey{}
+ timestamp := time.Now().Add(-time.Hour).UnixNano()
+ if err := s.db.SelectContext(ctx, &data, q, timestamp); err != nil {
+ return nil, fmt.Errorf("SELECT peer_pgp_keys: %v", err)
+ }
+
+ res := make([]*PeerPGPKey, len(data))
+ for i, datum := range data {
+ asn, err := strconv.ParseInt(datum.ASN, 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("data corruption: peer_pgp_keys as ASN %q", datum.ASN)
+ }
+ res[i] = &PeerPGPKey{
+ Fingerprint: datum.Fingerprint,
+ State: datum.State,
+ PeerASN: asn,
+ }
+ }
+
+ return res, nil
+}
+
+func (s *sqlModel) ValidatePGPKeys(ctx context.Context, positive, negative []string) error {
+ tx := s.db.MustBeginTx(ctx, &sql.TxOptions{})
+ defer tx.Rollback()
+
+ timestamp := time.Now().UnixNano()
+
+ for _, p := range positive {
+ q := `
+ UPDATE
+ peer_pgp_keys
+ SET
+ state = 'known',
+ time_created = $2
+ WHERE
+ fingerprint = $1
+ `
+
+ if _, err := tx.ExecContext(ctx, q, p, timestamp); err != nil {
+ return fmt.Errorf("UPDATE peer_pgp_keys: %v", err)
+ }
+ }
+
+ for _, n := range negative {
+ q := `
+ UPDATE
+ peer_pgp_keys
+ SET
+ state = 'unknown',
+ time_created = $2
+ WHERE
+ fingerprint = $1
+ `
+
+ if _, err := tx.ExecContext(ctx, q, n, timestamp); err != nil {
+ return fmt.Errorf("UPDATE peer_pgp_keys: %v", err)
+ }
+ }
+
+ return tx.Commit()
+}
+
+func (s *sqlModel) GetPeerPGPKey(ctx context.Context, asn int64) (*PeerPGPKey, error) {
+ q := `
+ SELECT peer_pgp_keys.fingerprint
+ FROM peer_pgp_keys
+ LEFT JOIN peers
+ ON peers.id = peer_pgp_keys.peer_id
+ WHERE peers.asn = $1
+ `
+ data := []*PeerPGPKey{}
+ if err := s.db.SelectContext(ctx, &data, q, asn); err != nil {
+ return nil, fmt.Errorf("SELECT peer_pgp_keys: %v", err)
+ }
+
+ if len(data) != 1 {
+ return nil, fmt.Errorf("wrong number of peer_pgp_keys (%d)", len(data))
+ }
+
+ return data[0], nil
+}
diff --git a/bgpwtf/cccampix/verifier/model/schema.go b/bgpwtf/cccampix/verifier/model/schema.go
index 093ecc8..1a483c2 100644
--- a/bgpwtf/cccampix/verifier/model/schema.go
+++ b/bgpwtf/cccampix/verifier/model/schema.go
@@ -38,6 +38,7 @@
PeerID string `db:"peer_id"`
Fingerprint string `db:"fingerprint"`
TimeCreated int64 `db:"time_created"`
+ State string `db:"state"`
// Fake, used by app logic.
ASN string `db:"asn"`
diff --git a/bgpwtf/cccampix/verifier/model/submit_checks.go b/bgpwtf/cccampix/verifier/model/submit_checks.go
index 79e2a84..0586766 100644
--- a/bgpwtf/cccampix/verifier/model/submit_checks.go
+++ b/bgpwtf/cccampix/verifier/model/submit_checks.go
@@ -8,15 +8,21 @@
"github.com/golang/glog"
)
-func (s *sqlModel) SubmitPeerCheckResults(ctx context.Context, res []*PeerCheckResult) error {
+func (s *sqlModel) SubmitPeerCheckResults(ctx context.Context, checkName string, res []*PeerCheckResult) error {
tx := s.db.MustBeginTx(ctx, &sql.TxOptions{})
defer tx.Rollback()
+ glog.Infof("SubmitPeerCheckResults:")
+ for _, r := range res {
+ glog.Infof(" - %+v", *r)
+ }
+
q := `
UPDATE peer_checks
SET delete = true
+ WHERE check_name = $1
`
- if _, err := tx.ExecContext(ctx, q); err != nil {
+ if _, err := tx.ExecContext(ctx, q, checkName); err != nil {
return fmt.Errorf("UPDATE for deletion peer_checks: %v", err)
}
@@ -64,8 +70,9 @@
q = `
DELETE FROM peer_checks
WHERE delete = true
+ AND check_name = $1
`
- if _, err := tx.ExecContext(ctx, q); err != nil {
+ if _, err := tx.ExecContext(ctx, q, checkName); err != nil {
return fmt.Errorf("DELETE FROM peer_checks: %v", err)
}