Skip to content

Commit

Permalink
Merge branch 'master' into doc-manual-fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
matzf authored Oct 12, 2023
2 parents ad8fcc8 + 734f909 commit 38f9562
Show file tree
Hide file tree
Showing 25 changed files with 298 additions and 64 deletions.
2 changes: 2 additions & 0 deletions control/beaconing/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ go_library(
"//private/segment/verifier:go_default_library",
"//private/topology:go_default_library",
"//private/tracing:go_default_library",
"//private/trust:go_default_library",
"@com_github_opentracing_opentracing_go//:go_default_library",
],
)
Expand Down Expand Up @@ -70,6 +71,7 @@ go_test(
"//pkg/scrypto/signed:go_default_library",
"//pkg/segment:go_default_library",
"//pkg/segment/extensions/staticinfo:go_default_library",
"//pkg/slayers/path:go_default_library",
"//pkg/slayers/path/scion:go_default_library",
"//pkg/snet:go_default_library",
"//pkg/snet/addrutil:go_default_library",
Expand Down
64 changes: 50 additions & 14 deletions control/beaconing/extender.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,22 @@ import (
"github.com/scionproto/scion/control/ifstate"
"github.com/scionproto/scion/pkg/addr"
"github.com/scionproto/scion/pkg/log"
"github.com/scionproto/scion/pkg/metrics"
"github.com/scionproto/scion/pkg/private/serrors"
"github.com/scionproto/scion/pkg/private/util"
seg "github.com/scionproto/scion/pkg/segment"
"github.com/scionproto/scion/pkg/segment/extensions/digest"
"github.com/scionproto/scion/pkg/segment/extensions/epic"
"github.com/scionproto/scion/pkg/slayers/path"
"github.com/scionproto/scion/private/trust"
)

// SignerGen generates signers and returns their expiration time.
type SignerGen interface {
// Generate generates a signer it.
Generate(ctx context.Context) (trust.Signer, error)
}

// Extender extends path segments.
type Extender interface {
// Extend extends the path segment. The zero value for ingress indicates
Expand All @@ -44,8 +52,8 @@ type Extender interface {
type DefaultExtender struct {
// IA is the local IA
IA addr.IA
// Signer is used to sign path segments.
Signer seg.Signer
// SignerGen is used to sign path segments.
SignerGen SignerGen
// MAC is used to calculate the hop field MAC.
MAC func() hash.Hash
// Intfs holds all interfaces in the AS.
Expand All @@ -60,6 +68,11 @@ type DefaultExtender struct {
StaticInfo func() *StaticInfoCfg
// EPIC defines whether the EPIC authenticators should be added when the segment is extended.
EPIC bool

// SegmentExpirationDeficient is a gauge that is set to 1 if the expiration time of the segment
// is below the maximum expiration time. This happens when the signer expiration time is lower
// than the maximum segment expiration time.
SegmentExpirationDeficient metrics.Gauge
}

// Extend extends the beacon with hop fields.
Expand All @@ -85,8 +98,27 @@ func (s *DefaultExtender) Extend(
}
ts := pseg.Info.Timestamp

signer, err := s.SignerGen.Generate(ctx)
if err != nil {
return serrors.WrapStr("getting signer", err)
}
// Make sure the hop expiration time is not longer than the signer expiration time.
expTime := s.MaxExpTime()
if ts.Add(path.ExpTimeToDuration(expTime)).After(signer.Expiration) {
metrics.GaugeSet(s.SegmentExpirationDeficient, 1)
var err error
expTime, err = path.ExpTimeFromDuration(signer.Expiration.Sub(ts))
if err != nil {
return serrors.WrapStr(
"calculating expiry time from signer expiration time", err,
"signer_expiration", signer.Expiration,
)
}
} else {
metrics.GaugeSet(s.SegmentExpirationDeficient, 0)
}
hopBeta := extractBeta(pseg)
hopEntry, epicHopMac, err := s.createHopEntry(ingress, egress, ts, hopBeta)
hopEntry, epicHopMac, err := s.createHopEntry(ingress, egress, expTime, ts, hopBeta)
if err != nil {
return serrors.WrapStr("creating hop entry", err)
}
Expand All @@ -104,7 +136,7 @@ func (s *DefaultExtender) Extend(
// is traversed.

peerBeta := hopBeta ^ binary.BigEndian.Uint16(hopEntry.HopField.MAC[:2])
peerEntries, epicPeerMacs, err := s.createPeerEntries(egress, peers, ts, peerBeta)
peerEntries, epicPeerMacs, err := s.createPeerEntries(egress, peers, expTime, ts, peerBeta)
if err != nil {
return err
}
Expand Down Expand Up @@ -143,7 +175,7 @@ func (s *DefaultExtender) Extend(
}
}

if err := pseg.AddASEntry(ctx, asEntry, s.Signer); err != nil {
if err := pseg.AddASEntry(ctx, asEntry, signer); err != nil {
return err
}
if egress == 0 {
Expand All @@ -153,12 +185,12 @@ func (s *DefaultExtender) Extend(
}

func (s *DefaultExtender) createPeerEntries(egress uint16, peers []uint16,
ts time.Time, beta uint16) ([]seg.PeerEntry, [][]byte, error) {
expTime uint8, ts time.Time, beta uint16) ([]seg.PeerEntry, [][]byte, error) {

peerEntries := make([]seg.PeerEntry, 0, len(peers))
peerEpicMacs := make([][]byte, 0, len(peers))
for _, peer := range peers {
peerEntry, epicMac, err := s.createPeerEntry(peer, egress, ts, beta)
peerEntry, epicMac, err := s.createPeerEntry(peer, egress, expTime, ts, beta)
if err != nil {
log.Debug("Ignoring peer link upon error",
"task", s.Task, "peer_interface", peer, "err", err)
Expand All @@ -170,15 +202,20 @@ func (s *DefaultExtender) createPeerEntries(egress uint16, peers []uint16,
return peerEntries, peerEpicMacs, nil
}

func (s *DefaultExtender) createHopEntry(ingress, egress uint16, ts time.Time,
beta uint16) (seg.HopEntry, []byte, error) {
func (s *DefaultExtender) createHopEntry(
ingress,
egress uint16,
expTime uint8,
ts time.Time,
beta uint16,
) (seg.HopEntry, []byte, error) {

remoteInMTU, err := s.remoteMTU(ingress)
if err != nil {
return seg.HopEntry{}, nil, serrors.WrapStr("checking remote ingress interface (mtu)", err,
"interfaces", ingress)
}
hopF, epicMac := s.createHopF(ingress, egress, ts, beta)
hopF, epicMac := s.createHopF(ingress, egress, expTime, ts, beta)
return seg.HopEntry{
IngressMTU: int(remoteInMTU),
HopField: seg.HopField{
Expand All @@ -190,15 +227,15 @@ func (s *DefaultExtender) createHopEntry(ingress, egress uint16, ts time.Time,
}, epicMac, nil
}

func (s *DefaultExtender) createPeerEntry(ingress, egress uint16, ts time.Time,
func (s *DefaultExtender) createPeerEntry(ingress, egress uint16, expTime uint8, ts time.Time,
beta uint16) (seg.PeerEntry, []byte, error) {

remoteInIA, remoteInIfID, remoteInMTU, err := s.remoteInfo(ingress)
if err != nil {
return seg.PeerEntry{}, nil, serrors.WrapStr("checking remote ingress interface", err,
"ingress_interface", ingress)
}
hopF, epicMac := s.createHopF(ingress, egress, ts, beta)
hopF, epicMac := s.createHopF(ingress, egress, expTime, ts, beta)
return seg.PeerEntry{
PeerMTU: int(remoteInMTU),
Peer: remoteInIA,
Expand Down Expand Up @@ -259,10 +296,9 @@ func (s *DefaultExtender) remoteInfo(ifid uint16) (
return topoInfo.IA, topoInfo.RemoteID, topoInfo.MTU, nil
}

func (s *DefaultExtender) createHopF(ingress, egress uint16, ts time.Time,
func (s *DefaultExtender) createHopF(ingress, egress uint16, expTime uint8, ts time.Time,
beta uint16) (path.HopField, []byte) {

expTime := s.MaxExpTime()
input := make([]byte, path.MACBufferSize)
path.MACInput(beta, util.TimeToSecs(ts), expTime, ingress, egress, input)

Expand Down
114 changes: 107 additions & 7 deletions control/beaconing/extender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ import (
cryptopb "github.com/scionproto/scion/pkg/proto/crypto"
"github.com/scionproto/scion/pkg/scrypto"
seg "github.com/scionproto/scion/pkg/segment"
"github.com/scionproto/scion/pkg/slayers/path"
"github.com/scionproto/scion/private/topology"
"github.com/scionproto/scion/private/trust"
)

func TestDefaultExtenderExtend(t *testing.T) {
Expand Down Expand Up @@ -98,8 +100,8 @@ func TestDefaultExtenderExtend(t *testing.T) {
intfs.Get(peer).Activate(peerRemoteIfs[peer])
}
ext := &beaconing.DefaultExtender{
IA: topo.IA(),
Signer: testSigner(t, priv, topo.IA()),
IA: topo.IA(),
SignerGen: testSignerGen{Signer: testSigner(t, priv, topo.IA())},
MAC: func() hash.Hash {
mac, err := scrypto.InitMac(make([]byte, 16))
require.NoError(t, err)
Expand Down Expand Up @@ -171,8 +173,8 @@ func TestDefaultExtenderExtend(t *testing.T) {
intfs := ifstate.NewInterfaces(interfaceInfos(topo), ifstate.Config{})
require.NoError(t, err)
ext := &beaconing.DefaultExtender{
IA: topo.IA(),
Signer: testSigner(t, priv, topo.IA()),
IA: topo.IA(),
SignerGen: testSignerGen{Signer: testSigner(t, priv, topo.IA())},
MAC: func() hash.Hash {
mac, err := scrypto.InitMac(make([]byte, 16))
require.NoError(t, err)
Expand All @@ -189,8 +191,106 @@ func TestDefaultExtenderExtend(t *testing.T) {
err = ext.Extend(context.Background(), pseg, 0, graph.If_111_A_112_X, []uint16{})
require.NoError(t, err)
assert.Equal(t, uint8(1), pseg.ASEntries[0].HopEntry.HopField.ExpTime)

})
t.Run("segment and signer expiration interaction", func(t *testing.T) {
ts := time.Now()
testCases := map[string]struct {
SignerGen beaconing.SignerGen
MaxExpTime func() uint8
ExpTime uint8
ErrAssertion assert.ErrorAssertionFunc
}{
"signer expires before max expiration time": {
SignerGen: testSignerGen{
Signer: func() trust.Signer {
s := testSigner(t, priv, topo.IA())
s.Expiration = ts.Add(path.MaxTTL / 2)
return s
}(),
},
ExpTime: 127,
MaxExpTime: func() uint8 { return 255 },
ErrAssertion: assert.NoError,
},
"signer expires after max expiration time": {
SignerGen: testSignerGen{
Signer: func() trust.Signer {
s := testSigner(t, priv, topo.IA())
s.Expiration = ts.Add(path.MaxTTL)
return s
}(),
},
ExpTime: 254,
MaxExpTime: func() uint8 { return 254 },
ErrAssertion: assert.NoError,
},
"minimum signer expiration time": {
SignerGen: testSignerGen{
Signer: func() trust.Signer {
s := testSigner(t, priv, topo.IA())
s.Expiration = ts.Add(path.MaxTTL / 256)
return s
}(),
},
ExpTime: 0,
MaxExpTime: func() uint8 { return 10 },
ErrAssertion: assert.NoError,
},
"signer expiration time too small": {
SignerGen: testSignerGen{
Signer: func() trust.Signer {
s := testSigner(t, priv, topo.IA())
s.Expiration = ts.Add(path.MaxTTL / 257)
return s
}(),
},
MaxExpTime: func() uint8 { return 10 },
ErrAssertion: assert.Error,
},
"signer expiration time too large uses MaxExpTime": {
SignerGen: testSignerGen{
Signer: func() trust.Signer {
s := testSigner(t, priv, topo.IA())
s.Expiration = ts.Add(2 * path.MaxTTL)
return s
}(),
},
ExpTime: 157,
MaxExpTime: func() uint8 { return 157 },
ErrAssertion: assert.NoError,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
mctrl := gomock.NewController(t)
defer mctrl.Finish()
intfs := ifstate.NewInterfaces(interfaceInfos(topo), ifstate.Config{})
require.NoError(t, err)
ext := &beaconing.DefaultExtender{
IA: topo.IA(),
SignerGen: tc.SignerGen,
MAC: func() hash.Hash {
mac, err := scrypto.InitMac(make([]byte, 16))
require.NoError(t, err)
return mac
},
Intfs: intfs,
MTU: 1337,
MaxExpTime: tc.MaxExpTime,
StaticInfo: func() *beaconing.StaticInfoCfg { return nil },
}
pseg, err := seg.CreateSegment(ts, uint16(mrand.Int()))
require.NoError(t, err)
err = ext.Extend(context.Background(), pseg, 0, graph.If_111_A_112_X, []uint16{})
tc.ErrAssertion(t, err)
if err != nil {
return
}
assert.Equal(t, tc.ExpTime, pseg.ASEntries[0].HopEntry.HopField.ExpTime)
})
}
})

t.Run("segment is not extended on error", func(t *testing.T) {
defaultSigner := func(t *testing.T) seg.Signer {
return testSigner(t, priv, topo.IA())
Expand Down Expand Up @@ -238,8 +338,8 @@ func TestDefaultExtenderExtend(t *testing.T) {
defer mctrl.Finish()
intfs := ifstate.NewInterfaces(interfaceInfos(topo), ifstate.Config{})
ext := &beaconing.DefaultExtender{
IA: topo.IA(),
Signer: testSigner(t, priv, topo.IA()),
IA: topo.IA(),
SignerGen: testSignerGen{Signer: testSigner(t, priv, topo.IA())},
MAC: func() hash.Hash {
mac, err := scrypto.InitMac(make([]byte, 16))
require.NoError(t, err)
Expand Down
4 changes: 2 additions & 2 deletions control/beaconing/originator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func TestOriginatorRun(t *testing.T) {
Extender: &beaconing.DefaultExtender{
IA: topo.IA(),
MTU: topo.MTU(),
Signer: signer,
SignerGen: testSignerGen{Signer: signer},
Intfs: intfs,
MAC: macFactory,
MaxExpTime: func() uint8 { return beacon.DefaultMaxExpTime },
Expand Down Expand Up @@ -130,7 +130,7 @@ func TestOriginatorRun(t *testing.T) {
Extender: &beaconing.DefaultExtender{
IA: topo.IA(),
MTU: topo.MTU(),
Signer: signer,
SignerGen: testSignerGen{Signer: signer},
Intfs: intfs,
MAC: macFactory,
MaxExpTime: func() uint8 { return beacon.DefaultMaxExpTime },
Expand Down
6 changes: 3 additions & 3 deletions control/beaconing/propagator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func TestPropagatorRunNonCore(t *testing.T) {
Extender: &beaconing.DefaultExtender{
IA: topo.IA(),
MTU: topo.MTU(),
Signer: testSigner(t, priv, topo.IA()),
SignerGen: testSignerGen{Signer: testSigner(t, priv, topo.IA())},
Intfs: intfs,
MAC: macFactory,
MaxExpTime: func() uint8 { return beacon.DefaultMaxExpTime },
Expand Down Expand Up @@ -138,7 +138,7 @@ func TestPropagatorRunCore(t *testing.T) {
Extender: &beaconing.DefaultExtender{
IA: topo.IA(),
MTU: topo.MTU(),
Signer: testSigner(t, priv, topo.IA()),
SignerGen: testSignerGen{Signer: testSigner(t, priv, topo.IA())},
Intfs: intfs,
MAC: macFactory,
MaxExpTime: func() uint8 { return beacon.DefaultMaxExpTime },
Expand Down Expand Up @@ -226,7 +226,7 @@ func TestPropagatorFastRecovery(t *testing.T) {
Extender: &beaconing.DefaultExtender{
IA: topo.IA(),
MTU: topo.MTU(),
Signer: testSigner(t, priv, topo.IA()),
SignerGen: testSignerGen{Signer: testSigner(t, priv, topo.IA())},
Intfs: intfs,
MAC: macFactory,
MaxExpTime: func() uint8 { return beacon.DefaultMaxExpTime },
Expand Down
Loading

0 comments on commit 38f9562

Please sign in to comment.