diff --git a/dv/config/config.go b/dv/config/config.go index 92d5182f..3cae70a6 100644 --- a/dv/config/config.go +++ b/dv/config/config.go @@ -17,6 +17,7 @@ const CostPfxInfinity = uint64(0xFFFFFFFF) // NlsrOrigin is the origin to use for local registration. const NlsrOrigin = uint64(mgmt.RouteOriginNLSR) +const PrefixInsOrigin = uint64(mgmt.RouteOriginPrefixIns) var MulticastStrategy = enc.LOCALHOST. Append(enc.NewGenericComponent("nfd")). @@ -39,6 +40,12 @@ type Config struct { KeyChainUri string `json:"keychain"` // List of trust anchor full names. TrustAnchors []string `json:"trust_anchors"` + // Path to trust schema for prefix insertion. + PrefixInsertionSchemaPath string `json:"prefix_insertion_schema"` + // URI specifying KeyChain location for prefix insertion verifier. + PrefixInsertionKeychainUri string `json:"prefix_insertion_keychain"` + // List of trust anchor full names for prefix insertion. + PrefixInsertionTrustAnchors []string `json:"prefix_insertion_trust_anchors"` // List of permanent neighbors. Neighbors []Neighbor `json:"neighbors"` @@ -60,6 +67,8 @@ type Config struct { mgmtPrefix enc.Name // Trust anchor names trustAnchorsN []enc.Name + // Prefix Insertion trust anchor names + prefixInsertionTrustAnchorsN []enc.Name } type Neighbor struct { @@ -81,6 +90,8 @@ func DefaultConfig() *Config { AdvertisementSyncInterval_ms: 5000, RouterDeadInterval_ms: 30000, KeyChainUri: "undefined", + PrefixInsertionSchemaPath: "deny", + PrefixInsertionKeychainUri: "undefined", } } @@ -136,6 +147,15 @@ func (c *Config) Parse() (err error) { c.trustAnchorsN = append(c.trustAnchorsN, name) } + c.prefixInsertionTrustAnchorsN = make([]enc.Name, 0, len(c.PrefixInsertionTrustAnchors)) + for _, anchor := range c.PrefixInsertionTrustAnchors { + name, err := enc.NameFromStr(anchor) + if err != nil { + return err + } + c.prefixInsertionTrustAnchorsN = append(c.prefixInsertionTrustAnchorsN, name) + } + // Advertisement sync and data prefixes c.advSyncPfxN = enc.LOCALHOP. Append(c.networkNameN...). @@ -206,6 +226,10 @@ func (c *Config) TrustAnchorNames() []enc.Name { return c.trustAnchorsN } +func (c *Config) PrefixInsertionTrustAnchorNames() []enc.Name { + return c.prefixInsertionTrustAnchorsN +} + func (c *Config) SchemaBytes() []byte { return SchemaBytes } diff --git a/dv/dv.sample.yml b/dv/dv.sample.yml index 435dbe63..6ea58698 100644 --- a/dv/dv.sample.yml +++ b/dv/dv.sample.yml @@ -12,6 +12,17 @@ dv: trust_anchors: - "/ndn/KEY/%27%C4%B2%2A%9F%7B%81%27/ndn/v=1651246789556" + # [optional] Trust schema for prefix insertion + # - If "insecure" is specified, security is disabled + # - If "deny" is specified, the prefix insertion handler will be turned off + # - Example: /absolute/path/to/schema.tlv + prefix_insertion_schema: "insecure" + # [optional] Keychain URI for prefix insertion + prefix_insertion_keychain: "insecure" + # [optional] List of full names of all prefix insertion trust anchors + # - There should be at least one trust anchor if the schema is not "insecure" or "deny" + prefix_insertion_trust_anchors: [] + # [optional] List of permanent neighbors # Example with all options: # - uri: udp4://suns.cs.ucla.edu:6363 # required diff --git a/dv/dv/insertion.go b/dv/dv/insertion.go new file mode 100644 index 00000000..73131e34 --- /dev/null +++ b/dv/dv/insertion.go @@ -0,0 +1,303 @@ +package dv + +import ( + "time" + + "github.com/named-data/ndnd/dv/config" + "github.com/named-data/ndnd/dv/nfdc" + "github.com/named-data/ndnd/dv/tlv" + enc "github.com/named-data/ndnd/std/encoding" + "github.com/named-data/ndnd/std/log" + "github.com/named-data/ndnd/std/ndn" + mgmt "github.com/named-data/ndnd/std/ndn/mgmt_2022" + spec "github.com/named-data/ndnd/std/ndn/spec_2022" + sig "github.com/named-data/ndnd/std/security/signer" + "github.com/named-data/ndnd/std/types/optional" +) + +func (dv *Router) onInsertion(args ndn.InterestHandlerArgs) { + resError := &mgmt.ControlResponse{ + Val: &mgmt.ControlResponseVal{ + StatusCode: 400, + StatusText: "Failed to execute prefix insertion", + Params: nil, + }, + } + + reply := func(res *mgmt.ControlResponse) { + signer := sig.NewSha256Signer() + data, err := dv.engine.Spec().MakeData( + args.Interest.Name(), + &ndn.DataConfig{ + ContentType: optional.Some(ndn.ContentTypeBlob), + Freshness: optional.Some(1 * time.Second), + }, + res.Encode(), + signer) + if err != nil { + log.Warn(dv, "Failed to make Prefix Insertion response Data", "err", err) + return + } + args.Reply(data.Wire) + } + + // If there is no incoming face ID, we can't use this + if !args.IncomingFaceId.IsSet() { + log.Warn(dv, "Received Prefix Insertion with no incoming face ID, ignoring") + reply(resError) + return + } + + // Check if app param is present + if args.Interest.AppParam() == nil { + log.Warn(dv, "Received Prefix Insertion with no AppParam, ignoring") + reply(resError) + return + } + + paParams, err := tlv.ParsePrefixInsertion(enc.NewWireView(args.Interest.AppParam()), true) + if err != nil { + log.Warn(dv, "Failed to parse Prefix Insertion AppParam", "err", err) + reply(resError) + return + } + + // Decode Prefix Announcement Object + dCtx := spec.DataParsingContext{} + dCtx.Init() + data, err := dCtx.Parse(enc.NewBufferView(paParams.Data), true) + if err != nil { + log.Warn(dv, "Failed to parse Prefix Insertion inner data", "err", err) + reply(resError) + return + } + sigCov := dCtx.SigCovered() + + var stapledCertCallbacks []ndn.ExpressCallbackArgs + for _, certWire := range paParams.StapledCertificates { + data, sigCov, err := spec.Spec{}.ReadData(enc.NewBufferView(certWire)) + if err != nil { + log.Warn(dv, "Stapled malformed certificate", "err", err) + reply(resError) + return + } + + stapledCertCallbacks = append(stapledCertCallbacks, + ndn.ExpressCallbackArgs{ + Result: ndn.InterestResultData, + Data: data, + RawData: enc.Wire{certWire}, + SigCovered: sigCov, + IsLocal: true, + }) + } + + // Validate signature + dv.prefixInsertionClient.ValidateExt(ndn.ValidateExtArgs{ + Data: data, + SigCovered: sigCov, + Fetch: optional.Some(func(name enc.Name, config *ndn.InterestConfig, callback ndn.ExpressCallbackFunc) { + for _, certCallback := range stapledCertCallbacks { + if certCallback.Data.Name().Equal(name) { + dv.prefixInsertionClient.Engine().Post(func() { + callback(certCallback) + }) + return + } + } + + config.NextHopId = optional.None[uint64]() + dv.prefixInsertionClient.ExpressR(ndn.ExpressRArgs{ + Name: name, + Config: config, + Retries: 3, + Callback: callback, + TryStore: dv.prefixInsertionClient.Store(), + }) + }), + Callback: func(valid bool, err error) { + if !valid || err != nil { + log.Warn(dv, "Failed to validate signature", "name", data.Name(), "valid", valid, "err", err) + reply(resError) + return + } + + res := dv.onPrefixInsertionObject(data, args.IncomingFaceId.Unwrap()) + reply(res) + }, + }) +} + +func (dv *Router) onPrefixInsertionObject(object ndn.Data, faceId uint64) *mgmt.ControlResponse { + resError := &mgmt.ControlResponse{ + Val: &mgmt.ControlResponseVal{ + StatusCode: 400, + StatusText: "Failed to execute prefix insertion", + Params: nil, + }, + } + + if contentType, set := object.ContentType().Get(); !set || contentType != ndn.ContentTypePrefixAnnouncement { + log.Warn(dv, "Prefix Announcement Object does not have the correct content type", + "contentType", object.ContentType()) + return resError + } + + var prefix enc.Name + found := false + var version uint64 + + for i, c := range object.Name() { + if c.IsKeyword("PA") { + if len(object.Name()) != i+3 || + !object.Name().At(i+1).IsVersion() || + !object.Name().At(i+2).IsSegment() || + object.Name().At(i+2).NumberVal() != 0 { + found = false + break + } + + prefix = object.Name().Prefix(i) + version = object.Name().At(i + 1).NumberVal() + found = true + break + } + } + + if !found { + log.Warn(dv, "Prefix Announcement Object name not in correct format", "name", object.Name()) + return resError + } + + // Check if we've seen a newer version of this prefix insertion + prefixStr := string(prefix.Bytes()) + if lastVersion, exists := dv.seenPrefixVersions[prefixStr]; exists && lastVersion >= version { + log.Info(dv, "Rejecting older or duplicate prefix insertion", + "prefix", prefix, + "version", version, + "lastVersion", lastVersion) + return &mgmt.ControlResponse{ + Val: &mgmt.ControlResponseVal{ + StatusCode: 409, + StatusText: "Older or duplicate prefix insertion version", + Params: nil, + }, + } + } + + dv.seenPrefixVersions[prefixStr] = version + + piWire := object.Content() + params, err := tlv.ParsePrefixInsertionInnerContent(enc.NewWireView(piWire), true) + if err != nil { + log.Warn(dv, "Failed to parse prefix announcement object", "err", err) + return resError + } + + // Check validity period if it exists + expirationPeriod := params.ExpirationPeriod + if params.ValidityPeriod != nil { + notBefore, err := time.Parse(spec.TimeFmt, params.ValidityPeriod.NotBefore) + if err != nil { + log.Warn(dv, "Failed to parse NotBefore time", "err", err, "value", params.ValidityPeriod.NotBefore) + return resError + } + notAfter, err := time.Parse(spec.TimeFmt, params.ValidityPeriod.NotAfter) + if err != nil { + log.Warn(dv, "Failed to parse NotAfter time", "err", err, "value", params.ValidityPeriod.NotAfter) + return resError + } + + now := time.Now().UTC() + if now.Before(notBefore) || now.After(notAfter) { + log.Info(dv, "Prefix insertion outside validity period", + "prefix", prefix, + "notBefore", notBefore, + "notAfter", notAfter, + "now", now) + return &mgmt.ControlResponse{ + Val: &mgmt.ControlResponseVal{ + StatusCode: 403, + StatusText: "Prefix insertion outside validity period", + Params: nil, + }, + } + } + + // Adjust expiration to be the minimum of the current expiration and notAfter - now + if expirationPeriod > 0 { + timeUntilExpiry := notAfter.Sub(now) + if timeUntilExpiry < time.Duration(expirationPeriod)*time.Millisecond { + expirationPeriod = uint64(timeUntilExpiry.Milliseconds()) + log.Debug(dv, "Adjusted expiration period based on validity period", + "prefix", prefix, + "newExpiration", expirationPeriod) + } + } + } + + var shouldRemove bool + var cost uint64 + if expirationPeriod == 0 { + // Remove the RIB entry + shouldRemove = true + cost = config.CostInfinity + } else { + // Add or update RIB entry + shouldRemove = false + cost = params.Cost.GetOr(0) + if cost > config.CostInfinity { + log.Warn(dv, "Invalid Cost value", "Cost", cost) + return resError + } + } + + // TODO: use the expiration period to set the lifetime of the RIB and prefix table entry + // (Currently the prefix table does not have a lifetime) + + if shouldRemove { + dv.nfdc.Exec(nfdc.NfdMgmtCmd{ + Module: "rib", + Cmd: "unregister", + Args: &mgmt.ControlArgs{ + Name: prefix, + FaceId: optional.Some(faceId), + }, + Retries: 3, + }) + } else { + dv.nfdc.Exec(nfdc.NfdMgmtCmd{ + Module: "rib", + Cmd: "register", + Args: &mgmt.ControlArgs{ + Name: prefix, + FaceId: optional.Some(faceId), + Origin: optional.Some(config.PrefixInsOrigin), + Cost: optional.Some(cost), + }, + Retries: 3, + }) + } + + dv.mutex.Lock() + defer dv.mutex.Unlock() + + if shouldRemove { + dv.pfx.Withdraw(prefix, faceId) + } else { + dv.pfx.Announce(prefix, faceId, cost) + } + + return &mgmt.ControlResponse{ + Val: &mgmt.ControlResponseVal{ + StatusCode: 200, + StatusText: "Prefix Insertion command successful", + Params: &mgmt.ControlArgs{ + Name: prefix, + FaceId: optional.Some(faceId), + Origin: optional.Some(config.PrefixInsOrigin), + Cost: optional.Some(cost), + }, + }, + } +} diff --git a/dv/dv/router.go b/dv/dv/router.go index 51c29a0b..72788870 100644 --- a/dv/dv/router.go +++ b/dv/dv/router.go @@ -1,6 +1,7 @@ package dv import ( + "os" "sync" "time" @@ -32,6 +33,10 @@ type Router struct { trust *sec.TrustConfig // object client client ndn.Client + // whether to do prefix insertion + enablePrefixInsertion bool + // prefix insertion client + prefixInsertionClient ndn.Client // nfd management thread nfdc *nfdc.NfdMgmtThread // single mutex for all operations @@ -60,6 +65,9 @@ type Router struct { rib *table.Rib // forwarding table fib *table.Fib + + // map to track seen prefix insertion versions (prefix string -> version) + seenPrefixVersions map[string]uint64 } // Create a new DV router. @@ -96,14 +104,48 @@ func NewRouter(config *config.Config, engine ndn.Engine) (*Router, error) { trust.UseDataNameFwHint = true } + enablePrefixInsertion := config.PrefixInsertionSchemaPath != "deny" + var prefixInsertionClient ndn.Client + if enablePrefixInsertion { + prefixInsertionStore := storage.NewMemoryStore() + var prefixInsertionTrust *sec.TrustConfig = nil + if config.PrefixInsertionSchemaPath == "insecure" || config.PrefixInsertionKeychainUri == "insecure" { + log.Warn(nil, "Prefix insertion module is in allow-all mode") + } else { + kc, err := keychain.NewKeyChain(config.PrefixInsertionKeychainUri, prefixInsertionStore) + if err != nil { + return nil, err + } + schemaData, err := os.ReadFile(config.PrefixInsertionSchemaPath) + if err != nil { + return nil, err + } + schema, err := trust_schema.NewLvsSchema(schemaData) + if err != nil { + return nil, err + } + anchors := config.PrefixInsertionTrustAnchorNames() + prefixInsertionTrust, err = sec.NewTrustConfig(kc, schema, anchors) + if err != nil { + return nil, err + } + } + prefixInsertionClient = object.NewClient(engine, prefixInsertionStore, prefixInsertionTrust) + } else { + log.Warn(nil, "Prefix insertion is disabled") + } + // Create the DV router dv := &Router{ - engine: engine, - config: config, - trust: trust, - client: object.NewClient(engine, store, trust), - nfdc: nfdc.NewNfdMgmtThread(engine), - mutex: sync.Mutex{}, + engine: engine, + config: config, + trust: trust, + client: object.NewClient(engine, store, trust), + enablePrefixInsertion: enablePrefixInsertion, + prefixInsertionClient: prefixInsertionClient, + nfdc: nfdc.NewNfdMgmtThread(engine), + mutex: sync.Mutex{}, + seenPrefixVersions: make(map[string]uint64), } // Initialize advertisement module @@ -239,6 +281,19 @@ func (dv *Router) register() (err error) { return err } + insertPrefix := enc.NewGenericComponent("routing"). + Append(enc.NewGenericComponent("insert")) + + if dv.enablePrefixInsertion { + err = dv.engine.AttachHandler(insertPrefix, + func(args ndn.InterestHandlerArgs) { + go dv.onInsertion(args) + }) + if err != nil { + return err + } + } + // Register routes to forwarder pfxs := []enc.Name{ dv.config.AdvertisementSyncPrefix(), @@ -247,6 +302,10 @@ func (dv *Router) register() (err error) { dv.pfxSvs.DataPrefix(), dv.config.MgmtPrefix(), } + if dv.enablePrefixInsertion { + pfxs = append(pfxs, insertPrefix) + } + for _, prefix := range pfxs { dv.nfdc.Exec(nfdc.NfdMgmtCmd{ Module: "rib", diff --git a/dv/tlv/definitions.go b/dv/tlv/definitions.go index a05e71be..cc5205de 100644 --- a/dv/tlv/definitions.go +++ b/dv/tlv/definitions.go @@ -1,7 +1,11 @@ //go:generate gondn_tlv_gen package tlv -import enc "github.com/named-data/ndnd/std/encoding" +import ( + enc "github.com/named-data/ndnd/std/encoding" + "github.com/named-data/ndnd/std/ndn/spec_2022" + "github.com/named-data/ndnd/std/types/optional" +) type Packet struct { //+field:struct:Advertisement @@ -68,3 +72,19 @@ type Status struct { //+field:natural NFibEntries uint64 `tlv:"0x19B"` } + +type PrefixInsertion struct { + //+field:sequence:[]byte:binary:[]byte + StapledCertificates [][]byte `tlv:"0x216"` + //+field:binary + Data []byte `tlv:"0x06"` +} + +type PrefixInsertionInnerContent struct { + //+field:natural + ExpirationPeriod uint64 `tlv:"0x6d"` + //+field:struct:spec_2022.ValidityPeriod + ValidityPeriod *spec_2022.ValidityPeriod `tlv:"0xfd"` + //+field:natural:optional + Cost optional.Optional[uint64] `tlv:"0x6a"` +} diff --git a/dv/tlv/zz_generated.go b/dv/tlv/zz_generated.go index b861309f..53315c93 100644 --- a/dv/tlv/zz_generated.go +++ b/dv/tlv/zz_generated.go @@ -7,6 +7,7 @@ import ( "strings" enc "github.com/named-data/ndnd/std/encoding" + "github.com/named-data/ndnd/std/ndn/spec_2022" ) type PacketEncoder struct { @@ -1683,3 +1684,430 @@ func ParseStatus(reader enc.WireView, ignoreCritical bool) (*Status, error) { context.Init() return context.Parse(reader, ignoreCritical) } + +type PrefixInsertionEncoder struct { + Length uint + + StapledCertificates_subencoder []struct { + } +} + +type PrefixInsertionParsingContext struct { +} + +func (encoder *PrefixInsertionEncoder) Init(value *PrefixInsertion) { + { + StapledCertificates_l := len(value.StapledCertificates) + encoder.StapledCertificates_subencoder = make([]struct { + }, StapledCertificates_l) + for i := 0; i < StapledCertificates_l; i++ { + pseudoEncoder := &encoder.StapledCertificates_subencoder[i] + pseudoValue := struct { + StapledCertificates []byte + }{ + StapledCertificates: value.StapledCertificates[i], + } + { + encoder := pseudoEncoder + value := &pseudoValue + + _ = encoder + _ = value + } + } + } + + l := uint(0) + if value.StapledCertificates != nil { + for seq_i, seq_v := range value.StapledCertificates { + pseudoEncoder := &encoder.StapledCertificates_subencoder[seq_i] + pseudoValue := struct { + StapledCertificates []byte + }{ + StapledCertificates: seq_v, + } + { + encoder := pseudoEncoder + value := &pseudoValue + if value.StapledCertificates != nil { + l += 3 + l += uint(enc.TLNum(len(value.StapledCertificates)).EncodingLength()) + l += uint(len(value.StapledCertificates)) + } + _ = encoder + _ = value + } + } + } + if value.Data != nil { + l += 1 + l += uint(enc.TLNum(len(value.Data)).EncodingLength()) + l += uint(len(value.Data)) + } + encoder.Length = l + +} + +func (context *PrefixInsertionParsingContext) Init() { + +} + +func (encoder *PrefixInsertionEncoder) EncodeInto(value *PrefixInsertion, buf []byte) { + + pos := uint(0) + + if value.StapledCertificates != nil { + for seq_i, seq_v := range value.StapledCertificates { + pseudoEncoder := &encoder.StapledCertificates_subencoder[seq_i] + pseudoValue := struct { + StapledCertificates []byte + }{ + StapledCertificates: seq_v, + } + { + encoder := pseudoEncoder + value := &pseudoValue + if value.StapledCertificates != nil { + buf[pos] = 253 + binary.BigEndian.PutUint16(buf[pos+1:], uint16(534)) + pos += 3 + pos += uint(enc.TLNum(len(value.StapledCertificates)).EncodeInto(buf[pos:])) + copy(buf[pos:], value.StapledCertificates) + pos += uint(len(value.StapledCertificates)) + } + _ = encoder + _ = value + } + } + } + if value.Data != nil { + buf[pos] = byte(6) + pos += 1 + pos += uint(enc.TLNum(len(value.Data)).EncodeInto(buf[pos:])) + copy(buf[pos:], value.Data) + pos += uint(len(value.Data)) + } +} + +func (encoder *PrefixInsertionEncoder) Encode(value *PrefixInsertion) enc.Wire { + + wire := make(enc.Wire, 1) + wire[0] = make([]byte, encoder.Length) + buf := wire[0] + encoder.EncodeInto(value, buf) + + return wire +} + +func (context *PrefixInsertionParsingContext) Parse(reader enc.WireView, ignoreCritical bool) (*PrefixInsertion, error) { + + var handled_StapledCertificates bool = false + var handled_Data bool = false + + progress := -1 + _ = progress + + value := &PrefixInsertion{} + var err error + var startPos int + for { + startPos = reader.Pos() + if startPos >= reader.Length() { + break + } + typ := enc.TLNum(0) + l := enc.TLNum(0) + typ, err = reader.ReadTLNum() + if err != nil { + return nil, enc.ErrFailToParse{TypeNum: 0, Err: err} + } + l, err = reader.ReadTLNum() + if err != nil { + return nil, enc.ErrFailToParse{TypeNum: 0, Err: err} + } + + err = nil + if handled := false; true { + switch typ { + case 534: + if true { + handled = true + handled_StapledCertificates = true + if value.StapledCertificates == nil { + value.StapledCertificates = make([][]byte, 0) + } + { + pseudoValue := struct { + StapledCertificates []byte + }{} + { + value := &pseudoValue + value.StapledCertificates = make([]byte, l) + _, err = reader.ReadFull(value.StapledCertificates) + _ = value + } + value.StapledCertificates = append(value.StapledCertificates, pseudoValue.StapledCertificates) + } + progress-- + } + case 6: + if true { + handled = true + handled_Data = true + value.Data = make([]byte, l) + _, err = reader.ReadFull(value.Data) + } + default: + if !ignoreCritical && ((typ <= 31) || ((typ & 1) == 1)) { + return nil, enc.ErrUnrecognizedField{TypeNum: typ} + } + handled = true + err = reader.Skip(int(l)) + } + if err == nil && !handled { + } + if err != nil { + return nil, enc.ErrFailToParse{TypeNum: typ, Err: err} + } + } + } + + startPos = reader.Pos() + err = nil + + if !handled_StapledCertificates && err == nil { + // sequence - skip + } + if !handled_Data && err == nil { + value.Data = nil + } + + if err != nil { + return nil, err + } + + return value, nil +} + +func (value *PrefixInsertion) Encode() enc.Wire { + encoder := PrefixInsertionEncoder{} + encoder.Init(value) + return encoder.Encode(value) +} + +func (value *PrefixInsertion) Bytes() []byte { + return value.Encode().Join() +} + +func ParsePrefixInsertion(reader enc.WireView, ignoreCritical bool) (*PrefixInsertion, error) { + context := PrefixInsertionParsingContext{} + context.Init() + return context.Parse(reader, ignoreCritical) +} + +type PrefixInsertionInnerContentEncoder struct { + Length uint + + ValidityPeriod_encoder spec_2022.ValidityPeriodEncoder +} + +type PrefixInsertionInnerContentParsingContext struct { + ValidityPeriod_context spec_2022.ValidityPeriodParsingContext +} + +func (encoder *PrefixInsertionInnerContentEncoder) Init(value *PrefixInsertionInnerContent) { + + if value.ValidityPeriod != nil { + encoder.ValidityPeriod_encoder.Init(value.ValidityPeriod) + } + + l := uint(0) + l += 1 + l += uint(1 + enc.Nat(value.ExpirationPeriod).EncodingLength()) + if value.ValidityPeriod != nil { + l += 3 + l += uint(enc.TLNum(encoder.ValidityPeriod_encoder.Length).EncodingLength()) + l += encoder.ValidityPeriod_encoder.Length + } + if optval, ok := value.Cost.Get(); ok { + l += 1 + l += uint(1 + enc.Nat(optval).EncodingLength()) + } + encoder.Length = l + +} + +func (context *PrefixInsertionInnerContentParsingContext) Init() { + + context.ValidityPeriod_context.Init() + +} + +func (encoder *PrefixInsertionInnerContentEncoder) EncodeInto(value *PrefixInsertionInnerContent, buf []byte) { + + pos := uint(0) + + buf[pos] = byte(109) + pos += 1 + + buf[pos] = byte(enc.Nat(value.ExpirationPeriod).EncodeInto(buf[pos+1:])) + pos += uint(1 + buf[pos]) + if value.ValidityPeriod != nil { + buf[pos] = 253 + binary.BigEndian.PutUint16(buf[pos+1:], uint16(253)) + pos += 3 + pos += uint(enc.TLNum(encoder.ValidityPeriod_encoder.Length).EncodeInto(buf[pos:])) + if encoder.ValidityPeriod_encoder.Length > 0 { + encoder.ValidityPeriod_encoder.EncodeInto(value.ValidityPeriod, buf[pos:]) + pos += encoder.ValidityPeriod_encoder.Length + } + } + if optval, ok := value.Cost.Get(); ok { + buf[pos] = byte(106) + pos += 1 + + buf[pos] = byte(enc.Nat(optval).EncodeInto(buf[pos+1:])) + pos += uint(1 + buf[pos]) + + } +} + +func (encoder *PrefixInsertionInnerContentEncoder) Encode(value *PrefixInsertionInnerContent) enc.Wire { + + wire := make(enc.Wire, 1) + wire[0] = make([]byte, encoder.Length) + buf := wire[0] + encoder.EncodeInto(value, buf) + + return wire +} + +func (context *PrefixInsertionInnerContentParsingContext) Parse(reader enc.WireView, ignoreCritical bool) (*PrefixInsertionInnerContent, error) { + + var handled_ExpirationPeriod bool = false + var handled_ValidityPeriod bool = false + var handled_Cost bool = false + + progress := -1 + _ = progress + + value := &PrefixInsertionInnerContent{} + var err error + var startPos int + for { + startPos = reader.Pos() + if startPos >= reader.Length() { + break + } + typ := enc.TLNum(0) + l := enc.TLNum(0) + typ, err = reader.ReadTLNum() + if err != nil { + return nil, enc.ErrFailToParse{TypeNum: 0, Err: err} + } + l, err = reader.ReadTLNum() + if err != nil { + return nil, enc.ErrFailToParse{TypeNum: 0, Err: err} + } + + err = nil + if handled := false; true { + switch typ { + case 109: + if true { + handled = true + handled_ExpirationPeriod = true + value.ExpirationPeriod = uint64(0) + { + for i := 0; i < int(l); i++ { + x := byte(0) + x, err = reader.ReadByte() + if err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + break + } + value.ExpirationPeriod = uint64(value.ExpirationPeriod<<8) | uint64(x) + } + } + } + case 253: + if true { + handled = true + handled_ValidityPeriod = true + value.ValidityPeriod, err = context.ValidityPeriod_context.Parse(reader.Delegate(int(l)), ignoreCritical) + } + case 106: + if true { + handled = true + handled_Cost = true + { + optval := uint64(0) + optval = uint64(0) + { + for i := 0; i < int(l); i++ { + x := byte(0) + x, err = reader.ReadByte() + if err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + break + } + optval = uint64(optval<<8) | uint64(x) + } + } + value.Cost.Set(optval) + } + } + default: + if !ignoreCritical && ((typ <= 31) || ((typ & 1) == 1)) { + return nil, enc.ErrUnrecognizedField{TypeNum: typ} + } + handled = true + err = reader.Skip(int(l)) + } + if err == nil && !handled { + } + if err != nil { + return nil, enc.ErrFailToParse{TypeNum: typ, Err: err} + } + } + } + + startPos = reader.Pos() + err = nil + + if !handled_ExpirationPeriod && err == nil { + err = enc.ErrSkipRequired{Name: "ExpirationPeriod", TypeNum: 109} + } + if !handled_ValidityPeriod && err == nil { + value.ValidityPeriod = nil + } + if !handled_Cost && err == nil { + value.Cost.Unset() + } + + if err != nil { + return nil, err + } + + return value, nil +} + +func (value *PrefixInsertionInnerContent) Encode() enc.Wire { + encoder := PrefixInsertionInnerContentEncoder{} + encoder.Init(value) + return encoder.Encode(value) +} + +func (value *PrefixInsertionInnerContent) Bytes() []byte { + return value.Encode().Join() +} + +func ParsePrefixInsertionInnerContent(reader enc.WireView, ignoreCritical bool) (*PrefixInsertionInnerContent, error) { + context := PrefixInsertionInnerContentParsingContext{} + context.Init() + return context.Parse(reader, ignoreCritical) +} diff --git a/std/ndn/client.go b/std/ndn/client.go index f978408a..b99bc75e 100644 --- a/std/ndn/client.go +++ b/std/ndn/client.go @@ -161,6 +161,9 @@ type ValidateExtArgs struct { CertNextHop optional.Optional[uint64] // UseDataNameFwHint overrides trust config option. UseDataNameFwHint optional.Optional[bool] + // Fetch function to use for fetching certificates. + // The fetcher MUST check the store for the certificate before fetching. + Fetch optional.Optional[func(enc.Name, *InterestConfig, ExpressCallbackFunc)] } // Announcement are the arguments for the announce prefix API. diff --git a/std/ndn/mgmt_2022/route.go b/std/ndn/mgmt_2022/route.go index fd29e957..ea9158c6 100644 --- a/std/ndn/mgmt_2022/route.go +++ b/std/ndn/mgmt_2022/route.go @@ -31,6 +31,7 @@ const ( RouteOriginStatic RouteOrigin = 255 RouteOriginNLSR RouteOrigin = 128 RouteOriginPrefixAnn RouteOrigin = 129 + RouteOriginPrefixIns RouteOrigin = 130 RouteOriginClient RouteOrigin = 65 RouteOriginAutoreg RouteOrigin = 64 RouteOriginAutoconf RouteOrigin = 66 diff --git a/std/object/client_trust.go b/std/object/client_trust.go index 3c0a5417..f5b7b9c7 100644 --- a/std/object/client_trust.go +++ b/std/object/client_trust.go @@ -40,22 +40,25 @@ func (c *Client) ValidateExt(args ndn.ValidateExtArgs) { overrideName = args.OverrideName } + // Default fetch function + fetch := args.Fetch.GetOr(func(name enc.Name, config *ndn.InterestConfig, callback ndn.ExpressCallbackFunc) { + config.NextHopId = args.CertNextHop + c.ExpressR(ndn.ExpressRArgs{ + Name: name, + Config: config, + Retries: 3, + Callback: callback, + TryStore: c.store, + }) + }) + c.trust.Validate(sec.TrustConfigValidateArgs{ Data: args.Data, DataSigCov: args.SigCovered, Callback: args.Callback, OverrideName: overrideName, UseDataNameFwHint: args.UseDataNameFwHint, - Fetch: func(name enc.Name, config *ndn.InterestConfig, callback ndn.ExpressCallbackFunc) { - config.NextHopId = args.CertNextHop - c.ExpressR(ndn.ExpressRArgs{ - Name: name, - Config: config, - Retries: 3, - Callback: callback, - TryStore: c.store, - }) - }, + Fetch: fetch, }) }