mirror of
https://github.com/go-i2p/go-i2p.git
synced 2025-07-04 21:55:18 -04:00
fix up structure
This commit is contained in:
13
lib/bootstrap/bootstrap.go
Normal file
13
lib/bootstrap/bootstrap.go
Normal file
@ -0,0 +1,13 @@
|
||||
package bootstrap
|
||||
|
||||
import "github.com/hkparker/go-i2p/lib/common"
|
||||
|
||||
// interface defining a way to bootstrap into the i2p network
|
||||
type Bootstrap interface {
|
||||
// get more peers for bootstrap
|
||||
// try obtaining at most n router infos
|
||||
// if n is 0 then try obtaining as many router infos as possible
|
||||
// returns nil and error if we cannot fetch ANY router infos
|
||||
// returns a channel that yields 1 slice of router infos containing n or fewer router infos, caller must close channel after use
|
||||
GetPeers(n int) (chan []common.RouterInfo, error)
|
||||
}
|
4
lib/bootstrap/doc.go
Normal file
4
lib/bootstrap/doc.go
Normal file
@ -0,0 +1,4 @@
|
||||
//
|
||||
// provides generic interfaces for initial bootstrap into network and network reseeding
|
||||
//
|
||||
package bootstrap
|
@ -7,7 +7,11 @@ import (
|
||||
b64 "encoding/base64"
|
||||
)
|
||||
|
||||
var I2PEncoding *b64.Encoding = b64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~")
|
||||
// i2p base64 alphabet
|
||||
const Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~"
|
||||
|
||||
// i2p base64 encoding
|
||||
var I2PEncoding *b64.Encoding = b64.NewEncoding(Alphabet)
|
||||
|
||||
//
|
||||
// Return a go string of the I2P base64
|
||||
@ -16,3 +20,11 @@ var I2PEncoding *b64.Encoding = b64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcde
|
||||
func EncodeToString(data []byte) string {
|
||||
return I2PEncoding.EncodeToString(data)
|
||||
}
|
||||
|
||||
//
|
||||
// decode string using i2p base64 encoding
|
||||
// returns error if data is malfromed
|
||||
//
|
||||
func DecodeFromString(str string) (d []byte, err error) {
|
||||
return I2PEncoding.DecodeString(str)
|
||||
}
|
||||
|
@ -1,3 +1,27 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"io"
|
||||
)
|
||||
|
||||
// sha256 hash of some data
|
||||
type Hash [32]byte
|
||||
|
||||
// calculate sha256 of a byte slice
|
||||
func HashData(data []byte) (h Hash) {
|
||||
h = sha256.Sum256(data)
|
||||
return
|
||||
}
|
||||
|
||||
// calulate sha256 of all data being read from an io.Reader
|
||||
// return error if one occurs while reading from reader
|
||||
func HashReader(r io.Reader) (h Hash, err error) {
|
||||
sha := sha256.New()
|
||||
_, err = io.Copy(sha, r)
|
||||
if err == nil {
|
||||
d := sha.Sum(nil)
|
||||
copy(h[:], d)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -89,6 +89,19 @@ func (router_info RouterInfo) RouterIdentity() (router_identity RouterIdentity,
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate this RouterInfo's Identity Hash (the sha256 of the RouterIdentity)
|
||||
// returns error if the RouterIdentity is malformed
|
||||
//
|
||||
func (router_info RouterInfo) IdentHash() (h Hash, err error) {
|
||||
var ri RouterIdentity
|
||||
ri, err = router_info.RouterIdentity()
|
||||
if err == nil {
|
||||
h = HashData(ri)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
// Return the Date the RouterInfo was published and any errors encountered parsing the RouterInfo.
|
||||
//
|
||||
@ -196,6 +209,7 @@ func (router_info RouterInfo) Options() (mapping Mapping) {
|
||||
func (router_info RouterInfo) Signature() (signature Signature) {
|
||||
head := router_info.optionsLocation()
|
||||
size := head + router_info.optionsSize()
|
||||
// TODO: signature is not always 40 bytes, is 40 bytes for DSA only
|
||||
signature = Signature(router_info[size : size+40])
|
||||
return
|
||||
}
|
||||
|
@ -1,5 +1,23 @@
|
||||
package config
|
||||
|
||||
type BootstrapConfig struct {
|
||||
LowPeerThreshold int
|
||||
// configuration for 1 reseed server
|
||||
type ReseedConfig struct {
|
||||
// url of reseed server
|
||||
Url string
|
||||
// fingerprint of reseed su3 signing key
|
||||
SU3Fingerprint string
|
||||
}
|
||||
|
||||
type BootstrapConfig struct {
|
||||
// if we have less than this many peers we should reseed
|
||||
LowPeerThreshold int
|
||||
// reseed servers
|
||||
ReseedServers []*ReseedConfig
|
||||
}
|
||||
|
||||
// default configuration for network bootstrap
|
||||
var DefaultBootstrapConfig = BootstrapConfig{
|
||||
LowPeerThreshold: 10,
|
||||
// TODO: add reseed servers
|
||||
ReseedServers: []*ReseedConfig{},
|
||||
}
|
||||
|
@ -2,12 +2,14 @@ package config
|
||||
|
||||
// router.config options
|
||||
type RouterConfig struct {
|
||||
NetDbDir string
|
||||
|
||||
Bootstrap BootstrapConfig
|
||||
// netdb configuration
|
||||
NetDb *NetDbConfig
|
||||
// configuration for bootstrapping into the network
|
||||
Bootstrap *BootstrapConfig
|
||||
}
|
||||
|
||||
// defaults for router
|
||||
var Router = &RouterConfig{
|
||||
NetDbDir: "./netDb",
|
||||
var DefaultRouterConfig = &RouterConfig{
|
||||
NetDb: &DefaultNetDbConfig,
|
||||
Bootstrap: &DefaultBootstrapConfig,
|
||||
}
|
||||
|
4
lib/crypto/doc.go
Normal file
4
lib/crypto/doc.go
Normal file
@ -0,0 +1,4 @@
|
||||
//
|
||||
// package for i2p specific crpytography
|
||||
//
|
||||
package crypto
|
@ -1,13 +0,0 @@
|
||||
package netdb
|
||||
|
||||
type Reseed interface {
|
||||
// do reseed, return nil on success otherwise error
|
||||
// sends down all Netdb entries down chan
|
||||
// closes channel when done
|
||||
Reseed(chnl chan *Entry) error
|
||||
}
|
||||
|
||||
func GetRandomReseed() Reseed {
|
||||
// TODO: hardcoded value
|
||||
return HTTPSReseed("https://i2p.rocks:445/")
|
||||
}
|
@ -1,16 +1,14 @@
|
||||
package netdb
|
||||
|
||||
import (
|
||||
"github.com/hkparker/go-i2p/lib/common"
|
||||
"io"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// netdb entry
|
||||
// wraps a router info and provides serialization
|
||||
type Entry struct {
|
||||
fname string
|
||||
}
|
||||
|
||||
func (e *Entry) FilePath(n StdNetDB) (str string) {
|
||||
return filepath.Join(string(n), e.fname)
|
||||
ri common.RouterInfo
|
||||
}
|
||||
|
||||
func (e *Entry) WriteTo(w io.Writer) (err error) {
|
||||
|
32
lib/netdb/kad.go
Normal file
32
lib/netdb/kad.go
Normal file
@ -0,0 +1,32 @@
|
||||
package netdb
|
||||
|
||||
import (
|
||||
"github.com/hkparker/go-i2p/lib/common"
|
||||
"github.com/hkparker/go-i2p/lib/tunnel"
|
||||
"time"
|
||||
)
|
||||
|
||||
// resolves router infos with recursive kademlia lookup
|
||||
type kadResolver struct {
|
||||
// netdb to store result into
|
||||
netDB NetworkDatabase
|
||||
// what tunnel pool to use when doing lookup
|
||||
// if nil the lookup will be done directly
|
||||
pool *tunnel.Pool
|
||||
}
|
||||
|
||||
// TODO: implement
|
||||
func (kr *kadResolver) Lookup(h common.Hash, timeout time.Duration) (chnl chan common.RouterInfo) {
|
||||
return
|
||||
}
|
||||
|
||||
// create a new resolver that stores result into a NetworkDatabase and uses a tunnel pool for the lookup
|
||||
func KademliaResolver(netDb NetworkDatabase, pool *tunnel.Pool) (r Resolver) {
|
||||
if pool != nil && netDb != nil {
|
||||
r = &kadResolver{
|
||||
netDB: netDb,
|
||||
pool: pool,
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
@ -1,14 +1,35 @@
|
||||
package netdb
|
||||
|
||||
import (
|
||||
"github.com/hkparker/go-i2p/lib/bootstrap"
|
||||
"github.com/hkparker/go-i2p/lib/common"
|
||||
"time"
|
||||
)
|
||||
|
||||
// resolves unknown RouterInfos given the hash of their RouterIdentity
|
||||
type Resolver interface {
|
||||
// resolve a router info by hash
|
||||
// return a chan that yields the found RouterInfo or nil if it could not be found after timeout
|
||||
Lookup(hash common.Hash, timeout time.Duration) chan common.RouterInfo
|
||||
}
|
||||
|
||||
// i2p network database, storage of i2p RouterInfos
|
||||
type NetworkDatabase interface {
|
||||
// obtain a RouterInfo by its hash
|
||||
// return a channel that gives 1 RouterInfo or nil if the RouterInfo cannot be found
|
||||
GetRouterInfo(hash common.Hash) chan *common.RouterInfo
|
||||
// obtain a RouterInfo by its hash locally
|
||||
// return a RouterInfo if we found it locally
|
||||
// return nil if the RouterInfo cannot be found locally
|
||||
GetRouterInfo(hash common.Hash) common.RouterInfo
|
||||
|
||||
// store a router info locally
|
||||
StoreRouterInfo(ri *common.RouterInfo)
|
||||
StoreRouterInfo(ri common.RouterInfo)
|
||||
|
||||
// try obtaining more peers with a bootstrap instance until we get minRouters number of router infos
|
||||
// returns error if bootstrap.GetPeers returns an error otherwise returns nil
|
||||
Reseed(b bootstrap.Bootstrap, minRouters int) error
|
||||
|
||||
// return how many router infos we have
|
||||
Size() int
|
||||
|
||||
// ensure underlying resources exist , i.e. directories, files, configs
|
||||
Ensure() error
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
package netdb
|
||||
|
||||
type HTTPSReseed string
|
||||
|
||||
func (r HTTPSReseed) Reseed(chnl chan *Entry) (err error) {
|
||||
close(chnl)
|
||||
return
|
||||
}
|
112
lib/netdb/std.go
112
lib/netdb/std.go
@ -1,14 +1,41 @@
|
||||
package netdb
|
||||
|
||||
import (
|
||||
log "github.com/golang/glog"
|
||||
"bytes"
|
||||
"fmt"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/hkparker/go-i2p/lib/bootstrap"
|
||||
"github.com/hkparker/go-i2p/lib/common"
|
||||
"github.com/hkparker/go-i2p/lib/common/base64"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// standard network database implementation
|
||||
// standard network database implementation using local filesystem skiplist
|
||||
type StdNetDB string
|
||||
|
||||
func (db StdNetDB) GetRouterInfo(hash common.Hash) (chnl chan common.RouterInfo) {
|
||||
fname := db.SkiplistFile(hash)
|
||||
f, err := os.Open(fname)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
buff := new(bytes.Buffer)
|
||||
_, err = io.Copy(buff, f)
|
||||
f.Close()
|
||||
chnl = make(chan common.RouterInfo)
|
||||
chnl <- common.RouterInfo(buff.Bytes())
|
||||
return
|
||||
}
|
||||
|
||||
// get the skiplist file that a RouterInfo with this hash would go in
|
||||
func (db StdNetDB) SkiplistFile(hash common.Hash) (fpath string) {
|
||||
fname := base64.EncodeToString(hash[:])
|
||||
fpath = filepath.Join(db.Path(), fmt.Sprintf("r%s", fname[0]), fmt.Sprintf("routerInfo-%s.dat", fname))
|
||||
return
|
||||
}
|
||||
|
||||
// get netdb path
|
||||
func (db StdNetDB) Path() string {
|
||||
return string(db)
|
||||
@ -17,26 +44,38 @@ func (db StdNetDB) Path() string {
|
||||
//
|
||||
// return how many routers we know about in our network database
|
||||
//
|
||||
func (db StdNetDB) KnownPeerCount() (routers int) {
|
||||
func (db StdNetDB) Size() (routers int) {
|
||||
return
|
||||
}
|
||||
|
||||
// return true if the network db directory exists and is writable
|
||||
func (db StdNetDB) Exists() bool {
|
||||
_, err := os.Stat(db.Path())
|
||||
return err != nil
|
||||
p := db.Path()
|
||||
// check root directory
|
||||
_, err := os.Stat(p)
|
||||
if err == nil {
|
||||
// check subdirectories for skiplist
|
||||
for _, c := range base64.Alphabet {
|
||||
if _, err = os.Stat(filepath.Join(p, fmt.Sprintf("r%s", c))); err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (db StdNetDB) SaveEntry(e *Entry) (err error) {
|
||||
var f io.WriteCloser
|
||||
f, err = os.OpenFile(e.FilePath(db), os.O_WRONLY, 0600)
|
||||
var h common.Hash
|
||||
h, err = e.ri.IdentHash()
|
||||
if err == nil {
|
||||
err = e.WriteTo(f)
|
||||
if err != nil {
|
||||
log.Errorf("failed to write netdb entry: %s", err.Error())
|
||||
f, err = os.OpenFile(db.SkiplistFile(h), os.O_WRONLY|os.O_CREATE, 0700)
|
||||
if err == nil {
|
||||
err = e.WriteTo(f)
|
||||
f.Close()
|
||||
}
|
||||
f.Close()
|
||||
} else {
|
||||
}
|
||||
if err != nil {
|
||||
log.Errorf("failed to save netdb entry: %s", err.Error())
|
||||
}
|
||||
return
|
||||
@ -44,49 +83,34 @@ func (db StdNetDB) SaveEntry(e *Entry) (err error) {
|
||||
|
||||
// reseed if we have less than minRouters known routers
|
||||
// returns error if reseed failed
|
||||
func (db StdNetDB) Reseed(minRouters int) (err error) {
|
||||
current := db.KnownPeerCount()
|
||||
if current <= minRouters {
|
||||
// we need to reseed
|
||||
rs := GetRandomReseed()
|
||||
log.Infof("Reseeding from %s", rs)
|
||||
chnl := make(chan *Entry)
|
||||
// receive entries from reseed
|
||||
go func(c chan *Entry) {
|
||||
count := 0
|
||||
for {
|
||||
e, ok := <-c
|
||||
if ok {
|
||||
// got an entry
|
||||
// save it to our netdb
|
||||
err := db.SaveEntry(e)
|
||||
if err == nil {
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
}(chnl) // call
|
||||
err = rs.Reseed(chnl)
|
||||
}
|
||||
func (db StdNetDB) Reseed(b bootstrap.Bootstrap, minRouters int) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// ensure that the network database exists and is seeded with a minimum number of routers
|
||||
func (db StdNetDB) Ensure(minRouters int) (err error) {
|
||||
// ensure that the network database exists
|
||||
func (db StdNetDB) Ensure() (err error) {
|
||||
if !db.Exists() {
|
||||
err = db.Create()
|
||||
}
|
||||
if err == nil {
|
||||
// database directory ensured
|
||||
// try to reseed
|
||||
err = db.Reseed(minRouters)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// create base network database directory
|
||||
func (db StdNetDB) Create() (err error) {
|
||||
log.Infof("Create network database in %s", db.Path())
|
||||
err = os.Mkdir(db.Path(), 0600)
|
||||
mode := os.FileMode(0600)
|
||||
p := db.Path()
|
||||
log.Infof("Create network database in %s", p)
|
||||
|
||||
// create root for skiplist
|
||||
err = os.Mkdir(p, mode)
|
||||
if err == nil {
|
||||
// create all subdirectories for skiplist
|
||||
for _, c := range base64.Alphabet {
|
||||
err = os.Mkdir(filepath.Join(p, fmt.Sprintf("r%s", c)), mode)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -11,19 +11,24 @@ type Router struct {
|
||||
ndb netdb.StdNetDB
|
||||
}
|
||||
|
||||
// create router with default configuration
|
||||
func CreateRouter() (r *Router, err error) {
|
||||
cfg := config.Router
|
||||
r = &Router{
|
||||
cfg: cfg,
|
||||
ndb: netdb.StdNetDB(cfg.NetDbDir),
|
||||
}
|
||||
cfg := config.DefaultRouterConfig
|
||||
r, err = FromConfig(cfg)
|
||||
return
|
||||
}
|
||||
|
||||
// create router from configuration
|
||||
func FromConfig(c *config.RouterConfig) (r *Router, err error) {
|
||||
|
||||
r = new(Router)
|
||||
return
|
||||
}
|
||||
|
||||
// run i2p router mainloop
|
||||
func (r *Router) Run() {
|
||||
// make sure the netdb is ready
|
||||
err := r.ndb.Ensure(r.cfg.Bootstrap.LowPeerThreshold)
|
||||
err := r.ndb.Ensure()
|
||||
if err == nil {
|
||||
// netdb ready
|
||||
}
|
||||
|
5
lib/tunnel/pool.go
Normal file
5
lib/tunnel/pool.go
Normal file
@ -0,0 +1,5 @@
|
||||
package tunnel
|
||||
|
||||
// a pool of tunnels which we have created
|
||||
type Pool struct {
|
||||
}
|
Reference in New Issue
Block a user