diff --git a/.circleci/config.yml b/.circleci/config.yml index 3a17e47c6..eb852093b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,7 +2,7 @@ version: 2 jobs: build: docker: - - image: cimg/go:1.21 + - image: cimg/go:1.24.2 steps: - run: name: Go version diff --git a/Makefile b/Makefile index 80d396ea9..22bb36b7f 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,6 @@ BIN = bin # If there are multiple entries in GOPATH, take the first. DESTDIR = $(shell set -a; eval $$( go env ); gopath=$${GOPATH%:*}; echo $${GOBIN:-$${gopath:-$${HOME}/go}/bin}) -# HINT: build with TAGS=norains to build without rains support TAGS = all: build lint diff --git a/README.md b/README.md index 011f55065..a31141b8c 100644 --- a/README.md +++ b/README.md @@ -64,21 +64,20 @@ You can modify this by changing the value on the `dispatcher.toml` configuration The SCION daemon is assumed to be at the default address, but this can be overridden using an environment variable: - SCION_DAEMON_ADDRESS: 127.0.0.1:30255 + SCION_DAEMON: 127.0.0.1:30255 This is convenient for the normal use case of running the endhost stack for a single SCION AS. When running multiple local ASes, e.g. during development, the address of the SCION daemon corresponding to the desired AS needs to be -specified in the `SCION_DAEMON_ADDRESS` environment variable. +specified in the `SCION_DAEMON` environment variable. In this case, the different daemon addresses can be found in their corresponding `sd.toml` configuration files in the `gen/ASx` directory, or summarized in the file `gen/sciond_addresses.json`. #### Hostnames -Hostnames are resolved by scanning `/etc/hosts`, `/etc/scion/hosts` and by a RAINS lookup. - -Hosts can be added to `/etc/hosts`, or `/etc/scion/hosts` by adding lines like this: +Hostnames are resolved by scanning `/etc/hosts` and `/etc/scion/hosts`. +Hosts can be added by adding lines like this: ``` # The following lines are SCION hosts @@ -86,11 +85,6 @@ Hosts can be added to `/etc/hosts`, or `/etc/scion/hosts` by adding lines like t 18-ffaa:0:11,[10.0.8.120] server2 ``` -The RAINS resolver address can be configured in `/etc/scion/rains.cfg`. -This configuration file needs to contain the SCION address of the RAINS -resolver, in the form `-,[]`. - - ## _examples The directory _examples contains examples for the usage of the SCION libraries. diff --git a/_examples/go.mod b/_examples/go.mod index b4ebba2bc..71a2d37fb 100644 --- a/_examples/go.mod +++ b/_examples/go.mod @@ -1,68 +1,49 @@ module examples -go 1.23.0 +go 1.24.2 require ( github.com/golang/protobuf v1.5.4 - github.com/gorilla/handlers v1.5.1 - github.com/netsec-ethz/scion-apps v0.5.0 - github.com/quic-go/quic-go v0.54.1 - google.golang.org/grpc v1.63.2 + github.com/gorilla/handlers v1.5.2 + github.com/netsec-ethz/scion-apps v0.6.0 + github.com/quic-go/quic-go v0.58.0 + github.com/scionproto/scion v0.14.0 + google.golang.org/grpc v1.78.0 ) require ( github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/britram/borat v0.0.0-20181011130314-f891bcfcfb9b // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/dchest/cmac v1.0.0 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect - github.com/felixge/httpsnoop v1.0.1 // indirect - github.com/go-stack/stack v1.8.0 // indirect - github.com/google/gopacket v1.1.19 // indirect - github.com/google/uuid v1.6.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/gopacket/gopacket v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect - github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-sqlite3 v1.14.22 // indirect - github.com/ncruces/go-strftime v0.1.9 // indirect - github.com/netsec-ethz/rains v0.5.1-0.20240619143424-8e9ef27f2403 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.53.0 // indirect - github.com/prometheus/procfs v0.14.0 // indirect - github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/scionproto/scion v0.12.1-0.20241223103250-0b42cbc42486 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/prometheus/client_golang v1.23.2 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // indirect + github.com/quic-go/qpack v0.6.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect go.uber.org/atomic v1.11.0 // indirect - go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.31.0 // indirect - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect - golang.org/x/mod v0.18.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect - golang.org/x/tools v0.22.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240509183442-62759503f434 // indirect - google.golang.org/protobuf v1.34.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b // indirect - modernc.org/libc v1.50.5 // indirect - modernc.org/mathutil v1.6.0 // indirect - modernc.org/memory v1.8.0 // indirect - modernc.org/sqlite v1.29.9 // indirect - modernc.org/strutil v1.2.0 // indirect - modernc.org/token v1.1.0 // indirect + go.uber.org/zap v1.27.1 // indirect + go.yaml.in/yaml/v2 v2.4.3 // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/text v0.32.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect + google.golang.org/protobuf v1.36.11 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) replace github.com/netsec-ethz/scion-apps => ../ diff --git a/_examples/go.sum b/_examples/go.sum index f8c9bc4b2..ade50aac1 100644 --- a/_examples/go.sum +++ b/_examples/go.sum @@ -7,8 +7,6 @@ github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmO github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/britram/borat v0.0.0-20181011130314-f891bcfcfb9b h1:eOJHzrH26TPsYqtMlhcRV5NZKwI7iopaFbYwhd03CjA= -github.com/britram/borat v0.0.0-20181011130314-f891bcfcfb9b/go.mod h1:iEd9IJ9SwedxB5kO5ypZMVq7PUNDW5lhQy92rbWBLGk= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -20,17 +18,18 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dchest/cmac v1.0.0 h1:Vaorm9FVpO2P+YmRdH0RVCUB1XF3Ge1yg9scPvJphyk= github.com/dchest/cmac v1.0.0/go.mod h1:0zViPqHm8iZwwMl1cuK3HqK7Tu4Q7DV4EuMIOUwBVQ0= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= -github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -43,26 +42,20 @@ github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaW github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= -github.com/google/pprof v0.0.0-20240509144519-723abb6459b7 h1:velgFPYr1X9TDwLIfkV7fWqsFlf7TeP11M/7kPd/dVI= -github.com/google/pprof v0.0.0-20240509144519-723abb6459b7/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= -github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gopacket/gopacket v1.5.0 h1:9s9fcSUVKFlRV97B77Bq9XNV3ly2gvvsneFMQUGjc+M= +github.com/gopacket/gopacket v1.5.0/go.mod h1:i3NaGaqfoWKAr1+g7qxEdWsmfT+MXuWkAe9+THv8LME= +github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= +github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= -github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= -github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec h1:CGkYB1Q7DSsH/ku+to+foV4agt2F2miquaLUgF6L178= -github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -73,97 +66,95 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= -github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= -github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= -github.com/netsec-ethz/rains v0.5.1-0.20240619143424-8e9ef27f2403 h1:Ve8YXv3K9Oxlo9c4aQBYXMwe7Dx0Khv5qytdM2qTsco= -github.com/netsec-ethz/rains v0.5.1-0.20240619143424-8e9ef27f2403/go.mod h1:YD8WuBUbAoxhvU/keqHboGDpFna9FSvklLLzTZSF7SE= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= -github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE= -github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= -github.com/prometheus/procfs v0.14.0 h1:Lw4VdGGoKEZilJsayHf0B+9YgLGREba2C6xr+Fdfq6s= -github.com/prometheus/procfs v0.14.0/go.mod h1:XL+Iwz8k8ZabyZfMFHPiilCniixqQarAy5Mu67pHlNQ= -github.com/quic-go/quic-go v0.54.1 h1:4ZAWm0AhCb6+hE+l5Q1NAL0iRn/ZrMwqHRGQiFwj2eg= -github.com/quic-go/quic-go v0.54.1/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= +github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= +github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= +github.com/quic-go/quic-go v0.58.0 h1:ggY2pvZaVdB9EyojxL1p+5mptkuHyX5MOSv4dgWF4Ug= +github.com/quic-go/quic-go v0.58.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/scionproto/scion v0.12.1-0.20241223103250-0b42cbc42486 h1:7hYIHKVxnrrvRvlHYX7cskTvXHCdb6HfFMYyzpZCPmk= -github.com/scionproto/scion v0.12.1-0.20241223103250-0b42cbc42486/go.mod h1:ZZdYvTNhrC3USJOP7XcMFFrwbyoYLGvTKb1L3aIzpxM= +github.com/scionproto/scion v0.14.0 h1:aoSM4f/klmhO/RsXG2RJ7KbaNZ6cujxe9APfqFby0Lw= +github.com/scionproto/scion v0.14.0/go.mod h1:gCXIVztXV7HMe9P/ymVk4U4oSZOYaNnhkeskYxl2h60= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= -go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= +go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= +golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= -golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -172,30 +163,28 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -203,72 +192,41 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= -golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240509183442-62759503f434 h1:umK/Ey0QEzurTNlsV3R+MfxHAb78HCEX/IkuR+zH4WQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240509183442-62759503f434/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b h1:Mv8VFug0MP9e5vUxfBcE3vUkV6CImK3cMNMIDFjmzxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= +google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= +google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= google.golang.org/grpc/examples v0.0.0-20240321213419-eb5828bae753 h1:crPucDOfTtZF6lBfOiv4ex+5g+TFoNjyiSrSDJUpYPc= google.golang.org/grpc/examples v0.0.0-20240321213419-eb5828bae753/go.mod h1:fYxPglWChrD7bqbWtDwno019ra5SPuE1c3i+4YAvado= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/d4l3k/messagediff.v1 v1.2.1 h1:70AthpjunwzUiarMHyED52mj9UwtAnE89l1Gmrt3EU0= -gopkg.in/d4l3k/messagediff.v1 v1.2.1/go.mod h1:EUzikiKadqXWcD1AzJLagx0j/BeeWGtn++04Xniyg44= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -modernc.org/cc/v4 v4.21.0 h1:D/gLKtcztomvWbsbvBKo3leKQv+86f+DdqEZBBXhnag= -modernc.org/cc/v4 v4.21.0/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= -modernc.org/ccgo/v4 v4.17.3 h1:t2CQci84jnxKw3GGnHvjGKjiNZeZqyQx/023spkk4hU= -modernc.org/ccgo/v4 v4.17.3/go.mod h1:1FCbAtWYJoKuc+AviS+dH+vGNtYmFJqBeRWjmnDWsIg= -modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= -modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= -modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= -modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= -modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b h1:BnN1t+pb1cy61zbvSUV7SeI0PwosMhlAEi/vBY4qxp8= -modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= -modernc.org/libc v1.50.5 h1:ZzeUd0dIc/sUtoPTCYIrgypkuzoGzNu6kbEWj2VuEmk= -modernc.org/libc v1.50.5/go.mod h1:rhzrUx5oePTSTIzBgM0mTftwWHK8tiT9aNFUt1mldl0= -modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= -modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= -modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= -modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= -modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= -modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= -modernc.org/sqlite v1.29.9 h1:9RhNMklxJs+1596GNuAX+O/6040bvOwacTxuFcRuQow= -modernc.org/sqlite v1.29.9/go.mod h1:ItX2a1OVGgNsFh6Dv60JQvGfJfTPHPVpV6DF59akYOA= -modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= -modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= -modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= -modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/_examples/helloquic/helloquic.go b/_examples/helloquic/helloquic.go index 98e2232a3..452e7a876 100644 --- a/_examples/helloquic/helloquic.go +++ b/_examples/helloquic/helloquic.go @@ -21,6 +21,7 @@ import ( "flag" "fmt" "io" + "net" "net/netip" "os" "time" @@ -28,6 +29,7 @@ import ( "github.com/netsec-ethz/scion-apps/pkg/pan" "github.com/netsec-ethz/scion-apps/pkg/quicutil" "github.com/quic-go/quic-go" + "github.com/scionproto/scion/pkg/snet" ) func main() { @@ -43,21 +45,30 @@ func main() { check(fmt.Errorf("either specify -listen for server or -remote for client")) } + p, err := pan.New(context.Background()) + if err != nil { + check(err) + } + if listen.Get().Port() > 0 { - err = runServer(listen.Get()) + err = runServer(p, listen.Get()) check(err) } else { - err = runClient(*remoteAddr, int(*count)) + err = runClient(p, *remoteAddr, int(*count)) check(err) } } -func runServer(listen netip.AddrPort) error { +func runServer(p *pan.PAN, listen netip.AddrPort) error { tlsCfg := &tls.Config{ Certificates: quicutil.MustGenerateSelfSignedCert(), NextProtos: []string{"hello-quic"}, } - listener, err := pan.ListenQUIC(context.Background(), listen, tlsCfg, nil) + localAddr := &snet.UDPAddr{ + IA: p.IA(), + Host: net.UDPAddrFromAddrPort(listen), + } + listener, err := pan.ListenQUIC(context.Background(), p, localAddr, tlsCfg, &quic.Config{}, nil) if err != nil { return err } @@ -104,7 +115,7 @@ func workSession(session *quic.Conn) error { } } -func runClient(address string, count int) error { +func runClient(p *pan.PAN, address string, count int) error { addr, err := pan.ResolveUDPAddr(context.TODO(), address) if err != nil { return err @@ -117,14 +128,15 @@ func runClient(address string, count int) error { selector := &pan.PingingSelector{ Interval: 2 * time.Second, Timeout: time.Second, + PAN: p, } selector.SetActive(2) - session, err := pan.DialQUIC(context.Background(), netip.AddrPort{}, addr, "", tlsCfg, nil, pan.WithSelector(selector)) + session, err := pan.DialQUIC(context.Background(), p, netip.AddrPort{}, addr, "", tlsCfg, &quic.Config{}, pan.WithSelector(selector)) if err != nil { return err } for i := 0; i < count; i++ { - stream, err := session.OpenStream() + stream, err := session.QUIC.OpenStream() if err != nil { return err } @@ -139,7 +151,7 @@ func runClient(address string, count int) error { } fmt.Printf("%s\n", reply) } - return session.CloseWithError(quic.ApplicationErrorCode(0), "") + return session.QUIC.CloseWithError(quic.ApplicationErrorCode(0), "") } // Check just ensures the error is nil, or complains and quits diff --git a/_examples/helloworld/helloworld.go b/_examples/helloworld/helloworld.go index c4bc1a011..3ac1f4077 100644 --- a/_examples/helloworld/helloworld.go +++ b/_examples/helloworld/helloworld.go @@ -39,17 +39,22 @@ func main() { check(fmt.Errorf("either specify -listen for server or -remote for client")) } + p, err := pan.New(context.Background()) + if err != nil { + check(err) + } + if listen.Get().Port() > 0 { - err = runServer(listen.Get()) + err = runServer(p, listen.Get()) check(err) } else { - err = runClient(*remoteAddr, int(*count)) + err = runClient(p, *remoteAddr, int(*count)) check(err) } } -func runServer(listen netip.AddrPort) error { - conn, err := pan.ListenUDP(context.Background(), listen) +func runServer(p *pan.PAN, listen netip.AddrPort) error { + conn, err := pan.ListenUDP(context.Background(), p, listen, nil) if err != nil { return err } @@ -73,12 +78,12 @@ func runServer(listen netip.AddrPort) error { } } -func runClient(address string, count int) error { +func runClient(p *pan.PAN, address string, count int) error { addr, err := pan.ResolveUDPAddr(context.TODO(), address) if err != nil { return err } - conn, err := pan.DialUDP(context.Background(), netip.AddrPort{}, addr) + conn, err := pan.DialUDP(context.Background(), p, netip.AddrPort{}, addr) if err != nil { return err } diff --git a/_examples/sgrpc/README.md b/_examples/sgrpc/README.md index da74fdb90..3b9dbca92 100644 --- a/_examples/sgrpc/README.md +++ b/_examples/sgrpc/README.md @@ -13,14 +13,14 @@ To test the server and client, run the SCION tiny test topology. Open a shell and run the server in the AS `1-ff00:0:111`: ```bash # Server in 1-ff00:0:111 -SCION_DAEMON_ADDRESS="127.0.0.20:30255" \ +SCION_DAEMON="127.0.0.20:30255" \ go run server/main.go --server-address 127.0.0.1:5000 ``` Open a shell and run the client in the AS `1-ff00:0:112` and send a message to the server: ```bash # Client in 1-ff00:0:112 -SCION_DAEMON_ADDRESS="127.0.0.28:30255" \ +SCION_DAEMON="127.0.0.28:30255" \ go run client/main.go --server-address "1-ff00:0:111,127.0.0.1:5000" --message "gRPC over SCION/QUIC" ``` diff --git a/_examples/sgrpc/client/main.go b/_examples/sgrpc/client/main.go index 56e01c95f..9f6631de4 100644 --- a/_examples/sgrpc/client/main.go +++ b/_examples/sgrpc/client/main.go @@ -24,7 +24,7 @@ var ( ServerAddr = flag.String("server-addr", "1-ff00:0:111,127.0.0.1:5000", "Address of the echo server") ) -func NewPanQuicDialer(tlsCfg *tls.Config) func(context.Context, string) (net.Conn, error) { +func NewPanQuicDialer(p *pan.PAN, tlsCfg *tls.Config) func(context.Context, string) (net.Conn, error) { dialer := func(ctx context.Context, addr string) (net.Conn, error) { panAddr, err := pan.ResolveUDPAddr(ctx, addr) if err != nil { @@ -32,7 +32,7 @@ func NewPanQuicDialer(tlsCfg *tls.Config) func(context.Context, string) (net.Con } clientQuicConfig := &quic.Config{KeepAlivePeriod: 15 * time.Second} - session, err := pan.DialQUIC(ctx, netip.AddrPort{}, panAddr, "", tlsCfg, clientQuicConfig) + session, err := pan.DialQUIC(ctx, p, netip.AddrPort{}, panAddr, "", tlsCfg, clientQuicConfig) if err != nil { return nil, fmt.Errorf("did not dial: %w", err) } @@ -45,16 +45,22 @@ func NewPanQuicDialer(tlsCfg *tls.Config) func(context.Context, string) (net.Con func main() { flag.Parse() + p, err := pan.New(context.Background()) + if err != nil { + log.Fatalf("failed to create PAN: %v", err) + } + tlsCfg := &tls.Config{ InsecureSkipVerify: true, NextProtos: []string{"echo_service"}, } - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + dialCtx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() - grpcDial, err := grpc.DialContext(ctx, *ServerAddr, - grpc.WithContextDialer(NewPanQuicDialer(tlsCfg)), + //nolint:staticcheck + grpcDial, err := grpc.DialContext(dialCtx, *ServerAddr, + grpc.WithContextDialer(NewPanQuicDialer(p, tlsCfg)), grpc.WithTransportCredentials(insecure.NewCredentials()), ) if err != nil { @@ -66,7 +72,7 @@ func main() { req := &pb.EchoRequest{ Msg: *Message, } - resp, err := c.Echo(ctx, req) + resp, err := c.Echo(dialCtx, req) if err != nil { log.Fatalf("gRPC did not connect: %v", err) } diff --git a/_examples/sgrpc/server/main.go b/_examples/sgrpc/server/main.go index 648e5f333..47c3db06f 100644 --- a/_examples/sgrpc/server/main.go +++ b/_examples/sgrpc/server/main.go @@ -5,10 +5,13 @@ import ( "crypto/tls" "flag" "log" + "net" "net/netip" "github.com/netsec-ethz/scion-apps/pkg/pan" "github.com/netsec-ethz/scion-apps/pkg/quicutil" + "github.com/quic-go/quic-go" + "github.com/scionproto/scion/pkg/snet" "google.golang.org/grpc" pb "examples/sgrpc/proto" @@ -35,6 +38,11 @@ var ( func main() { flag.Parse() + p, err := pan.New(context.Background()) + if err != nil { + log.Fatalf("failed to create PAN: %v", err) + } + addr, err := netip.ParseAddrPort(*ServerAddr) if err != nil { log.Fatalf("failed to parse server address") @@ -49,14 +57,18 @@ func main() { NextProtos: []string{"echo_service"}, } - quicListener, err := pan.ListenQUIC(context.Background(), addr, tlsCfg, nil) + localAddr := &snet.UDPAddr{ + IA: p.IA(), + Host: net.UDPAddrFromAddrPort(addr), + } + quicListener, err := pan.ListenQUIC(context.Background(), p, localAddr, tlsCfg, &quic.Config{}, nil) if err != nil { log.Fatalf("failed to listen SCION QUIC on %s: %v", *ServerAddr, err) } lis := quicutil.SingleStreamListener{QUICListener: quicListener} log.Println("listen on", quicListener.Addr()) - if err := grpcServer.Serve(lis); err != nil { + if err := grpcServer.Serve(&lis); err != nil { log.Fatalf("failed to serve: %v", err) } } diff --git a/_examples/shttp/client/main.go b/_examples/shttp/client/main.go index c6d5ecbbe..c3c82fc4f 100644 --- a/_examples/shttp/client/main.go +++ b/_examples/shttp/client/main.go @@ -15,6 +15,7 @@ package main import ( + "context" "flag" "fmt" "io" @@ -24,6 +25,7 @@ import ( "strings" "time" + "github.com/netsec-ethz/scion-apps/pkg/pan" "github.com/netsec-ethz/scion-apps/pkg/shttp" ) @@ -36,14 +38,20 @@ func main() { os.Exit(2) } + p, err := pan.New(context.Background()) + if err != nil { + log.Fatal(err) + } + // Create a standard client with our custom Transport/Dialer c := &http.Client{ - Transport: shttp.DefaultTransport, + Transport: shttp.NewDefaultTransport(p), } // Make a get request start := time.Now() query := fmt.Sprintf("http://%s/hello", *serverAddrStr) + //nolint:staticcheck resp, err := c.Get(shttp.MangleSCIONAddrURL(query)) if err != nil { log.Fatal("GET request failed: ", err) @@ -60,6 +68,7 @@ func main() { start = time.Now() query = fmt.Sprintf("http://%s/form", *serverAddrStr) resp, err = c.Post( + //nolint:staticcheck shttp.MangleSCIONAddrURL(query), "application/x-www-form-urlencoded", strings.NewReader("surname=threepwood&firstname=guybrush"), diff --git a/_examples/shttp/fileserver/main.go b/_examples/shttp/fileserver/main.go index 4b783dc81..027e841ba 100644 --- a/_examples/shttp/fileserver/main.go +++ b/_examples/shttp/fileserver/main.go @@ -17,12 +17,14 @@ package main import ( + "context" "flag" "log" "net/http" "os" "github.com/gorilla/handlers" + "github.com/netsec-ethz/scion-apps/pkg/pan" "github.com/netsec-ethz/scion-apps/pkg/shttp" ) @@ -33,6 +35,11 @@ func main() { "directives similar as in the HSTS header are to be defined by this flag") flag.Parse() + p, err := pan.New(context.Background()) + if err != nil { + log.Fatal(err) + } + handler := handlers.LoggingHandler( os.Stdout, func(h http.Handler) http.HandlerFunc { @@ -47,7 +54,7 @@ func main() { }(http.FileServer(http.Dir(""))), ) if *certFile != "" && *keyFile != "" { - go func() { log.Fatal(shttp.ListenAndServeTLS(":443", *certFile, *keyFile, handler)) }() + go func() { log.Fatal(shttp.ListenAndServeTLS(p, ":443", *certFile, *keyFile, handler)) }() } - log.Fatal(shttp.ListenAndServe(":80", handler)) + log.Fatal(shttp.ListenAndServe(p, ":80", handler)) } diff --git a/_examples/shttp/proxy/main.go b/_examples/shttp/proxy/main.go index dde4eb0aa..5d8aea973 100644 --- a/_examples/shttp/proxy/main.go +++ b/_examples/shttp/proxy/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "flag" "fmt" "log" @@ -10,6 +11,7 @@ import ( "os" "github.com/gorilla/handlers" + "github.com/netsec-ethz/scion-apps/pkg/pan" "github.com/netsec-ethz/scion-apps/pkg/shttp" ) @@ -25,14 +27,22 @@ func main() { flag.Usage() os.Exit(2) } + + // Initialize SCION PAN context if needed for either listening or dialing over SCION + p, err := pan.New(context.Background()) + if err != nil { + log.Fatal(err) + } + //nolint:staticcheck remoteMangled := shttp.MangleSCIONAddrURL(*remote) + remoteURL, err := url.Parse(remoteMangled) if err != nil { log.Fatal(err) } proxy := httputil.NewSingleHostReverseProxy(remoteURL) if remoteMangled != *remote { - proxy.Transport = shttp.DefaultTransport + proxy.Transport = shttp.NewDefaultTransport(p) log.Printf("Proxy to SCION remote %s\n", remoteURL) } else { log.Printf("Proxy to IP/TCP remote %s\n", remoteURL) @@ -44,7 +54,7 @@ func main() { log.Printf("Listen on SCION %s\n", local) // ListenAndServe does not support listening on a complete SCION Address, // Consequently, we only use the port (as seen in the server example) - log.Fatal(shttp.ListenAndServe(local, handler)) + log.Fatal(shttp.ListenAndServe(p, local, handler)) } else { log.Printf("Listen on IP/TCP %s\n", local) log.Fatal(http.ListenAndServe(local, handler)) diff --git a/_examples/shttp/server/main.go b/_examples/shttp/server/main.go index aa0a477af..7dfef2d66 100644 --- a/_examples/shttp/server/main.go +++ b/_examples/shttp/server/main.go @@ -15,6 +15,7 @@ package main import ( + "context" "encoding/json" "flag" "fmt" @@ -24,6 +25,7 @@ import ( "time" "github.com/gorilla/handlers" + "github.com/netsec-ethz/scion-apps/pkg/pan" "github.com/netsec-ethz/scion-apps/pkg/shttp" ) @@ -32,6 +34,11 @@ func main() { keyFile := flag.String("key", "", "Path to TLS server key for optional https") flag.Parse() + p, err := pan.New(context.Background()) + if err != nil { + log.Fatal(err) + } + m := http.NewServeMux() // handler that responds with a friendly greeting @@ -91,7 +98,7 @@ func main() { handler := handlers.LoggingHandler(os.Stdout, m) if *certFile != "" && *keyFile != "" { - go func() { log.Fatal(shttp.ListenAndServeTLS(":443", *certFile, *keyFile, handler)) }() + go func() { log.Fatal(shttp.ListenAndServeTLS(p, ":443", *certFile, *keyFile, handler)) }() } - log.Fatal(shttp.ListenAndServe(":80", handler)) + log.Fatal(shttp.ListenAndServe(p, ":80", handler)) } diff --git a/bat/README.md b/bat/README.md index 52f827039..71b4a15c7 100644 --- a/bat/README.md +++ b/bat/README.md @@ -15,7 +15,7 @@ bat The scheme defaults to HTTPS -- HTTP is not supported. The method defaults to GET in case there is no data to be sent and to POST otherwise. -URLs can use SCION addresses or hostnames. Hostnames are resolved by scanning the `/etc/hosts` file or by a RAINS lookup (if configured) -- see the toplevel README. +URLs can use SCION addresses or hostnames. Hostnames are resolved by scanning the `/etc/hosts` file -- see the toplevel README. ### Examples diff --git a/bat/bat.go b/bat/bat.go index e1069dd74..ca389e139 100644 --- a/bat/bat.go +++ b/bat/bat.go @@ -21,6 +21,7 @@ package main import ( "bytes" + "context" "crypto/tls" "encoding/json" "flag" @@ -102,12 +103,6 @@ func init() { log.SetFlags(log.LstdFlags | log.Lshortfile | log.Lmicroseconds) flag.Usage = usage flag.Parse() - - policy, err := pan.PolicyFromCommandline(sequence, preference, interactive) - if err != nil { - log.Fatal(err) - } - defaultSetting.Transport, _ = shttp.NewTransport(nil, policy) } func parsePrintOption(s string) { @@ -131,15 +126,26 @@ func parsePrintOption(s string) { } func main() { + if ver { + fmt.Println("Version:", version) + os.Exit(2) + } + + // Initialize SCION PAN and transport + p, err := pan.New(context.Background()) + if err != nil { + log.Fatal(err) + } + policy, err := pan.PolicyFromCommandline(sequence, preference, interactive) + if err != nil { + log.Fatal(err) + } + defaultSetting.Transport, _ = shttp.NewTransport(p, nil, policy) args := flag.Args() if len(args) > 0 { args = filter(args) } - if ver { - fmt.Println("Version:", version) - os.Exit(2) - } parsePrintOption(printV) if printOption&printReqBody != printReqBody { defaultSetting.DumpBody = false @@ -176,6 +182,7 @@ func main() { if !strings.HasPrefix(*URL, "http://") && !strings.HasPrefix(*URL, "https://") { *URL = "http://" + *URL } + //nolint:staticcheck u, err := url.Parse(shttp.MangleSCIONAddrURL(*URL)) if err != nil { log.Fatal(err) @@ -200,6 +207,7 @@ func main() { } // Proxy Support if proxy != "" { + //nolint:staticcheck purl, err := url.Parse(shttp.MangleSCIONAddrURL(proxy)) if err != nil { log.Fatal("Proxy Url parse err", err) diff --git a/bwtester/bwtestclient/bwtestclient.go b/bwtester/bwtestclient/bwtestclient.go index 2eefd5b22..f9e704dd8 100644 --- a/bwtester/bwtestclient/bwtestclient.go +++ b/bwtester/bwtestclient/bwtestclient.go @@ -291,6 +291,10 @@ func main() { if !serverCCAddr.IsValid() { usageErr("server address needs to be specified with -s") } + + p, err := pan.New(context.Background()) + bwtest.Check(err) + policy, err := pan.PolicyFromCommandline(sequence, preference, interactive) checkUsageErr(err) @@ -320,7 +324,7 @@ func main() { fmt.Printf("server->client: %d seconds, %d bytes, %d packets\n", int(serverBwp.BwtestDuration/time.Second), serverBwp.PacketSize, serverBwp.NumPackets) - clientRes, serverRes, err := runBwtest(local.Get(), serverCCAddr, policy, clientBwp, serverBwp) + clientRes, serverRes, err := runBwtest(p, local.Get(), serverCCAddr, policy, clientBwp, serverBwp) bwtest.Check(err) fmt.Println("\nS->C results") @@ -330,12 +334,12 @@ func main() { } // runBwtest runs the bandwidth test with the given parameters against the server at serverCCAddr. -func runBwtest(local netip.AddrPort, serverCCAddr pan.UDPAddr, policy pan.Policy, +func runBwtest(p *pan.PAN, local netip.AddrPort, serverCCAddr pan.UDPAddr, policy pan.Policy, clientBwp, serverBwp bwtest.Parameters) (clientRes, serverRes bwtest.Result, err error) { // Control channel connection ccSelector := pan.NewDefaultSelector() - ccConn, err := pan.DialUDP(context.Background(), local, serverCCAddr, pan.WithPolicy(policy), pan.WithSelector(ccSelector)) + ccConn, err := p.DialUDP(context.Background(), local, serverCCAddr, pan.WithPolicy(policy), pan.WithSelector(ccSelector)) if err != nil { return } @@ -345,7 +349,7 @@ func runBwtest(local netip.AddrPort, serverCCAddr pan.UDPAddr, policy pan.Policy serverDCAddr := serverCCAddr.WithPort(serverCCAddr.Port + 1) // Data channel connection - dcConn, err := pan.DialUDP(context.Background(), dcLocal, serverDCAddr, pan.WithPolicy(policy)) + dcConn, err := p.DialUDP(context.Background(), dcLocal, serverDCAddr, pan.WithPolicy(policy)) if err != nil { return } diff --git a/bwtester/bwtestserver/bwtestserver.go b/bwtester/bwtestserver/bwtestserver.go index 076f0e877..318bd96a2 100644 --- a/bwtester/bwtestserver/bwtestserver.go +++ b/bwtester/bwtestserver/bwtestserver.go @@ -38,11 +38,14 @@ func main() { kingpin.Flag("listen", "Address to listen on").Default(":40002").SetValue(&listen) kingpin.Parse() - err := runServer(listen.Get()) + p, err := pan.New(context.Background()) + bwtest.Check(err) + + err = runServer(p, listen.Get()) bwtest.Check(err) } -func runServer(listen netip.AddrPort) error { +func runServer(p *pan.PAN, listen netip.AddrPort) error { receivePacketBuffer := make([]byte, 2500) var currentBwtest string @@ -51,9 +54,8 @@ func runServer(listen netip.AddrPort) error { results := make(resultsMap) - ctx := context.Background() ccSelector := pan.NewDefaultReplySelector() - ccConn, err := pan.ListenUDP(context.Background(), listen, pan.WithReplySelector(ccSelector)) + ccConn, err := p.ListenUDP(context.Background(), listen, ccSelector) if err != nil { return err } @@ -102,8 +104,8 @@ func runServer(listen netip.AddrPort) error { if err != nil { continue } - path := ccSelector.Path(ctx, clientCCAddr.(pan.UDPAddr)) - finishTime, err := startBwtestBackground(serverCCAddr, clientCCAddr.(pan.UDPAddr), path, + path := ccSelector.Path(clientCCAddr.(pan.UDPAddr)) + finishTime, err := startBwtestBackground(p, serverCCAddr, clientCCAddr.(pan.UDPAddr), path, clientBwp, serverBwp, currentResult) if err != nil { // Ask the client to try again in 1 second @@ -134,7 +136,7 @@ func runServer(listen netip.AddrPort) error { // startBwtestBackground starts a bandwidth test, in the background. // Returns the expected finish time of the test, or any error during the setup. -func startBwtestBackground(serverCCAddr pan.UDPAddr, clientCCAddr pan.UDPAddr, +func startBwtestBackground(p *pan.PAN, serverCCAddr pan.UDPAddr, clientCCAddr pan.UDPAddr, path *pan.Path, clientBwp, serverBwp bwtest.Parameters, res chan<- bwtest.Result) (time.Time, error) { // Data Connection addresses: @@ -144,7 +146,7 @@ func startBwtestBackground(serverCCAddr pan.UDPAddr, clientCCAddr pan.UDPAddr, // Open Data Connection dcSelector := initializedReplySelector(clientDCAddr, path) - dcConn, err := listenConnected(serverDCAddr, clientDCAddr, dcSelector) + dcConn, err := listenConnected(p, serverDCAddr, clientDCAddr, dcSelector) if err != nil { return time.Time{}, err } @@ -287,8 +289,8 @@ func (r resultsMap) purgeExpired() { } } -func listenConnected(local netip.AddrPort, remote pan.UDPAddr, selector pan.ReplySelector) (net.Conn, error) { - conn, err := pan.ListenUDP(context.Background(), local, pan.WithReplySelector(selector)) +func listenConnected(p *pan.PAN, local netip.AddrPort, remote pan.UDPAddr, selector pan.ReplySelector) (net.Conn, error) { + conn, err := p.ListenUDP(context.Background(), local, selector) return connectedPacketConn{ ListenConn: conn, remote: remote, diff --git a/go.mod b/go.mod index 3b94a169b..af400e993 100644 --- a/go.mod +++ b/go.mod @@ -1,84 +1,67 @@ module github.com/netsec-ethz/scion-apps -go 1.23.0 +go 1.24.2 require ( - github.com/creack/pty v1.1.17 - github.com/gorilla/handlers v1.5.1 - github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec + github.com/creack/pty v1.1.24 + github.com/gorilla/handlers v1.5.2 + github.com/inconshreveable/log15 v2.16.0+incompatible github.com/kormat/fmt15 v0.0.0-20181112140556-ee69fecb2656 - github.com/mattn/go-sqlite3 v1.14.22 - github.com/msteinert/pam v0.0.0-20190215180659-f29b9f28d6f9 - github.com/netsec-ethz/rains v0.5.1-0.20240619143424-8e9ef27f2403 + github.com/mattn/go-sqlite3 v1.14.32 + github.com/msteinert/pam v1.2.0 github.com/pelletier/go-toml v1.9.5 - github.com/quic-go/quic-go v0.54.1 - github.com/scionproto/scion v0.12.1-0.20241223103250-0b42cbc42486 + github.com/quic-go/quic-go v0.58.0 + github.com/scionproto/scion v0.14.0 github.com/smartystreets/goconvey v1.8.1 - github.com/stretchr/testify v1.9.0 - golang.org/x/crypto v0.31.0 - golang.org/x/term v0.27.0 + github.com/stretchr/testify v1.11.1 + golang.org/x/crypto v0.46.0 + golang.org/x/term v0.38.0 gopkg.in/alecthomas/kingpin.v2 v2.2.6 ) require ( github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect - github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect + github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bgentry/speakeasy v0.1.0 // indirect - github.com/britram/borat v0.0.0-20181011130314-f891bcfcfb9b // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dchest/cmac v1.0.0 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect - github.com/felixge/httpsnoop v1.0.1 // indirect - github.com/go-stack/stack v1.8.0 // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/google/gopacket v1.1.19 // indirect - github.com/google/uuid v1.6.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-stack/stack v1.8.1 // indirect + github.com/gopacket/gopacket v1.5.0 // indirect github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.53.0 // indirect - github.com/prometheus/procfs v0.14.0 // indirect - github.com/quic-go/qpack v0.5.1 // indirect - github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/prometheus/client_golang v1.23.2 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // indirect + github.com/quic-go/qpack v0.6.0 // indirect github.com/smarty/assertions v1.16.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect go.uber.org/atomic v1.11.0 // indirect - go.uber.org/mock v0.5.0 // indirect + go.uber.org/mock v0.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect - golang.org/x/mod v0.18.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect - golang.org/x/tools v0.22.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240509183442-62759503f434 // indirect - google.golang.org/grpc v1.63.2 // indirect - google.golang.org/protobuf v1.34.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect + go.uber.org/zap v1.27.1 // indirect + go.yaml.in/yaml/v2 v2.4.3 // indirect + golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/text v0.32.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect + google.golang.org/grpc v1.78.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b // indirect - modernc.org/libc v1.50.5 // indirect - modernc.org/mathutil v1.6.0 // indirect - modernc.org/memory v1.8.0 // indirect - modernc.org/sqlite v1.29.9 // indirect - modernc.org/strutil v1.2.0 // indirect - modernc.org/token v1.1.0 // indirect ) diff --git a/go.sum b/go.sum index e0afb0bf2..da7422a97 100644 --- a/go.sum +++ b/go.sum @@ -4,42 +4,41 @@ github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0= +github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/britram/borat v0.0.0-20181011130314-f891bcfcfb9b h1:eOJHzrH26TPsYqtMlhcRV5NZKwI7iopaFbYwhd03CjA= -github.com/britram/borat v0.0.0-20181011130314-f891bcfcfb9b/go.mod h1:iEd9IJ9SwedxB5kO5ypZMVq7PUNDW5lhQy92rbWBLGk= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= -github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dchest/cmac v1.0.0 h1:Vaorm9FVpO2P+YmRdH0RVCUB1XF3Ge1yg9scPvJphyk= github.com/dchest/cmac v1.0.0/go.mod h1:0zViPqHm8iZwwMl1cuK3HqK7Tu4Q7DV4EuMIOUwBVQ0= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= -github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -51,30 +50,26 @@ github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaW github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= -github.com/google/pprof v0.0.0-20240509144519-723abb6459b7 h1:velgFPYr1X9TDwLIfkV7fWqsFlf7TeP11M/7kPd/dVI= -github.com/google/pprof v0.0.0-20240509144519-723abb6459b7/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopacket/gopacket v1.5.0 h1:9s9fcSUVKFlRV97B77Bq9XNV3ly2gvvsneFMQUGjc+M= +github.com/gopacket/gopacket v1.5.0/go.mod h1:i3NaGaqfoWKAr1+g7qxEdWsmfT+MXuWkAe9+THv8LME= github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= -github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= -github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= +github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= -github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= -github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec h1:CGkYB1Q7DSsH/ku+to+foV4agt2F2miquaLUgF6L178= -github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= +github.com/inconshreveable/log15 v2.16.0+incompatible h1:6nvMKxtGcpgm7q0KiGs+Vc+xDvUXaBqsPKHWKsinccw= +github.com/inconshreveable/log15 v2.16.0+incompatible/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -89,54 +84,53 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= -github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/msteinert/pam v0.0.0-20190215180659-f29b9f28d6f9 h1:ZivaaKmjs9q90zi6I4gTLW6tbVGtlBjellr3hMYaly0= -github.com/msteinert/pam v0.0.0-20190215180659-f29b9f28d6f9/go.mod h1:np1wUFZ6tyoke22qDJZY40URn9Ae51gX7ljIWXN5TJs= -github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= -github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= -github.com/netsec-ethz/rains v0.5.1-0.20240619143424-8e9ef27f2403 h1:Ve8YXv3K9Oxlo9c4aQBYXMwe7Dx0Khv5qytdM2qTsco= -github.com/netsec-ethz/rains v0.5.1-0.20240619143424-8e9ef27f2403/go.mod h1:YD8WuBUbAoxhvU/keqHboGDpFna9FSvklLLzTZSF7SE= +github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs= +github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/msteinert/pam v1.2.0 h1:mYfjlvN2KYs2Pb9G6nb/1f/nPfAttT/Jee5Sq9r3bGE= +github.com/msteinert/pam v1.2.0/go.mod h1:d2n0DCUK8rGecChV3JzvmsDjOY4R7AYbsNxAT+ftQl0= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= -github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE= -github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= -github.com/prometheus/procfs v0.14.0 h1:Lw4VdGGoKEZilJsayHf0B+9YgLGREba2C6xr+Fdfq6s= -github.com/prometheus/procfs v0.14.0/go.mod h1:XL+Iwz8k8ZabyZfMFHPiilCniixqQarAy5Mu67pHlNQ= -github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= -github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.54.1 h1:4ZAWm0AhCb6+hE+l5Q1NAL0iRn/ZrMwqHRGQiFwj2eg= -github.com/quic-go/quic-go v0.54.1/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= +github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= +github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= +github.com/quic-go/quic-go v0.58.0 h1:ggY2pvZaVdB9EyojxL1p+5mptkuHyX5MOSv4dgWF4Ug= +github.com/quic-go/quic-go v0.58.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/scionproto/scion v0.12.1-0.20241223103250-0b42cbc42486 h1:7hYIHKVxnrrvRvlHYX7cskTvXHCdb6HfFMYyzpZCPmk= -github.com/scionproto/scion v0.12.1-0.20241223103250-0b42cbc42486/go.mod h1:ZZdYvTNhrC3USJOP7XcMFFrwbyoYLGvTKb1L3aIzpxM= +github.com/scionproto/scion v0.14.0 h1:aoSM4f/klmhO/RsXG2RJ7KbaNZ6cujxe9APfqFby0Lw= +github.com/scionproto/scion v0.14.0/go.mod h1:gCXIVztXV7HMe9P/ymVk4U4oSZOYaNnhkeskYxl2h60= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smarty/assertions v1.16.0 h1:EvHNkdRA4QHMrn75NZSoUQ/mAUXAYWfatfB01yTCzfY= github.com/smarty/assertions v1.16.0/go.mod h1:duaaFdCS0K9dnoM50iyek/eYINOZ64gbh1Xlf6LG7AI= github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY= github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -150,46 +144,57 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= -go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= +go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= +golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= -golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -198,32 +203,31 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -231,74 +235,43 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= -golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240509183442-62759503f434 h1:umK/Ey0QEzurTNlsV3R+MfxHAb78HCEX/IkuR+zH4WQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240509183442-62759503f434/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b h1:Mv8VFug0MP9e5vUxfBcE3vUkV6CImK3cMNMIDFjmzxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= +google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= +google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= google.golang.org/grpc/examples v0.0.0-20240321213419-eb5828bae753 h1:crPucDOfTtZF6lBfOiv4ex+5g+TFoNjyiSrSDJUpYPc= google.golang.org/grpc/examples v0.0.0-20240321213419-eb5828bae753/go.mod h1:fYxPglWChrD7bqbWtDwno019ra5SPuE1c3i+4YAvado= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/d4l3k/messagediff.v1 v1.2.1 h1:70AthpjunwzUiarMHyED52mj9UwtAnE89l1Gmrt3EU0= -gopkg.in/d4l3k/messagediff.v1 v1.2.1/go.mod h1:EUzikiKadqXWcD1AzJLagx0j/BeeWGtn++04Xniyg44= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -modernc.org/cc/v4 v4.21.0 h1:D/gLKtcztomvWbsbvBKo3leKQv+86f+DdqEZBBXhnag= -modernc.org/cc/v4 v4.21.0/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= -modernc.org/ccgo/v4 v4.17.3 h1:t2CQci84jnxKw3GGnHvjGKjiNZeZqyQx/023spkk4hU= -modernc.org/ccgo/v4 v4.17.3/go.mod h1:1FCbAtWYJoKuc+AviS+dH+vGNtYmFJqBeRWjmnDWsIg= -modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= -modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= -modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= -modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= -modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b h1:BnN1t+pb1cy61zbvSUV7SeI0PwosMhlAEi/vBY4qxp8= -modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= -modernc.org/libc v1.50.5 h1:ZzeUd0dIc/sUtoPTCYIrgypkuzoGzNu6kbEWj2VuEmk= -modernc.org/libc v1.50.5/go.mod h1:rhzrUx5oePTSTIzBgM0mTftwWHK8tiT9aNFUt1mldl0= -modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= -modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= -modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= -modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= -modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= -modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= -modernc.org/sqlite v1.29.9 h1:9RhNMklxJs+1596GNuAX+O/6040bvOwacTxuFcRuQow= -modernc.org/sqlite v1.29.9/go.mod h1:ItX2a1OVGgNsFh6Dv60JQvGfJfTPHPVpV6DF59akYOA= -modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= -modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= -modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= -modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/netcat/main.go b/netcat/main.go index da3af4a00..291aec9d2 100644 --- a/netcat/main.go +++ b/netcat/main.go @@ -15,6 +15,7 @@ package main import ( + "context" "flag" "fmt" "io" @@ -47,6 +48,8 @@ var ( interactive bool sequence string preference string + + p *pan.PAN ) func printUsage() { @@ -113,6 +116,12 @@ func main() { log.Fatalf("-K flag requires -c flag!") } + var err error + p, err = pan.New(context.Background()) + if err != nil { + log.Fatal(err) + } + var conns chan io.ReadWriteCloser if listen { diff --git a/netcat/quic.go b/netcat/quic.go index 4d5757569..827186d23 100644 --- a/netcat/quic.go +++ b/netcat/quic.go @@ -18,10 +18,12 @@ import ( "context" "crypto/tls" "io" + "net" "net/netip" "time" "github.com/quic-go/quic-go" + "github.com/scionproto/scion/pkg/snet" "github.com/netsec-ethz/scion-apps/pkg/pan" "github.com/netsec-ethz/scion-apps/pkg/quicutil" @@ -33,14 +35,19 @@ var ( // DoListenQUIC listens on a QUIC socket func DoListenQUIC(port uint16) (chan io.ReadWriteCloser, error) { - quicListener, err := pan.ListenQUIC( + localAddr := &snet.UDPAddr{ + IA: p.IA(), + Host: net.UDPAddrFromAddrPort(netip.AddrPortFrom(p.LocalAddr(), port)), + } + quicListener, err := p.ListenQUIC( context.Background(), - netip.AddrPortFrom(netip.Addr{}, port), + localAddr, &tls.Config{ Certificates: quicutil.MustGenerateSelfSignedCert(), NextProtos: nextProtos, }, &quic.Config{KeepAlivePeriod: 15 * time.Second}, + nil, ) if err != nil { return nil, err @@ -69,7 +76,7 @@ func DoDialQUIC(remote string, policy pan.Policy) (io.ReadWriteCloser, error) { if err != nil { return nil, err } - sess, err := pan.DialQUIC( + sess, err := p.DialQUIC( context.Background(), netip.AddrPort{}, remoteAddr, diff --git a/netcat/udp.go b/netcat/udp.go index dd727e468..4062a2884 100644 --- a/netcat/udp.go +++ b/netcat/udp.go @@ -58,7 +58,7 @@ func DoDialUDP(remote string, policy pan.Policy) (io.ReadWriteCloser, error) { if err != nil { return nil, err } - conn, err := pan.DialUDP(context.Background(), netip.AddrPort{}, remoteAddr, pan.WithPolicy(policy)) + conn, err := p.DialUDP(context.Background(), netip.AddrPort{}, remoteAddr, pan.WithPolicy(policy)) if err != nil { return nil, err } @@ -68,9 +68,10 @@ func DoDialUDP(remote string, policy pan.Policy) (io.ReadWriteCloser, error) { // DoListenUDP listens on a UDP socket func DoListenUDP(port uint16) (chan io.ReadWriteCloser, error) { - conn, err := pan.ListenUDP( + conn, err := p.ListenUDP( context.Background(), netip.AddrPortFrom(netip.Addr{}, port), + nil, ) if err != nil { return nil, err diff --git a/pkg/integration/apps.go b/pkg/integration/apps.go index df7e95b46..8c4cd647b 100644 --- a/pkg/integration/apps.go +++ b/pkg/integration/apps.go @@ -88,7 +88,7 @@ func (sai *ScionAppsIntegration) StartServer(ctx context.Context, cmd := exec.CommandContext(ctx, sai.serverCmd, args...) cmd.Env = os.Environ() cmd.Env = append(cmd.Env, fmt.Sprintf("%s=1", GoIntegrationEnv)) - cmd.Env = append(cmd.Env, fmt.Sprintf("SCION_DAEMON_ADDRESS=%s", sciondAddr)) + cmd.Env = append(cmd.Env, fmt.Sprintf("SCION_DAEMON=%s", sciondAddr)) id := fmt.Sprintf("server_%s", addr.FormatIA(dst.IA, addr.WithFileSeparator())) stdoutLog := sai.openLogFile(id, ".log") @@ -143,7 +143,7 @@ func (sai *ScionAppsIntegration) StartClient(ctx context.Context, cmd := exec.CommandContext(ctx, sai.clientCmd, args...) cmd.Env = os.Environ() cmd.Env = append(cmd.Env, fmt.Sprintf("%s=1", GoIntegrationEnv)) - cmd.Env = append(cmd.Env, fmt.Sprintf("SCION_DAEMON_ADDRESS=%s", sciondAddr)) + cmd.Env = append(cmd.Env, fmt.Sprintf("SCION_DAEMON=%s", sciondAddr)) id := fmt.Sprintf("client_%s", clientID(src, dst)) stdoutLog := sai.openLogFile(id, ".log") diff --git a/pkg/integration/integration.go b/pkg/integration/integration.go index d0e499f2f..8de37a5bb 100644 --- a/pkg/integration/integration.go +++ b/pkg/integration/integration.go @@ -200,12 +200,19 @@ func replacePattern(pattern string, replacement string, args []string) []string // hostAddr gets _a_ host address, the same way pan does, for a given IA func hostAddr(ia addr.IA) *snet.UDPAddr { - daemon, err := getSCIONDAddress(ia) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + sciondAddress, err := getSCIONDAddress(ia) + if err != nil { + log.Error("Failed to get sciond address", "err", err) + return nil + } + sciondConn, err := connSciond(ctx, sciondAddress) if err != nil { log.Error("Failed to get sciond address", "err", err) return nil } - hostIP, err := defaultLocalIPAddress(daemon) + hostIP, err := addrutil.DefaultLocalIP(ctx, daemon.TopoQuerier{Connector: sciondConn}) if err != nil { log.Error("Failed to get valid host IP", "err", err) return nil @@ -217,37 +224,14 @@ func getSCIONDAddress(ia addr.IA) (addr string, err error) { return sintegration.GetSCIONDAddress(sintegration.GenFile(sintegration.SCIONDAddressesFile), ia) } -func defaultLocalIPAddress(sciondAddress string) (net.IP, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - sciondConn, err := connSciond(ctx, sciondAddress) - if err != nil { - return nil, err - } - hostInLocalAS, err := findAnyHostInLocalAS(ctx, sciondConn) - if err != nil { - return nil, err - } - return addrutil.ResolveLocal(hostInLocalAS) -} - func connSciond(ctx context.Context, sciondAddress string) (daemon.Connector, error) { sciondConn, err := daemon.NewService(sciondAddress).Connect(ctx) if err != nil { - return nil, fmt.Errorf("unable to connect to SCIOND at %s (override with SCION_DAEMON_ADDRESS): %w", sciondAddress, err) + return nil, fmt.Errorf("unable to connect to SCIOND at %s (override with SCION_DAEMON): %w", sciondAddress, err) } return sciondConn, nil } -// findAnyHostInLocalAS returns the IP address of some (infrastructure) host in the local AS. -func findAnyHostInLocalAS(ctx context.Context, sciondConn daemon.Connector) (net.IP, error) { - bsAddr, err := daemon.TopoQuerier{Connector: sciondConn}.UnderlayAnycast(ctx, addr.SvcCS) - if err != nil { - return nil, err - } - return bsAddr.IP, nil -} - func iaIPtoString(addr *snet.UDPAddr) string { return fmt.Sprintf("%s,[%s]", addr.IA.String(), addr.Host.IP.String()) } diff --git a/pkg/pan/addr.go b/pkg/pan/addr.go index f6e17c5b1..4b55e2e42 100644 --- a/pkg/pan/addr.go +++ b/pkg/pan/addr.go @@ -27,7 +27,7 @@ import ( // UDPAddr is an address for a SCION/UDP end point. type UDPAddr struct { - IA IA + IA addr.IA IP netip.Addr Port uint16 } @@ -60,8 +60,8 @@ func (a UDPAddr) WithPort(port uint16) UDPAddr { return UDPAddr{IA: a.IA, IP: a.IP, Port: port} } -func (a UDPAddr) scionAddr() scionAddr { - return scionAddr{IA: a.IA, IP: a.IP} +func (a UDPAddr) scionAddr() SCIONAddr { + return SCIONAddr{IA: a.IA, IP: a.IP} } // Set implements flag.Value @@ -82,7 +82,7 @@ func ParseUDPAddr(s string) (UDPAddr, error) { panic("snet.ParseUDPAddr returned invalid IP") } return UDPAddr{ - IA: IA(addr.IA), + IA: addr.IA, IP: ip.Unmap(), Port: uint16(addr.Host.Port), }, nil @@ -98,64 +98,30 @@ func MustParseUDPAddr(s string) UDPAddr { return addr } -type IA addr.IA - -// IsZero reports whether ia is the zero value of the IA type. -func (ia IA) IsZero() bool { - return ia == 0 -} - -// IsWildcard reports whether ia has a wildcard part (isd or as, or both). -func (ia IA) IsWildcard() bool { - return addr.IA(ia).IsWildcard() -} - -func (ia IA) String() string { - return addr.IA(ia).String() -} - -// ParseIA parses an IA from a string of the format 'ia-as'. -func ParseIA(s string) (IA, error) { - ia, err := addr.ParseIA(s) - return IA(ia), err -} - -// MustParseIA calls ParseIA and panics on error. This is -// intended for testing. -func MustParseIA(s string) IA { - ia, err := ParseIA(s) - if err != nil { - panic(err) - } - return ia -} - -// scionAddr is a SCION/IP host address. +// SCIONAddr is a SCION/IP host address. // Not exported for now as it's not used in the API for now. Might be // useful for applicications later. -type scionAddr struct { - IA IA +type SCIONAddr struct { + IA addr.IA IP netip.Addr } -func (a scionAddr) String() string { +func (a SCIONAddr) String() string { return fmt.Sprintf("%s,%s", a.IA, a.IP) } -func (a scionAddr) WithPort(port uint16) UDPAddr { +func (a SCIONAddr) WithPort(port uint16) UDPAddr { return UDPAddr{IA: a.IA, IP: a.IP, Port: port} } -func (a scionAddr) snetUDPAddr() *snet.UDPAddr { +func (a SCIONAddr) snetUDPAddr() *snet.UDPAddr { return &snet.UDPAddr{ - IA: addr.IA(a.IA), + IA: a.IA, Host: net.UDPAddrFromAddrPort(netip.AddrPortFrom(a.IP, 0)), } } -var ( - addrRegexp = regexp.MustCompile(`^(\d+-[\d:A-Fa-f]+),(\[[^\]]+\]|[^\[\]]+)$`) -) +var addrRegexp = regexp.MustCompile(`^(\d+-[\d:A-Fa-f]+),(\[[^\]]+\]|[^\[\]]+)$`) const ( addrRegexpIaIndex = 1 @@ -163,21 +129,21 @@ const ( ) // parseSCIONAddr converts an SCION address string to a SCION address. -func parseSCIONAddr(address string) (scionAddr, error) { +func parseSCIONAddr(address string) (SCIONAddr, error) { parts := addrRegexp.FindStringSubmatch(address) if parts == nil { - return scionAddr{}, parseSCIONAddrError{in: address, msg: "unable to parse SCION address"} + return SCIONAddr{}, parseSCIONAddrError{in: address, msg: "unable to parse SCION address"} } - ia, err := ParseIA(parts[addrRegexpIaIndex]) + ia, err := addr.ParseIA(parts[addrRegexpIaIndex]) if err != nil { - return scionAddr{}, parseSCIONAddrError{in: address, msg: "invalid IA", cause: err} + return SCIONAddr{}, parseSCIONAddrError{in: address, msg: "invalid IA", cause: err} } l3Trimmed := strings.Trim(parts[addrRegexpL3Index], "[]") ip, err := netip.ParseAddr(l3Trimmed) if err != nil { - return scionAddr{}, parseSCIONAddrError{in: address, msg: "invalid IP", cause: err} + return SCIONAddr{}, parseSCIONAddrError{in: address, msg: "invalid IP", cause: err} } - return scionAddr{IA: ia, IP: ip}, nil + return SCIONAddr{IA: ia, IP: ip}, nil } type parseSCIONAddrError struct { @@ -198,7 +164,7 @@ func (err parseSCIONAddrError) Unwrap() error { } // mustParseSCIONAddr calls parseSCIONAddr and panics on error. -func mustParseSCIONAddr(s string) scionAddr { +func mustParseSCIONAddr(s string) SCIONAddr { addr, err := parseSCIONAddr(s) if err != nil { panic(err) @@ -206,8 +172,8 @@ func mustParseSCIONAddr(s string) scionAddr { return addr } -var ( - hostPortRegexp = regexp.MustCompile(`^((?:[-.\da-zA-Z]+)|(?:\d+-[\d:A-Fa-f]+,(?:\[[^\]]+\]|[^\[\]:]+))):(\d+)$`) +var hostPortRegexp = regexp.MustCompile( + `^((?:[-.\da-zA-Z]+)|(?:\d+-[\d:A-Fa-f]+,(?:\[[^\]]+\]|[^\[\]:]+))):(\d+)$`, ) const ( diff --git a/pkg/pan/addr_test.go b/pkg/pan/addr_test.go index bc8be0a80..6cb977cd1 100644 --- a/pkg/pan/addr_test.go +++ b/pkg/pan/addr_test.go @@ -19,14 +19,15 @@ import ( "net/netip" "testing" + "github.com/scionproto/scion/pkg/addr" "github.com/stretchr/testify/assert" "github.com/netsec-ethz/scion-apps/pkg/pan" ) func TestUDPAddrIsValid(t *testing.T) { - ia := pan.MustParseIA("1-ff00:0:0") - iaWildcard := pan.MustParseIA("1-0") + ia := addr.MustParseIA("1-ff00:0:0") + iaWildcard := addr.MustParseIA("1-0") ip := netip.MustParseAddr("127.0.0.1") cases := []struct { addr pan.UDPAddr diff --git a/pkg/pan/def.go b/pkg/pan/def.go index 07a0b51bc..dae94a535 100644 --- a/pkg/pan/def.go +++ b/pkg/pan/def.go @@ -18,11 +18,13 @@ import ( "errors" "fmt" "time" + + "github.com/scionproto/scion/pkg/addr" ) var ErrNoPath = errors.New("no path") -func errNoPathTo(ia IA) error { +func errNoPathTo(ia addr.IA) error { return fmt.Errorf("%w to %s", ErrNoPath, ia) } @@ -48,5 +50,7 @@ const ( ) // maxTime is the maximum usable time value (https://stackoverflow.com/a/32620397) -var maxTime = time.Unix(1<<63-62135596801, 999999999) -var maxDuration = time.Duration(1<<63 - 1) +var ( + maxTime = time.Unix(1<<63-62135596801, 999999999) + maxDuration = time.Duration(1<<63 - 1) +) diff --git a/pkg/pan/dns_txt.go b/pkg/pan/dns_txt.go index c08c8eab3..cbc5e5fb7 100644 --- a/pkg/pan/dns_txt.go +++ b/pkg/pan/dns_txt.go @@ -30,15 +30,15 @@ type dnsTXTResolver interface { LookupTXT(context.Context, string) ([]string, error) } -var _ resolver = &dnsResolver{} +var _ Resolver = &dnsResolver{} const scionAddrTXTTag = "scion=" // Resolve the name via DNS to return one scionAddr or an error. -func (d *dnsResolver) Resolve(ctx context.Context, name string) (saddr scionAddr, err error) { +func (d *dnsResolver) Resolve(ctx context.Context, name string) (saddr SCIONAddr, err error) { addresses, err := d.queryTXTRecord(ctx, name) if err != nil { - return scionAddr{}, err + return SCIONAddr{}, err } var perr error for _, addr := range addresses { @@ -47,12 +47,16 @@ func (d *dnsResolver) Resolve(ctx context.Context, name string) (saddr scionAddr return saddr, nil } } - return scionAddr{}, fmt.Errorf("error parsing TXT SCION address records: %w", perr) + return SCIONAddr{}, fmt.Errorf("error parsing TXT SCION address records: %w", perr) } // queryTXTRecord queries the DNS for DNS TXT record(s) specifying the SCION address(es) for host. -// Returns either at least one address, or else an error, of type HostNotFoundError if no matching record was found. -func (d *dnsResolver) queryTXTRecord(ctx context.Context, host string) (addresses []string, err error) { +// Returns either at least one address, or else an error, of type HostNotFoundError if no matching +// record was found. +func (d *dnsResolver) queryTXTRecord( + ctx context.Context, + host string, +) (addresses []string, err error) { if d.res == nil { return addresses, fmt.Errorf("invalid DNS resolver: %v", d.res) } diff --git a/pkg/pan/dns_txt_test.go b/pkg/pan/dns_txt_test.go index c30409249..317494406 100644 --- a/pkg/pan/dns_txt_test.go +++ b/pkg/pan/dns_txt_test.go @@ -26,18 +26,18 @@ func TestDNSResolver(t *testing.T) { cases := []struct { name string assertErr assert.ErrorAssertionFunc - expected scionAddr + expected SCIONAddr }{ {"example.com", assert.NoError, mustParse("1-ff00:0:f00,[192.0.2.1]")}, {"example.net", assert.NoError, mustParse("1-ff00:0:ba5,[192.0.2.38]")}, - {"example.org", assert.Error, scionAddr{}}, - {"noia.example.org", assert.Error, scionAddr{}}, - {"noip.example.org", assert.Error, scionAddr{}}, - {"trailing.example.org", assert.Error, scionAddr{}}, - {"example.edu", assertErrHostNotFound, scionAddr{}}, - {"empty.example.edu", assertErrHostNotFound, scionAddr{}}, - {"dummy4", assertErrHostNotFound, scionAddr{}}, - {"barbaz", assertErrHostNotFound, scionAddr{}}, + {"example.org", assert.Error, SCIONAddr{}}, + {"noia.example.org", assert.Error, SCIONAddr{}}, + {"noip.example.org", assert.Error, SCIONAddr{}}, + {"trailing.example.org", assert.Error, SCIONAddr{}}, + {"example.edu", assertErrHostNotFound, SCIONAddr{}}, + {"empty.example.edu", assertErrHostNotFound, SCIONAddr{}}, + {"dummy4", assertErrHostNotFound, SCIONAddr{}}, + {"barbaz", assertErrHostNotFound, SCIONAddr{}}, } var m mockResolver resolver := &dnsResolver{res: &m} diff --git a/pkg/pan/hosts.go b/pkg/pan/hosts.go index 260d13b94..ef7f9d407 100644 --- a/pkg/pan/hosts.go +++ b/pkg/pan/hosts.go @@ -23,32 +23,32 @@ import ( ) var ( - resolveEtcHosts resolver = &hostsfileResolver{"/etc/hosts"} - resolveEtcScionHosts resolver = &hostsfileResolver{"/etc/scion/hosts"} - resolveRains resolver = nil - resolveDNSTxt resolver = &dnsResolver{net.DefaultResolver} + resolveEtcHosts Resolver = &hostsfileResolver{"/etc/hosts"} + resolveEtcScionHosts Resolver = &hostsfileResolver{"/etc/scion/hosts"} + resolveRains Resolver = nil + resolveDNSTxt Resolver = &dnsResolver{net.DefaultResolver} ) -// resolveUDPAddrAt parses the address and resolves the hostname. +// ResolveUDPAddrAt parses the address and resolves the hostname. // The address can be of the form of a SCION address (i.e. of the form "ISD-AS,[IP]:port") // or in the form of "hostname:port". // If the address is in the form of a hostname, resolver is used to resolve the name. -func resolveUDPAddrAt(ctx context.Context, address string, resolver resolver) (UDPAddr, error) { +func ResolveUDPAddrAt(ctx context.Context, address string, resolver Resolver) (UDPAddr, error) { raddr, err := ParseUDPAddr(address) if err == nil { return raddr, nil } hostStr, portStr, err := net.SplitHostPort(address) if err != nil { - return UDPAddr{}, err + return UDPAddr{}, fmt.Errorf("invalid address: %w", err) } port, err := strconv.ParseUint(portStr, 10, 16) if err != nil { - return UDPAddr{}, err + return UDPAddr{}, fmt.Errorf("invalid port: %w", err) } host, err := resolver.Resolve(ctx, hostStr) if err != nil { - return UDPAddr{}, err + return UDPAddr{}, fmt.Errorf("using resolver: %w", err) } return host.WithPort(uint16(port)), nil } @@ -61,7 +61,7 @@ func resolveUDPAddrAt(ctx context.Context, address string, resolver resolver) (U // - /etc/scion/hosts // - RAINS, if a server is configured in /etc/scion/rains.cfg. Disabled if built with !norains. // - DNS TXT records using the local DNS resolver (depending on OS config, see "Name Resolution" in net package docs) -func defaultResolver() resolver { +func defaultResolver() Resolver { return resolverList{ resolveEtcHosts, resolveEtcScionHosts, @@ -70,21 +70,21 @@ func defaultResolver() resolver { } } -// resolver is the interface to resolve a host name to a SCION host address. +// Resolver is the interface to resolve a host name to a SCION host address. // Currently, this is implemented for reading the system hosts file, a SCION specific hosts file, // RAINS, and DNS TXT records for SCION of the format "scion=ia,ip" -type resolver interface { +type Resolver interface { // Resolve finds an address for the name. // Returns a HostNotFoundError if the name was not found, but otherwise no // error occurred. - Resolve(ctx context.Context, name string) (scionAddr, error) + Resolve(ctx context.Context, name string) (SCIONAddr, error) } // resolverList represents a list of Resolvers that are processed in sequence // to return the first match. -type resolverList []resolver +type resolverList []Resolver -func (resolvers resolverList) Resolve(ctx context.Context, name string) (scionAddr, error) { +func (resolvers resolverList) Resolve(ctx context.Context, name string) (SCIONAddr, error) { var errHostNotFound HostNotFoundError var rerr error for _, resolver := range resolvers { @@ -107,7 +107,7 @@ func (resolvers resolverList) Resolve(ctx context.Context, name string) (scionAd } if rerr != nil { // fmt.Fprintf(os.Stderr, "pan library: resolver error: %w", rerr) - return scionAddr{}, fmt.Errorf("pan library: resolver error: %w", rerr) + return SCIONAddr{}, fmt.Errorf("pan library: resolver error: %w", rerr) } - return scionAddr{}, HostNotFoundError{name} + return SCIONAddr{}, HostNotFoundError{name} } diff --git a/pkg/pan/hosts_test.go b/pkg/pan/hosts_test.go index bdd45684f..f9287452c 100644 --- a/pkg/pan/hosts_test.go +++ b/pkg/pan/hosts_test.go @@ -20,10 +20,11 @@ import ( "net/netip" "testing" + "github.com/scionproto/scion/pkg/addr" "github.com/stretchr/testify/assert" ) -const hostsTestFile = "hosts_test_file" +const hostsTestFile = "testdata/hosts_test_file" func TestCount(t *testing.T) { hosts, err := loadHostsFile(hostsTestFile) @@ -40,18 +41,18 @@ func TestHostsfileResolver(t *testing.T) { cases := []struct { name string assertErr assert.ErrorAssertionFunc - expected scionAddr + expected SCIONAddr }{ {"host1.1", assert.NoError, mustParse("17-ffaa:0:1,[192.168.1.1]")}, {"host1.2", assert.NoError, mustParse("17-ffaa:0:1,[192.168.1.1]")}, {"host2", assert.NoError, mustParse("18-ffaa:1:2,[10.0.8.10]")}, {"host3", assert.NoError, mustParse("17-ffaa:0:1,[192.168.1.1]")}, {"host4", assert.NoError, mustParse("20-ffaa:c0ff:ee12,[::ff1:ce00:dead:10cc:baad:f00d]")}, - {"commented", assertErrHostNotFound, scionAddr{}}, - {"dummy1", assertErrHostNotFound, scionAddr{}}, - {"dummy2", assertErrHostNotFound, scionAddr{}}, - {"dummy3", assertErrHostNotFound, scionAddr{}}, - {"foobar", assertErrHostNotFound, scionAddr{}}, + {"commented", assertErrHostNotFound, SCIONAddr{}}, + {"dummy1", assertErrHostNotFound, SCIONAddr{}}, + {"dummy2", assertErrHostNotFound, SCIONAddr{}}, + {"dummy3", assertErrHostNotFound, SCIONAddr{}}, + {"foobar", assertErrHostNotFound, SCIONAddr{}}, } for _, c := range cases { actual, err := resolver.Resolve(context.TODO(), c.name) @@ -69,12 +70,13 @@ func TestHostsfileResolverNonexisting(t *testing.T) { } func TestResolverList(t *testing.T) { - primary := map[string]scionAddr{ + primary := map[string]SCIONAddr{ "foo": mustParse("1-ff00:0:f00,[192.0.2.1]"), "bar": mustParse("1-ff00:0:ba3,[192.0.2.1]"), } - secondary := map[string]scionAddr{ - "bar": mustParse("1-ff00:0:ba3,[2001:db8:ffff:ffff:ffff:ffff:baad:f00d]"), // shadowed by bar in primary + secondary := map[string]SCIONAddr{ + // shadowed by bar in primary + "bar": mustParse("1-ff00:0:ba3,[2001:db8:ffff:ffff:ffff:ffff:baad:f00d]"), "baz": mustParse("1-ff00:0:ba5,[192.0.2.1]"), } resolver := resolverList{ @@ -85,12 +87,12 @@ func TestResolverList(t *testing.T) { cases := []struct { name string assertErr assert.ErrorAssertionFunc - expected scionAddr + expected SCIONAddr }{ {"foo", assert.NoError, mustParse("1-ff00:0:f00,[192.0.2.1]")}, {"bar", assert.NoError, mustParse("1-ff00:0:ba3,[192.0.2.1]")}, {"baz", assert.NoError, mustParse("1-ff00:0:ba5,[192.0.2.1]")}, - {"boo", assertErrHostNotFound, scionAddr{}}, + {"boo", assertErrHostNotFound, SCIONAddr{}}, } for _, c := range cases { actual, err := resolver.Resolve(context.TODO(), c.name) @@ -105,20 +107,20 @@ func assertErrHostNotFound(t assert.TestingT, err error, msgAndArgs ...interface } type dummyResolver struct { - hosts map[string]scionAddr + hosts map[string]SCIONAddr } -var _ resolver = &dummyResolver{} +var _ Resolver = &dummyResolver{} -func (r dummyResolver) Resolve(ctx context.Context, name string) (scionAddr, error) { +func (r dummyResolver) Resolve(ctx context.Context, name string) (SCIONAddr, error) { if h, ok := r.hosts[name]; ok { return h, nil } else { - return scionAddr{}, HostNotFoundError{Host: name} + return SCIONAddr{}, HostNotFoundError{Host: name} } } -func mustParse(address string) scionAddr { +func mustParse(address string) SCIONAddr { a, err := parseSCIONAddr(address) if err != nil { panic(fmt.Sprintf("test input must parse %s", err)) @@ -130,27 +132,33 @@ func TestParseSCIONAddr(t *testing.T) { cases := []struct { input string assertErr assert.ErrorAssertionFunc - expected scionAddr + expected SCIONAddr }{ { input: "1-ff00:0:0,[1.1.1.1]", assertErr: assert.NoError, - expected: scionAddr{IA: MustParseIA("1-ff00:0:0"), IP: netip.MustParseAddr("1.1.1.1")}, + expected: SCIONAddr{ + IA: addr.MustParseIA("1-ff00:0:0"), + IP: netip.MustParseAddr("1.1.1.1"), + }, }, { input: "1-ff00:0:0,1.1.1.1", assertErr: assert.NoError, - expected: scionAddr{IA: MustParseIA("1-ff00:0:0"), IP: netip.MustParseAddr("1.1.1.1")}, + expected: SCIONAddr{ + IA: addr.MustParseIA("1-ff00:0:0"), + IP: netip.MustParseAddr("1.1.1.1"), + }, }, { input: "1-ff00:0:0,[::]", assertErr: assert.NoError, - expected: scionAddr{IA: MustParseIA("1-ff00:0:0"), IP: netip.MustParseAddr("::")}, + expected: SCIONAddr{IA: addr.MustParseIA("1-ff00:0:0"), IP: netip.MustParseAddr("::")}, }, { input: "1-ff00:0:0,::", assertErr: assert.NoError, - expected: scionAddr{IA: MustParseIA("1-ff00:0:0"), IP: netip.MustParseAddr("::")}, + expected: SCIONAddr{IA: addr.MustParseIA("1-ff00:0:0"), IP: netip.MustParseAddr("::")}, }, {input: "1-ff00:0:0,[[::]]", assertErr: assert.Error}, {input: "1-ff00:0:0,::]", assertErr: assert.Error}, @@ -163,7 +171,6 @@ func TestParseSCIONAddr(t *testing.T) { } assert.Equal(t, c.expected, actual, "bad result for input '%s'", c.input) } - } func TestSplitHostPort(t *testing.T) { diff --git a/pkg/pan/hostsfile.go b/pkg/pan/hostsfile.go index 040a4d43c..27080afed 100644 --- a/pkg/pan/hostsfile.go +++ b/pkg/pan/hostsfile.go @@ -22,7 +22,7 @@ import ( "strings" ) -type hostsTable map[string]scionAddr +type hostsTable map[string]SCIONAddr // hostsfileResolver is an implementation of the resolver interface, backed // by an /etc/hosts-like file. @@ -30,18 +30,18 @@ type hostsfileResolver struct { path string } -func (r *hostsfileResolver) Resolve(ctx context.Context, name string) (scionAddr, error) { +func (r *hostsfileResolver) Resolve(ctx context.Context, name string) (SCIONAddr, error) { // Note: obviously not perfectly elegant to parse the entire file for // every query. However, properly caching this and still always provide // fresh results after changes to the hosts file seems like a bigger task and // for now that would be overkill. table, err := loadHostsFile(r.path) if err != nil { - return scionAddr{}, fmt.Errorf("error loading %s: %w", r.path, err) + return SCIONAddr{}, fmt.Errorf("error loading %s: %w", r.path, err) } addr, ok := table[name] if !ok { - return scionAddr{}, HostNotFoundError{name} + return SCIONAddr{}, HostNotFoundError{name} } return addr, nil } diff --git a/pkg/pan/interactive.go b/pkg/pan/interactive.go index 989d45904..98ae22fac 100644 --- a/pkg/pan/interactive.go +++ b/pkg/pan/interactive.go @@ -21,6 +21,8 @@ import ( "strconv" "strings" "sync" + + "github.com/scionproto/scion/pkg/addr" ) type InteractiveSelectionType int @@ -29,7 +31,7 @@ type InteractiveSelectionType int // destination IA type InteractiveSelection struct { Prompter Prompter - choices map[IA][]PathFingerprint + choices map[addr.IA][]PathFingerprint } func (p *InteractiveSelection) Filter(paths []*Path) []*Path { @@ -39,7 +41,7 @@ func (p *InteractiveSelection) Filter(paths []*Path) []*Path { chosenPaths := p.Prompter.Prompt(paths, dstIA) choice = pathFingerprints(chosenPaths) if p.choices == nil { - p.choices = make(map[IA][]PathFingerprint) + p.choices = make(map[addr.IA][]PathFingerprint) } p.choices[dstIA] = choice } @@ -48,20 +50,18 @@ func (p *InteractiveSelection) Filter(paths []*Path) []*Path { // Prompter is used by InteractiveSelection to prompt a user for path type Prompter interface { - Prompt(paths []*Path, remote IA) []*Path + Prompt(paths []*Path, remote addr.IA) []*Path } -var ( - // commandlinePrompterMutex asserts that only one CommandlinePrompter is prompting at - // any time - commandlinePrompterMutex sync.Mutex -) +// commandlinePrompterMutex asserts that only one CommandlinePrompter is prompting at +// any time +var commandlinePrompterMutex sync.Mutex // CommandlinePrompter is a Prompter for InteractiveSelection, prompting the user for textual // path selection input on stdin/out. type CommandlinePrompter struct{} -func (p CommandlinePrompter) Prompt(paths []*Path, remote IA) []*Path { +func (p CommandlinePrompter) Prompt(paths []*Path, remote addr.IA) []*Path { commandlinePrompterMutex.Lock() defer commandlinePrompterMutex.Unlock() diff --git a/pkg/pan/internal/ping/ping.go b/pkg/pan/internal/ping/ping.go index 1b05dea54..01363ea66 100644 --- a/pkg/pan/internal/ping/ping.go +++ b/pkg/pan/internal/ping/ping.go @@ -53,7 +53,6 @@ func NewPinger(ctx context.Context, topo snet.Topology, local *snet.UDPAddr, ) (*Pinger, error) { - replies := make(chan Reply, 10) scmpHandler := &scmpHandler{ replies: replies, @@ -86,8 +85,8 @@ func NewPinger(ctx context.Context, } func (p *Pinger) Send(ctx context.Context, remote *snet.UDPAddr, - sequence uint16, size int) error { - + sequence uint16, size int, +) error { // we need to have at least 8 bytes to store the request time in the // payload. if size < 8 { @@ -222,15 +221,14 @@ func pack(local, remote *snet.UDPAddr, req snet.SCMPEchoRequest) (*snet.Packet, if _, ok := remote.Path.(path.Empty); (remote.Path == nil || ok) && !local.IA.Equal(remote.IA) { return nil, serrors.New("no path for remote ISD-AS", "local", local.IA, "remote", remote.IA) } - localIP, ok := netip.AddrFromSlice(local.Host.IP) + remoteIP, ok := netip.AddrFromSlice(remote.Host.IP) if !ok { - return nil, serrors.New("invalid local IP", "local", local.Host.IP) + return nil, serrors.New("invalid remote IP address") } - remoteIP, ok := netip.AddrFromSlice(remote.Host.IP) + localIP, ok := netip.AddrFromSlice(local.Host.IP) if !ok { - return nil, serrors.New("invalid remote IP", "remote", remote.Host.IP) + return nil, serrors.New("invalid local IP address") } - pkt := &snet.Packet{ PacketInfo: snet.PacketInfo{ Destination: snet.SCIONAddress{ diff --git a/pkg/pan/pan.go b/pkg/pan/pan.go index ce5fe0f13..e010db75b 100644 --- a/pkg/pan/pan.go +++ b/pkg/pan/pan.go @@ -59,12 +59,12 @@ recorded paths to try routing around temporarily broken paths. The SCION daemon is assumed to be at the default address, but this can be overridden using an environment variable: - SCION_DAEMON_ADDRESS: 127.0.0.1:30255 + SCION_DAEMON: 127.0.0.1:30255 This is convenient for the normal use case of running the endhost stack for a single SCION AS. When running multiple local ASes, e.g. during development, the address of the SCION daemon corresponding to the desired AS needs to be -specified in the SCION_DAEMON_ADDRESS environment variable. +specified in the SCION_DAEMON environment variable. # Wildcard IP Addresses @@ -95,22 +95,23 @@ package pan import ( "context" "fmt" + + "github.com/scionproto/scion/pkg/addr" ) // ResolveUDPAddr parses the address and resolves the hostname. // The address can be of the form of a SCION address (i.e. of the form "ISD-AS,[IP]:port") // or in the form of "hostname:port". -// If the address is in the form of a hostname, the the following sources will +// If the address is in the form of a hostname, the following sources will // be used to resolve a name, in the given order of precedence. // // - /etc/hosts // - /etc/scion/hosts -// - RAINS, if a server is configured in /etc/scion/rains.cfg. Disabled if built with !norains. // - DNS TXT records using the local DNS resolver (depending on OS config, see "Name Resolution" in net package docs) // // Returns HostNotFoundError if none of the sources did resolve the hostname. func ResolveUDPAddr(ctx context.Context, address string) (UDPAddr, error) { - return resolveUDPAddrAt(ctx, address, defaultResolver()) + return ResolveUDPAddrAt(ctx, address, defaultResolver()) } // HostNotFoundError is returned by ResolveUDPAddr when the name was not found, but @@ -123,8 +124,11 @@ func (e HostNotFoundError) Error() string { return fmt.Sprintf("host not found: '%s'", e.Host) } -// Query paths to a particular destination AS. -func QueryPaths(ctx context.Context, dst IA) ([]*Path, error) { - paths, _, err := (&pool).paths(ctx, dst) - return paths, err +// QueryPaths queries paths to a particular destination AS. +// +// Deprecated: Use PAN.QueryPaths instead. This standalone function is deprecated +// because it requires implicit global state. Create a PAN with New and use +// its QueryPaths method. +func QueryPaths(ctx context.Context, dst addr.IA) ([]*Path, error) { + return nil, fmt.Errorf("QueryPaths is deprecated; use PAN.QueryPaths instead") } diff --git a/pkg/pan/pan_test.go b/pkg/pan/pan_test.go index a32155212..27de585e7 100644 --- a/pkg/pan/pan_test.go +++ b/pkg/pan/pan_test.go @@ -18,11 +18,12 @@ import ( "errors" "testing" + "github.com/scionproto/scion/pkg/addr" "github.com/stretchr/testify/assert" ) func TestErrNoPathTo(t *testing.T) { - ia := MustParseIA("1-ff00:0:1") + ia := addr.MustParseIA("1-ff00:0:1") err := errNoPathTo(ia) assert.Equal(t, err.Error(), "no path to 1-ff00:0:1") assert.True(t, errors.Is(err, ErrNoPath)) diff --git a/pkg/pan/path.go b/pkg/pan/path.go index 902c9b8a7..8fdc44153 100644 --- a/pkg/pan/path.go +++ b/pkg/pan/path.go @@ -20,6 +20,7 @@ import ( "strings" "time" + "github.com/scionproto/scion/pkg/addr" "github.com/scionproto/scion/pkg/slayers/path" "github.com/scionproto/scion/pkg/slayers/path/scion" "github.com/scionproto/scion/pkg/snet" @@ -28,8 +29,8 @@ import ( // TODO: revisit: pointer or value type? what goes where? should ForwardingPath be exported? type Path struct { - Source IA - Destination IA + Source addr.IA + Destination addr.IA ForwardingPath ForwardingPath Metadata *PathMetadata // optional Fingerprint PathFingerprint @@ -40,7 +41,7 @@ func (p *Path) String() string { if p.Metadata != nil { return p.Metadata.fmtInterfaces() } else { - return fmt.Sprintf("%s %s %s", p.Source, p.Destination, p.Fingerprint) + return fmt.Sprintf("%s %s %s", p.Source, p.Fingerprint, p.Destination) } } @@ -68,6 +69,13 @@ type ForwardingPath struct { underlay netip.AddrPort } +func NewForwardingPath(dp snet.DataplanePath, underlay netip.AddrPort) ForwardingPath { + return ForwardingPath{ + dataplanePath: dp, + underlay: underlay, + } +} + func (p ForwardingPath) forwardingPathInfo() (forwardingPathInfo, error) { var raw []byte switch dataplanePath := p.dataplanePath.(type) { @@ -79,14 +87,18 @@ func (p ForwardingPath) forwardingPathInfo() (forwardingPathInfo, error) { return forwardingPathInfo{}, err } default: - return forwardingPathInfo{}, fmt.Errorf("unsupported path type %v inside RawReplyPath", dataplanePath.Path.Type()) + return forwardingPathInfo{}, fmt.Errorf( + "unsupported path type %v inside RawReplyPath", dataplanePath.Path.Type(), + ) } case snet.RawPath: switch dataplanePath.PathType { case scion.PathType: raw = dataplanePath.Raw default: - return forwardingPathInfo{}, fmt.Errorf("unsupported path type %v inside RawPath", dataplanePath.PathType) + return forwardingPathInfo{}, fmt.Errorf( + "unsupported path type %v inside RawPath", dataplanePath.PathType, + ) } case snetpath.SCION: raw = dataplanePath.Raw @@ -106,7 +118,7 @@ func (p ForwardingPath) forwardingPathInfo() (forwardingPathInfo, error) { // reversePathFromForwardingPath creates a Path for the return direction from the information // on a received packet. // The created Path includes fingerprint and expiry information. -func reversePathFromForwardingPath(src, dst IA, fwPath ForwardingPath) (*Path, error) { +func reversePathFromForwardingPath(src, dst addr.IA, fwPath ForwardingPath) (*Path, error) { // FIXME: inefficient, decoding twice! Change this to decode and then both // reverse and extract fw info rp, ok := fwPath.dataplanePath.(snet.RawPath) @@ -160,7 +172,7 @@ func expiryFromDecoded(sp scion.Decoded) time.Time { ret := maxTime hop := 0 for i, info := range sp.InfoFields { - seglen := int(sp.Base.PathMeta.SegLen[i]) + seglen := int(sp.PathMeta.SegLen[i]) for h := 0; h < seglen; h++ { exp := hopExpiry(info, sp.HopFields[hop]) if exp.Before(ret) { @@ -194,7 +206,7 @@ func interfaceIDsFromDecoded(sp scion.Decoded) []IfID { hop := 0 for i, info := range sp.InfoFields { - seglen := int(sp.Base.PathMeta.SegLen[i]) + seglen := int(sp.PathMeta.SegLen[i]) for h := 0; h < seglen; h++ { if h > 0 || (info.Peer && i == 1) { ifIDs = append(ifIDs, first(sp.HopFields[hop], info.ConsDir)) @@ -225,7 +237,7 @@ type pathSequence struct { InterfaceIDs []IfID } -func pathSequenceFromInterfaces(interfaces []PathInterface) pathSequence { +func PathSequenceFromInterfaces(interfaces []PathInterface) pathSequence { ifIDs := make([]IfID, len(interfaces)) for i, iface := range interfaces { ifIDs[i] = iface.IfID @@ -243,9 +255,12 @@ func (s pathSequence) Fingerprint() PathFingerprint { } b := &strings.Builder{} fmt.Fprintf(b, "%d", s.InterfaceIDs[0]) - for _, ifID := range s.InterfaceIDs[1:] { - fmt.Fprintf(b, " %d", ifID) + for i := 1; i < len(s.InterfaceIDs)-1; i += 2 { + inIntf := s.InterfaceIDs[i] + outIntf := s.InterfaceIDs[i+1] + fmt.Fprintf(b, ">%d %d", inIntf, outIntf) } + fmt.Fprintf(b, ">%d", s.InterfaceIDs[len(s.InterfaceIDs)-1]) return PathFingerprint(b.String()) } diff --git a/pkg/pan/path_metadata.go b/pkg/pan/path_metadata.go index 1b3845426..e5d316bbf 100644 --- a/pkg/pan/path_metadata.go +++ b/pkg/pan/path_metadata.go @@ -20,13 +20,14 @@ import ( "strings" "time" + "github.com/scionproto/scion/pkg/addr" "github.com/scionproto/scion/pkg/snet" ) type IfID uint64 type PathInterface struct { - IA IA + IA addr.IA IfID IfID } @@ -77,8 +78,10 @@ type PathMetadata struct { Notes []string } -type GeoCoordinates = snet.GeoCoordinates -type LinkType = snet.LinkType +type ( + GeoCoordinates = snet.GeoCoordinates + LinkType = snet.LinkType +) func (pm *PathMetadata) Copy() *PathMetadata { if pm == nil { diff --git a/pkg/pan/path_test.go b/pkg/pan/path_test.go index 4d5a41dc3..b2106bbe5 100644 --- a/pkg/pan/path_test.go +++ b/pkg/pan/path_test.go @@ -18,6 +18,7 @@ import ( "testing" "time" + "github.com/scionproto/scion/pkg/addr" "github.com/scionproto/scion/pkg/slayers/path/scion" "github.com/scionproto/scion/pkg/snet" snetpath "github.com/scionproto/scion/pkg/snet/path" @@ -25,9 +26,9 @@ import ( ) func TestPathString(t *testing.T) { - asA := MustParseIA("1-ff00:0:a") - asB := MustParseIA("1-ff00:0:b") - asC := MustParseIA("1-ff00:0:c") + asA := addr.MustParseIA("1-ff00:0:a") + asB := addr.MustParseIA("1-ff00:0:b") + asC := addr.MustParseIA("1-ff00:0:c") ifA1 := PathInterface{IA: asA, IfID: 1} ifB1 := PathInterface{IA: asB, IfID: 11} @@ -44,7 +45,7 @@ func TestPathString(t *testing.T) { { name: "no metadata", interfaces: nil, - expected: "0-0 0-0 " + testFingerprint, + expected: "0-0 " + testFingerprint + " 0-0", }, { name: "empty", @@ -155,9 +156,9 @@ func TestDataplaneLen(t *testing.T) { func TestInterfacesFromDecoded(t *testing.T) { // Not a great test case... rawPath := []byte("\x00\x00\x20\x80\x00\x00\x01\x11\x00\x00\x01\x00\x01\x00\x02\x22\x00\x00" + - "\x01\x00\x00\x3f\x00\x01\x00\x00\x01\x02\x03\x04\x05\x06\x00\x3f\x00\x03\x00\x02\x01\x02\x03" + - "\x04\x05\x06\x00\x3f\x00\x00\x00\x02\x01\x02\x03\x04\x05\x06\x00\x3f\x00\x01\x00\x00\x01\x02" + - "\x03\x04\x05\x06") + "\x01\x00\x00\x3f\x00\x01\x00\x00\x01\x02\x03\x04\x05\x06\x00\x3f\x00\x03\x00\x02\x01\x02" + + "\x03\x04\x05\x06\x00\x3f\x00\x00\x00\x02\x01\x02\x03\x04\x05\x06\x00\x3f\x00\x01\x00\x00" + + "\x01\x02\x03\x04\x05\x06") sp := scion.Decoded{} err := sp.DecodeFromBytes(rawPath) @@ -172,9 +173,9 @@ func TestInterfacesFromDecoded(t *testing.T) { func TestLowerLatency(t *testing.T) { unknown := time.Duration(0) - asA := MustParseIA("1-0:0:1") - asB := MustParseIA("1-0:0:2") - asC := MustParseIA("1-0:0:3") + asA := addr.MustParseIA("1-0:0:1") + asB := addr.MustParseIA("1-0:0:2") + asC := addr.MustParseIA("1-0:0:3") ifA1 := PathInterface{IA: asA, IfID: 1} ifB1 := PathInterface{IA: asB, IfID: 1} diff --git a/pkg/pan/pathquerier.go b/pkg/pan/pathquerier.go new file mode 100644 index 000000000..4410fc2da --- /dev/null +++ b/pkg/pan/pathquerier.go @@ -0,0 +1,116 @@ +// Copyright 2021 ETH Zurich +// +// 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 pan + +import ( + "context" + "net/netip" + "sync/atomic" + + "github.com/scionproto/scion/pkg/addr" + "github.com/scionproto/scion/pkg/daemon" + "github.com/scionproto/scion/pkg/snet" +) + +// PathQuerier queries paths from the SCION daemon and converts them to Path objects. +// It implements PathSource for use with PathPool. +// It also maintains the interface cache which is updated on each path query. +type PathQuerier struct { + localIA addr.IA + scionD daemon.Connector + interfaces atomic.Pointer[map[uint16]netip.AddrPort] +} + +// NewPathQuerier creates a new PathQuerier with an initial interface set. +func NewPathQuerier( + localIA addr.IA, + scionD daemon.Connector, + initialInterfaces map[uint16]netip.AddrPort, +) *PathQuerier { + q := &PathQuerier{ + localIA: localIA, + scionD: scionD, + } + q.interfaces.Store(&initialInterfaces) + return q +} + +// Interface returns the underlay address for the given interface ID. +func (q *PathQuerier) Interface(ifID uint16) (netip.AddrPort, bool) { + m := q.interfaces.Load() + if m == nil { + return netip.AddrPort{}, false + } + a, ok := (*m)[ifID] + return a, ok +} + +// Paths queries paths to the destination IA from the SCION daemon. +func (q *PathQuerier) Paths(ctx context.Context, dst addr.IA) ([]*Path, error) { + flags := daemon.PathReqFlags{Refresh: false, Hidden: false} + snetPaths, err := q.scionD.Paths(ctx, dst, 0, flags) + if err != nil { + return nil, err + } + // when querying paths we also reload the interfaces, to make sure we have + // correct information about them. + interfaces, err := q.scionD.Interfaces(ctx) + if err != nil { + return nil, err + } + q.interfaces.Store(&interfaces) //nolint:gosec + return q.convertPaths(dst, snetPaths), nil +} + +func (q *PathQuerier) convertPaths(dst addr.IA, snetPaths []snet.Path) []*Path { + paths := make([]*Path, len(snetPaths)) + for i, p := range snetPaths { + snetMetadata := p.Metadata() + metadata := &PathMetadata{ + Interfaces: convertPathInterfaceSlice(snetMetadata.Interfaces), + MTU: snetMetadata.MTU, + Latency: snetMetadata.Latency, + Bandwidth: snetMetadata.Bandwidth, + Geo: snetMetadata.Geo, + LinkType: snetMetadata.LinkType, + InternalHops: snetMetadata.InternalHops, + Notes: snetMetadata.Notes, + } + underlay := p.UnderlayNextHop().AddrPort() + paths[i] = &Path{ + Source: q.localIA, + Destination: dst, + Metadata: metadata, + Fingerprint: PathSequenceFromInterfaces(metadata.Interfaces).Fingerprint(), + Expiry: snetMetadata.Expiry, + ForwardingPath: ForwardingPath{ + dataplanePath: p.Dataplane(), + underlay: underlay, + }, + } + } + return paths +} + +func convertPathInterfaceSlice(spis []snet.PathInterface) []PathInterface { + pis := make([]PathInterface, len(spis)) + for i, spi := range spis { + pis[i] = PathInterface{ + IA: spi.IA, + IfID: IfID(spi.ID), + } + } + return pis +} diff --git a/pkg/pan/policy.go b/pkg/pan/policy.go index f82b797be..43c6017e2 100644 --- a/pkg/pan/policy.go +++ b/pkg/pan/policy.go @@ -194,7 +194,7 @@ func (p snetPathWrapper) Metadata() *snet.PathMetadata { pis := make([]snet.PathInterface, len(p.wrapped.Metadata.Interfaces)) for i, spi := range p.wrapped.Metadata.Interfaces { pis[i] = snet.PathInterface{ - IA: addr.IA(spi.IA), + IA: spi.IA, ID: iface.ID(spi.IfID), } } diff --git a/pkg/pan/policy_test.go b/pkg/pan/policy_test.go index 440edcb01..84aee0e69 100644 --- a/pkg/pan/policy_test.go +++ b/pkg/pan/policy_test.go @@ -19,6 +19,7 @@ import ( "strings" "testing" + "github.com/scionproto/scion/pkg/addr" "github.com/stretchr/testify/assert" ) @@ -172,6 +173,7 @@ func TestSortStablePartialOrder(t *testing.T) { }) } } + func TestPinnedPolicy(t *testing.T) { cases := []struct { name string @@ -296,9 +298,9 @@ func fingerprintsFromTestdataPaths(paths []*Path) []PathFingerprint { // works correctly. We do not need to extensively test the sequence // language itself here. func TestSequencePolicy(t *testing.T) { - asA := MustParseIA("1-ff00:0:a") - asB := MustParseIA("1-ff00:0:b") - asC := MustParseIA("1-ff00:0:c") + asA := addr.MustParseIA("1-ff00:0:a") + asB := addr.MustParseIA("1-ff00:0:b") + asC := addr.MustParseIA("1-ff00:0:c") pAB := &Path{ Metadata: &PathMetadata{ Interfaces: []PathInterface{ @@ -368,9 +370,9 @@ func TestSequencePolicy(t *testing.T) { // works correctly. We do not need to extensively test the sequence // language itself here. func TestACLPolicy(t *testing.T) { - asA := MustParseIA("1-ff00:0:a") - asB := MustParseIA("1-ff00:0:b") - asC := MustParseIA("1-ff00:0:c") + asA := addr.MustParseIA("1-ff00:0:a") + asB := addr.MustParseIA("1-ff00:0:b") + asC := addr.MustParseIA("1-ff00:0:c") pAB := &Path{ Metadata: &PathMetadata{ Interfaces: []PathInterface{ diff --git a/pkg/pan/pool.go b/pkg/pan/pool.go index 270199a36..8164a0af9 100644 --- a/pkg/pan/pool.go +++ b/pkg/pan/pool.go @@ -18,24 +18,54 @@ import ( "context" "sync" "time" + + "github.com/scionproto/scion/pkg/addr" + "github.com/scionproto/scion/pkg/log" ) -// pool is the *global* path pool. -// - share cache between multiple connections -// - centrally refresh paths before expiration -var pool pathPool +type PathSource interface { + Paths(ctx context.Context, dst addr.IA) ([]*Path, error) +} + +type PathPoolConfig struct { + RefreshMinInterval time.Duration + RefreshInterval time.Duration + RefreshLeadTime time.Duration + PruneLeadTime time.Duration +} + +func DefaultPathPoolConfig() PathPoolConfig { + return PathPoolConfig{ + RefreshMinInterval: pathRefreshMinInterval, + RefreshInterval: pathRefreshInterval, + RefreshLeadTime: pathRefreshLeadTime, + PruneLeadTime: pathPruneLeadTime, + } +} -func init() { - pool.refresher = makeRefresher(&pool) - pool.entries = make(map[IA]pathPoolDst) +func NewPathPool(pathSource PathSource, stats *pathStatsDB, config PathPoolConfig) *PathPool { + p := &PathPool{ + pathSource: pathSource, + stats: stats, + entries: make(map[addr.IA]pathPoolDst), + config: config, + } + p.refresher = makeRefresher(p) // note: start refresher, but won't do anything until paths are added to the pool - go pool.refresher.run() + go func() { + defer log.HandlePanic() + p.refresher.run() + }() + return p } -type pathPool struct { +type PathPool struct { + pathSource PathSource + stats *pathStatsDB refresher refresher entriesMutex sync.RWMutex - entries map[IA]pathPoolDst + entries map[addr.IA]pathPoolDst + config PathPoolConfig } // pathPoolDst is path pool entry for one destination IA @@ -50,65 +80,63 @@ type pathPoolSubscriber interface { pathDownNotifyee } -func (p *pathPool) subscribe(ctx context.Context, dstIA IA, - s pathPoolSubscriber) ([]*Path, error) { - +func (p *PathPool) subscribe( + ctx context.Context, + dstIA addr.IA, + s pathPoolSubscriber, +) ([]*Path, error) { paths, err := p.refresher.subscribe(ctx, dstIA, s) if err != nil { return nil, err } - stats.subscribe(s) + p.stats.subscribe(s) return paths, nil } -func (p *pathPool) unsubscribe(dstIA IA, s pathPoolSubscriber) { +func (p *PathPool) unsubscribe(dstIA addr.IA, s pathPoolSubscriber) { p.refresher.unsubscribe(dstIA, s) - stats.unsubscribe(s) + p.stats.unsubscribe(s) } // paths returns paths to dstIA. This _may_ query paths, unless they have recently been queried. -func (p *pathPool) paths(ctx context.Context, dstIA IA) ([]*Path, bool, error) { +func (p *PathPool) paths(ctx context.Context, dstIA addr.IA) ([]*Path, bool, error) { p.entriesMutex.RLock() entry, ok := p.entries[dstIA] p.entriesMutex.RUnlock() - if ok && !shouldQuery(time.Now(), entry.earliestExpiry, entry.lastQuery) { + if ok && time.Since(entry.lastQuery) < p.config.RefreshMinInterval { return append([]*Path{}, entry.paths...), false, nil } - paths, err := p.queryPaths(ctx, dstIA) + paths, err := p.QueryPaths(ctx, dstIA) if err != nil { return nil, false, err } return paths, true, nil } -// queryPaths returns paths to dstIA. Unconditionally requests paths from sciond. -func (p *pathPool) queryPaths(ctx context.Context, dstIA IA) ([]*Path, error) { - host, err := getHost() - if err != nil { - return nil, err - } - paths, err := host.queryPaths(ctx, dstIA) +// QueryPaths returns paths to dstIA. Unconditionally requests paths from sciond. +func (p *PathPool) QueryPaths(ctx context.Context, dstIA addr.IA) ([]*Path, error) { + paths, err := p.pathSource.Paths(ctx, dstIA) if err != nil { return nil, err } p.entriesMutex.Lock() defer p.entriesMutex.Unlock() entry := p.entries[dstIA] - entry.update(paths) + entry.update(paths, p.config.PruneLeadTime) p.entries[dstIA] = entry return append([]*Path{}, paths...), nil } // cachedPaths returns paths to dstIA. Always returns the cached paths, never queries paths. -func (p *pathPool) cachedPaths(dst IA) []*Path { +func (p *PathPool) cachedPaths(dstIA addr.IA) []*Path { p.entriesMutex.RLock() defer p.entriesMutex.RUnlock() - return append([]*Path{}, p.entries[dst].paths...) + return append([]*Path{}, p.entries[dstIA].paths...) } -func (e *pathPoolDst) update(paths []*Path) { +func (e *pathPoolDst) update(paths []*Path, pathPruneLeadTime time.Duration) { now := time.Now() expiryDropTime := now.Add(-pathPruneLeadTime) @@ -130,7 +158,7 @@ func (e *pathPoolDst) update(paths []*Path) { e.paths = paths } -func (p *pathPool) earliestPathExpiry() time.Time { +func (p *PathPool) earliestPathExpiry() time.Time { p.entriesMutex.RLock() defer p.entriesMutex.RUnlock() if len(p.entries) == 0 { @@ -158,9 +186,3 @@ func earliestPathExpiry(paths []*Path) time.Time { } return ret } - -func shouldQuery(now, expiry, lastQuery time.Time) bool { - earliestAllowedRefresh := lastQuery.Add(pathRefreshMinInterval) - timeForRefresh := expiry.Add(-pathRefreshLeadTime) - return now.After(earliestAllowedRefresh) && now.After(timeForRefresh) -} diff --git a/pkg/pan/quic_dial.go b/pkg/pan/quic_dial.go index 8c1d0029e..973474672 100644 --- a/pkg/pan/quic_dial.go +++ b/pkg/pan/quic_dial.go @@ -19,28 +19,23 @@ import ( "crypto/tls" "net" "net/netip" + "runtime" "github.com/quic-go/quic-go" ) -// QUICConn is a wrapper around quic.Conn that always closes the -// underlying conn when closing the connection. -type QUICConn struct { - *quic.Conn - UnderlayConn Conn -} - -func (s *QUICConn) CloseWithError(code quic.ApplicationErrorCode, desc string) error { - err := s.Conn.CloseWithError(code, desc) - s.UnderlayConn.Close() - return err +// QUICSession is a wrapper around quic.Connection that always closes the +// underlying conn when closing the session. +type QUICSession struct { + QUIC *quic.Conn + Conn Conn } // DialQUIC establishes a new QUIC connection to a server at the remote address. // // The host parameter is used for SNI. // The tls.Config must define an application protocol (using NextProtos). -func DialQUIC( +func (p *PAN) DialQUIC( ctx context.Context, local netip.AddrPort, remote UDPAddr, @@ -48,9 +43,8 @@ func DialQUIC( tlsConf *tls.Config, quicConf *quic.Config, connOptions ...ConnOptions, -) (*QUICConn, error) { - - conn, err := DialUDP(ctx, local, remote, connOptions...) +) (*QUICSession, error) { + conn, err := p.DialUDP(ctx, local, remote, connOptions...) if err != nil { return nil, err } @@ -77,11 +71,14 @@ func DialQUIC( pconn.Close() return nil, err } - return &QUICConn{Conn: session, UnderlayConn: conn}, nil + runtime.AddCleanup(session, func(pconn connectedPacketConn) { + pconn.Close() + }, pconn) + return &QUICSession{QUIC: session, Conn: conn}, nil } // DialQUICEarly establishes a new 0-RTT QUIC connection to a server. Analogous to DialQUIC. -func DialQUICEarly( +func (p *PAN) DialQUICEarly( ctx context.Context, local netip.AddrPort, remote UDPAddr, @@ -89,9 +86,8 @@ func DialQUICEarly( tlsConf *tls.Config, quicConf *quic.Config, connOptions ...ConnOptions, -) (*QUICConn, error) { - - conn, err := DialUDP(ctx, local, remote, connOptions...) +) (*QUICSession, error) { + conn, err := p.DialUDP(ctx, local, remote, connOptions...) if err != nil { return nil, err } @@ -102,9 +98,13 @@ func DialQUICEarly( defer unsilenceLog() session, err := quic.DialEarly(ctx, pconn, remote, tlsConf, quicConf) if err != nil { + pconn.Close() return nil, err } - return &QUICConn{Conn: session, UnderlayConn: conn}, nil + runtime.AddCleanup(session, func(pconn connectedPacketConn) { + pconn.Close() + }, pconn) + return &QUICSession{QUIC: session, Conn: conn}, nil } // connectedPacketConn wraps a Conn into a PacketConn interface. diff --git a/pkg/pan/quic_listen.go b/pkg/pan/quic_listen.go index 43ee17829..7bacfdb61 100644 --- a/pkg/pan/quic_listen.go +++ b/pkg/pan/quic_listen.go @@ -18,9 +18,9 @@ import ( "context" "crypto/tls" "net" - "net/netip" "github.com/quic-go/quic-go" + "github.com/scionproto/scion/pkg/snet" ) // QUICListener is a wrapper around a quic.Listener that also holds the underlying @@ -40,26 +40,25 @@ func (l *QUICListener) Close() error { // ListenQUIC listens for QUIC connections on a SCION/UDP port. // // See note on wildcard addresses in the package documentation. -func ListenQUIC( +func (p *PAN) ListenQUIC( ctx context.Context, - local netip.AddrPort, + listen *snet.UDPAddr, tlsConf *tls.Config, quicConfig *quic.Config, - listenConnOptions ...ListenConnOptions, -) (*QUICListener, error) { - - conn, err := ListenUDP(ctx, local, listenConnOptions...) + selector ReplySelector, +) (*quic.EarlyListener, error) { + conn, err := p.ListenUDP(ctx, listen.Host.AddrPort(), selector) if err != nil { return nil, err } - // HACK: we silence the log here to shut up quic-go's warning about trying to - // set receive buffer size (it's not a UDPConn, we know). - silenceLog() - defer unsilenceLog() - listener, err := quic.Listen(conn, tlsConf, quicConfig) + + listener, err := quic.ListenEarly( + conn, + tlsConf, + quicConfig) if err != nil { conn.Close() return nil, err } - return &QUICListener{Listener: listener, Conn: conn}, nil + return listener, nil } diff --git a/pkg/pan/rains.go b/pkg/pan/rains.go deleted file mode 100644 index a51c5df76..000000000 --- a/pkg/pan/rains.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2020 ETH Zurich -// -// 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. - -//go:build !norains -// +build !norains - -package pan - -import ( - "context" - "fmt" - "net" - "net/netip" - "os" - "strings" - "time" - - "github.com/netsec-ethz/rains/pkg/rains" - "github.com/scionproto/scion/pkg/addr" - "github.com/scionproto/scion/pkg/snet" -) - -const rainsConfigPath = "/etc/scion/rains.cfg" - -func init() { - resolveRains = &rainsResolver{} -} - -type rainsResolver struct{} - -var _ resolver = &rainsResolver{} - -func (r *rainsResolver) Resolve(ctx context.Context, name string) (scionAddr, error) { - server, err := readRainsConfig() - if err != nil { - return scionAddr{}, err - } - if server.Port == 0 { - // nobody to ask, so we won't get a reply - return scionAddr{}, HostNotFoundError{name} - } - return rainsQuery(ctx, server, name) -} - -func readRainsConfig() (UDPAddr, error) { - bs, err := os.ReadFile(rainsConfigPath) - if os.IsNotExist(err) { - return UDPAddr{}, nil - } else if err != nil { - return UDPAddr{}, fmt.Errorf("error loading %s: %w", rainsConfigPath, err) - } - address, err := ParseUDPAddr(strings.TrimSpace(string(bs))) - if err != nil { - return UDPAddr{}, fmt.Errorf("error parsing %s, expected SCION UDP address: %w", rainsConfigPath, err) - } - return address, nil -} - -func rainsQuery(ctx context.Context, server UDPAddr, hostname string) (scionAddr, error) { - const ( - rainsCtx = "." // use global context - qType = rains.OTScionAddr // request SCION addresses - expire = 5 * time.Minute // sensible expiry date? - timeout = 500 * time.Millisecond // timeout for query - ) - qOpts := []rains.Option{} // no options - - // TODO(chaehni): This call can sometimes cause a timeout even though the server is reachable (see issue #221) - // The (default) timeout value has been decreased to counter this behavior until the problem is resolved. - srv := &snet.UDPAddr{ - IA: addr.IA(server.IA), - Host: net.UDPAddrFromAddrPort(netip.AddrPortFrom(server.IP, server.Port)), - } - - reply, err := rainsQueryChecked(ctx, hostname, rainsCtx, []rains.Type{qType}, qOpts, expire, timeout, srv) - if err != nil { - return scionAddr{}, err - } - addrStr, ok := reply[qType] - if !ok { - return scionAddr{}, &HostNotFoundError{hostname} - } - addr, err := parseSCIONAddr(addrStr) - if err != nil { - return scionAddr{}, fmt.Errorf("address for host %q invalid: %w", hostname, err) - } - return addr, nil -} - -func rainsQueryChecked(ctx context.Context, name, rainsCtx string, types []rains.Type, opts []rains.Option, - expire, timeout time.Duration, addr net.Addr) (res map[rains.Type]string, err error) { - - var contextTimeout time.Duration - deadline, finite := ctx.Deadline() - if finite { - contextTimeout = time.Until(deadline) - if contextTimeout < 0 { - return res, context.DeadlineExceeded - } - } else { - contextTimeout = timeout - } - - done := make(chan struct{}) - go func() { - defer close(done) - res, err = rains.Query(name, rainsCtx, types, opts, expire, contextTimeout, addr) - }() - select { - case <-ctx.Done(): - return res, ctx.Err() - case <-done: - } - return -} diff --git a/pkg/pan/raw.go b/pkg/pan/raw.go index 69f46c0e7..d40e83b35 100644 --- a/pkg/pan/raw.go +++ b/pkg/pan/raw.go @@ -15,13 +15,13 @@ package pan import ( - "fmt" "net" "net/netip" "sync" "time" "github.com/scionproto/scion/pkg/addr" + "github.com/scionproto/scion/pkg/log" "github.com/scionproto/scion/pkg/private/common" "github.com/scionproto/scion/pkg/slayers" "github.com/scionproto/scion/pkg/snet" @@ -84,11 +84,11 @@ func (c *baseUDPConn) writeMsg(src, dst UDPAddr, path *Path, b []byte) (int, err Bytes: c.writeBuffer, PacketInfo: snet.PacketInfo{ Source: snet.SCIONAddress{ - IA: addr.IA(src.IA), + IA: src.IA, Host: addr.HostIP(src.IP), }, Destination: snet.SCIONAddress{ - IA: addr.IA(dst.IA), + IA: dst.IA, Host: addr.HostIP(dst.IP), }, Path: dataplanePath, @@ -134,7 +134,7 @@ func (c *baseUDPConn) readMsg(b []byte) (int, UDPAddr, ForwardingPath, error) { continue // ignore non-IP destination } remote := UDPAddr{ - IA: IA(pkt.Source.IA), + IA: pkt.Source.IA, IP: pkt.Source.Host.IP(), Port: udp.SrcPort, } @@ -152,7 +152,9 @@ func (c *baseUDPConn) Close() error { return c.raw.Close() } -type DefaultSCMPHandler struct{} +type DefaultSCMPHandler struct { + Stats *pathStatsDB +} func (h DefaultSCMPHandler) Handle(pkt *snet.Packet) error { scmp := pkt.Payload.(snet.SCMPPayload) @@ -160,7 +162,7 @@ func (h DefaultSCMPHandler) Handle(pkt *snet.Packet) error { case slayers.SCMPTypeExternalInterfaceDown: msg := pkt.Payload.(snet.SCMPExternalInterfaceDown) pi := PathInterface{ - IA: IA(msg.IA), + IA: msg.IA, IfID: IfID(msg.Interface), } pf, err := reversePathFingerprint(pkt.Path.(snet.RawPath)) @@ -168,59 +170,33 @@ func (h DefaultSCMPHandler) Handle(pkt *snet.Packet) error { return nil //nolint:nilerr } // FIXME: can block _all_ connections, call async (or internally async) - stats.NotifyPathDown(pf, pi) + if h.Stats != nil { + h.Stats.NotifyPathDown(pf, pi) + } return nil case slayers.SCMPTypeInternalConnectivityDown: msg := pkt.Payload.(snet.SCMPInternalConnectivityDown) pi := PathInterface{ - IA: IA(msg.IA), + IA: msg.IA, IfID: IfID(msg.Egress), } pf, err := reversePathFingerprint(pkt.Path.(snet.RawPath)) if err != nil { return nil //nolint:nilerr } - stats.NotifyPathDown(pf, pi) - return nil - default: - ip := netip.Addr{} - if pkt.Source.Host.Type() == addr.HostTypeIP { - ip = pkt.Source.Host.IP() - } - return SCMPError{ - typeCode: slayers.CreateSCMPTypeCode(scmp.Type(), scmp.Code()), - ErrorIA: IA(pkt.Source.IA), - ErrorIP: ip, + if h.Stats != nil { + h.Stats.NotifyPathDown(pf, pi) } - } -} - -type SCMPError struct { - typeCode slayers.SCMPTypeCode - // ErrorIA is the source IA of the SCMP error message - ErrorIA IA - // ErrorIP is the source IP of the SCMP error message - ErrorIP netip.Addr - // TODO: include quote information (pkt destinition, path, ...) -} - -func (e SCMPError) Error() string { - return fmt.Sprintf("SCMP %s from %s,%s", e.typeCode.String(), e.ErrorIA, e.ErrorIP) -} - -func (e SCMPError) Temporary() bool { - switch e.typeCode.Type() { - case slayers.SCMPTypeDestinationUnreachable: - return false + return nil + // Packet too big errors can happen when QUIC probes for the MTU. case slayers.SCMPTypePacketTooBig: - return false - case slayers.SCMPTypeParameterProblem: - return false - case slayers.SCMPTypeExternalInterfaceDown: - return true - case slayers.SCMPTypeInternalConnectivityDown: - return true + msg := pkt.Payload.(snet.SCMPPacketTooBig) + log.Info("SCMP PacketTooBig", "scmp", scmp, "mtu", msg.MTU) + return nil default: - panic("invalid error code") + log.Info( + "SCMP error encountered", "type", scmp.Type(), + "code", scmp.Code(), "host", pkt.Source.Host, "source", pkt.Source.IA) + return nil } } diff --git a/pkg/pan/refresher.go b/pkg/pan/refresher.go index 471a399c6..5b8a5747e 100644 --- a/pkg/pan/refresher.go +++ b/pkg/pan/refresher.go @@ -16,32 +16,40 @@ package pan import ( "context" + "maps" "math/rand" + "slices" "sync" "time" + + "github.com/scionproto/scion/pkg/addr" +) + +const ( + refreshIntervalForSubscribersWithoutPath = 6 * time.Second ) type refreshee interface { - refresh(dst IA, paths []*Path) + refresh(dst addr.IA, paths []*Path) } type refresher struct { subscribersMutex sync.Mutex - subscribers map[IA][]refreshee + subscribers map[addr.IA][]refreshee newSubscription chan bool - pool *pathPool + pool *PathPool } -func makeRefresher(pool *pathPool) refresher { +func makeRefresher(pool *PathPool) refresher { return refresher{ pool: pool, - subscribers: make(map[IA][]refreshee), + subscribers: make(map[addr.IA][]refreshee), newSubscription: make(chan bool), } } // subscribe for paths to dst. -func (r *refresher) subscribe(ctx context.Context, dst IA, s refreshee) ([]*Path, error) { +func (r *refresher) subscribe(ctx context.Context, dst addr.IA, s refreshee) ([]*Path, error) { // BUG: oops, this will not inform subscribers of updated paths. Need to explicily check here paths, _, err := r.pool.paths(ctx, dst) if err != nil { @@ -60,7 +68,7 @@ func (r *refresher) subscribe(ctx context.Context, dst IA, s refreshee) ([]*Path return paths, nil } -func (r *refresher) unsubscribe(ia IA, s refreshee) { +func (r *refresher) unsubscribe(ia addr.IA, s refreshee) { r.subscribersMutex.Lock() defer r.subscribersMutex.Unlock() @@ -82,6 +90,9 @@ func (r *refresher) unsubscribe(ia IA, s refreshee) { func (r *refresher) run() { refreshTimer := time.NewTimer(0) + refreshTimerForSubscribersWithoutPath := time.NewTicker( + refreshIntervalForSubscribersWithoutPath, + ) <-refreshTimer.C var prevRefresh time.Time for { @@ -100,19 +111,40 @@ func (r *refresher) run() { prevRefresh = time.Now() nextRefresh := r.untilNextRefresh(prevRefresh) refreshTimer.Reset(nextRefresh) + case <-refreshTimerForSubscribersWithoutPath.C: + r.refreshSubscribersWithoutPath() } } } func (r *refresher) refresh() { - // when a refresh is triggered, we batch all + r.refreshIAs(r.subscribersToRefresh(false)) +} + +func (r *refresher) refreshSubscribersWithoutPath() { + r.refreshIAs(r.subscribersToRefresh(true)) +} + +func (r *refresher) subscribersToRefresh(onlySubscribersWithoutPath bool) []addr.IA { r.subscribersMutex.Lock() - refreshIAs := make([]IA, 0, len(r.subscribers)) - for dstIA := range r.subscribers { - refreshIAs = append(refreshIAs, dstIA) + defer r.subscribersMutex.Unlock() + + keys := slices.Collect(maps.Keys(r.subscribers)) + if !onlySubscribersWithoutPath { + return keys } - r.subscribersMutex.Unlock() + // Filter to only subscribers without cached paths + result := keys[:0] + for _, dstIA := range keys { + if len(r.pool.cachedPaths(dstIA)) == 0 { + result = append(result, dstIA) + } + } + return result +} + +func (r *refresher) refreshIAs(refreshIAs []addr.IA) { for _, dstIA := range refreshIAs { paths, areFresh, err := r.pool.paths(context.Background(), dstIA) if err != nil || !areFresh { @@ -139,11 +171,13 @@ func (r *refresher) nextRefresh(prevRefresh time.Time) time.Time { if len(r.subscribers) == 0 { return maxTime } - nextRefresh := prevRefresh.Add(pathRefreshInterval) + + nextRefresh := prevRefresh.Add(r.pool.config.RefreshInterval) expiry := r.pool.earliestPathExpiry() - randOffset := time.Duration(rand.Intn(10)) * time.Second // avoid everbody refreshing simultaneously - expiryRefresh := expiry.Add(-pathRefreshLeadTime + randOffset) + // avoid everbody refreshing simultaneously + randOffset := time.Duration(rand.Intn(10)) * time.Second + expiryRefresh := expiry.Add(-r.pool.config.RefreshLeadTime + randOffset) if expiryRefresh.Before(nextRefresh) { nextRefresh = expiryRefresh @@ -152,7 +186,7 @@ func (r *refresher) nextRefresh(prevRefresh time.Time) time.Time { // if there are still paths that expire very soon (or have already expired), // we still wait a little bit until the next refresh. Otherwise, failing // refresh of an expired path would make us refresh continuously. - earliestAllowed := prevRefresh.Add(pathRefreshMinInterval) + earliestAllowed := prevRefresh.Add(r.pool.config.RefreshMinInterval) if nextRefresh.Before(earliestAllowed) { return earliestAllowed } diff --git a/pkg/pan/sciond.go b/pkg/pan/sciond.go index b0846de25..c451c2232 100644 --- a/pkg/pan/sciond.go +++ b/pkg/pan/sciond.go @@ -17,177 +17,136 @@ package pan import ( "context" "fmt" - "net" "net/netip" - "os" - "sync" "time" "github.com/scionproto/scion/pkg/addr" "github.com/scionproto/scion/pkg/daemon" + "github.com/scionproto/scion/pkg/log" "github.com/scionproto/scion/pkg/snet" "github.com/scionproto/scion/pkg/snet/addrutil" + "github.com/scionproto/scion/private/app/flag" +) + +const ( + initTimeout = 1 * time.Second ) // hostContext contains the information needed to connect to the host's local SCION stack, // i.e. the connection to sciond. type hostContext struct { - ia IA - sciond daemon.Connector - hostInLocalAS net.IP + ia addr.IA + topology snet.Topology + addr netip.Addr + pathQuerier *PathQuerier + pool *PathPool + stats *pathStatsDB } -const ( - initTimeout = 1 * time.Second -) - -// HostContextError is returned by the API if the SCION host context initialization -// failed. This error most likely appears if the SCION daemon is not running or -// can't be reached. -type HostContextError struct { - Cause error +func (h *hostContext) IA() addr.IA { + return h.ia } -func (e HostContextError) Error() string { - return fmt.Sprintf("error initializing SCION host context: '%v'", e.Cause) +func (h *hostContext) Topology() snet.Topology { + return h.topology } -var singletonHostContext hostContext -var initOnce = sync.OnceValue(mustInitHostContext) +func (h *hostContext) LocalAddr() netip.Addr { + return h.addr +} -// host initialises and returns the singleton hostContext. -func getHost() (*hostContext, error) { - err := initOnce() - if err != nil { - return nil, err - } - return &singletonHostContext, nil +func (h *hostContext) PathPool() *PathPool { + return h.pool } -func mustInitHostContext() error { - hostCtx, err := initHostContext() - if err != nil { - return HostContextError{Cause: err} - } - singletonHostContext = hostCtx - return nil +func (h *hostContext) Stats() *pathStatsDB { + return h.stats } -func initHostContext() (hostContext, error) { - ctx, cancel := context.WithTimeout(context.Background(), initTimeout) - defer cancel() - sciondConn, err := findSciond(ctx) - if err != nil { - return hostContext{}, err - } - localIA, err := sciondConn.LocalIA(ctx) - if err != nil { - return hostContext{}, err - } - hostInLocalAS, err := findAnyHostInLocalAS(ctx, sciondConn) - if err != nil { - return hostContext{}, err - } - return hostContext{ - ia: IA(localIA), - sciond: sciondConn, - hostInLocalAS: hostInLocalAS, - }, nil +// PAN is the main entry point for SCION networking with pan. +// It manages the connection to the SCION daemon, path caching, and statistics. +// A PAN must be created with New and should be closed when no longer needed. +type PAN struct { + hostContext } -func findSciond(ctx context.Context) (daemon.Connector, error) { - address, ok := os.LookupEnv("SCION_DAEMON_ADDRESS") - if !ok { - address = daemon.DefaultAPIAddress +// New creates a new PAN instance by connecting to the local SCION daemon +// and initializing the path pool. +func New(ctx context.Context) (*PAN, error) { + var scionEnv flag.SCIONEnvironment + if err := scionEnv.LoadExternalVars(); err != nil { + return nil, fmt.Errorf("unable to load SCION environment: %w", err) } - sciondConn, err := daemon.NewService(address).Connect(ctx) + log.FromCtx(ctx).Debug("SCION environment loaded", "daemon", scionEnv.Daemon(), + "local", scionEnv.Local(), + ) + initCtx, cancel := context.WithTimeout(ctx, initTimeout) + defer cancel() + sciondConn, err := daemon.NewService(scionEnv.Daemon()).Connect(initCtx) if err != nil { - return nil, fmt.Errorf("unable to connect to SCIOND at %s (override with SCION_DAEMON_ADDRESS): %w", address, err) + return nil, fmt.Errorf( + "unable to connect to SCIOND at %s (override with SCION_DAEMON): %w", + scionEnv.Daemon(), err, + ) } - return sciondConn, nil -} - -// findAnyHostInLocalAS returns the IP address of some (infrastructure) host in the local AS. -func findAnyHostInLocalAS(ctx context.Context, sciondConn daemon.Connector) (net.IP, error) { - addr, err := daemon.TopoQuerier{Connector: sciondConn}.UnderlayAnycast(ctx, addr.SvcCS) + localIA, err := sciondConn.LocalIA(initCtx) if err != nil { - return nil, err + return nil, fmt.Errorf("unable to get local ISD-AS from SCIOND: %w", err) } - return addr.IP, nil -} - -// defaultLocalIP returns _a_ IP of this host in the local AS. -// -// The purpose of this function is to workaround not being able to bind to -// wildcard addresses in snet. -// See note on wildcard addresses in the package documentation. -func defaultLocalIP() (netip.Addr, error) { - host, err := getHost() + start, end, err := sciondConn.PortRange(initCtx) if err != nil { - return netip.Addr{}, err + return nil, fmt.Errorf("unable to get port range from SCIOND: %w", err) } - stdIP, err := addrutil.ResolveLocal(host.hostInLocalAS) - ip, ok := netip.AddrFromSlice(stdIP) - if err != nil || !ok { - return netip.Addr{}, fmt.Errorf("unable to resolve default local address %w", err) + interfaces, err := sciondConn.Interfaces(initCtx) + if err != nil { + return nil, fmt.Errorf("unable to get interfaces from SCIOND: %w", err) } - return ip.Unmap(), nil -} - -// defaultLocalAddr fills in a missing or unspecified IP field with defaultLocalIP. -func defaultLocalAddr(local netip.AddrPort) (netip.AddrPort, error) { - if !local.Addr().IsValid() || local.Addr().IsUnspecified() { - localIP, err := defaultLocalIP() + localAddr := scionEnv.Local() + if !scionEnv.Local().IsValid() { + localIP, err := addrutil.DefaultLocalIP(initCtx, daemon.TopoQuerier{Connector: sciondConn}) if err != nil { - return netip.AddrPort{}, err + return nil, fmt.Errorf("unable to determine local IP: %w", err) } - local = netip.AddrPortFrom(localIP, local.Port()) - } - return local, nil -} - -func (h *hostContext) queryPaths(ctx context.Context, dst IA) ([]*Path, error) { - flags := daemon.PathReqFlags{Refresh: false, Hidden: false} - snetPaths, err := h.sciond.Paths(ctx, addr.IA(dst), 0, flags) - if err != nil { - return nil, err - } - paths := make([]*Path, len(snetPaths)) - for i, p := range snetPaths { - snetMetadata := p.Metadata() - metadata := &PathMetadata{ - Interfaces: convertPathInterfaceSlice(snetMetadata.Interfaces), - MTU: snetMetadata.MTU, - Latency: snetMetadata.Latency, - Bandwidth: snetMetadata.Bandwidth, - Geo: snetMetadata.Geo, - LinkType: snetMetadata.LinkType, - InternalHops: snetMetadata.InternalHops, - Notes: snetMetadata.Notes, + var ok bool + localAddr, ok = netip.AddrFromSlice(localIP) + if !ok { + return nil, fmt.Errorf( + "unable to convert local IP to netip.Addr: %v", + localIP, + ) } - underlay := p.UnderlayNextHop().AddrPort() - paths[i] = &Path{ - Source: h.ia, - Destination: dst, - Metadata: metadata, - Fingerprint: pathSequenceFromInterfaces(metadata.Interfaces).Fingerprint(), - Expiry: snetMetadata.Expiry, - ForwardingPath: ForwardingPath{ - dataplanePath: p.Dataplane(), - underlay: underlay, + } + localAddr = localAddr.Unmap() + + // Create path querier for fetching paths from SCIOND + pathQuerier := NewPathQuerier(localIA, sciondConn, interfaces) + + // Create stats database for path statistics + stats := newPathStatsDB() + + c := &PAN{ + hostContext: hostContext{ + ia: localIA, + addr: localAddr, + pathQuerier: pathQuerier, + stats: &stats, + topology: snet.Topology{ + LocalIA: localIA, + PortRange: snet.TopologyPortRange{ + Start: start, + End: end, + }, + Interface: pathQuerier.Interface, }, - } + }, } - return paths, nil + // Create path pool with pathQuerier as the PathSource. + c.pool = NewPathPool(pathQuerier, c.stats, DefaultPathPoolConfig()) + + return c, nil } -func convertPathInterfaceSlice(spis []snet.PathInterface) []PathInterface { - pis := make([]PathInterface, len(spis)) - for i, spi := range spis { - pis[i] = PathInterface{ - IA: IA(spi.IA), - IfID: IfID(spi.ID), - } - } - return pis +// QueryPaths queries paths to a particular destination AS. +func (p *PAN) QueryPaths(ctx context.Context, dst addr.IA) ([]*Path, error) { + return p.pool.QueryPaths(ctx, dst) } diff --git a/pkg/pan/selector.go b/pkg/pan/selector.go index 152b93729..a6d0a5fc4 100644 --- a/pkg/pan/selector.go +++ b/pkg/pan/selector.go @@ -23,6 +23,8 @@ import ( "time" "github.com/scionproto/scion/pkg/addr" + "github.com/scionproto/scion/pkg/log" + "github.com/scionproto/scion/pkg/snet" "github.com/netsec-ethz/scion-apps/pkg/pan/internal/ping" ) @@ -35,7 +37,7 @@ type Selector interface { // Initialize the selector for a connection with the initial list of paths, // filtered/ordered by the Policy. // Invoked once during the creation of a Conn. - Initialize(local, remote UDPAddr, paths []*Path) + Initialize(local, remote UDPAddr, paths []*Path, p *PAN) // Refresh updates the paths. This is called whenever the Policy is changed or // when paths were about to expire and are refreshed from the SCION daemon. // The set and order of paths may differ from previous invocations. @@ -56,6 +58,7 @@ type Selector interface { // affected by down notifications. type DefaultSelector struct { mutex sync.Mutex + stats *pathStatsDB paths []*Path current int } @@ -74,10 +77,13 @@ func (s *DefaultSelector) Path(_ context.Context) *Path { return s.paths[s.current] } -func (s *DefaultSelector) Initialize(local, remote UDPAddr, paths []*Path) { +func (s *DefaultSelector) Initialize(local, remote UDPAddr, paths []*Path, p *PAN) { s.mutex.Lock() defer s.mutex.Unlock() + if p != nil { + s.stats = p.stats + } s.paths = paths s.current = 0 } @@ -104,9 +110,12 @@ func (s *DefaultSelector) PathDown(pf PathFingerprint, pi PathInterface) { s.mutex.Lock() defer s.mutex.Unlock() + if s.stats == nil { + return + } if current := s.paths[s.current]; isInterfaceOnPath(current, pi) || pf == current.Fingerprint { fmt.Println("down:", s.current, len(s.paths)) - better := stats.FirstMoreAlive(current, s.paths) + better := s.stats.FirstMoreAlive(current, s.paths) if better >= 0 { // Try next path. Note that this will keep cycling if we get down notifications s.current = better @@ -125,11 +134,13 @@ type PingingSelector struct { // Timeout for the individual pings. Must be positive and less than Interval. Timeout time.Duration - mutex sync.Mutex - paths []*Path - current int - local scionAddr - remote scionAddr + mutex sync.Mutex + stats *pathStatsDB + topology snet.Topology + paths []*Path + current int + local SCIONAddr + remote SCIONAddr numActive int64 pingerCtx context.Context @@ -153,14 +164,16 @@ func (s *PingingSelector) Path(_ context.Context) *Path { return s.paths[s.current] } -func (s *PingingSelector) Initialize(local, remote UDPAddr, paths []*Path) { +func (s *PingingSelector) Initialize(local, remote UDPAddr, paths []*Path, p *PAN) { s.mutex.Lock() defer s.mutex.Unlock() + s.stats = p.stats + s.topology = p.topology s.local = local.scionAddr() s.remote = remote.scionAddr() s.paths = paths - s.current = stats.LowestLatency(s.remote, s.paths) + s.current = s.stats.LowestLatency(s.remote, s.paths) } func (s *PingingSelector) Refresh(paths []*Path) { @@ -168,7 +181,7 @@ func (s *PingingSelector) Refresh(paths []*Path) { defer s.mutex.Unlock() s.paths = paths - s.current = stats.LowestLatency(s.remote, s.paths) + s.current = s.stats.LowestLatency(s.remote, s.paths) } func (s *PingingSelector) PathDown(pf PathFingerprint, pi PathInterface) { @@ -179,32 +192,37 @@ func (s *PingingSelector) reselectPath() { s.mutex.Lock() defer s.mutex.Unlock() - s.current = stats.LowestLatency(s.remote, s.paths) + s.current = s.stats.LowestLatency(s.remote, s.paths) } func (s *PingingSelector) ensureRunning() { s.mutex.Lock() defer s.mutex.Unlock() - host, err := getHost() - if err != nil { - return - } if s.local.IA == s.remote.IA { return } if s.pinger != nil { return } + if s.stats == nil { + panic("PingingSelector requires Initialize to be called first") + } s.pingerCtx, s.pingerCancel = context.WithCancel(context.Background()) local := s.local.snetUDPAddr() - pinger, err := ping.NewPinger(s.pingerCtx, host.sciond, local) + pinger, err := ping.NewPinger(s.pingerCtx, s.topology, local) if err != nil { return } s.pinger = pinger - go s.pinger.Drain(s.pingerCtx) - go s.run() + go func() { + defer log.HandlePanic() + s.pinger.Drain(s.pingerCtx) + }() + go func() { + defer log.HandlePanic() + s.run() + }() } func (s *PingingSelector) run() { @@ -248,7 +266,7 @@ func (s *PingingSelector) run() { continue // already handled above } for pf := range replyPending { - stats.RecordLatency(s.remote, pf, s.Timeout) + s.stats.RecordLatency(s.remote, pf, s.Timeout) delete(replyPending, pf) } s.reselectPath() @@ -270,7 +288,8 @@ func (s *PingingSelector) sendPings(paths []*Path, sequenceNo uint16) { func (s *PingingSelector) handlePingReply(reply ping.Reply, expectedReplies map[PathFingerprint]struct{}, - expectedSequenceNo uint16) { + expectedSequenceNo uint16, +) { if reply.Error != nil { // handle NotifyPathDown. // The Pinger is not using the normal scmp handler in raw.go, so we have to @@ -282,16 +301,16 @@ func (s *PingingSelector) handlePingReply(reply ping.Reply, switch e := reply.Error.(type) { //nolint:errorlint case ping.InternalConnectivityDownError: pi := PathInterface{ - IA: IA(e.IA), + IA: e.IA, IfID: IfID(e.Egress), } - stats.NotifyPathDown(pf, pi) + s.stats.NotifyPathDown(pf, pi) case ping.ExternalInterfaceDownError: pi := PathInterface{ - IA: IA(e.IA), + IA: e.IA, IfID: IfID(e.Interface), } - stats.NotifyPathDown(pf, pi) + s.stats.NotifyPathDown(pf, pi) } return } @@ -299,8 +318,9 @@ func (s *PingingSelector) handlePingReply(reply ping.Reply, if reply.Source.Host.Type() != addr.HostTypeIP { return // ignore replies from non-IP addresses } - src := scionAddr{ - IA: IA(reply.Source.IA), + + src := SCIONAddr{ + IA: reply.Source.IA, IP: reply.Source.Host.IP(), } if src != s.remote || reply.Reply.SeqNumber != expectedSequenceNo { @@ -313,7 +333,7 @@ func (s *PingingSelector) handlePingReply(reply ping.Reply, if _, expected := expectedReplies[pf]; !expected { return } - stats.RecordLatency(s.remote, pf, reply.RTT()) + s.stats.RecordLatency(s.remote, pf, reply.RTT()) delete(expectedReplies, pf) } diff --git a/pkg/pan/silence.go b/pkg/pan/silence.go index 820c33e2a..6cd7d3d49 100644 --- a/pkg/pan/silence.go +++ b/pkg/pan/silence.go @@ -20,9 +20,11 @@ import ( "sync" ) -var logSilencerMutex sync.Mutex -var logSilencerCount int32 -var logSilencerOriginal io.Writer +var ( + logSilencerMutex sync.Mutex + logSilencerCount int32 + logSilencerOriginal io.Writer +) // silenceLog redirects the log.Default writer to a black hole. // It can be reenabled by calling unsilenceLog. diff --git a/pkg/pan/stats.go b/pkg/pan/stats.go index 7008451e5..abfc7efb6 100644 --- a/pkg/pan/stats.go +++ b/pkg/pan/stats.go @@ -17,13 +17,9 @@ package pan import ( "sync" "time" -) - -var stats pathStatsDB -func init() { - stats = newPathStatsDB() -} + "github.com/scionproto/scion/pkg/log" +) type PathStats struct { // Was notified down at the recorded time (0 for never notified down) @@ -59,7 +55,7 @@ type pathStatsDB struct { // consecutive (unordered?) interface IDs. interfaces map[PathInterface]PathInterfaceStats // TODO: cleanup of this map on connection end, reference counted handle? - destinations map[scionAddr]DestinationStats + destinations map[SCIONAddr]DestinationStats notifier pathDownNotifier } @@ -68,11 +64,11 @@ func newPathStatsDB() pathStatsDB { return pathStatsDB{ paths: make(map[PathFingerprint]PathStats), interfaces: make(map[PathInterface]PathInterfaceStats), - destinations: make(map[scionAddr]DestinationStats), + destinations: make(map[SCIONAddr]DestinationStats), } } -func (s *pathStatsDB) RecordLatency(dst scionAddr, p PathFingerprint, latency time.Duration) { +func (s *pathStatsDB) RecordLatency(dst SCIONAddr, p PathFingerprint, latency time.Duration) { s.mutex.Lock() defer s.mutex.Unlock() @@ -90,7 +86,7 @@ func (s *pathStatsDB) RecordLatency(dst scionAddr, p PathFingerprint, latency ti // recorded down notification for the corresponding path are ignored. Paths // with no recorded latency value, or with down notifications, are treated with // least priority. -func (s *pathStatsDB) LowestLatency(dst scionAddr, paths []*Path) int { +func (s *pathStatsDB) LowestLatency(dst SCIONAddr, paths []*Path) int { if len(paths) == 0 { return -1 } @@ -130,7 +126,7 @@ func (s *pathStatsDB) FirstMoreAlive(p *Path, paths []*Path) int { defer s.mutex.RUnlock() for i, pc := range paths { - if s.IsMoreAlive(pc, p) { + if s.isMoreAliveLocked(pc, p) { return i } } @@ -144,10 +140,14 @@ func (s *pathStatsDB) FirstMoreAlive(p *Path, paths []*Path) int { func (s *pathStatsDB) IsMoreAlive(a, b *Path) bool { s.mutex.RLock() defer s.mutex.RUnlock() + return s.isMoreAliveLocked(a, b) +} +func (s *pathStatsDB) isMoreAliveLocked(a, b *Path) bool { newestA := s.newestDownNotification(a) oldestB := s.oldestDownNotification(b) - return newestA.Before(oldestB.Add(-pathDownNotificationTimeout)) // XXX: what is this value, what does it mean? + // XXX: what is this value, what does it mean? + return newestA.Before(oldestB.Add(-pathDownNotificationTimeout)) } // newestDownNotification returns the time of the newest relevant down @@ -258,6 +258,7 @@ func (n *pathDownNotifier) run() { n.notifications = notifications go func() { + defer log.HandlePanic() for notification := range notifications { n.notify(notification.Fingerprint, notification.Interface) } diff --git a/pkg/pan/stats_test.go b/pkg/pan/stats_test.go index 04f52fc94..054f1f391 100644 --- a/pkg/pan/stats_test.go +++ b/pkg/pan/stats_test.go @@ -18,15 +18,16 @@ import ( "testing" "time" + "github.com/scionproto/scion/pkg/addr" "github.com/stretchr/testify/assert" ) func TestNotifyPathDown(t *testing.T) { - stats = newPathStatsDB() + stats := newPathStatsDB() pf := PathFingerprint("x") pi := PathInterface{ - IA: MustParseIA("1-ff00:0:110"), + IA: addr.MustParseIA("1-ff00:0:110"), IfID: 5, } @@ -56,7 +57,7 @@ func (s *dummyPathDownSubscriber) PathDown(_ PathFingerprint, _ PathInterface) { } func TestRecordLatency(t *testing.T) { - stats = newPathStatsDB() + stats := newPathStatsDB() dst := mustParseSCIONAddr("1-ff00:0:110,192.0.2.1") p := PathFingerprint("x") diff --git a/pkg/pan/testdata/hosts_test_file b/pkg/pan/testdata/hosts_test_file new file mode 100644 index 000000000..13581a8ca --- /dev/null +++ b/pkg/pan/testdata/hosts_test_file @@ -0,0 +1,14 @@ +# regular IPv4 hosts +127.0.0.1 localhost +123.456.789.0 dummy1 + +# regular IPv6 hosts +fe80:cd00:0:cde:1257:0:211e:729c dummy2 +123:4567:89ab:cdef:123:4567:89ab:cdef dummy3 + +# SCION hosts +#17-ffaa:0:0,[10.0.8.15] commented +17-ffaa:0:1,[192.168.1.1] host1.1 host1.2 +18-ffaa:1:2,[10.0.8.10] host2 # comment +17-ffaa:0:1,[192.168.1.1] host3 +20-ffaa:c0ff:ee12,[0:0:0ff1:ce00:dead:10cc:baad:f00d] host4 diff --git a/pkg/pan/udp_dial.go b/pkg/pan/udp_dial.go index e475e6255..64724a597 100644 --- a/pkg/pan/udp_dial.go +++ b/pkg/pan/udp_dial.go @@ -19,6 +19,7 @@ import ( "net" "net/netip" + "github.com/scionproto/scion/pkg/addr" "github.com/scionproto/scion/pkg/snet" ) @@ -53,25 +54,20 @@ type Conn interface { // a path among this set for each Write operation. // If the policy is nil, all paths are allowed. // If the selector is nil, a DefaultSelector is used. -func DialUDP( +func (p *PAN) DialUDP( ctx context.Context, local netip.AddrPort, remote UDPAddr, opts ...ConnOptions, ) (Conn, error) { - o := applyConnOpts(opts) + o := applyConnOpts(p.stats, opts) - host, err := getHost() - if err != nil { - return nil, err - } - - local, err = defaultLocalAddr(local) - if err != nil { - return nil, err + // Fill in wildcard address with the default local IP. + if !local.Addr().IsValid() || local.Addr().IsUnspecified() { + local = netip.AddrPortFrom(p.addr, local.Port()) } sn := snet.SCIONNetwork{ - Topology: host.sciond, + Topology: p.topology, SCMPHandler: o.scmpHandler, } conn, err := sn.OpenRaw(ctx, net.UDPAddrFromAddrPort(local)) @@ -80,13 +76,13 @@ func DialUDP( } ipport := conn.LocalAddr().(*net.UDPAddr).AddrPort() localUDPAddr := UDPAddr{ - IA: host.ia, + IA: p.ia, IP: ipport.Addr(), Port: ipport.Port(), } var subscriber *pathRefreshSubscriber if remote.IA != localUDPAddr.IA { - subscriber, err = openPathRefreshSubscriber(ctx, localUDPAddr, remote, o.policy, o.selector) + subscriber, err = openPathRefreshSubscriber(ctx, p.pool, localUDPAddr, remote, p, o.policy, o.selector) if err != nil { return nil, err } @@ -137,9 +133,9 @@ type connOptions struct { policy Policy } -func applyConnOpts(opts []ConnOptions) connOptions { +func applyConnOpts(stats *pathStatsDB, opts []ConnOptions) connOptions { o := connOptions{ - scmpHandler: DefaultSCMPHandler{}, + scmpHandler: DefaultSCMPHandler{Stats: stats}, selector: NewDefaultSelector(), } for _, opt := range opts { @@ -193,16 +189,16 @@ func (c *dialedConn) WriteWithCtx(ctx context.Context, b []byte) (int, error) { return 0, errNoPathTo(c.remote.IA) } } - return c.baseUDPConn.writeMsg(c.local, c.remote, path, b) + return c.writeMsg(c.local, c.remote, path, b) } func (c *dialedConn) WriteVia(path *Path, b []byte) (int, error) { - return c.baseUDPConn.writeMsg(c.local, c.remote, path, b) + return c.writeMsg(c.local, c.remote, path, b) } func (c *dialedConn) Read(b []byte) (int, error) { for { - n, remote, _, err := c.baseUDPConn.readMsg(b) + n, remote, _, err := c.readMsg(b) if err != nil { return n, err } @@ -215,7 +211,7 @@ func (c *dialedConn) Read(b []byte) (int, error) { func (c *dialedConn) ReadVia(b []byte) (int, *Path, error) { for { - n, remote, fwPath, err := c.baseUDPConn.readMsg(b) + n, remote, fwPath, err := c.readMsg(b) if err != nil { return n, nil, err } @@ -240,19 +236,21 @@ func (c *dialedConn) Close() error { return c.baseUDPConn.Close() } -// pathRefreshSubscriber is the glue between a connection and the global path +// pathRefreshSubscriber is the glue between a connection and the path // pool. It gets the paths to dst and sets the filtered path set on the // target Selector. type pathRefreshSubscriber struct { - remoteIA IA + pool *PathPool + remoteIA addr.IA policy Policy target Selector } -func openPathRefreshSubscriber(ctx context.Context, local, remote UDPAddr, policy Policy, - target Selector) (*pathRefreshSubscriber, error) { - +func openPathRefreshSubscriber(ctx context.Context, pool *PathPool, local, remote UDPAddr, p *PAN, policy Policy, + target Selector, +) (*pathRefreshSubscriber, error) { s := &pathRefreshSubscriber{ + pool: pool, remoteIA: remote.IA, policy: policy, target: target, @@ -261,22 +259,22 @@ func openPathRefreshSubscriber(ctx context.Context, local, remote UDPAddr, polic if err != nil { return nil, err } - s.target.Initialize(local, remote, filtered(s.policy, paths)) + s.target.Initialize(local, remote, filtered(s.policy, paths), p) return s, nil } func (s *pathRefreshSubscriber) Close() error { - pool.unsubscribe(s.remoteIA, s) + s.pool.unsubscribe(s.remoteIA, s) return nil } func (s *pathRefreshSubscriber) setPolicy(policy Policy) { s.policy = policy - paths := pool.cachedPaths(s.remoteIA) + paths := s.pool.cachedPaths(s.remoteIA) s.target.Refresh(filtered(s.policy, paths)) } -func (s *pathRefreshSubscriber) refresh(dst IA, paths []*Path) { +func (s *pathRefreshSubscriber) refresh(dst addr.IA, paths []*Path) { s.target.Refresh(filtered(s.policy, paths)) } diff --git a/pkg/pan/udp_listen.go b/pkg/pan/udp_listen.go index e2b8d9bea..a78fbab24 100644 --- a/pkg/pan/udp_listen.go +++ b/pkg/pan/udp_listen.go @@ -33,10 +33,10 @@ var errBadDstAddress error = errors.New("dst address not a UDPAddr") type ReplySelector interface { // Path selects the path for the next packet to remote. // Invoked for each packet sent with WriteTo. - Path(ctx context.Context, remote UDPAddr) *Path + Path(remote UDPAddr) *Path // Initialize the selector. // Invoked once during the creation of a ListenConn. - Initialize(local UDPAddr) + Initialize(local UDPAddr, p *PAN) // Record a path used by the remote for a packet received. // Invoked whenever a packet is received. // The path is reversed, i.e. it's the path from here to remote. @@ -53,37 +53,34 @@ type ListenConn interface { // ReadFromVia reads a message and returns the (return-)path via which the // message was received. ReadFromVia(b []byte) (int, UDPAddr, *Path, error) - // WriteToWithCtx writes a message to the remote address using a path from - // the path selector. ctx is passed to the path selector where it can - // provide additional user-defined information, e.g., whether the packet is - // urgent or not. - WriteToWithCtx(ctx context.Context, b []byte, dst net.Addr) (n int, err error) // WriteToVia writes a message to the remote address via the given path. // This bypasses selector used for WriteTo. WriteToVia(b []byte, dst UDPAddr, path *Path) (int, error) } -func ListenUDP( - ctx context.Context, +// ListenUDP opens a SCION/UDP socket, listening on the local address. +// If the local address, or either its IP or port, are left unspecified, they +// will be automatically chosen. +// +// The selector controls which path is used for reply packets. If nil, a +// DefaultReplySelector is used. +func (p *PAN) ListenUDP(ctx context.Context, local netip.AddrPort, - opts ...ListenConnOptions, + selector ReplySelector, ) (ListenConn, error) { - o := apply(opts) - - host, err := getHost() - if err != nil { - return nil, err + if selector == nil { + selector = NewDefaultReplySelector() } - - local, err = defaultLocalAddr(local) - if err != nil { - return nil, err + // Fill in wildcard address with the default local IP. + if !local.Addr().IsValid() || local.Addr().IsUnspecified() { + local = netip.AddrPortFrom(p.addr, local.Port()) } - - stats.subscribe(o.selector) + p.stats.subscribe(selector) sn := snet.SCIONNetwork{ - Topology: host.sciond, - SCMPHandler: o.scmpHandler, + // TODO(lukedirtwalker): Do we need something that refreshes interfaces, + // because we don't fetch paths here? + Topology: p.topology, + SCMPHandler: DefaultSCMPHandler{Stats: p.stats}, } conn, err := sn.OpenRaw(ctx, net.UDPAddrFromAddrPort(local)) if err != nil { @@ -91,11 +88,11 @@ func ListenUDP( } ipport := conn.LocalAddr().(*net.UDPAddr).AddrPort() localUDPAddr := UDPAddr{ - IA: host.ia, + IA: p.ia, IP: ipport.Addr(), Port: ipport.Port(), } - o.selector.Initialize(localUDPAddr) + selector.Initialize(localUDPAddr, p) if len(os.Getenv("SCION_GO_INTEGRATION")) > 0 { fmt.Printf("Listening addr=%s\n", localUDPAddr) @@ -106,55 +103,17 @@ func ListenUDP( raw: conn, }, local: localUDPAddr, - selector: o.selector, + selector: selector, + stats: p.stats, }, nil } -type ListenConnOptions func(*listenConnOptions) - -// WithListenSCMPHandler sets the SCMP handler for the ListenConn. -func WithListenSCMPHandler(handler snet.SCMPHandler) ListenConnOptions { - return func(o *listenConnOptions) { - if handler == nil { - panic("nil SCMP handler not allowed") - } - o.scmpHandler = handler - } -} - -// WithReplySelector sets the reply path selector for the ListenConn. -func WithReplySelector(selector ReplySelector) ListenConnOptions { - return func(o *listenConnOptions) { - if selector == nil { - panic("nil selector not allowed") - } - o.selector = selector - } -} - -type listenConnOptions struct { - scmpHandler snet.SCMPHandler - selector ReplySelector -} - -func apply(opts []ListenConnOptions) listenConnOptions { - o := listenConnOptions{ - scmpHandler: DefaultSCMPHandler{}, - selector: NewDefaultReplySelector(), - } - for _, opt := range opts { - if opt != nil { - opt(&o) - } - } - return o -} - type listenConn struct { baseUDPConn local UDPAddr selector ReplySelector + stats *pathStatsDB } func (c *listenConn) LocalAddr() net.Addr { @@ -167,7 +126,7 @@ func (c *listenConn) ReadFrom(b []byte) (int, net.Addr, error) { } func (c *listenConn) ReadFromVia(b []byte) (int, UDPAddr, *Path, error) { - n, remote, fwPath, err := c.baseUDPConn.readMsg(b) + n, remote, fwPath, err := c.readMsg(b) if err != nil { return n, UDPAddr{}, nil, err } @@ -177,17 +136,13 @@ func (c *listenConn) ReadFromVia(b []byte) (int, UDPAddr, *Path, error) { } func (c *listenConn) WriteTo(b []byte, dst net.Addr) (int, error) { - return c.WriteToWithCtx(context.TODO(), b, dst) -} - -func (c *listenConn) WriteToWithCtx(ctx context.Context, b []byte, dst net.Addr) (n int, err error) { sdst, ok := dst.(UDPAddr) if !ok { return 0, errBadDstAddress } var path *Path if c.local.IA != sdst.IA { - path = c.selector.Path(ctx, sdst) + path = c.selector.Path(sdst) if path == nil { return 0, errNoPathTo(sdst.IA) } @@ -196,11 +151,11 @@ func (c *listenConn) WriteToWithCtx(ctx context.Context, b []byte, dst net.Addr) } func (c *listenConn) WriteToVia(b []byte, dst UDPAddr, path *Path) (int, error) { - return c.baseUDPConn.writeMsg(c.local, dst, path, b) + return c.writeMsg(c.local, dst, path, b) } func (c *listenConn) Close() error { - stats.unsubscribe(c.selector) + c.stats.unsubscribe(c.selector) // FIXME: multierror! _ = c.selector.Close() return c.baseUDPConn.Close() @@ -217,10 +172,10 @@ func NewDefaultReplySelector() *DefaultReplySelector { } } -func (s *DefaultReplySelector) Initialize(local UDPAddr) { +func (s *DefaultReplySelector) Initialize(local UDPAddr, p *PAN) { } -func (s *DefaultReplySelector) Path(_ context.Context, remote UDPAddr) *Path { +func (s *DefaultReplySelector) Path(remote UDPAddr) *Path { s.mtx.RLock() defer s.mtx.RUnlock() r, ok := s.remotes[remote] diff --git a/pkg/quicutil/single.go b/pkg/quicutil/single.go index cae2ff323..0a555d6ec 100644 --- a/pkg/quicutil/single.go +++ b/pkg/quicutil/single.go @@ -17,6 +17,7 @@ package quicutil import ( "context" "errors" + "fmt" "io" "net" "sync" @@ -61,18 +62,26 @@ var ( // SingleStream connections from Accept. This allows to use quic in contexts // where a (TCP-)net.Listener is expected. type SingleStreamListener struct { - *pan.QUICListener + QUICListener *quic.EarlyListener } -func (l SingleStreamListener) Accept() (net.Conn, error) { +func (l *SingleStreamListener) Accept() (net.Conn, error) { ctx := context.Background() - connection, err := l.Listener.Accept(ctx) + connection, err := l.QUICListener.Accept(ctx) if err != nil { return nil, err } return NewSingleStream(connection) } +func (l *SingleStreamListener) Close() error { + return l.QUICListener.Close() +} + +func (l *SingleStreamListener) Addr() net.Addr { + return l.QUICListener.Addr() +} + // SingleStream implements an opaque, bi-directional data stream using QUIC, // intending to be a drop-in replacement for TCP. // A SingleStream is either created by @@ -83,6 +92,7 @@ func (l SingleStreamListener) Accept() (net.Conn, error) { // returns SingleStream from Accept. type SingleStream struct { Connection quicConnection + panSession *pan.QUICSession // set if created from QUICSession for GetPath() support sendStream *quic.SendStream receiveStream *quic.ReceiveStream readDeadline time.Time @@ -90,13 +100,29 @@ type SingleStream struct { onceOK sync.Once } -func NewSingleStream(connection quicConnection) (*SingleStream, error) { - sendStream, err := connection.OpenUniStream() +// NewSingleStream creates a SingleStream from either a quicConnection or a *pan.QUICSession. +// If a *pan.QUICSession is passed, GetPath() will be available. +func NewSingleStream(conn interface{}) (*SingleStream, error) { + var qconn quicConnection + var sess *pan.QUICSession + + switch c := conn.(type) { + case *pan.QUICSession: + qconn = c.QUIC + sess = c + case quicConnection: + qconn = c + default: + return nil, fmt.Errorf("NewSingleStream: expected *pan.QUICSession or quicConnection, got %T", conn) + } + + sendStream, err := qconn.OpenUniStream() if err != nil { return nil, err } return &SingleStream{ - Connection: connection, + Connection: qconn, + panSession: sess, sendStream: sendStream, receiveStream: nil, }, nil @@ -107,18 +133,12 @@ func (s *SingleStream) LocalAddr() net.Addr { } func (s *SingleStream) GetPath() *pan.Path { - if s.Connection == nil { - // XXX(JordiSubira): To be refactored when proper support - // for retrieving path information. - return nil - } - quicConn, ok := s.Connection.(*pan.QUICConn) - if !ok { + if s.panSession == nil { // XXX(JordiSubira): To be refactored when proper support // for retrieving path information. return nil } - return quicConn.UnderlayConn.GetPath() + return s.panSession.Conn.GetPath() } func (s *SingleStream) RemoteAddr() net.Addr { diff --git a/pkg/shttp/README.md b/pkg/shttp/README.md index a7eee052c..f4d8250cd 100644 --- a/pkg/shttp/README.md +++ b/pkg/shttp/README.md @@ -26,8 +26,7 @@ client := &http.Client{ resp, err := client.Get("http://server:8080/download") ``` -Hostnames are resolved by parsing the `/etc/hosts` file or by a RAINS lookup -(see [Hostnames](../../README.md#Hostnames)). +Hostnames are resolved by parsing the `/etc/hosts` file (see [Hostnames](../../README.md#Hostnames)). URLs potentially containing raw SCION addresses must be *mangled* before passing into the client (or any other place where they might be parsed as URL). ```Go diff --git a/pkg/shttp/server.go b/pkg/shttp/server.go index 2d58ad839..2519eafa9 100644 --- a/pkg/shttp/server.go +++ b/pkg/shttp/server.go @@ -20,6 +20,9 @@ import ( "net" "net/http" + "github.com/quic-go/quic-go" + "github.com/scionproto/scion/pkg/snet" + "github.com/netsec-ethz/scion-apps/pkg/pan" "github.com/netsec-ethz/scion-apps/pkg/quicutil" ) @@ -27,28 +30,31 @@ import ( // Server wraps a http.Server making it work with SCION type Server struct { *http.Server + PAN *pan.PAN } // ListenAndServe listens for HTTP connections on the SCION address addr and calls Serve -// with handler to handle requests -func ListenAndServe(addr string, handler http.Handler) error { +// with handler to handle requests. +func ListenAndServe(p *pan.PAN, addr string, handler http.Handler) error { s := &Server{ Server: &http.Server{ Addr: addr, Handler: handler, }, + PAN: p, } return s.ListenAndServe() } -// ListenAndServe listens for HTTPS connections on the SCION address addr and calls Serve -// with handler to handle requests -func ListenAndServeTLS(addr, certFile, keyFile string, handler http.Handler) error { +// ListenAndServeTLS listens for HTTPS connections on the SCION address addr and calls Serve +// with handler to handle requests. +func ListenAndServeTLS(p *pan.PAN, addr, certFile, keyFile string, handler http.Handler) error { s := &Server{ Server: &http.Server{ Addr: addr, Handler: handler, }, + PAN: p, } return s.ListenAndServeTLS(certFile, keyFile) } @@ -64,9 +70,10 @@ func (srv *Server) ServeTLS(l net.Listener, certFile, keyFile string) error { } // ListenAndServe listens for QUIC connections on srv.Addr and -// calls Serve to handle incoming requests +// calls Serve to handle incoming requests. +// Note: The Server must have its PAN field set before calling this method. func (srv *Server) ListenAndServe() error { - listener, err := listen(srv.Addr) + listener, err := srv.listen() if err != nil { return err } @@ -74,8 +81,11 @@ func (srv *Server) ListenAndServe() error { return srv.Server.Serve(listener) } +// ListenAndServeTLS listens for QUIC connections on srv.Addr and +// calls ServeTLS to handle incoming requests. +// Note: The Server must have its PAN field set before calling this method. func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error { - listener, err := listen(srv.Addr) + listener, err := srv.listen() if err != nil { return err } @@ -83,18 +93,24 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error { return srv.Server.ServeTLS(listener, certFile, keyFile) } -func listen(addr string) (net.Listener, error) { +func (srv *Server) listen() (net.Listener, error) { tlsCfg := &tls.Config{ NextProtos: []string{quicutil.SingleStreamProto}, Certificates: quicutil.MustGenerateSelfSignedCert(), } - laddr, err := pan.ParseOptionalIPPort(addr) + laddr, err := pan.ParseOptionalIPPort(srv.Addr) if err != nil { return nil, err } - quicListener, err := pan.ListenQUIC(context.Background(), laddr, tlsCfg, nil) + + localAddr := &snet.UDPAddr{ + IA: srv.PAN.IA(), + Host: net.UDPAddrFromAddrPort(laddr), + } + + quicListener, err := srv.PAN.ListenQUIC(context.Background(), localAddr, tlsCfg, &quic.Config{}, nil) if err != nil { return nil, err } - return quicutil.SingleStreamListener{QUICListener: quicListener}, nil + return &quicutil.SingleStreamListener{QUICListener: quicListener}, nil } diff --git a/pkg/shttp/transport.go b/pkg/shttp/transport.go index ebfb42120..f4df91fea 100644 --- a/pkg/shttp/transport.go +++ b/pkg/shttp/transport.go @@ -30,21 +30,24 @@ import ( "github.com/netsec-ethz/scion-apps/pkg/quicutil" ) -// DefaultTransport is the default RoundTripper that can be used for HTTP over +// NewDefaultTransport creates a new RoundTripper that can be used for HTTP over // SCION/QUIC. // This is equivalent to net/http.DefaultTransport with DialContext overridden // to use shttp.Dialer, which dials connections over SCION/QUIC. -var DefaultTransport = &http.Transport{ - Proxy: http.ProxyFromEnvironment, - DialContext: (&Dialer{ - QuicConfig: nil, - Policy: nil, - }).DialContext, - ForceAttemptHTTP2: true, - MaxIdleConns: 100, - IdleConnTimeout: 90 * time.Second, - TLSHandshakeTimeout: 10 * time.Second, - ExpectContinueTimeout: 1 * time.Second, +func NewDefaultTransport(p *pan.PAN) *http.Transport { + return &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&Dialer{ + PAN: p, + QuicConfig: nil, + Policy: nil, + }).DialContext, + ForceAttemptHTTP2: true, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + } } // NewTransport creates a new RoundTripper that can be used for HTTP over @@ -52,12 +55,13 @@ var DefaultTransport = &http.Transport{ // This equivalent to net/http.DefaultTransport with an overridden DialContext. // Both the Transport and the Dialer are returned, as the Dialer is not otherwise // accessible from the Transport. -func NewTransport(quicCfg *quic.Config, policy pan.Policy) (*http.Transport, *Dialer) { +func NewTransport(p *pan.PAN, quicCfg *quic.Config, policy pan.Policy) (*http.Transport, *Dialer) { dialer := &Dialer{ + PAN: p, QuicConfig: quicCfg, Policy: policy, } - transport := DefaultTransport.Clone() + transport := NewDefaultTransport(p) transport.DialContext = dialer.DialContext return transport, dialer } @@ -65,14 +69,16 @@ func NewTransport(quicCfg *quic.Config, policy pan.Policy) (*http.Transport, *Di // Dialer dials an insecure, single-stream QUIC connection over SCION (just pretend it's TCP). // This is the Dialer used for shttp.DefaultTransport. type Dialer struct { + PAN *pan.PAN Local netip.AddrPort QuicConfig *quic.Config Policy pan.Policy - sessions []*pan.QUICConn + sessions []*pan.QUICSession } // DialContext dials an insecure, single-stream QUIC connection over SCION. This can be used // as the DialContext function in net/http.Transport. +// Note: The Dialer must have its PAN field set before calling this method. func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { tlsCfg := &tls.Config{ NextProtos: []string{quicutil.SingleStreamProto}, @@ -84,7 +90,7 @@ func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Con return nil, err } - session, err := pan.DialQUIC(ctx, d.Local, remote, addr, tlsCfg, d.QuicConfig, pan.WithPolicy(d.Policy)) + session, err := d.PAN.DialQUIC(ctx, d.Local, remote, addr, tlsCfg, d.QuicConfig, pan.WithPolicy(d.Policy)) if err != nil { return nil, err } @@ -95,7 +101,7 @@ func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Con func (d *Dialer) SetPolicy(policy pan.Policy) { d.Policy = policy for _, s := range d.sessions { - s.UnderlayConn.SetPolicy(policy) + s.Conn.SetPolicy(policy) } } @@ -105,6 +111,9 @@ var scionAddrURLRegexp = regexp.MustCompile( // MangleSCIONAddrURL mangles a SCION address in the host part of a URL-ish // string so that it can be safely used as a URL, i.e. it can be parsed by // net/url.Parse +// +// Deprecated: This workaround relies on behavior affected by CVE-2025-47912 +// and will not be supported after Go 1.24.8. func MangleSCIONAddrURL(url string) string { match := scionAddrURLRegexp.FindStringSubmatch(url) if len(match) == 0 { diff --git a/pkg/shttp/transport_test.go b/pkg/shttp/transport_test.go index 299b69a7c..b90e64f46 100644 --- a/pkg/shttp/transport_test.go +++ b/pkg/shttp/transport_test.go @@ -26,6 +26,7 @@ import ( "strings" "testing" + scionaddr "github.com/scionproto/scion/pkg/addr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -98,8 +99,7 @@ func TestRoundTripper(t *testing.T) { port, err := strconv.Atoi(portStr) require.NoError(t, err) require.Equal(t, hostStr, "host") - hostIA, err := pan.ParseIA("1-ff00:0:1") - require.NoError(t, err) + hostIA := scionaddr.MustParseIA("1-ff00:0:1") hostIP := netip.MustParseAddr("192.0.2.1") remote := pan.UDPAddr{IA: hostIA, IP: hostIP, Port: uint16(port)} assert.Equal(t, expected, remote.String()) diff --git a/pkg/shttp3/server.go b/pkg/shttp3/server.go index 3a28fe16a..322016226 100644 --- a/pkg/shttp3/server.go +++ b/pkg/shttp3/server.go @@ -28,12 +28,13 @@ import ( // Server wraps a http3.Server making it work with SCION type Server struct { *http3.Server + PAN *pan.PAN } // ListenAndServe listens on the SCION/UDP address addr and calls the handler // for HTTP/3 requests on incoming connections. http.DefaultServeMux is used // when handler is nil. -func ListenAndServe(addr string, certFile, keyFile string, handler http.Handler) error { +func ListenAndServe(p *pan.PAN, addr string, certFile, keyFile string, handler http.Handler) error { var err error certs := make([]tls.Certificate, 1) certs[0], err = tls.LoadX509KeyPair(certFile, keyFile) @@ -48,18 +49,21 @@ func ListenAndServe(addr string, certFile, keyFile string, handler http.Handler) Certificates: certs, }, }, + PAN: p, } return s.ListenAndServe() } // ListenAndServe listens on the UDP address s.Addr and calls s.Handler to // handle HTTP/3 requests on incoming connections. +// Note: The Server must have its PAN field set before calling this method. func (s *Server) ListenAndServe() error { laddr, err := pan.ParseOptionalIPPort(s.Addr) if err != nil { return err } - sconn, err := pan.ListenUDP(context.Background(), laddr) + + sconn, err := s.PAN.ListenUDP(context.Background(), laddr, nil) if err != nil { return err } diff --git a/pkg/shttp3/transport.go b/pkg/shttp3/transport.go index db4baf6c4..10258eae6 100644 --- a/pkg/shttp3/transport.go +++ b/pkg/shttp3/transport.go @@ -27,23 +27,28 @@ import ( "github.com/netsec-ethz/scion-apps/pkg/pan" ) -// DefaultTransport is the default RoundTripper that can be used for HTTP/3 +// NewDefaultTransport creates a new RoundTripper that can be used for HTTP/3 // over SCION. -var DefaultTransport = &http3.Transport{ - Dial: (&Dialer{ - Policy: nil, - }).Dial, +func NewDefaultTransport(p *pan.PAN) *http3.Transport { + return &http3.Transport{ + Dial: (&Dialer{ + PAN: p, + Policy: nil, + }).Dial, + } } // Dialer dials a QUIC connection over SCION. // This is the Dialer used for shttp3.DefaultTransport. type Dialer struct { + PAN *pan.PAN Local netip.AddrPort Policy pan.Policy - sessions []*pan.QUICConn + sessions []*pan.QUICSession } // Dial dials a QUIC connection over SCION. +// Note: The Dialer must have its PAN field set before calling this method. func (d *Dialer) Dial(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (*quic.Conn, error) { @@ -51,17 +56,18 @@ func (d *Dialer) Dial(ctx context.Context, addr string, tlsCfg *tls.Config, if err != nil { return nil, err } - session, err := pan.DialQUICEarly(ctx, d.Local, remote, addr, tlsCfg, cfg, pan.WithPolicy(d.Policy)) + + session, err := d.PAN.DialQUICEarly(ctx, d.Local, remote, addr, tlsCfg, cfg, pan.WithPolicy(d.Policy)) if err != nil { return nil, err } d.sessions = append(d.sessions, session) - return session.Conn, nil + return session.QUIC, nil } func (d *Dialer) SetPolicy(policy pan.Policy) { d.Policy = policy for _, s := range d.sessions { - s.UnderlayConn.SetPolicy(policy) + s.Conn.SetPolicy(policy) } } diff --git a/sensorapp/sensorfetcher/sensorfetcher.go b/sensorapp/sensorfetcher/sensorfetcher.go index 7edaf260a..e3281cb18 100644 --- a/sensorapp/sensorfetcher/sensorfetcher.go +++ b/sensorapp/sensorfetcher/sensorfetcher.go @@ -50,11 +50,14 @@ func main() { os.Exit(2) } + p, err := pan.New(context.Background()) + check(err) + policy, err := pan.PolicyFromCommandline(*sequence, *preference, *interactive) check(err) serverAddr, err := pan.ResolveUDPAddr(context.TODO(), *serverAddrStr) check(err) - conn, err := pan.DialUDP(context.Background(), netip.AddrPort{}, serverAddr, pan.WithPolicy(policy)) + conn, err := p.DialUDP(context.Background(), netip.AddrPort{}, serverAddr, pan.WithPolicy(policy)) check(err) receivePacketBuffer := make([]byte, 2500) diff --git a/sensorapp/sensorserver/sensorserver.go b/sensorapp/sensorserver/sensorserver.go index 183232795..e448b99b5 100644 --- a/sensorapp/sensorserver/sensorserver.go +++ b/sensorapp/sensorserver/sensorserver.go @@ -80,8 +80,11 @@ func main() { port := flag.Uint("p", 40002, "Server Port") flag.Parse() + p, err := pan.New(context.Background()) + check(err) + local := netip.AddrPortFrom(netip.Addr{}, uint16(*port)) - conn, err := pan.ListenUDP(context.Background(), local) + conn, err := p.ListenUDP(context.Background(), local, nil) check(err) receivePacketBuffer := make([]byte, 2500) diff --git a/skip/main.go b/skip/main.go index b580b4ceb..106db23ba 100644 --- a/skip/main.go +++ b/skip/main.go @@ -91,7 +91,11 @@ func main() { kingpin.Flag("bind", "Address to bind on").Default("localhost:8888").TCPVar(&bindAddress) kingpin.Parse() - transport, dialer := shttp.NewTransport(nil, nil) + p, err := pan.New(context.Background()) + if err != nil { + log.Fatal(err) + } + transport, dialer := shttp.NewTransport(p, nil, nil) proxy := &proxyHandler{ transport: transport, diff --git a/ssh/client/main.go b/ssh/client/main.go index 09dd75ca9..005dad0d1 100644 --- a/ssh/client/main.go +++ b/ssh/client/main.go @@ -156,10 +156,15 @@ func main() { golog.Fatal(err) } + p, err := pan.New(context.Background()) + if err != nil { + golog.Fatalf("Error creating pan client: %v", err) + } + serverAddress := fmt.Sprintf("%s:%v", conf.HostAddress, conf.Port) ctx := context.Background() - err = sshClient.Connect(ctx, serverAddress, policy, *pathSelector) + err = sshClient.Connect(ctx, p, serverAddress, policy, *pathSelector) if err != nil { golog.Panicf("Error connecting: %v", err) } @@ -174,7 +179,7 @@ func main() { } local := netip.AddrPortFrom(netip.Addr{}, uint16(port)) - err = sshClient.StartTunnel(local, localForward[1]) + err = sshClient.StartTunnel(p, local, localForward[1]) if err != nil { golog.Panicf("Error starting tunnel: %v", err) } diff --git a/ssh/client/ssh/scion.go b/ssh/client/ssh/scion.go index 6375136c5..4cbc18cde 100644 --- a/ssh/client/ssh/scion.go +++ b/ssh/client/ssh/scion.go @@ -29,6 +29,7 @@ import ( // dialSCION starts a client connection to the given SSH server over SCION using QUIC. func dialSCION(ctx context.Context, + p *pan.PAN, addr string, policy pan.Policy, selector string, @@ -49,7 +50,7 @@ func dialSCION(ctx context.Context, quicConf := &quic.Config{ KeepAlivePeriod: 15 * time.Second, } - sess, err := pan.DialQUIC(ctx, netip.AddrPort{}, remote, "", tlsConf, quicConf, pan.WithPolicy(policy), pan.WithSelector(sel)) + sess, err := p.DialQUIC(ctx, netip.AddrPort{}, remote, "", tlsConf, quicConf, pan.WithPolicy(policy), pan.WithSelector(sel)) if err != nil { return nil, err } diff --git a/ssh/client/ssh/selector.go b/ssh/client/ssh/selector.go index 4b45ad033..621988171 100644 --- a/ssh/client/ssh/selector.go +++ b/ssh/client/ssh/selector.go @@ -68,7 +68,7 @@ func (s *roundRobinSelector) Path(_ context.Context) *pan.Path { return p } -func (s *roundRobinSelector) Initialize(local, remote pan.UDPAddr, paths []*pan.Path) { +func (s *roundRobinSelector) Initialize(local, remote pan.UDPAddr, paths []*pan.Path, _ *pan.PAN) { s.mutex.Lock() defer s.mutex.Unlock() s.paths = paths @@ -107,7 +107,7 @@ func (s *randomSelector) Path(_ context.Context) *pan.Path { return p } -func (s *randomSelector) Initialize(local, remote pan.UDPAddr, paths []*pan.Path) { +func (s *randomSelector) Initialize(local, remote pan.UDPAddr, paths []*pan.Path, _ *pan.PAN) { s.mutex.Lock() defer s.mutex.Unlock() s.paths = paths diff --git a/ssh/client/ssh/ssh.go b/ssh/client/ssh/ssh.go index 5a89cfb4a..fe2bfd871 100644 --- a/ssh/client/ssh/ssh.go +++ b/ssh/client/ssh/ssh.go @@ -29,6 +29,8 @@ import ( "sync" log "github.com/inconshreveable/log15" + "github.com/quic-go/quic-go" + "github.com/scionproto/scion/pkg/snet" "golang.org/x/crypto/ssh" "github.com/netsec-ethz/scion-apps/pkg/pan" @@ -114,8 +116,8 @@ func Create(username string, config *clientconfig.ClientConfig, passAuthHandler } // Connect connects the Client to the given address. -func (client *Client) Connect(ctx context.Context, addr string, policy pan.Policy, selector string) error { - goClient, err := dialSCION(ctx, addr, policy, selector, client.config) +func (client *Client) Connect(ctx context.Context, p *pan.PAN, addr string, policy pan.Policy, selector string) error { + goClient, err := dialSCION(ctx, p, addr, policy, selector, client.config) if err != nil { return err } @@ -195,17 +197,22 @@ func (client *Client) forward(addr string, localConn net.Conn) error { // StartTunnel creates a new tunnel to the given address, forwarding all // connections on the given port over the server to the given address. If the // given address is a SCION address, QUIC is used; else TCP. -func (client *Client) StartTunnel(local netip.AddrPort, addr string) error { +// The p parameter is required when the address is a SCION address. +func (client *Client) StartTunnel(p *pan.PAN, local netip.AddrPort, addr string) error { var localListener net.Listener if strings.Contains(addr, ",") { tlsConf := &tls.Config{ NextProtos: []string{quicutil.SingleStreamProto}, } - ql, err := pan.ListenQUIC(context.Background(), local, tlsConf, nil) + localAddr := &snet.UDPAddr{ + IA: p.IA(), + Host: net.UDPAddrFromAddrPort(local), + } + ql, err := p.ListenQUIC(context.Background(), localAddr, tlsConf, &quic.Config{}, nil) if err != nil { return err } - localListener = quicutil.SingleStreamListener{QUICListener: ql} + localListener = &quicutil.SingleStreamListener{QUICListener: ql} } else { // That's right, TCP listen on UDPAddr. XXX replace with netip.AddrPort once available tl, err := net.Listen("tcp", local.String()) diff --git a/ssh/server/main.go b/ssh/server/main.go index 4cc017592..2c9ea0694 100644 --- a/ssh/server/main.go +++ b/ssh/server/main.go @@ -18,11 +18,14 @@ import ( "context" "crypto/tls" golog "log" + "net" "net/netip" "os" "strconv" log "github.com/inconshreveable/log15" + "github.com/quic-go/quic-go" + "github.com/scionproto/scion/pkg/snet" "gopkg.in/alecthomas/kingpin.v2" "github.com/netsec-ethz/scion-apps/pkg/pan" @@ -83,6 +86,13 @@ func main() { golog.Panicf("Error creating ssh server: %v", err) } + p, err := pan.New(context.Background()) + if err != nil { + golog.Fatalf("Error creating pan client: %v", err) + } + + sshServer.SetPAN(p) + port, err := strconv.ParseUint(conf.Port, 10, 16) if err != nil { golog.Panicf("Can't parse port %v: %v", conf.Port, err) @@ -94,11 +104,15 @@ func main() { Certificates: quicutil.MustGenerateSelfSignedCert(), NextProtos: []string{quicutil.SingleStreamProto}, } - ql, err := pan.ListenQUIC(context.Background(), local, tlsConf, nil) + localAddr := &snet.UDPAddr{ + IA: p.IA(), + Host: net.UDPAddrFromAddrPort(local), + } + ql, err := p.ListenQUIC(context.Background(), localAddr, tlsConf, &quic.Config{}, nil) if err != nil { golog.Panicf("Failed to listen (%v)", err) } - listener := quicutil.SingleStreamListener{QUICListener: ql} + listener := &quicutil.SingleStreamListener{QUICListener: ql} log.Debug("Starting to wait for connections") for { diff --git a/ssh/server/ssh/ssh.go b/ssh/server/ssh/ssh.go index b7701d1b5..b0926107d 100644 --- a/ssh/server/ssh/ssh.go +++ b/ssh/server/ssh/ssh.go @@ -23,6 +23,7 @@ import ( log "github.com/inconshreveable/log15" "golang.org/x/crypto/ssh" + "github.com/netsec-ethz/scion-apps/pkg/pan" "github.com/netsec-ethz/scion-apps/ssh/server/serverconfig" "github.com/netsec-ethz/scion-apps/ssh/utils" ) @@ -37,6 +38,8 @@ type Server struct { configuration *ssh.ServerConfig channelHandlers map[string]channelHandlerFunction + + p *pan.PAN } // Create creates a new unconnected Server object. @@ -66,11 +69,21 @@ func Create(config *serverconfig.ServerConfig, version string) (*Server, error) server.channelHandlers["session"] = handleSession server.channelHandlers["direct-tcpip"] = handleTCPTunnel - server.channelHandlers["direct-scionquic"] = handleSCIONQUICTunnel + server.channelHandlers["direct-scionquic"] = server.handleSCIONQUICTunnelWrapper return server, nil } +// SetPAN sets the pan client for the server +func (s *Server) SetPAN(p *pan.PAN) { + s.p = p +} + +// handleSCIONQUICTunnelWrapper wraps handleSCIONQUICTunnel to provide the pan client +func (s *Server) handleSCIONQUICTunnelWrapper(perms *ssh.Permissions, newChannel ssh.NewChannel) error { + return handleSCIONQUICTunnel(s.p, perms, newChannel) +} + func (s *Server) handleChannels(perms *ssh.Permissions, chans <-chan ssh.NewChannel) { // Service the incoming Channel channel in go routine for newChannel := range chans { diff --git a/ssh/server/ssh/tunnelchannel.go b/ssh/server/ssh/tunnelchannel.go index 853f3d946..bf499e460 100644 --- a/ssh/server/ssh/tunnelchannel.go +++ b/ssh/server/ssh/tunnelchannel.go @@ -24,6 +24,7 @@ import ( "net/netip" "sync" + "github.com/quic-go/quic-go" "golang.org/x/crypto/ssh" "github.com/netsec-ethz/scion-apps/pkg/pan" @@ -70,7 +71,7 @@ func handleTCPTunnel(perms *ssh.Permissions, newChannel ssh.NewChannel) error { return nil } -func handleSCIONQUICTunnel(perms *ssh.Permissions, newChannel ssh.NewChannel) error { +func handleSCIONQUICTunnel(p *pan.PAN, perms *ssh.Permissions, newChannel ssh.NewChannel) error { extraData := newChannel.ExtraData() addressLen := binary.BigEndian.Uint32(extraData[0:4]) address := string(extraData[4 : addressLen+4]) @@ -91,7 +92,7 @@ func handleSCIONQUICTunnel(perms *ssh.Permissions, newChannel ssh.NewChannel) er NextProtos: []string{quicutil.SingleStreamProto}, InsecureSkipVerify: true, } - sess, err := pan.DialQUIC(ctx, netip.AddrPort{}, remote, "", tlsConf, nil) + sess, err := p.DialQUIC(ctx, netip.AddrPort{}, remote, "", tlsConf, &quic.Config{}) if err != nil { return fmt.Errorf("could not open remote connection: %w", err) } diff --git a/web-gateway/main.go b/web-gateway/main.go index 621b735a4..8a5930f87 100644 --- a/web-gateway/main.go +++ b/web-gateway/main.go @@ -31,6 +31,7 @@ import ( "github.com/gorilla/handlers" "github.com/quic-go/quic-go" + "github.com/scionproto/scion/pkg/snet" "gopkg.in/alecthomas/kingpin.v2" "github.com/netsec-ethz/scion-apps/pkg/pan" @@ -44,6 +45,12 @@ func main() { hosts := kingpin.Arg("hosts", "Hostnames for hosts to proxy").Required().Strings() kingpin.Parse() + // Initialize SCION PAN once + p, err := pan.New(context.Background()) + if err != nil { + log.Fatal(err) + } + // Proxy HTTP: mux := http.NewServeMux() for _, host := range *hosts { @@ -72,7 +79,7 @@ func main() { mux, ) go func() { - log.Fatalf("%s", shttp.ListenAndServe(":80", loggedMux)) + log.Fatalf("%s", shttp.ListenAndServe(p, ":80", loggedMux)) }() // For HTTPS, forward the entire TLS traffic data @@ -80,13 +87,13 @@ func main() { for _, h := range *hosts { hostSet[h] = struct{}{} } - log.Fatalf("%s", forwardTLS(hostSet)) + log.Fatalf("%s", forwardTLS(p, hostSet)) } // forwardTLS listens on 443 and forwards each sessions to the corresponding // TCP/IP host identified by SNI -func forwardTLS(hosts map[string]struct{}) error { - listener, err := listen(netip.AddrPortFrom(netip.Addr{}, 443)) +func forwardTLS(p *pan.PAN, hosts map[string]struct{}) error { + listener, err := listen(p, netip.AddrPortFrom(netip.Addr{}, 443)) if err != nil { return err } @@ -160,10 +167,15 @@ func transfer(dst io.WriteCloser, src io.ReadCloser) { } } -func listen(laddr netip.AddrPort) (*pan.QUICListener, error) { +func listen(p *pan.PAN, laddr netip.AddrPort) (*quic.EarlyListener, error) { + localAddr := &snet.UDPAddr{ + IA: p.IA(), + Host: net.UDPAddrFromAddrPort(laddr), + } + tlsCfg := &tls.Config{ NextProtos: []string{quicutil.SingleStreamProto}, Certificates: quicutil.MustGenerateSelfSignedCert(), } - return pan.ListenQUIC(context.Background(), laddr, tlsCfg, nil) + return p.ListenQUIC(context.Background(), localAddr, tlsCfg, &quic.Config{}, nil) } diff --git a/webapp/development.md b/webapp/development.md index 5eb17f225..2f61fcb47 100644 --- a/webapp/development.md +++ b/webapp/development.md @@ -49,7 +49,6 @@ Webapp is a go application designed to operate a web server for purposes of visu ## Future Features * **Latency Tests**: *(in development)* SCION ping and traceroute results would be listed next to available paths or overlaid on path graphs allowing easy examination of performance. -* **Name Resolution**: Integration with the SCION name resolution service (RAINS), would optionally show human-readable hostnames rather than IA numbers. * **Geolocation**: Dynamic locations provided by ASes issuing beacons with geolocation would be more accurate and complete than the current static geolocation data on the global paths map. * **Web sockets**: Data between the go web-server and the browser is requested by AJAX and polling from the browser. Implementing websockets would avoid timing issues polling for updated graph data from the web-server and reduce browser load. diff --git a/webapp/lib/config.go b/webapp/lib/config.go index d934e7ade..16a3e0837 100644 --- a/webapp/lib/config.go +++ b/webapp/lib/config.go @@ -195,7 +195,7 @@ func getSDFromSDTomlFile(path string) string { } } log.Info(fmt.Sprintf("sciond address could not be read from toml file %s", path)) - if sd, ok := os.LookupEnv("SCION_DAEMON_ADDRESS"); ok { + if sd, ok := os.LookupEnv("SCION_DAEMON"); ok { return sd } return daemon.DefaultAPIAddress diff --git a/webapp/lib/sciond.go b/webapp/lib/sciond.go index 2cfe996e7..35bdff588 100644 --- a/webapp/lib/sciond.go +++ b/webapp/lib/sciond.go @@ -246,7 +246,7 @@ func getPathsJSON(sciondConn daemon.Connector, dstIA addr.IA) ([]byte, error) { rPaths := make([]Path, 0, len(paths)) for _, path := range paths { rpath := Path{ - Fingerprint: snet.Fingerprint(path).String()[:16], + Fingerprint: snet.Fingerprint(path.Metadata().Interfaces).String()[:16], Expiry: path.Metadata().Expiry, MTU: path.Metadata().MTU, } @@ -299,8 +299,8 @@ func AsTopoHandler(w http.ResponseWriter, r *http.Request, options *CmdOptions, sjsonInfo, _ := json.Marshal(svcirs) log.Debug("AsTopoHandler:", "sjsonInfo", string(sjsonInfo)) - fmt.Fprintf(w, fmt.Sprintf(`{"as_info":%s,"if_info":%s,"svc_info":%s}`, - ajsonInfo, ijsonInfo, sjsonInfo)) + fmt.Fprintf(w, `{"as_info":%s,"if_info":%s,"svc_info":%s}`, + ajsonInfo, ijsonInfo, sjsonInfo) } // TrcHandler handles requests for all local trust root data. diff --git a/webapp/tests/asviz/json_trc.html b/webapp/tests/asviz/json_trc.html index ac8e836f2..db6632e12 100644 --- a/webapp/tests/asviz/json_trc.html +++ b/webapp/tests/asviz/json_trc.html @@ -2,7 +2,6 @@
  • ISD1-V1.trc
    • Quorum CAs: 0 -
    • RAINS
    • Quorum TRC: 1 diff --git a/webapp/webapp.go b/webapp/webapp.go index 7ef0f1723..02d422b15 100644 --- a/webapp/webapp.go +++ b/webapp/webapp.go @@ -487,7 +487,7 @@ func executeCommand(w http.ResponseWriter, r *http.Request) { log.Info("Executing:", "command", strings.Join(command, " ")) cmd := exec.Command(command[0], command[1:]...) cmd.Dir = getClientCwd(appSel) - cmd.Env = append(os.Environ(), "SCION_DAEMON_ADDRESS="+asCfg[myIA].Sciond) + cmd.Env = append(os.Environ(), "SCION_DAEMON="+asCfg[myIA].Sciond) log.Info("Chosen Path:", "pathStr", pathStr)