Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
tzaeschke authored Sep 20, 2024
2 parents 56c8101 + 2610321 commit bac651f
Show file tree
Hide file tree
Showing 373 changed files with 5,280 additions and 2,377 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/gobra.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
caching: '1'
statsFile: ${{ env.statsFile }}
- name: Upload the verification report
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: verification_stats.json
path: ${{ env.statsFile }}
4 changes: 2 additions & 2 deletions .github/workflows/pr-title.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ jobs:
# Check that PR is of the form `<subsystem>: <lowercase message>`
url='https://docs.scion.org/en/latest/dev/git.html#good-commit-messages'
if [[ ! "$TITLE" =~ ^[a-z0-9,/]*:[[:space:]] ]]; then
if [[ ! "$TITLE" =~ ^[a-z0-9,/-]*:[[:space:]] ]]; then
echo '::error::The PR title should start with `<substystem>: `. See '"$url"
exit 1
fi
# Title should be lower case; initialisms and identifiers still occur occasionally and should be allowed.
# -> enforce only the first word
if [[ ! "$TITLE" =~ ^[a-z0-9,/]*:[[:space:]][a-z] ]]; then
if [[ ! "$TITLE" =~ ^[a-z0-9,/-]*:[[:space:]][a-z] ]]; then
echo '::error::The PR title should be lower case (enforced on first letter). See '"$url"
exit 1
fi
Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ mocks:

gazelle: go_deps.bzl
bazel run //:gazelle --verbose_failures --config=quiet
./tools/buildrill/go_integration_test_sync

licenses:
tools/licenses.sh
Expand Down Expand Up @@ -120,7 +121,7 @@ GO_BUILD_TAGS_ARG=$(shell bazel info --ui_event_filters=-stdout,-stderr --announ
lint-go-golangci:
$(info ==> $@)
@if [ -t 1 ]; then tty=true; else tty=false; fi; \
tools/quiet docker run --tty=$$tty --rm -v golangci-lint-modcache:/go -v golangci-lint-buildcache:/root/.cache -v "${PWD}:/src" -w /src golangci/golangci-lint:v1.54.2 golangci-lint run --config=/src/.golangcilint.yml --timeout=3m $(GO_BUILD_TAGS_ARG) --skip-dirs doc ./...
tools/quiet docker run --tty=$$tty --rm -v golangci-lint-modcache:/go -v golangci-lint-buildcache:/root/.cache -v "${PWD}:/src" -w /src golangci/golangci-lint:v1.60.3 golangci-lint run --config=/src/.golangcilint.yml --timeout=3m $(GO_BUILD_TAGS_ARG) --skip-dirs doc ./...

lint-go-semgrep:
$(info ==> $@)
Expand Down
15 changes: 7 additions & 8 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,20 @@ aspect_bazel_lib_register_toolchains()
# Bazel rules for Golang
http_archive(
name = "io_bazel_rules_go",
sha256 = "91585017debb61982f7054c9688857a2ad1fd823fc3f9cb05048b0025c47d023",
sha256 = "af47f30e9cbd70ae34e49866e201b3f77069abb111183f2c0297e7e74ba6bbc0",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.42.0/rules_go-v0.42.0.zip",
"https://github.com/bazelbuild/rules_go/releases/download/v0.42.0/rules_go-v0.42.0.zip",
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.47.0/rules_go-v0.47.0.zip",
"https://github.com/bazelbuild/rules_go/releases/download/v0.47.0/rules_go-v0.47.0.zip",
],
)

load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")

go_rules_dependencies()

go_register_toolchains(
nogo = "@//:nogo",
version = "1.21.10",
version = "1.22.7",
)

# Gazelle
Expand All @@ -71,9 +73,6 @@ http_archive(
)

load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")

go_rules_dependencies()

load("//:tool_deps.bzl", "tool_deps")

tool_deps()
Expand Down Expand Up @@ -266,7 +265,7 @@ load("@aspect_rules_js//js:repositories.bzl", "rules_js_dependencies")

rules_js_dependencies()

load("@rules_nodejs//nodejs:repositories.bzl", "DEFAULT_NODE_VERSION", "nodejs_register_toolchains")
load("@rules_nodejs//nodejs:repositories.bzl", "nodejs_register_toolchains")

nodejs_register_toolchains(
name = "nodejs",
Expand Down
4 changes: 3 additions & 1 deletion acceptance/router_benchmark/benchmarklib.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ def run_test_case(self, case: str, map_args: list[str]) -> (int, int):
output = self.exec_br_load(case, map_args, 13)
end = "0"
for line in output.splitlines():
logger.info("BrLoad output: " + line)
if line.startswith("metricsBegin"):
end = line.split()[3] # "... metricsEnd: <end>"

Expand Down Expand Up @@ -322,7 +323,8 @@ def run_bm(self, test_cases: [str]) -> Results:
self.exec_br_load(test_cases[0], map_args, 5)

# Fetch the core count once. It doesn't change while the router is running.
# We can't get it until the router has done some work, but the warmup is enough.
# We cannot get this until the router has been up for a few seconds. If you shorten
# the warmup for some reason, make sure to add a delay.
cores = self.core_count()

# At long last, run the tests.
Expand Down
5 changes: 3 additions & 2 deletions acceptance/router_benchmark/brload/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ func run(cmd *cobra.Command) int {
binary.BigEndian.PutUint16(allPkts[j][44:46], uint16(numPkt%int(numStreams)))
numPkt++
}

if _, err := sender.sendAll(); err != nil {
log.Error("writing input packet", "case", string(caseToRun), "error", err)
return 1
Expand Down Expand Up @@ -303,9 +304,9 @@ func openDevices(interfaceNames []string) (map[string]*afpacket.TPacket, error)
handles := make(map[string]*afpacket.TPacket)

for _, intf := range interfaceNames {
handle, err := afpacket.NewTPacket(afpacket.OptInterface(intf))
handle, err := afpacket.NewTPacket(afpacket.OptInterface(intf), afpacket.OptFrameSize(4096))
if err != nil {
return nil, serrors.WrapStr("creating TPacket", err)
return nil, serrors.Wrap("creating TPacket", err)
}
handles[intf] = handle
}
Expand Down
6 changes: 5 additions & 1 deletion acceptance/router_benchmark/brload/mmsg.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@ import (
type mmsgHdr struct {
hdr unix.Msghdr
len uint32
_ [4]byte
}

// mpktSender is a helper class to add the ability of using the sendmmsg system call
// with afpacket sockets.
type mpktSender struct {
fd int
tp *afpacket.TPacket
msgs []mmsgHdr
iovecs []unix.Iovec
}
Expand All @@ -42,6 +44,8 @@ func newMpktSender(tp *afpacket.TPacket) *mpktSender {
// than this) to the afpacket project and get it merged.
fdv := reflect.ValueOf(tp).Elem().FieldByName("fd")
sender.fd = int(fdv.Int())
// This is to make sure that tp cannot be finalized before we're done abusing its file desc.
sender.tp = tp
return sender
}

Expand All @@ -66,7 +70,7 @@ func (sender *mpktSender) sendAll() (int, error) {
// use case.
n, _, err := unix.Syscall6(unix.SYS_SENDMMSG,
uintptr(sender.fd),
(uintptr)(unsafe.Pointer(&sender.msgs[0])),
uintptr(unsafe.Pointer(&sender.msgs[0])),
uintptr(len(sender.msgs)),
0, 0, 0)
if err == 0 {
Expand Down
2 changes: 1 addition & 1 deletion acceptance/router_benchmark/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
logger = logging.getLogger(__name__)

# Default packet length for CI testing
BM_PACKET_SIZE = 172
BM_PACKET_SIZE = 1500

# Router profiling ON or OFF?
PROFILING = False
Expand Down
8 changes: 8 additions & 0 deletions control/beacon/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go_library(
name = "go_default_library",
srcs = [
"beacon.go",
"chain_checker.go",
"db.go",
"policy.go",
"selection_algo.go",
Expand All @@ -18,7 +19,14 @@ go_library(
"//pkg/private/ptr:go_default_library",
"//pkg/private/serrors:go_default_library",
"//pkg/proto/control_plane:go_default_library",
"//pkg/proto/crypto:go_default_library",
"//pkg/scrypto/cppki:go_default_library",
"//pkg/scrypto/signed:go_default_library",
"//pkg/segment:go_default_library",
"//private/segment/segverifier:go_default_library",
"//private/segment/verifier:go_default_library",
"//private/trust:go_default_library",
"@com_github_patrickmn_go_cache//:go_default_library",
"@in_gopkg_yaml_v2//:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
],
Expand Down
2 changes: 1 addition & 1 deletion control/beacon/beacondbtest/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ go_library(
deps = [
"//control/beacon:go_default_library",
"//pkg/addr:go_default_library",
"//pkg/private/common:go_default_library",
"//pkg/private/xtest/graph:go_default_library",
"//pkg/segment:go_default_library",
"//pkg/segment/iface:go_default_library",
"//pkg/slayers/path:go_default_library",
"@com_github_stretchr_testify//assert:go_default_library",
"@com_github_stretchr_testify//require:go_default_library",
Expand Down
8 changes: 4 additions & 4 deletions control/beacon/beacondbtest/beacondbtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ import (

"github.com/scionproto/scion/control/beacon"
"github.com/scionproto/scion/pkg/addr"
"github.com/scionproto/scion/pkg/private/common"
"github.com/scionproto/scion/pkg/private/xtest/graph"
seg "github.com/scionproto/scion/pkg/segment"
"github.com/scionproto/scion/pkg/segment/iface"
"github.com/scionproto/scion/pkg/slayers/path"
)

Expand Down Expand Up @@ -334,14 +334,14 @@ func InsertBeacon(t *testing.T, db beacon.DB, ases []IfInfo,

type PeerEntry struct {
IA addr.IA
Ingress common.IfIDType
Ingress iface.ID
}

type IfInfo struct {
IA addr.IA
Next addr.IA
Ingress common.IfIDType
Egress common.IfIDType
Ingress iface.ID
Egress iface.ID
Peers []PeerEntry
}

Expand Down
166 changes: 166 additions & 0 deletions control/beacon/chain_checker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// Copyright 2024 Anapaya Systems
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package beacon

import (
"context"
"crypto/x509"
"fmt"
"net"
"time"

"github.com/patrickmn/go-cache"
"google.golang.org/protobuf/proto"

"github.com/scionproto/scion/pkg/addr"
"github.com/scionproto/scion/pkg/private/serrors"
cppb "github.com/scionproto/scion/pkg/proto/control_plane"
cryptopb "github.com/scionproto/scion/pkg/proto/crypto"
"github.com/scionproto/scion/pkg/scrypto/cppki"
"github.com/scionproto/scion/pkg/scrypto/signed"
infra "github.com/scionproto/scion/private/segment/verifier"
"github.com/scionproto/scion/private/trust"
)

type ChainProvider interface {
GetChains(context.Context, trust.ChainQuery, ...trust.Option) ([][]*x509.Certificate, error)
}

const (
defaultCacheHitExpiration = 10 * time.Minute
defaultCacheMissExpiration = 30 * time.Second
)

var _ infra.Verifier = (chainChecker{})

// chainChecker checks that the certificate chain is available locally. This is used
// to ensure we do not propagate beacons that are not verifiable.
type chainChecker struct {
BoundValidity cppki.Validity
Engine ChainProvider

Cache *cache.Cache
}

func (v chainChecker) WithValidity(val cppki.Validity) infra.Verifier {
v.BoundValidity = val
return v
}

func (v chainChecker) Verify(ctx context.Context, signedMsg *cryptopb.SignedMessage,
associatedData ...[]byte) (*signed.Message, error) {

hdr, err := signed.ExtractUnverifiedHeader(signedMsg)
if err != nil {
return nil, err
}

var keyID cppb.VerificationKeyID
if err := proto.Unmarshal(hdr.VerificationKeyID, &keyID); err != nil {
return nil, serrors.Wrap("parsing verification key ID", err)
}
if len(keyID.SubjectKeyId) == 0 {
return nil, serrors.Wrap("subject key ID must be set", err)
}
ia := addr.IA(keyID.IsdAs)
if ia.IsWildcard() {
return nil, serrors.New("ISD-AS must not contain wildcard", "isd_as", ia)
}
if v.Engine == nil {
return nil, serrors.New("nil engine that provides cert chains")
}
query := trust.ChainQuery{
IA: ia,
SubjectKeyID: keyID.SubjectKeyId,
Validity: v.BoundValidity,
}
if err := v.checkChains(ctx, query); err != nil {
return nil, serrors.Wrap("getting chains", err,
"query.isd_as", query.IA,
"query.subject_key_id", fmt.Sprintf("%x", query.SubjectKeyID),
"query.validity", query.Validity.String(),
)
}
return nil, nil
}

func (v chainChecker) checkChains(ctx context.Context, q trust.ChainQuery) error {
key := fmt.Sprintf("chain-%s-%x", q.IA, q.SubjectKeyID)

cachedChains, ok := v.getChainsCached(key)
if ok {
if len(cachedChains) == 0 {
return serrors.New("cached certificate chains are empty")
}

var validChains int
for _, chain := range cachedChains {
if len(chain) == 0 {
continue // This should never happen.
}
chainValidity := cppki.Validity{
NotBefore: chain[0].NotBefore,
NotAfter: chain[0].NotAfter,
}
if v.BoundValidity != (cppki.Validity{}) && !chainValidity.Covers(v.BoundValidity) {
continue
}
validChains++
}
if validChains == 0 {
// Remove the invalid chains from the cache. This is a rare case if
// we have previously cached chains, but they have now expired.
// After the cache is cleared here, we will attempt to fetch and
// cache the empty result, thus, not hitting this code path again.
v.Cache.Delete(key)
return serrors.New("chached certificate chains do not cover required validity")
}
return nil
}

chains, err := v.Engine.GetChains(ctx, q)
if err != nil {
return err
}
v.cacheChains(key, chains, v.cacheExpiration(chains))
if len(chains) == 0 {
return serrors.New("no certificate chains found")
}
return nil
}

func (v chainChecker) getChainsCached(key string) ([][]*x509.Certificate, bool) {
chain, ok := v.Cache.Get(key)
if !ok {
return nil, false
}
return chain.([][]*x509.Certificate), true
}

func (v chainChecker) cacheChains(key string, chain [][]*x509.Certificate, d time.Duration) {
v.Cache.Set(key, chain, d)
}

func (v chainChecker) cacheExpiration(chains [][]*x509.Certificate) time.Duration {
// In case of a miss, we cache the result for a short time. This allows us to
// learn about new chains more quickly.
if len(chains) == 0 {
return defaultCacheMissExpiration
}
return defaultCacheHitExpiration
}

func (v chainChecker) WithServer(server net.Addr) infra.Verifier { return v }
func (v chainChecker) WithIA(ia addr.IA) infra.Verifier { return v }
Loading

0 comments on commit bac651f

Please sign in to comment.