Skip to content

Commit

Permalink
dv: integrate validation
Browse files Browse the repository at this point in the history
  • Loading branch information
pulsejet committed Jan 22, 2025
1 parent 56ecdcf commit f987dce
Show file tree
Hide file tree
Showing 13 changed files with 156 additions and 38 deletions.
17 changes: 16 additions & 1 deletion dv/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ type Config struct {
advSyncPassivePfxN enc.Name
// Advertisement Data Prefix
advDataPfxN enc.Name
// Universal router data prefix
routerDataPfxN enc.Name
// Prefix Table Sync Prefix
pfxSyncPfxN enc.Name
// Prefix Table Data Prefix
Expand Down Expand Up @@ -103,7 +105,7 @@ func (c *Config) Parse() (err error) {
c.trustAnchorsN = append(c.trustAnchorsN, name)
}

// Create name table
// Advertisement sync and data prefixes
c.advSyncPfxN = enc.LOCALHOP.Append(c.networkNameN.Append(
enc.NewStringComponent(enc.TypeKeywordNameComponent, "DV"),
enc.NewStringComponent(enc.TypeKeywordNameComponent, "ADS"),
Expand All @@ -118,14 +120,23 @@ func (c *Config) Parse() (err error) {
enc.NewStringComponent(enc.TypeKeywordNameComponent, "DV"),
enc.NewStringComponent(enc.TypeKeywordNameComponent, "ADV"),
)...)

// Prefix table sync prefix
c.pfxSyncPfxN = c.networkNameN.Append(
enc.NewStringComponent(enc.TypeKeywordNameComponent, "DV"),
enc.NewStringComponent(enc.TypeKeywordNameComponent, "PFS"),
)

// Router data prefix including prefix data and certificates
c.routerDataPfxN = c.routerNameN.Append(
enc.NewStringComponent(enc.TypeKeywordNameComponent, "DV"),
)
c.pfxDataPfxN = c.routerNameN.Append(
enc.NewStringComponent(enc.TypeKeywordNameComponent, "DV"),
enc.NewStringComponent(enc.TypeKeywordNameComponent, "PFX"),
)

// Local prefixes to NFD
c.localPfxN = enc.LOCALHOST.Append(
enc.NewStringComponent(enc.TypeGenericNameComponent, "nlsr"),
)
Expand Down Expand Up @@ -157,6 +168,10 @@ func (c *Config) AdvertisementDataPrefix() enc.Name {
return c.advDataPfxN
}

func (c *Config) RouterDataPrefix() enc.Name {
return c.routerDataPfxN
}

func (c *Config) PrefixTableSyncPrefix() enc.Name {
return c.pfxSyncPfxN
}
Expand Down
Binary file modified dv/config/schema.tlv
Binary file not shown.
2 changes: 1 addition & 1 deletion dv/config/schema.trust
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

// Certificate definitions
#root_cert: #network/#KEY
#router_cert: #router/#KEY <= #root_cert
#router_cert: #router/"32=DV"/#KEY <= #root_cert

// Standard NDN conventions
#KEY: "KEY"/_/_/_
4 changes: 2 additions & 2 deletions dv/dv/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func NewRouter(config *config.Config, engine ndn.Engine) (*Router, error) {

// Create sync groups
dv.pfxSvs = ndn_sync.NewSvSync(ndn_sync.SvSyncOpts{
Engine: engine,
Client: dv.client,
GroupPrefix: config.PrefixTableSyncPrefix(),
OnUpdate: func(ssu ndn_sync.SvSyncUpdate) { go dv.onPfxSyncUpdate(ssu) },
BootTime: dv.advert.bootTime,
Expand Down Expand Up @@ -244,7 +244,7 @@ func (dv *Router) register() (err error) {
dv.config.AdvertisementSyncPrefix(),
dv.config.AdvertisementDataPrefix(),
dv.config.PrefixTableSyncPrefix(),
dv.config.PrefixTableDataPrefix(),
dv.config.RouterDataPrefix(),
dv.config.LocalPrefix(),
}
for _, prefix := range pfxs {
Expand Down
15 changes: 8 additions & 7 deletions dv/table/neighbor_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,8 @@ func (ns *NeighborState) delete() {
ns.isFaceActive = false
}

func (ns *NeighborState) localRoute() enc.Name {
return enc.LOCALHOP.Append(ns.Name.Append(
enc.NewStringComponent(enc.TypeKeywordNameComponent, "DV"),
)...)
func (ns *NeighborState) route() enc.Name {
return ns.Name.Append(enc.NewStringComponent(enc.TypeKeywordNameComponent, "DV"))
}

// Register route to this neighbor
Expand All @@ -157,7 +155,9 @@ func (ns *NeighborState) routeRegister(faceId uint64) {
}

// For fetching advertisements from neighbor
register(ns.localRoute())
register(enc.LOCALHOP.Append(ns.route()...))
// For fetching certificates from neighbor
register(ns.route())
// Passive advertisement sync to neighbor
register(ns.nt.config.AdvertisementSyncPassivePrefix())
// For prefix table sync group
Expand All @@ -183,8 +183,9 @@ func (ns *NeighborState) routeUnregister() {
})
}

// Always remove local data route to neighbor
unregister(ns.localRoute())
// Always remove local data routes to neighbor
unregister(enc.LOCALHOP.Append(ns.route()...))
unregister(ns.route())

// If there are multiple neighbors on this face, we do not
// want to unregister the global routes to the face.
Expand Down
13 changes: 12 additions & 1 deletion std/examples/low-level/svs/main.go → std/examples/svs/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
enc "github.com/named-data/ndnd/std/encoding"
"github.com/named-data/ndnd/std/engine"
"github.com/named-data/ndnd/std/log"
"github.com/named-data/ndnd/std/object"
"github.com/named-data/ndnd/std/sync"
)

Expand Down Expand Up @@ -39,10 +40,20 @@ func main() {
}
defer app.Stop()

// Create object client
store := object.NewMemoryStore()
client := object.NewClient(app, store, nil)
err = client.Start()
if err != nil {
log.Error(nil, "Unable to start object client", "err", err)
return
}
defer client.Stop()

// Start SVS instance
group, _ := enc.NameFromStr("/ndn/svs")
svsync := sync.NewSvSync(sync.SvSyncOpts{
Engine: app,
Client: client,
GroupPrefix: group,
OnUpdate: func(ssu sync.SvSyncUpdate) {
log.Info(nil, "Received update", "update", ssu)
Expand Down
2 changes: 2 additions & 0 deletions std/ndn/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ type Client interface {
ConsumeExt(args ConsumeExtArgs)
// Express a single interest with reliability
ExpressR(args ExpressRArgs)
// Validate a single data packet
Validate(data Data, callback func(bool, error))
}

// ProduceArgs are the arguments for the produce API
Expand Down
5 changes: 5 additions & 0 deletions std/object/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ type Client struct {
segfetch chan *ConsumeState
// [fetcher] recheck segment fetcher
segcheck chan bool
// [validate] queue for new object validation
validatepipe chan sec.ValidateArgs
}

// Create a new client with given engine and store
Expand All @@ -43,6 +45,7 @@ func NewClient(engine ndn.Engine, store ndn.Store, trust *sec.TrustConfig) ndn.C
client.seginpipe = make(chan rrSegHandleDataArgs, 512)
client.segfetch = make(chan *ConsumeState, 128)
client.segcheck = make(chan bool, 2)
client.validatepipe = make(chan sec.ValidateArgs, 64)

return client
}
Expand Down Expand Up @@ -101,6 +104,8 @@ func (c *Client) run() {
c.fetcher.add(state)
case <-c.segcheck:
c.fetcher.doCheck()
case args := <-c.validatepipe:
c.trust.Validate(args)
}
}
}
32 changes: 21 additions & 11 deletions std/object/client_consume.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,17 +199,25 @@ func (c *Client) fetchMetadata(
return
}

// parse metadata
metadata, err := rdr.ParseMetaData(enc.NewWireReader(args.Data.Content()), false)
if err != nil {
callback(nil, fmt.Errorf("consume: failed to parse object metadata %v", err))
return
}
c.Validate(args.Data, func(valid bool, err error) {
// validate with trust config
if !valid {
callback(nil, fmt.Errorf("consume: failed to validate metadata (%v)", err))
return
}

// clone fields for lifetime
metadata.Name = metadata.Name.Clone()
metadata.FinalBlockID = append([]byte{}, metadata.FinalBlockID...)
callback(metadata, nil)
// parse metadata
metadata, err := rdr.ParseMetaData(enc.NewWireReader(args.Data.Content()), false)
if err != nil {
callback(nil, fmt.Errorf("consume: failed to parse object metadata (%v)", err))
return
}

// clone fields for lifetime
metadata.Name = metadata.Name.Clone()
metadata.FinalBlockID = append([]byte{}, metadata.FinalBlockID...)
callback(metadata, nil)
})
},
})
}
Expand Down Expand Up @@ -239,7 +247,9 @@ func (c *Client) fetchDataByPrefix(
return
}

callback(args.Data, nil)
c.Validate(args.Data, func(valid bool, err error) {
callback(args.Data, nil)
})
},
})
}
Expand Down
12 changes: 11 additions & 1 deletion std/object/client_consume_seg.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func (s *rrSegFetcher) handleData(args ndn.ExpressCallbackArgs, state *ConsumeSt
}

if args.Result == ndn.InterestResultError {
state.finalizeError(fmt.Errorf("consume: fetch failed with error %v", args.Error))
state.finalizeError(fmt.Errorf("consume: fetch failed with error (%v)", args.Error))
return
}

Expand All @@ -168,6 +168,16 @@ func (s *rrSegFetcher) handleData(args ndn.ExpressCallbackArgs, state *ConsumeSt
return
}

s.client.Validate(args.Data, func(valid bool, err error) {
if !valid {
state.finalizeError(fmt.Errorf("consume: validation failed with error (%v)", err))
} else {
s.handleValidatedData(args, state)
}
})
}

func (s *rrSegFetcher) handleValidatedData(args ndn.ExpressCallbackArgs, state *ConsumeState) {
// get the final block id if we don't know the segment count
if state.segCnt == -1 { // TODO: can change?
fbId := args.Data.FinalBlockID()
Expand Down
56 changes: 56 additions & 0 deletions std/object/client_validate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package object

import (
"fmt"

enc "github.com/named-data/ndnd/std/encoding"
"github.com/named-data/ndnd/std/ndn"
sec "github.com/named-data/ndnd/std/security"
)

// Validate a data packet using the client configuration
func (c *Client) Validate(data ndn.Data, callback func(bool, error)) {
if c.trust == nil {
callback(true, nil)
return
}

// Pop off the version and segment components
name := data.Name()
if len(name) > 2 {
if name[len(name)-1].Typ == enc.TypeSegmentNameComponent {
name = name[:len(name)-1]
}
if name[len(name)-1].Typ == enc.TypeVersionNameComponent {
name = name[:len(name)-1]
}
}

// Add to queue of validation
select {
case c.validatepipe <- sec.ValidateArgs{
Data: data,
Callback: callback,
DataName: name,
Fetch: func(name enc.Name, config *ndn.InterestConfig, found func(ndn.Data, []byte, error)) {
c.ExpressR(ndn.ExpressRArgs{
Name: name,
Config: config,
Retries: 3,
Callback: func(res ndn.ExpressCallbackArgs) {
if res.Result == ndn.InterestResultData {
found(res.Data, res.RawData.Join(), nil)
} else if res.Error != nil {
found(nil, nil, res.Error)
} else {
found(nil, nil, fmt.Errorf("failed to fetch certificate (%s) with result: %v", name, res.Result))
}
},
})
},
}:
// Queued successfully
default:
callback(false, fmt.Errorf("validation queue full"))
}
}
18 changes: 13 additions & 5 deletions std/security/trust_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type ValidateArgs struct {
Data ndn.Data
Fetch func(enc.Name, *ndn.InterestConfig, func(ndn.Data, []byte, error))
Callback func(bool, error)
DataName enc.Name

cert ndn.Data
depth int
Expand All @@ -80,22 +81,28 @@ func (tc *TrustConfig) Validate(args ValidateArgs) {
}

if args.cert != nil {
certName := args.cert.Name()
dataName := args.Data.Name()
if len(args.DataName) > 0 {
dataName = args.DataName
}

// Check if the data claims to be a root certificate.
// This breaks the recursion for validation.
if args.Data.Name().Equal(args.cert.Name()) {
if dataName.Equal(certName) {
for _, root := range tc.Roots {
if args.Data.Name().Equal(root) {
if dataName.Equal(root) {
args.Callback(true, nil)
return
}
}
args.Callback(false, fmt.Errorf("data claims to be a trust anchor: %s", args.Data.Name()))
args.Callback(false, fmt.Errorf("data claims to be a trust anchor: %s", dataName))
return
}

// Check schema if the key is allowed
if !tc.Schema.Check(args.Data.Name(), args.cert.Name()) {
args.Callback(false, fmt.Errorf("key is not allowed: %s signed by %s", args.Data.Name(), args.cert.Name()))
if !tc.Schema.Check(dataName, certName) {
args.Callback(false, fmt.Errorf("key is not allowed: %s signed by %s", dataName, certName))
return
}

Expand All @@ -106,6 +113,7 @@ func (tc *TrustConfig) Validate(args ValidateArgs) {
Data: args.cert,
Fetch: args.Fetch,
Callback: args.Callback,
DataName: nil,
depth: args.depth,
cert: nil,
})
Expand Down
Loading

0 comments on commit f987dce

Please sign in to comment.