WIP - cleanup / local discovery
This commit is contained in:
parent
f47a8245b4
commit
8407fd5b48
@ -15,6 +15,7 @@ import (
|
|||||||
"git.crumpington.com/lib/go/sqliteutil"
|
"git.crumpington.com/lib/go/sqliteutil"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
"golang.org/x/crypto/nacl/box"
|
"golang.org/x/crypto/nacl/box"
|
||||||
|
"golang.org/x/crypto/nacl/sign"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed migrations
|
//go:embed migrations
|
||||||
@ -24,6 +25,7 @@ type API struct {
|
|||||||
db *sql.DB
|
db *sql.DB
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
peerIntents map[string]PeerCreateArgs
|
peerIntents map[string]PeerCreateArgs
|
||||||
|
initIntents map[string]byte // Map from intent key to peer IP
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(dbPath string) (*API, error) {
|
func New(dbPath string) (*API, error) {
|
||||||
@ -39,6 +41,7 @@ func New(dbPath string) (*API, error) {
|
|||||||
a := &API{
|
a := &API{
|
||||||
db: sqlDB,
|
db: sqlDB,
|
||||||
peerIntents: map[string]PeerCreateArgs{},
|
peerIntents: map[string]PeerCreateArgs{},
|
||||||
|
initIntents: map[string]byte{},
|
||||||
}
|
}
|
||||||
|
|
||||||
return a, a.ensurePassword()
|
return a, a.ensurePassword()
|
||||||
@ -141,6 +144,16 @@ func (a *API) Session_SignIn(s *Session, pwd string) error {
|
|||||||
return db.Session_SetSignedIn(a.db, s.SessionID)
|
return db.Session_SetSignedIn(a.db, s.SessionID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *API) Peer_CreateNew(p *Peer) error {
|
||||||
|
p.Version = idgen.NextID(0)
|
||||||
|
p.PubKey = []byte{}
|
||||||
|
p.PubSignKey = []byte{}
|
||||||
|
p.APIKey = idgen.NewToken()
|
||||||
|
|
||||||
|
return db.Peer_Insert(a.db, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove
|
||||||
type PeerCreateArgs struct {
|
type PeerCreateArgs struct {
|
||||||
Name string
|
Name string
|
||||||
PublicIP []byte
|
PublicIP []byte
|
||||||
@ -148,6 +161,7 @@ type PeerCreateArgs struct {
|
|||||||
Relay bool
|
Relay bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Remove
|
||||||
// Create the intention to add a peer. The returned code is used to complete
|
// Create the intention to add a peer. The returned code is used to complete
|
||||||
// the peer creation. The code is valid for 5 minutes.
|
// the peer creation. The code is valid for 5 minutes.
|
||||||
func (a *API) Peer_CreateIntent(args PeerCreateArgs) string {
|
func (a *API) Peer_CreateIntent(args PeerCreateArgs) string {
|
||||||
@ -167,6 +181,78 @@ func (a *API) Peer_CreateIntent(args PeerCreateArgs) string {
|
|||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create the intention to initialize a peer. The returned code is used to
|
||||||
|
// complete the peer initialization. The code is valid for 5 minutes.
|
||||||
|
func (a *API) Peer_CreateInitIntent(peerIP byte) string {
|
||||||
|
a.lock.Lock()
|
||||||
|
defer a.lock.Unlock()
|
||||||
|
|
||||||
|
code := idgen.NewToken()
|
||||||
|
a.initIntents[code] = peerIP
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
time.Sleep(5 * time.Minute)
|
||||||
|
a.lock.Lock()
|
||||||
|
defer a.lock.Unlock()
|
||||||
|
delete(a.initIntents, code)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) Peer_Init(initCode string) (*m.PeerConfig, error) {
|
||||||
|
a.lock.Lock()
|
||||||
|
defer a.lock.Unlock()
|
||||||
|
|
||||||
|
ip, ok := a.initIntents[initCode]
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrNotAuthorized
|
||||||
|
}
|
||||||
|
|
||||||
|
peer, err := a.Peer_Get(ip)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(a.initIntents, initCode)
|
||||||
|
|
||||||
|
encPubKey, encPrivKey, err := box.GenerateKey(rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
signPubKey, signPrivKey, err := sign.GenerateKey(rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
peer.Version = idgen.NextID(0)
|
||||||
|
peer.APIKey = idgen.NewToken()
|
||||||
|
peer.PubKey = encPubKey[:]
|
||||||
|
peer.PubSignKey = signPubKey[:]
|
||||||
|
|
||||||
|
if err := db.Peer_UpdateFull(a.db, peer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
conf := a.Config_Get()
|
||||||
|
|
||||||
|
return &m.PeerConfig{
|
||||||
|
PeerIP: peer.PeerIP,
|
||||||
|
HubAddress: conf.HubAddress,
|
||||||
|
APIKey: peer.APIKey,
|
||||||
|
Network: conf.VPNNetwork,
|
||||||
|
PublicIP: peer.PublicIP,
|
||||||
|
Port: peer.Port,
|
||||||
|
Relay: peer.Relay,
|
||||||
|
PubKey: encPubKey[:],
|
||||||
|
PrivKey: encPrivKey[:],
|
||||||
|
PubSignKey: signPubKey[:],
|
||||||
|
PrivSignKey: signPrivKey[:],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove
|
||||||
func (a *API) Peer_Create(creationCode string) (*m.PeerConfig, error) {
|
func (a *API) Peer_Create(creationCode string) (*m.PeerConfig, error) {
|
||||||
a.lock.Lock()
|
a.lock.Lock()
|
||||||
defer a.lock.Unlock()
|
defer a.lock.Unlock()
|
||||||
@ -183,6 +269,11 @@ func (a *API) Peer_Create(creationCode string) (*m.PeerConfig, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signPubKey, signPrivKey, err := sign.GenerateKey(rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Get peer IP.
|
// Get peer IP.
|
||||||
peerIP := byte(0)
|
peerIP := byte(0)
|
||||||
|
|
||||||
@ -210,6 +301,7 @@ func (a *API) Peer_Create(creationCode string) (*m.PeerConfig, error) {
|
|||||||
Port: args.Port,
|
Port: args.Port,
|
||||||
Relay: args.Relay,
|
Relay: args.Relay,
|
||||||
PubKey: encPubKey[:],
|
PubKey: encPubKey[:],
|
||||||
|
PubSignKey: signPubKey[:],
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := db.Peer_Insert(a.db, peer); err != nil {
|
if err := db.Peer_Insert(a.db, peer); err != nil {
|
||||||
@ -228,6 +320,8 @@ func (a *API) Peer_Create(creationCode string) (*m.PeerConfig, error) {
|
|||||||
Relay: peer.Relay,
|
Relay: peer.Relay,
|
||||||
PubKey: encPubKey[:],
|
PubKey: encPubKey[:],
|
||||||
PrivKey: encPrivKey[:],
|
PrivKey: encPrivKey[:],
|
||||||
|
PubSignKey: signPubKey[:],
|
||||||
|
PrivSignKey: signPrivKey[:],
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,9 +315,10 @@ type Peer struct {
|
|||||||
Port uint16
|
Port uint16
|
||||||
Relay bool
|
Relay bool
|
||||||
PubKey []byte
|
PubKey []byte
|
||||||
|
PubSignKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
const Peer_SelectQuery = "SELECT PeerIP,Version,APIKey,Name,PublicIP,Port,Relay,PubKey FROM peers"
|
const Peer_SelectQuery = "SELECT PeerIP,Version,APIKey,Name,PublicIP,Port,Relay,PubKey,PubSignKey FROM peers"
|
||||||
|
|
||||||
func Peer_Insert(
|
func Peer_Insert(
|
||||||
tx TX,
|
tx TX,
|
||||||
@ -328,7 +329,7 @@ func Peer_Insert(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tx.Exec("INSERT INTO peers(PeerIP,Version,APIKey,Name,PublicIP,Port,Relay,PubKey) VALUES(?,?,?,?,?,?,?,?)", row.PeerIP, row.Version, row.APIKey, row.Name, row.PublicIP, row.Port, row.Relay, row.PubKey)
|
_, err = tx.Exec("INSERT INTO peers(PeerIP,Version,APIKey,Name,PublicIP,Port,Relay,PubKey,PubSignKey) VALUES(?,?,?,?,?,?,?,?,?)", row.PeerIP, row.Version, row.APIKey, row.Name, row.PublicIP, row.Port, row.Relay, row.PubKey, row.PubSignKey)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,7 +370,7 @@ func Peer_UpdateFull(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := tx.Exec("UPDATE peers SET Version=?,APIKey=?,Name=?,PublicIP=?,Port=?,Relay=?,PubKey=? WHERE PeerIP=?", row.Version, row.APIKey, row.Name, row.PublicIP, row.Port, row.Relay, row.PubKey, row.PeerIP)
|
result, err := tx.Exec("UPDATE peers SET Version=?,APIKey=?,Name=?,PublicIP=?,Port=?,Relay=?,PubKey=?,PubSignKey=? WHERE PeerIP=?", row.Version, row.APIKey, row.Name, row.PublicIP, row.Port, row.Relay, row.PubKey, row.PubSignKey, row.PeerIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -419,8 +420,8 @@ func Peer_Get(
|
|||||||
err error,
|
err error,
|
||||||
) {
|
) {
|
||||||
row = &Peer{}
|
row = &Peer{}
|
||||||
r := tx.QueryRow("SELECT PeerIP,Version,APIKey,Name,PublicIP,Port,Relay,PubKey FROM peers WHERE PeerIP=?", PeerIP)
|
r := tx.QueryRow("SELECT PeerIP,Version,APIKey,Name,PublicIP,Port,Relay,PubKey,PubSignKey FROM peers WHERE PeerIP=?", PeerIP)
|
||||||
err = r.Scan(&row.PeerIP, &row.Version, &row.APIKey, &row.Name, &row.PublicIP, &row.Port, &row.Relay, &row.PubKey)
|
err = r.Scan(&row.PeerIP, &row.Version, &row.APIKey, &row.Name, &row.PublicIP, &row.Port, &row.Relay, &row.PubKey, &row.PubSignKey)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,7 +435,7 @@ func Peer_GetWhere(
|
|||||||
) {
|
) {
|
||||||
row = &Peer{}
|
row = &Peer{}
|
||||||
r := tx.QueryRow(query, args...)
|
r := tx.QueryRow(query, args...)
|
||||||
err = r.Scan(&row.PeerIP, &row.Version, &row.APIKey, &row.Name, &row.PublicIP, &row.Port, &row.Relay, &row.PubKey)
|
err = r.Scan(&row.PeerIP, &row.Version, &row.APIKey, &row.Name, &row.PublicIP, &row.Port, &row.Relay, &row.PubKey, &row.PubSignKey)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,7 +455,7 @@ func Peer_Iterate(
|
|||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
row := &Peer{}
|
row := &Peer{}
|
||||||
err := rows.Scan(&row.PeerIP, &row.Version, &row.APIKey, &row.Name, &row.PublicIP, &row.Port, &row.Relay, &row.PubKey)
|
err := rows.Scan(&row.PeerIP, &row.Version, &row.APIKey, &row.Name, &row.PublicIP, &row.Port, &row.Relay, &row.PubKey, &row.PubSignKey)
|
||||||
if !yield(row, err) {
|
if !yield(row, err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -21,5 +21,6 @@ TABLE peers OF Peer (
|
|||||||
PublicIP []byte,
|
PublicIP []byte,
|
||||||
Port uint16,
|
Port uint16,
|
||||||
Relay bool,
|
Relay bool,
|
||||||
PubKey []byte NoUpdate
|
PubKey []byte NoUpdate,
|
||||||
|
PubSignKey []byte NoUpdate
|
||||||
);
|
);
|
||||||
|
1
hub/api/migrations/2024-12-27-signing-keys.sql
Normal file
1
hub/api/migrations/2024-12-27-signing-keys.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE peers ADD COLUMN PubSignKey BLOB NOT NULL DEFAULT '';
|
@ -54,11 +54,18 @@ func (a *App) _adminSignOutSubmit(s *api.Session, w http.ResponseWriter, r *http
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) _adminConfig(s *api.Session, w http.ResponseWriter, r *http.Request) error {
|
func (a *App) _adminConfig(s *api.Session, w http.ResponseWriter, r *http.Request) error {
|
||||||
|
peers, err := a.api.Peer_List()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return a.render("/admin-config.html", w, struct {
|
return a.render("/admin-config.html", w, struct {
|
||||||
Session *api.Session
|
Session *api.Session
|
||||||
|
Peers []*api.Peer
|
||||||
Config *api.Config
|
Config *api.Config
|
||||||
}{
|
}{
|
||||||
s,
|
s,
|
||||||
|
peers,
|
||||||
a.api.Config_Get(),
|
a.api.Config_Get(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -142,21 +149,6 @@ func (a *App) _adminPasswordSubmit(s *api.Session, w http.ResponseWriter, r *htt
|
|||||||
return a.redirect(w, r, "/admin/config/")
|
return a.redirect(w, r, "/admin/config/")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) _adminPeerList(s *api.Session, w http.ResponseWriter, r *http.Request) error {
|
|
||||||
peers, err := a.api.Peer_List()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return a.render("/admin-peer-list.html", w, struct {
|
|
||||||
Session *api.Session
|
|
||||||
Peers []*api.Peer
|
|
||||||
}{
|
|
||||||
s,
|
|
||||||
peers,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) _adminHosts(s *api.Session, w http.ResponseWriter, r *http.Request) error {
|
func (a *App) _adminHosts(s *api.Session, w http.ResponseWriter, r *http.Request) error {
|
||||||
conf := a.api.Config_Get()
|
conf := a.api.Config_Get()
|
||||||
|
|
||||||
@ -187,25 +179,45 @@ func (a *App) _adminPeerCreate(s *api.Session, w http.ResponseWriter, r *http.Re
|
|||||||
func (a *App) _adminPeerCreateSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error {
|
func (a *App) _adminPeerCreateSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error {
|
||||||
var ipStr string
|
var ipStr string
|
||||||
|
|
||||||
args := api.PeerCreateArgs{}
|
p := &api.Peer{}
|
||||||
err := webutil.NewFormScanner(r.Form).
|
err := webutil.NewFormScanner(r.Form).
|
||||||
Scan("Name", &args.Name).
|
Scan("IP", &p.PeerIP).
|
||||||
|
Scan("Name", &p.Name).
|
||||||
Scan("PublicIP", &ipStr).
|
Scan("PublicIP", &ipStr).
|
||||||
Scan("Port", &args.Port).
|
Scan("Port", &p.Port).
|
||||||
Scan("Relay", &args.Relay).
|
Scan("Relay", &p.Relay).
|
||||||
Error()
|
Error()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.PublicIP, err = stringToIP(ipStr); err != nil {
|
if p.PublicIP, err = stringToIP(ipStr); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
code := a.api.Peer_CreateIntent(args)
|
if err := a.api.Peer_CreateNew(p); err != nil {
|
||||||
return a.redirect(w, r, "/admin/peer/intent-created/?Code=%s", code)
|
return err
|
||||||
|
}
|
||||||
|
return a.redirect(w, r, "/admin/peer/view/?PeerIP=%d", p.PeerIP)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) _adminPeerInit(s *api.Session, w http.ResponseWriter, r *http.Request) error {
|
||||||
|
var peerIP byte
|
||||||
|
err := webutil.NewFormScanner(r.Form).Scan("PeerIP", &peerIP).Error()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
code := a.api.Peer_CreateInitIntent(peerIP)
|
||||||
|
log.Printf("Got code: %v / %v", peerIP, cod)
|
||||||
|
|
||||||
|
return a.render("/admin-peer-init.html", w, struct {
|
||||||
|
Session *api.Session
|
||||||
|
HubAddress string
|
||||||
|
Code string
|
||||||
|
}{s, a.api.Config_Get().HubAddress, code})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove
|
||||||
func (a *App) _adminPeerIntentCreated(s *api.Session, w http.ResponseWriter, r *http.Request) error {
|
func (a *App) _adminPeerIntentCreated(s *api.Session, w http.ResponseWriter, r *http.Request) error {
|
||||||
code := r.FormValue("Code")
|
code := r.FormValue("Code")
|
||||||
if code == "" {
|
if code == "" {
|
||||||
@ -323,6 +335,17 @@ func (a *App) _adminPeerDeleteSubmit(s *api.Session, w http.ResponseWriter, r *h
|
|||||||
return a.redirect(w, r, "/admin/peer/list/")
|
return a.redirect(w, r, "/admin/peer/list/")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) _peerInit(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
code := r.FormValue("Code")
|
||||||
|
conf, err := a.api.Peer_Init(code)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.sendJSON(w, conf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove
|
||||||
func (a *App) _peerCreate(w http.ResponseWriter, r *http.Request) error {
|
func (a *App) _peerCreate(w http.ResponseWriter, r *http.Request) error {
|
||||||
code := r.FormValue("Code")
|
code := r.FormValue("Code")
|
||||||
conf, err := a.api.Peer_Create(code)
|
conf, err := a.api.Peer_Create(code)
|
||||||
@ -360,6 +383,7 @@ func (a *App) _peerFetchState(w http.ResponseWriter, r *http.Request) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range peers {
|
for _, p := range peers {
|
||||||
|
if len(p.PubKey) != 0 {
|
||||||
state.Peers[p.PeerIP] = &m.Peer{
|
state.Peers[p.PeerIP] = &m.Peer{
|
||||||
PeerIP: p.PeerIP,
|
PeerIP: p.PeerIP,
|
||||||
Version: p.Version,
|
Version: p.Version,
|
||||||
@ -370,6 +394,7 @@ func (a *App) _peerFetchState(w http.ResponseWriter, r *http.Request) error {
|
|||||||
PubKey: p.PubKey,
|
PubKey: p.PubKey,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return a.sendJSON(w, state)
|
return a.sendJSON(w, state)
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,11 @@ func (a *App) registerRoutes() {
|
|||||||
a.handleSignedIn("POST /admin/sign-out/", a._adminSignOutSubmit)
|
a.handleSignedIn("POST /admin/sign-out/", a._adminSignOutSubmit)
|
||||||
a.handleSignedIn("GET /admin/password/edit/", a._adminPasswordEdit)
|
a.handleSignedIn("GET /admin/password/edit/", a._adminPasswordEdit)
|
||||||
a.handleSignedIn("POST /admin/password/edit/", a._adminPasswordSubmit)
|
a.handleSignedIn("POST /admin/password/edit/", a._adminPasswordSubmit)
|
||||||
a.handleSignedIn("GET /admin/peer/list/", a._adminPeerList)
|
|
||||||
a.handleSignedIn("GET /admin/peer/hosts/", a._adminHosts)
|
a.handleSignedIn("GET /admin/peer/hosts/", a._adminHosts)
|
||||||
a.handleSignedIn("GET /admin/peer/create/", a._adminPeerCreate)
|
a.handleSignedIn("GET /admin/peer/create/", a._adminPeerCreate)
|
||||||
a.handleSignedIn("POST /admin/peer/create/", a._adminPeerCreateSubmit)
|
a.handleSignedIn("POST /admin/peer/create/", a._adminPeerCreateSubmit)
|
||||||
|
a.handleSignedIn("GET /admin/peer/init/", a._adminPeerInit)
|
||||||
|
// TODO: Remove
|
||||||
a.handleSignedIn("GET /admin/peer/intent-created/", a._adminPeerIntentCreated)
|
a.handleSignedIn("GET /admin/peer/intent-created/", a._adminPeerIntentCreated)
|
||||||
a.handleSignedIn("GET /admin/peer/view/", a._adminPeerView)
|
a.handleSignedIn("GET /admin/peer/view/", a._adminPeerView)
|
||||||
a.handleSignedIn("GET /admin/peer/edit/", a._adminPeerEdit)
|
a.handleSignedIn("GET /admin/peer/edit/", a._adminPeerEdit)
|
||||||
@ -27,6 +28,7 @@ func (a *App) registerRoutes() {
|
|||||||
a.handleSignedIn("GET /admin/peer/delete/", a._adminPeerDelete)
|
a.handleSignedIn("GET /admin/peer/delete/", a._adminPeerDelete)
|
||||||
a.handleSignedIn("POST /admin/peer/delete/", a._adminPeerDeleteSubmit)
|
a.handleSignedIn("POST /admin/peer/delete/", a._adminPeerDeleteSubmit)
|
||||||
|
|
||||||
a.handlePeer("GET /peer/create/", a._peerCreate)
|
a.handlePeer("GET /peer/create/", a._peerCreate) // TODO: Remove
|
||||||
|
a.handlePeer("GET /peer/init/", a._peerInit)
|
||||||
a.handlePeer("GET /peer/fetch-state/", a._peerFetchState)
|
a.handlePeer("GET /peer/fetch-state/", a._peerFetchState)
|
||||||
}
|
}
|
||||||
|
@ -16,4 +16,42 @@
|
|||||||
<td>{{ipToString .Config.VPNNetwork}}</td>
|
<td>{{ipToString .Config.VPNNetwork}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<h2>Peers</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a href="/admin/peer/create/">Add Peer</a> /
|
||||||
|
<a href="/admin/peer/hosts/">Hosts</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{if .Peers -}}
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>PeerIP</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Public IP</th>
|
||||||
|
<th>Port</th>
|
||||||
|
<th>Relay</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{range .Peers -}}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/admin/peer/view/?PeerIP={{.PeerIP}}">
|
||||||
|
{{.PeerIP}}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>{{.Name}}</td>
|
||||||
|
<td>{{ipToString .PublicIP}}</td>
|
||||||
|
<td>{{.Port}}</td>
|
||||||
|
<td>{{if .Relay}}T{{else}}F{{end}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
{{- end}}
|
||||||
|
</table>
|
||||||
|
{{- else}}
|
||||||
|
<p>No peers.</p>
|
||||||
|
{{- end}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
|
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
<input type="hidden" name="CSRF" value="{{.Session.CSRF}}">
|
<input type="hidden" name="CSRF" value="{{.Session.CSRF}}">
|
||||||
|
<p>
|
||||||
|
<label>IP</label><br>
|
||||||
|
<input type="number" name="IP" min="1" max="255" value="0">
|
||||||
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<label>Name</label><br>
|
<label>Name</label><br>
|
||||||
<input type="text" name="Name">
|
<input type="text" name="Name">
|
||||||
|
13
hub/templates/admin-peer-init.html
Normal file
13
hub/templates/admin-peer-init.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{{define "body" -}}
|
||||||
|
<h2>Initialize Peer</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Configure the peer with the following URL:
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
{{.HubAddress}}/peer/init/?Code={{.Code}}
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
<a href="/admin/config/">Done</a>
|
||||||
|
</p>
|
||||||
|
{{- end}}
|
@ -8,6 +8,6 @@
|
|||||||
{{.HubAddress}}/peer/create/?Code={{.Code}}
|
{{.HubAddress}}/peer/create/?Code={{.Code}}
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
<a href="/admin/peer/list/">Done</a>
|
<a href="/admin/config/">Done</a>
|
||||||
</p>
|
</p>
|
||||||
{{- end}}
|
{{- end}}
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
{{define "body" -}}
|
|
||||||
<h2>Peers</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<a href="/admin/peer/create/">Add Peer</a> /
|
|
||||||
<a href="/admin/peer/hosts/">Hosts</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{{if .Peers -}}
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>PeerIP</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Public IP</th>
|
|
||||||
<th>Port</th>
|
|
||||||
<th>Relay</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{{range .Peers -}}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<a href="/admin/peer/view/?PeerIP={{.PeerIP}}">
|
|
||||||
{{.PeerIP}}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>{{.Name}}</td>
|
|
||||||
<td>{{ipToString .PublicIP}}</td>
|
|
||||||
<td>{{.Port}}</td>
|
|
||||||
<td>{{if .Relay}}T{{else}}F{{end}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
{{- end}}
|
|
||||||
</table>
|
|
||||||
{{- else}}
|
|
||||||
<p>No peers.</p>
|
|
||||||
{{- end}}
|
|
||||||
|
|
||||||
{{- end}}
|
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a href="/admin/peer/edit/?PeerIP={{.Peer.PeerIP}}">Edit</a> /
|
<a href="/admin/peer/edit/?PeerIP={{.Peer.PeerIP}}">Edit</a> /
|
||||||
|
<a href="/admin/peer/init/?PeerIP={{.Peer.PeerIP}}">Initialize</a> /
|
||||||
<a href="/admin/peer/delete/?PeerIP={{.Peer.PeerIP}}">Delete</a>
|
<a href="/admin/peer/delete/?PeerIP={{.Peer.PeerIP}}">Delete</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -10,8 +10,6 @@
|
|||||||
<h1>VPPN</h1>
|
<h1>VPPN</h1>
|
||||||
<nav>
|
<nav>
|
||||||
{{if .Session.SignedIn -}}
|
{{if .Session.SignedIn -}}
|
||||||
<a href="/admin/config/">Config</a> /
|
|
||||||
<a href="/admin/peer/list/">Peers</a> /
|
|
||||||
<a href="/admin/sign-out/">Sign out</a>
|
<a href="/admin/sign-out/">Sign out</a>
|
||||||
{{- end}}
|
{{- end}}
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -11,6 +11,8 @@ type PeerConfig struct {
|
|||||||
Relay bool
|
Relay bool
|
||||||
PubKey []byte
|
PubKey []byte
|
||||||
PrivKey []byte
|
PrivKey []byte
|
||||||
|
PubSignKey []byte
|
||||||
|
PrivSignKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type Peer struct {
|
type Peer struct {
|
||||||
@ -21,6 +23,7 @@ type Peer struct {
|
|||||||
Port uint16
|
Port uint16
|
||||||
Relay bool
|
Relay bool
|
||||||
PubKey []byte
|
PubKey []byte
|
||||||
|
PubSignKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type NetworkState struct {
|
type NetworkState struct {
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Use [32]byte for simplicity everywhere.
|
|
||||||
type dataCipher struct {
|
type dataCipher struct {
|
||||||
key [32]byte
|
key [32]byte
|
||||||
aead cipher.AEAD
|
aead cipher.AEAD
|
||||||
@ -20,7 +19,6 @@ func newDataCipher() *dataCipher {
|
|||||||
return newDataCipherFromKey(key)
|
return newDataCipherFromKey(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// key must be 32 bytes.
|
|
||||||
func newDataCipherFromKey(key [32]byte) *dataCipher {
|
func newDataCipherFromKey(key [32]byte) *dataCipher {
|
||||||
block, err := aes.NewCipher(key[:])
|
block, err := aes.NewCipher(key[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
13
node/cipher-discovery.go
Normal file
13
node/cipher-discovery.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
/*
|
||||||
|
func signData(privKey *[64]byte, h header, data, out []byte) []byte {
|
||||||
|
out = out[:headerSize]
|
||||||
|
h.Marshal(out)
|
||||||
|
return sign.Sign(out, data, privKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func openData(pubKey *[32]byte, signed, out []byte) (data []byte, ok bool) {
|
||||||
|
return sign.Open(out[:0], signed[headerSize:], pubKey)
|
||||||
|
}
|
||||||
|
*/
|
@ -25,7 +25,7 @@ func (w *connWriter) WriteTo(packet []byte, addr netip.AddrPort) {
|
|||||||
// packets may fail to be sent in a timely manner causing timeouts.
|
// packets may fail to be sent in a timely manner causing timeouts.
|
||||||
w.lock.Lock()
|
w.lock.Lock()
|
||||||
if _, err := w.conn.WriteToUDPAddrPort(packet, addr); err != nil {
|
if _, err := w.conn.WriteToUDPAddrPort(packet, addr); err != nil {
|
||||||
log.Fatalf("Failed to write to UDP port: %v", err)
|
log.Printf("Failed to write to UDP port: %v", err)
|
||||||
}
|
}
|
||||||
w.lock.Unlock()
|
w.lock.Unlock()
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ type peerRoute struct {
|
|||||||
Up bool // True if data can be sent on the route.
|
Up bool // True if data can be sent on the route.
|
||||||
Relay bool // True if the peer is a relay.
|
Relay bool // True if the peer is a relay.
|
||||||
Direct bool // True if this is a direct connection.
|
Direct bool // True if this is a direct connection.
|
||||||
|
PubSignKey []byte
|
||||||
ControlCipher *controlCipher
|
ControlCipher *controlCipher
|
||||||
DataCipher *dataCipher
|
DataCipher *dataCipher
|
||||||
RemoteAddr netip.AddrPort // Remote address if directly connected.
|
RemoteAddr netip.AddrPort // Remote address if directly connected.
|
||||||
@ -30,7 +31,8 @@ var (
|
|||||||
netName string
|
netName string
|
||||||
localIP byte
|
localIP byte
|
||||||
localPub bool
|
localPub bool
|
||||||
privateKey []byte
|
privKey []byte
|
||||||
|
privSignKey []byte
|
||||||
|
|
||||||
// Shared interface for writing.
|
// Shared interface for writing.
|
||||||
_iface *ifWriter
|
_iface *ifWriter
|
||||||
@ -80,7 +82,7 @@ var (
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// Managed by the relayManager.
|
// Managed by the relayManager.
|
||||||
discoveryPackets chan controlPacket
|
discoveryPackets = make(chan controlPacket, 256)
|
||||||
localAddr *atomic.Pointer[netip.AddrPort] // May be nil.
|
localAddr = &atomic.Pointer[netip.AddrPort]{}
|
||||||
relayIP *atomic.Pointer[byte] // May be nil.
|
relayIP = &atomic.Pointer[byte]{}
|
||||||
)
|
)
|
||||||
|
75
node/localbroadcaster.go
Normal file
75
node/localbroadcaster.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func localBroadcaster() {
|
||||||
|
var (
|
||||||
|
buf1 = make([]byte, bufferSize)
|
||||||
|
buf2 = make([]byte, bufferSize)
|
||||||
|
)
|
||||||
|
time.Sleep(4 * time.Second)
|
||||||
|
doBroadcast(buf1, buf2)
|
||||||
|
for range time.Tick(32 * time.Second) {
|
||||||
|
doBroadcast(buf1, buf2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func doBroadcast(buf1, buf2 []byte) {
|
||||||
|
ifaces, err := net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to list interfaces: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, iface := range ifaces {
|
||||||
|
if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagRunning == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if iface.Flags&net.FlagPointToPoint != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if iface.Flags&net.FlagBroadcast == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs, err := iface.Addrs()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to get interface addresses: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range addrs {
|
||||||
|
ipNet, ok := addr.(*net.IPNet)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ip4 := ipNet.IP.To4()
|
||||||
|
if ip4 == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ip, ok := lastAddr(ipNet)
|
||||||
|
if !ok {
|
||||||
|
log.Printf("Failed to find broadcast address: %v", ipNet)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Broadcasting on address: %v", ip)
|
||||||
|
//addr := netip.AddrPortFrom(ip, 456)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// works when the n is a prefix, otherwise...
|
||||||
|
func lastAddr(n *net.IPNet) (netip.Addr, bool) {
|
||||||
|
ip := make(net.IP, len(n.IP.To4()))
|
||||||
|
binary.BigEndian.PutUint32(ip, binary.BigEndian.Uint32(n.IP.To4())|
|
||||||
|
^binary.BigEndian.Uint32(net.IP(n.Mask).To4()))
|
||||||
|
return netip.AddrFromSlice(ip)
|
||||||
|
}
|
101
node/localdiscovery.go
Normal file
101
node/localdiscovery.go
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/nacl/sign"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
signOverhead = 64
|
||||||
|
multicastIP = netip.AddrFrom4([4]byte{224, 0, 0, 157})
|
||||||
|
multicastAddr = net.UDPAddrFromAddrPort(netip.AddrPortFrom(multicastIP, 4560))
|
||||||
|
)
|
||||||
|
|
||||||
|
func localDiscovery() {
|
||||||
|
conn, err := net.ListenMulticastUDP("udp", nil, multicastAddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to bind to multicast address: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
go sendLocalDiscovery(conn)
|
||||||
|
go recvLocalDiscovery(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendLocalDiscovery(conn *net.UDPConn) {
|
||||||
|
var (
|
||||||
|
buf1 = make([]byte, bufferSize)
|
||||||
|
buf2 = make([]byte, bufferSize)
|
||||||
|
)
|
||||||
|
|
||||||
|
for range time.Tick(16 * time.Second) {
|
||||||
|
signed := buildLocalDiscoveryPacket(buf1, buf2)
|
||||||
|
if _, err := conn.WriteToUDP(signed, multicastAddr); err != nil {
|
||||||
|
log.Printf("Failed to write multicast UDP packet: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func recvLocalDiscovery(conn *net.UDPConn) {
|
||||||
|
var (
|
||||||
|
raw = make([]byte, bufferSize)
|
||||||
|
buf = make([]byte, bufferSize)
|
||||||
|
)
|
||||||
|
|
||||||
|
for {
|
||||||
|
n, remoteAddr, err := conn.ReadFromUDPAddrPort(raw[:bufferSize])
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to read from UDP port (multicast): %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
raw = raw[:n]
|
||||||
|
h, ok := openLocalDiscoveryPacket(raw, buf)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt := controlPacket{
|
||||||
|
SrcIP: h.SourceIP,
|
||||||
|
SrcAddr: remoteAddr,
|
||||||
|
Payload: localDiscoveryPacket{},
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case controlPackets[h.SourceIP] <- pkt:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildLocalDiscoveryPacket(buf1, buf2 []byte) []byte {
|
||||||
|
h := header{
|
||||||
|
StreamID: controlStreamID,
|
||||||
|
Counter: 0,
|
||||||
|
SourceIP: localIP,
|
||||||
|
DestIP: 255,
|
||||||
|
}
|
||||||
|
out := buf1[:headerSize]
|
||||||
|
h.Marshal(out)
|
||||||
|
return sign.Sign(buf2[:0], out, (*[64]byte)(privSignKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
func openLocalDiscoveryPacket(raw, buf []byte) (h header, ok bool) {
|
||||||
|
if len(raw) != headerSize+signOverhead {
|
||||||
|
ok = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Parse(raw[signOverhead:])
|
||||||
|
route := routingTable[h.SourceIP].Load()
|
||||||
|
if route == nil || route.PubSignKey == nil {
|
||||||
|
ok = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok = sign.Open(buf[:0], raw, (*[32]byte)(route.PubSignKey))
|
||||||
|
return
|
||||||
|
}
|
35
node/localdiscovery_test.go
Normal file
35
node/localdiscovery_test.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/nacl/sign"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLocalDiscoveryPacketSigning(t *testing.T) {
|
||||||
|
localIP = 32
|
||||||
|
|
||||||
|
var (
|
||||||
|
buf1 = make([]byte, bufferSize)
|
||||||
|
buf2 = make([]byte, bufferSize)
|
||||||
|
pubSignKey, privSigKey, _ = sign.GenerateKey(rand.Reader)
|
||||||
|
)
|
||||||
|
|
||||||
|
privSignKey = privSigKey[:]
|
||||||
|
route := routingTable[localIP].Load()
|
||||||
|
route.IP = byte(localIP)
|
||||||
|
route.PubSignKey = pubSignKey[0:32]
|
||||||
|
routingTable[localIP].Store(route)
|
||||||
|
|
||||||
|
out := buildLocalDiscoveryPacket(buf1, buf2)
|
||||||
|
|
||||||
|
h, ok := openLocalDiscoveryPacket(bytes.Clone(out), buf1)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal(h, ok)
|
||||||
|
}
|
||||||
|
if h.StreamID != controlStreamID || h.SourceIP != localIP || h.DestIP != 255 {
|
||||||
|
t.Fatal(h)
|
||||||
|
}
|
||||||
|
}
|
26
node/main.go
26
node/main.go
@ -11,7 +11,6 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"sync/atomic"
|
|
||||||
"vppn/m"
|
"vppn/m"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,10 +49,6 @@ func Main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func mainInit(initURL string) {
|
func mainInit(initURL string) {
|
||||||
if _, err := loadPeerConfig(netName); err == nil {
|
|
||||||
log.Fatalf("Network is already initialized.")
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := http.Get(initURL)
|
resp, err := http.Get(initURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to fetch data from hub: %v", err)
|
log.Fatalf("Failed to fetch data from hub: %v", err)
|
||||||
@ -102,14 +97,14 @@ func main(listenIP string, port uint16) {
|
|||||||
log.Fatalf("Failed to open UDP port: %v", err)
|
log.Fatalf("Failed to open UDP port: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conn.SetReadBuffer(1024 * 1024 * 8)
|
||||||
|
conn.SetWriteBuffer(1024 * 1024 * 8)
|
||||||
|
|
||||||
// Intialize globals.
|
// Intialize globals.
|
||||||
_iface = newIFWriter(iface)
|
_iface = newIFWriter(iface)
|
||||||
_conn = newConnWriter(conn)
|
_conn = newConnWriter(conn)
|
||||||
|
|
||||||
localIP = config.PeerIP
|
localIP = config.PeerIP
|
||||||
discoveryPackets = make(chan controlPacket, 256)
|
|
||||||
localAddr = &atomic.Pointer[netip.AddrPort]{}
|
|
||||||
relayIP = &atomic.Pointer[byte]{}
|
|
||||||
|
|
||||||
ip, ok := netip.AddrFromSlice(config.PublicIP)
|
ip, ok := netip.AddrFromSlice(config.PublicIP)
|
||||||
if ok {
|
if ok {
|
||||||
@ -118,7 +113,8 @@ func main(listenIP string, port uint16) {
|
|||||||
localAddr.Store(&addr)
|
localAddr.Store(&addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
privateKey = config.PrivKey
|
privKey = config.PrivKey
|
||||||
|
privSignKey = config.PrivSignKey
|
||||||
|
|
||||||
// Start supervisors.
|
// Start supervisors.
|
||||||
for i := range 256 {
|
for i := range 256 {
|
||||||
@ -130,7 +126,9 @@ func main(listenIP string, port uint16) {
|
|||||||
} else {
|
} else {
|
||||||
go addrDiscoveryClient()
|
go addrDiscoveryClient()
|
||||||
go relayManager()
|
go relayManager()
|
||||||
|
go localDiscovery()
|
||||||
}
|
}
|
||||||
|
|
||||||
go newHubPoller(config).Run()
|
go newHubPoller(config).Run()
|
||||||
go readFromConn(conn)
|
go readFromConn(conn)
|
||||||
readFromIFace(iface)
|
readFromIFace(iface)
|
||||||
@ -206,17 +204,17 @@ func handleControlPacket(addr netip.AddrPort, h header, data, decBuf []byte) {
|
|||||||
|
|
||||||
out, ok := route.ControlCipher.Decrypt(data, decBuf)
|
out, ok := route.ControlCipher.Decrypt(data, decBuf)
|
||||||
if !ok {
|
if !ok {
|
||||||
//log.Printf("Failed to decrypt control packet.")
|
log.Printf("Failed to decrypt control packet.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(out) == 0 {
|
if len(out) == 0 {
|
||||||
//log.Printf("Empty control packet from: %d", h.SourceIP)
|
log.Printf("Empty control packet from: %d", h.SourceIP)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if dupChecks[h.SourceIP].IsDup(h.Counter) {
|
if dupChecks[h.SourceIP].IsDup(h.Counter) {
|
||||||
//log.Printf("[%03d] Duplicate control packet: %d", h.SourceIP, h.Counter)
|
log.Printf("[%03d] Duplicate control packet: %d", h.SourceIP, h.Counter)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,7 +250,7 @@ func handleControlPacket(addr netip.AddrPort, h header, data, decBuf []byte) {
|
|||||||
func handleDataPacket(h header, data []byte, decBuf []byte) {
|
func handleDataPacket(h header, data []byte, decBuf []byte) {
|
||||||
route := routingTable[h.SourceIP].Load()
|
route := routingTable[h.SourceIP].Load()
|
||||||
if !route.Up {
|
if !route.Up {
|
||||||
//log.Printf("Not connected (recv).")
|
log.Printf("Not connected (recv).")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,7 +261,7 @@ func handleDataPacket(h header, data []byte, decBuf []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if dupChecks[h.SourceIP].IsDup(h.Counter) {
|
if dupChecks[h.SourceIP].IsDup(h.Counter) {
|
||||||
//log.Printf("[%03d] Duplicate data packet: %d", h.SourceIP, h.Counter)
|
log.Printf("[%03d] Duplicate data packet: %d", h.SourceIP, h.Counter)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
node/messages.go
Normal file
1
node/messages.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package node
|
@ -138,3 +138,7 @@ func parseProbePacket(buf []byte) (p probePacket, err error) {
|
|||||||
Error()
|
Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type localDiscoveryPacket struct{}
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
func TestPacketSyn(t *testing.T) {
|
func TestPacketSyn(t *testing.T) {
|
||||||
in := synPacket{
|
in := synPacket{
|
||||||
TraceID: newTraceID(),
|
TraceID: newTraceID(),
|
||||||
RelayIP: 4,
|
|
||||||
FromAddr: netip.AddrPortFrom(netip.AddrFrom4([4]byte{4, 5, 6, 7}), 22),
|
FromAddr: netip.AddrPortFrom(netip.AddrFrom4([4]byte{4, 5, 6, 7}), 22),
|
||||||
}
|
}
|
||||||
rand.Read(in.SharedKey[:])
|
rand.Read(in.SharedKey[:])
|
||||||
|
@ -115,7 +115,8 @@ func (s *peerSupervisor) _peerUpdate(peer *m.Peer) stateFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.staged.IP = s.remoteIP
|
s.staged.IP = s.remoteIP
|
||||||
s.staged.ControlCipher = newControlCipher(privateKey, peer.PubKey)
|
s.staged.ControlCipher = newControlCipher(privKey, peer.PubKey)
|
||||||
|
s.staged.PubSignKey = peer.PubSignKey
|
||||||
s.staged.DataCipher = newDataCipher()
|
s.staged.DataCipher = newDataCipher()
|
||||||
|
|
||||||
if ip, isValid := netip.AddrFromSlice(peer.PublicIP); isValid {
|
if ip, isValid := netip.AddrFromSlice(peer.PublicIP); isValid {
|
||||||
@ -241,7 +242,7 @@ func (s *peerSupervisor) client() stateFunc {
|
|||||||
probe probePacket
|
probe probePacket
|
||||||
probeAddr netip.AddrPort
|
probeAddr netip.AddrPort
|
||||||
|
|
||||||
lAddr netip.AddrPort
|
remoteAddr netip.AddrPort
|
||||||
|
|
||||||
timeoutTimer = time.NewTimer(timeoutInterval)
|
timeoutTimer = time.NewTimer(timeoutInterval)
|
||||||
pingTimer = time.NewTimer(pingInterval)
|
pingTimer = time.NewTimer(pingInterval)
|
||||||
@ -306,9 +307,9 @@ func (s *peerSupervisor) client() stateFunc {
|
|||||||
// Send syn.
|
// Send syn.
|
||||||
|
|
||||||
syn.FromAddr = getLocalAddr()
|
syn.FromAddr = getLocalAddr()
|
||||||
if syn.FromAddr != lAddr {
|
if syn.FromAddr != remoteAddr {
|
||||||
syn.TraceID = newTraceID()
|
syn.TraceID = newTraceID()
|
||||||
lAddr = syn.FromAddr
|
remoteAddr = syn.FromAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
s.sendControlPacket(syn)
|
s.sendControlPacket(syn)
|
||||||
@ -319,6 +320,9 @@ func (s *peerSupervisor) client() stateFunc {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Check if we have local address.
|
||||||
|
// TODO: Send local probe
|
||||||
|
|
||||||
if !ack.FromAddr.IsValid() {
|
if !ack.FromAddr.IsValid() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
1
node/signing.go
Normal file
1
node/signing.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package node
|
Loading…
x
Reference in New Issue
Block a user