mirror of
https://github.com/cloudflare/cloudflared
synced 2026-06-08 13:33:07 +00:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 159fcb44ce | |||
| 8e69f41833 | |||
| 00cd7c333c | |||
| 86b50eda15 | |||
| 652df22831 | |||
| 33baad35b8 | |||
| 12dd91ada1 | |||
| b901d73d9b | |||
| 61a16538a1 | |||
| 9e1f4c2bca | |||
| f51be82729 | |||
| fd5d8260bb | |||
| f2c4fdb0ae | |||
| a4a84bb27e | |||
| 4ddc8d758b | |||
| 8068cdebb6 | |||
| 45236a1f7d | |||
| e0a55f9c0e | |||
| c1d8c5e960 | |||
| 7ae1d4668e | |||
| adb7d40084 | |||
| 541c63d737 | |||
| f1d6f0c0be | |||
| 958b6f1d24 | |||
| 6d1d91d9f9 | |||
| fc0ecf4185 | |||
| 349586007c | |||
| 569a7c3c9e | |||
| bec683b67d | |||
| 38d3c3cae5 | |||
| f2d765351d | |||
| 5d8f60873d | |||
| b474778cf1 | |||
| 65247b6f0f | |||
| 5f3cfe044f | |||
| 81fe0bd12b | |||
| bfeaa3418d |
@@ -4,7 +4,7 @@ jobs:
|
||||
check:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.19.x]
|
||||
go-version: [1.21.x]
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
|
||||
+2
-2
@@ -143,7 +143,7 @@ if [[ ! -z "$CODE_SIGN_NAME" ]]; then
|
||||
codesign -s "${CODE_SIGN_NAME}" -f -v --timestamp --options runtime ${BINARY_NAME}
|
||||
|
||||
# notarize the binary
|
||||
# TODO: https://jira.cfdata.org/browse/TUN-5789
|
||||
# TODO: TUN-5789
|
||||
fi
|
||||
|
||||
# creating build directory
|
||||
@@ -169,7 +169,7 @@ if [[ ! -z "$PKG_SIGN_NAME" ]]; then
|
||||
${PKGNAME}
|
||||
|
||||
# notarize the package
|
||||
# TODO: https://jira.cfdata.org/browse/TUN-5789
|
||||
# TODO: TUN-5789
|
||||
else
|
||||
pkgbuild --identifier com.cloudflare.${PRODUCT} \
|
||||
--version ${VERSION} \
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
cd /tmp/
|
||||
rm -rf go
|
||||
rm -rf gocache
|
||||
export GOCACHE=/tmp/gocache
|
||||
|
||||
git clone -q https://github.com/cloudflare/go
|
||||
cd go/src
|
||||
# https://github.com/cloudflare/go/tree/34129e47042e214121b6bbff0ded4712debed18e is version go1.21.5-devel-cf
|
||||
git checkout -q 34129e47042e214121b6bbff0ded4712debed18e
|
||||
./make.bash
|
||||
|
||||
export PATH="/tmp/go/bin:$PATH"
|
||||
go version
|
||||
which go
|
||||
go env
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
$ProgressPreference = "SilentlyContinue"
|
||||
|
||||
# Relative path to working directory
|
||||
$CloudflaredDirectory = "go\src\github.com\cloudflare\cloudflared"
|
||||
|
||||
cd $CloudflaredDirectory
|
||||
|
||||
Write-Output "Building for amd64"
|
||||
$env:TARGET_OS = "windows"
|
||||
$env:CGO_ENABLED = 1
|
||||
$env:TARGET_ARCH = "amd64"
|
||||
$env:Path = "$Env:Temp\go\bin;$($env:Path)"
|
||||
|
||||
go env
|
||||
go version
|
||||
|
||||
& make cloudflared
|
||||
if ($LASTEXITCODE -ne 0) { throw "Failed to build cloudflared for amd64" }
|
||||
copy .\cloudflared.exe .\cloudflared-windows-amd64.exe
|
||||
|
||||
Write-Output "Building for 386"
|
||||
$env:CGO_ENABLED = 0
|
||||
$env:TARGET_ARCH = "386"
|
||||
make cloudflared
|
||||
if ($LASTEXITCODE -ne 0) { throw "Failed to build cloudflared for 386" }
|
||||
copy .\cloudflared.exe .\cloudflared-windows-386.exe
|
||||
Vendored
+82
@@ -0,0 +1,82 @@
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
$ProgressPreference = "SilentlyContinue"
|
||||
|
||||
$WorkingDirectory = Get-Location
|
||||
$CloudflaredDirectory = "$WorkingDirectory\go\src\github.com\cloudflare\cloudflared"
|
||||
|
||||
Write-Output "Installing python..."
|
||||
|
||||
$PythonVersion = "3.10.11"
|
||||
$PythonZipFile = "$env:Temp\python-$PythonVersion-embed-amd64.zip"
|
||||
$PipInstallFile = "$env:Temp\get-pip.py"
|
||||
$PythonZipUrl = "https://www.python.org/ftp/python/$PythonVersion/python-$PythonVersion-embed-amd64.zip"
|
||||
$PythonPath = "$WorkingDirectory\Python"
|
||||
$PythonBinPath = "$PythonPath\python.exe"
|
||||
|
||||
# Download Python zip file
|
||||
Invoke-WebRequest -Uri $PythonZipUrl -OutFile $PythonZipFile
|
||||
|
||||
# Download Python pip file
|
||||
Invoke-WebRequest -Uri "https://bootstrap.pypa.io/get-pip.py" -OutFile $PipInstallFile
|
||||
|
||||
# Extract Python files
|
||||
Expand-Archive $PythonZipFile -DestinationPath $PythonPath -Force
|
||||
|
||||
# Add Python to PATH
|
||||
$env:Path = "$PythonPath\Scripts;$PythonPath;$($env:Path)"
|
||||
|
||||
Write-Output "Installed to $PythonPath"
|
||||
|
||||
# Install pip
|
||||
& $PythonBinPath $PipInstallFile
|
||||
|
||||
# Add package paths in pythonXX._pth to unblock python -m pip
|
||||
$PythonImportPathFile = "$PythonPath\python310._pth"
|
||||
$ComponentTestsDir = "$CloudflaredDirectory\component-tests\"
|
||||
@($ComponentTestsDir, "Lib\site-packages", $(Get-Content $PythonImportPathFile)) | Set-Content $PythonImportPathFile
|
||||
|
||||
# Test Python installation
|
||||
& $PythonBinPath --version
|
||||
& $PythonBinPath -m pip --version
|
||||
|
||||
go env
|
||||
go version
|
||||
|
||||
$env:TARGET_OS = "windows"
|
||||
$env:CGO_ENABLED = 1
|
||||
$env:TARGET_ARCH = "amd64"
|
||||
$env:Path = "$Env:Temp\go\bin;$($env:Path)"
|
||||
|
||||
& $PythonBinPath --version
|
||||
& $PythonBinPath -m pip --version
|
||||
|
||||
cd $CloudflaredDirectory
|
||||
|
||||
go env
|
||||
go version
|
||||
|
||||
Write-Output "Building cloudflared"
|
||||
|
||||
& make cloudflared
|
||||
if ($LASTEXITCODE -ne 0) { throw "Failed to build cloudflared" }
|
||||
|
||||
echo $LASTEXITCODE
|
||||
|
||||
Write-Output "Running unit tests"
|
||||
|
||||
# Not testing with race detector because of https://github.com/golang/go/issues/61058
|
||||
# We already test it on other platforms
|
||||
& go test -failfast -mod=vendor ./...
|
||||
if ($LASTEXITCODE -ne 0) { throw "Failed unit tests" }
|
||||
|
||||
Write-Output "Running component tests"
|
||||
|
||||
& $PythonBinPath -m pip install --upgrade -r component-tests/requirements.txt
|
||||
& $PythonBinPath component-tests/setup.py --type create
|
||||
& $PythonBinPath -m pytest component-tests -o log_cli=true --log-cli-level=INFO
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
& $PythonBinPath component-tests/setup.py --type cleanup
|
||||
throw "Failed component tests"
|
||||
}
|
||||
& $PythonBinPath component-tests/setup.py --type cleanup
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
$ProgressPreference = "SilentlyContinue"
|
||||
|
||||
Write-Output "Downloading cloudflare go..."
|
||||
|
||||
Set-Location "$Env:Temp"
|
||||
|
||||
git clone -q https://github.com/cloudflare/go
|
||||
Write-Output "Building go..."
|
||||
cd go/src
|
||||
# https://github.com/cloudflare/go/tree/34129e47042e214121b6bbff0ded4712debed18e is version go1.21.5-devel-cf
|
||||
git checkout -q 34129e47042e214121b6bbff0ded4712debed18e
|
||||
& ./make.bat
|
||||
|
||||
Write-Output "Installed"
|
||||
Vendored
+20
@@ -0,0 +1,20 @@
|
||||
$ErrorActionPreference = "Stop"
|
||||
$ProgressPreference = "SilentlyContinue"
|
||||
$GoMsiVersion = "go1.21.5.windows-amd64.msi"
|
||||
|
||||
Write-Output "Downloading go installer..."
|
||||
|
||||
Set-Location "$Env:Temp"
|
||||
|
||||
(New-Object System.Net.WebClient).DownloadFile(
|
||||
"https://go.dev/dl/$GoMsiVersion",
|
||||
"$Env:Temp\$GoMsiVersion"
|
||||
)
|
||||
|
||||
Write-Output "Installing go..."
|
||||
Install-Package "$Env:Temp\$GoMsiVersion" -Force
|
||||
|
||||
# Go installer updates global $PATH
|
||||
go env
|
||||
|
||||
Write-Output "Installed"
|
||||
@@ -1,3 +1,6 @@
|
||||
## 2023.9.0
|
||||
### Notices
|
||||
- The `warp-routing` `enabled: boolean` flag is no longer supported in the configuration file. Warp Routing traffic (eg TCP, UDP, ICMP) traffic is proxied to cloudflared if routes to the target tunnel are configured. This change does not affect remotely managed tunnels, but for locally managed tunnels, users that might be relying on this feature flag to block traffic should instead guarantee that tunnel has no Private Routes configured for the tunnel.
|
||||
## 2023.7.0
|
||||
### New Features
|
||||
- You can now enable additional diagnostics over the management.argotunnel.com service for your active cloudflared connectors via a new runtime flag `--management-diagnostics` (or env `TUNNEL_MANAGEMENT_DIAGNOSTICS`). This feature is provided as opt-in and requires the flag to enable. Endpoints such as /metrics provides your prometheus metrics endpoint another mechanism to be reached. Additionally /debug/pprof/(goroutine|heap) are also introduced to allow for remotely retrieving active pprof information from a running cloudflared connector.
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
# use a builder image for building cloudflare
|
||||
ARG TARGET_GOOS
|
||||
ARG TARGET_GOARCH
|
||||
FROM golang:1.19 as builder
|
||||
FROM golang:1.21.5 as builder
|
||||
ENV GO111MODULE=on \
|
||||
CGO_ENABLED=0 \
|
||||
TARGET_GOOS=${TARGET_GOOS} \
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
# use a builder image for building cloudflare
|
||||
FROM golang:1.19 as builder
|
||||
FROM golang:1.21.5 as builder
|
||||
ENV GO111MODULE=on \
|
||||
CGO_ENABLED=0
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
# use a builder image for building cloudflare
|
||||
FROM golang:1.19 as builder
|
||||
FROM golang:1.21.5 as builder
|
||||
ENV GO111MODULE=on \
|
||||
CGO_ENABLED=0
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ ifeq ($(FIPS), true)
|
||||
$(info Building cloudflared with go-fips)
|
||||
cp -f fips/fips.go.linux-amd64 cmd/cloudflared/fips.go
|
||||
endif
|
||||
GOOS=$(TARGET_OS) GOARCH=$(TARGET_ARCH) $(ARM_COMMAND) go build -v -mod=vendor $(GO_BUILD_TAGS) $(LDFLAGS) $(IMPORT_PATH)/cmd/cloudflared
|
||||
GOOS=$(TARGET_OS) GOARCH=$(TARGET_ARCH) $(ARM_COMMAND) go build -mod=vendor $(GO_BUILD_TAGS) $(LDFLAGS) $(IMPORT_PATH)/cmd/cloudflared
|
||||
ifeq ($(FIPS), true)
|
||||
rm -f cmd/cloudflared/fips.go
|
||||
./check-fips.sh cloudflared
|
||||
@@ -260,7 +260,7 @@ quic-deps:
|
||||
|
||||
.PHONY: vet
|
||||
vet:
|
||||
go vet -v -mod=vendor github.com/cloudflare/cloudflared/...
|
||||
go vet -mod=vendor github.com/cloudflare/cloudflared/...
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
|
||||
@@ -53,9 +53,6 @@ Want to test Cloudflare Tunnel before adding a website to Cloudflare? You can do
|
||||
|
||||
## Deprecated versions
|
||||
|
||||
Cloudflare currently supports versions of `cloudflared` 2020.5.1 and later. Breaking changes unrelated to feature availability may be introduced that will impact versions released prior to 2020.5.1. You can read more about upgrading `cloudflared` in our [developer documentation](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation#updating-cloudflared).
|
||||
Cloudflare currently supports versions of cloudflared that are **within one year** of the most recent release. Breaking changes unrelated to feature availability may be introduced that will impact versions released more than one year ago. You can read more about upgrading cloudflared in our [developer documentation](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/#updating-cloudflared).
|
||||
|
||||
| Version(s) | Deprecation status |
|
||||
|---|---|
|
||||
| 2020.5.1 and later | Supported |
|
||||
| Versions prior to 2020.5.1 | No longer supported |
|
||||
For example, as of January 2023 Cloudflare will support cloudflared version 2023.1.1 to cloudflared 2022.1.1.
|
||||
|
||||
@@ -1,3 +1,46 @@
|
||||
2024.1.0
|
||||
- 2024-01-01 TUN-7934: Update quic-go to a version that queues datagrams for better throughput and drops large datagram
|
||||
- 2023-12-20 TUN-8072: Need to set GOCACHE in mac go installation script
|
||||
- 2023-12-17 TUN-8072: Add script to download cloudflare go for Mac build agents
|
||||
- 2023-12-15 Fix nil pointer dereference segfault when passing "null" config json to cloudflared tunnel ingress validate (#1070)
|
||||
- 2023-12-15 configuration.go: fix developerPortal link (#960)
|
||||
- 2023-12-14 tunnelrpc/pogs: fix dropped test errors (#1106)
|
||||
- 2023-12-14 cmd/cloudflared/updater: fix dropped error (#1055)
|
||||
- 2023-12-14 use os.Executable to discover the path to cloudflared (#1040)
|
||||
- 2023-12-14 Remove extraneous `period` from Path Environment Variable (#1009)
|
||||
- 2023-12-14 Use CLI context when running tunnel (#597)
|
||||
- 2023-12-14 TUN-8066: Define scripts to build on Windows agents
|
||||
- 2023-12-11 TUN-8052: Update go to 1.21.5
|
||||
- 2023-12-07 TUN-7970: Default to enable post quantum encryption for quic transport
|
||||
- 2023-12-04 TUN-8006: Update quic-go to latest upstream
|
||||
- 2023-11-15 VULN-44842 Add a flag that allows users to not send the Access JWT to stdout
|
||||
- 2023-11-13 TUN-7965: Remove legacy incident status page check
|
||||
- 2023-11-13 AUTH-5682 Org token flow in Access logins should pass CF_AppSession cookie
|
||||
|
||||
2023.10.0
|
||||
- 2023-10-06 TUN-7864: Document cloudflared versions support
|
||||
- 2023-10-03 CUSTESC-33731: Make rule match test report rule in 0-index base
|
||||
- 2023-09-22 TUN-7824: Fix usage of systemctl status to detect which services are installed
|
||||
- 2023-09-20 TUN-7813: Improve tunnel delete command to use cascade delete
|
||||
- 2023-09-20 TUN-7787: cloudflared only list ip routes targeted for cfd_tunnel
|
||||
- 2023-09-15 TUN-7787: Refactor cloudflared to use new route endpoints based on route IDs
|
||||
- 2023-09-08 TUN-7776: Remove warp-routing flag from cloudflared
|
||||
- 2023-09-05 TUN-7756: Clarify that QUIC is mandatory to support ICMP proxying
|
||||
|
||||
2023.8.2
|
||||
- 2023-08-25 TUN-7700: Implement feature selector to determine if connections will prefer post quantum cryptography
|
||||
- 2023-08-22 TUN-7707: Use X25519Kyber768Draft00 curve when post-quantum feature is enabled
|
||||
|
||||
2023.8.1
|
||||
- 2023-08-23 TUN-7718: Update R2 Token to no longer encode secret
|
||||
|
||||
2023.8.0
|
||||
- 2023-07-26 TUN-7584: Bump go 1.20.6
|
||||
|
||||
2023.7.3
|
||||
- 2023-07-25 TUN-7628: Correct Host parsing for Access
|
||||
- 2023-07-24 TUN-7624: Fix flaky TestBackoffGracePeriod test in cloudflared
|
||||
|
||||
2023.7.2
|
||||
- 2023-07-19 TUN-7599: Onboard cloudflared to Software Dashboard
|
||||
- 2023-07-19 TUN-7587: Remove junos builds
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ type TunnelClient interface {
|
||||
GetTunnel(tunnelID uuid.UUID) (*Tunnel, error)
|
||||
GetTunnelToken(tunnelID uuid.UUID) (string, error)
|
||||
GetManagementToken(tunnelID uuid.UUID) (string, error)
|
||||
DeleteTunnel(tunnelID uuid.UUID) error
|
||||
DeleteTunnel(tunnelID uuid.UUID, cascade bool) error
|
||||
ListTunnels(filter *TunnelFilter) ([]*Tunnel, error)
|
||||
ListActiveClients(tunnelID uuid.UUID) ([]*ActiveClient, error)
|
||||
CleanupConnections(tunnelID uuid.UUID, params *CleanupParams) error
|
||||
@@ -22,7 +22,7 @@ type HostnameClient interface {
|
||||
type IPRouteClient interface {
|
||||
ListRoutes(filter *IpRouteFilter) ([]*DetailedRoute, error)
|
||||
AddRoute(newRoute NewRoute) (Route, error)
|
||||
DeleteRoute(params DeleteRouteParams) error
|
||||
DeleteRoute(id uuid.UUID) error
|
||||
GetByIP(params GetRouteByIpParams) (DetailedRoute, error)
|
||||
}
|
||||
|
||||
|
||||
+8
-11
@@ -75,10 +75,12 @@ type NewRoute struct {
|
||||
// MarshalJSON handles fields with non-JSON types (e.g. net.IPNet).
|
||||
func (r NewRoute) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(&struct {
|
||||
Network string `json:"network"`
|
||||
TunnelID uuid.UUID `json:"tunnel_id"`
|
||||
Comment string `json:"comment"`
|
||||
VNetID *uuid.UUID `json:"virtual_network_id,omitempty"`
|
||||
}{
|
||||
Network: r.Network.String(),
|
||||
TunnelID: r.TunnelID,
|
||||
Comment: r.Comment,
|
||||
VNetID: r.VNetID,
|
||||
@@ -87,6 +89,7 @@ func (r NewRoute) MarshalJSON() ([]byte, error) {
|
||||
|
||||
// DetailedRoute is just a Route with some extra fields, e.g. TunnelName.
|
||||
type DetailedRoute struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Network CIDR `json:"network"`
|
||||
TunnelID uuid.UUID `json:"tunnel_id"`
|
||||
// Optional field. When unset, it means the DetailedRoute belongs to the default virtual network.
|
||||
@@ -115,7 +118,8 @@ func (r DetailedRoute) TableString() string {
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"%s\t%s\t%s\t%s\t%s\t%s\t%s\t",
|
||||
"%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t",
|
||||
r.ID,
|
||||
r.Network.String(),
|
||||
vnetColumn,
|
||||
r.Comment,
|
||||
@@ -126,12 +130,6 @@ func (r DetailedRoute) TableString() string {
|
||||
)
|
||||
}
|
||||
|
||||
type DeleteRouteParams struct {
|
||||
Network net.IPNet
|
||||
// Optional field. If unset, backend will assume the default vnet for the account.
|
||||
VNetID *uuid.UUID
|
||||
}
|
||||
|
||||
type GetRouteByIpParams struct {
|
||||
Ip net.IP
|
||||
// Optional field. If unset, backend will assume the default vnet for the account.
|
||||
@@ -158,7 +156,7 @@ func (r *RESTClient) ListRoutes(filter *IpRouteFilter) ([]*DetailedRoute, error)
|
||||
// AddRoute calls the Tunnelstore POST endpoint for a given route.
|
||||
func (r *RESTClient) AddRoute(newRoute NewRoute) (Route, error) {
|
||||
endpoint := r.baseEndpoints.accountRoutes
|
||||
endpoint.Path = path.Join(endpoint.Path, "network", url.PathEscape(newRoute.Network.String()))
|
||||
endpoint.Path = path.Join(endpoint.Path)
|
||||
resp, err := r.sendRequest("POST", endpoint, newRoute)
|
||||
if err != nil {
|
||||
return Route{}, errors.Wrap(err, "REST request failed")
|
||||
@@ -173,10 +171,9 @@ func (r *RESTClient) AddRoute(newRoute NewRoute) (Route, error) {
|
||||
}
|
||||
|
||||
// DeleteRoute calls the Tunnelstore DELETE endpoint for a given route.
|
||||
func (r *RESTClient) DeleteRoute(params DeleteRouteParams) error {
|
||||
func (r *RESTClient) DeleteRoute(id uuid.UUID) error {
|
||||
endpoint := r.baseEndpoints.accountRoutes
|
||||
endpoint.Path = path.Join(endpoint.Path, "network", url.PathEscape(params.Network.String()))
|
||||
setVnetParam(&endpoint, params.VNetID)
|
||||
endpoint.Path = path.Join(endpoint.Path, url.PathEscape(id.String()))
|
||||
|
||||
resp, err := r.sendRequest("DELETE", endpoint, nil)
|
||||
if err != nil {
|
||||
|
||||
+25
-18
@@ -58,31 +58,29 @@ type IpRouteFilter struct {
|
||||
|
||||
// NewIpRouteFilterFromCLI parses CLI flags to discover which filters should get applied.
|
||||
func NewIpRouteFilterFromCLI(c *cli.Context) (*IpRouteFilter, error) {
|
||||
f := &IpRouteFilter{
|
||||
queryParams: url.Values{},
|
||||
}
|
||||
f := NewIPRouteFilter()
|
||||
|
||||
// Set deletion filter
|
||||
if flag := filterIpRouteDeleted.Name; c.IsSet(flag) && c.Bool(flag) {
|
||||
f.deleted()
|
||||
f.Deleted()
|
||||
} else {
|
||||
f.notDeleted()
|
||||
f.NotDeleted()
|
||||
}
|
||||
|
||||
if subset, err := cidrFromFlag(c, filterSubsetIpRoute); err != nil {
|
||||
return nil, err
|
||||
} else if subset != nil {
|
||||
f.networkIsSupersetOf(*subset)
|
||||
f.NetworkIsSupersetOf(*subset)
|
||||
}
|
||||
|
||||
if superset, err := cidrFromFlag(c, filterSupersetIpRoute); err != nil {
|
||||
return nil, err
|
||||
} else if superset != nil {
|
||||
f.networkIsSupersetOf(*superset)
|
||||
f.NetworkIsSupersetOf(*superset)
|
||||
}
|
||||
|
||||
if comment := c.String(filterIpRouteComment.Name); comment != "" {
|
||||
f.commentIs(comment)
|
||||
f.CommentIs(comment)
|
||||
}
|
||||
|
||||
if tunnelID := c.String(filterIpRouteTunnelID.Name); tunnelID != "" {
|
||||
@@ -90,7 +88,7 @@ func NewIpRouteFilterFromCLI(c *cli.Context) (*IpRouteFilter, error) {
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Couldn't parse UUID from %s", filterIpRouteTunnelID.Name)
|
||||
}
|
||||
f.tunnelID(u)
|
||||
f.TunnelID(u)
|
||||
}
|
||||
|
||||
if vnetId := c.String(filterIpRouteByVnet.Name); vnetId != "" {
|
||||
@@ -98,7 +96,7 @@ func NewIpRouteFilterFromCLI(c *cli.Context) (*IpRouteFilter, error) {
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Couldn't parse UUID from %s", filterIpRouteByVnet.Name)
|
||||
}
|
||||
f.vnetID(u)
|
||||
f.VNetID(u)
|
||||
}
|
||||
|
||||
if maxFetch := c.Int("max-fetch-size"); maxFetch > 0 {
|
||||
@@ -124,35 +122,44 @@ func cidrFromFlag(c *cli.Context, flag cli.StringFlag) (*net.IPNet, error) {
|
||||
return subset, nil
|
||||
}
|
||||
|
||||
func (f *IpRouteFilter) commentIs(comment string) {
|
||||
func NewIPRouteFilter() *IpRouteFilter {
|
||||
values := &IpRouteFilter{queryParams: url.Values{}}
|
||||
|
||||
// always list cfd_tunnel routes only
|
||||
values.queryParams.Set("tun_types", "cfd_tunnel")
|
||||
|
||||
return values
|
||||
}
|
||||
|
||||
func (f *IpRouteFilter) CommentIs(comment string) {
|
||||
f.queryParams.Set("comment", comment)
|
||||
}
|
||||
|
||||
func (f *IpRouteFilter) notDeleted() {
|
||||
func (f *IpRouteFilter) NotDeleted() {
|
||||
f.queryParams.Set("is_deleted", "false")
|
||||
}
|
||||
|
||||
func (f *IpRouteFilter) deleted() {
|
||||
func (f *IpRouteFilter) Deleted() {
|
||||
f.queryParams.Set("is_deleted", "true")
|
||||
}
|
||||
|
||||
func (f *IpRouteFilter) networkIsSubsetOf(superset net.IPNet) {
|
||||
func (f *IpRouteFilter) NetworkIsSubsetOf(superset net.IPNet) {
|
||||
f.queryParams.Set("network_subset", superset.String())
|
||||
}
|
||||
|
||||
func (f *IpRouteFilter) networkIsSupersetOf(subset net.IPNet) {
|
||||
func (f *IpRouteFilter) NetworkIsSupersetOf(subset net.IPNet) {
|
||||
f.queryParams.Set("network_superset", subset.String())
|
||||
}
|
||||
|
||||
func (f *IpRouteFilter) existedAt(existedAt time.Time) {
|
||||
func (f *IpRouteFilter) ExistedAt(existedAt time.Time) {
|
||||
f.queryParams.Set("existed_at", existedAt.Format(time.RFC3339))
|
||||
}
|
||||
|
||||
func (f *IpRouteFilter) tunnelID(id uuid.UUID) {
|
||||
func (f *IpRouteFilter) TunnelID(id uuid.UUID) {
|
||||
f.queryParams.Set("tunnel_id", id.String())
|
||||
}
|
||||
|
||||
func (f *IpRouteFilter) vnetID(id uuid.UUID) {
|
||||
func (f *IpRouteFilter) VNetID(id uuid.UUID) {
|
||||
f.queryParams.Set("virtual_network_id", id.String())
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ func TestDetailedRouteJsonRoundtrip(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
`{
|
||||
"id":"91ebc578-cc99-4641-9937-0fb630505fa0",
|
||||
"network":"10.1.2.40/29",
|
||||
"tunnel_id":"fba6ffea-807f-4e7a-a740-4184ee1b82c8",
|
||||
"comment":"test",
|
||||
@@ -80,6 +81,7 @@ func TestDetailedRouteJsonRoundtrip(t *testing.T) {
|
||||
},
|
||||
{
|
||||
`{
|
||||
"id":"91ebc578-cc99-4641-9937-0fb630505fa0",
|
||||
"network":"10.1.2.40/29",
|
||||
"tunnel_id":"fba6ffea-807f-4e7a-a740-4184ee1b82c8",
|
||||
"virtual_network_id":"38c95083-8191-4110-8339-3f438d44fdb9",
|
||||
@@ -167,9 +169,10 @@ func TestRouteTableString(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, network)
|
||||
r := DetailedRoute{
|
||||
ID: uuid.Nil,
|
||||
Network: CIDR(*network),
|
||||
}
|
||||
row := r.TableString()
|
||||
fmt.Println(row)
|
||||
require.True(t, strings.HasPrefix(row, "1.2.3.4/32"))
|
||||
require.True(t, strings.HasPrefix(row, "00000000-0000-0000-0000-000000000000\t1.2.3.4/32"))
|
||||
}
|
||||
|
||||
+6
-1
@@ -159,9 +159,14 @@ func (r *RESTClient) GetManagementToken(tunnelID uuid.UUID) (token string, err e
|
||||
return "", r.statusCodeToError("get tunnel token", resp)
|
||||
}
|
||||
|
||||
func (r *RESTClient) DeleteTunnel(tunnelID uuid.UUID) error {
|
||||
func (r *RESTClient) DeleteTunnel(tunnelID uuid.UUID, cascade bool) error {
|
||||
endpoint := r.baseEndpoints.accountLevel
|
||||
endpoint.Path = path.Join(endpoint.Path, fmt.Sprintf("%v", tunnelID))
|
||||
// Cascade will delete all tunnel dependencies (connections, routes, etc.) that
|
||||
// are linked to the deleted tunnel.
|
||||
if cascade {
|
||||
endpoint.RawQuery = "cascade=true"
|
||||
}
|
||||
resp, err := r.sendRequest("DELETE", endpoint, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "REST request failed")
|
||||
|
||||
+7
-11
@@ -1,5 +1,4 @@
|
||||
pinned_go: &pinned_go go=1.19.6-1
|
||||
pinned_go_fips: &pinned_go_fips go-boring=1.19.6-1
|
||||
pinned_go: &pinned_go go-boring=1.21.5-1
|
||||
|
||||
build_dir: &build_dir /cfsetup_build
|
||||
default-flavor: bullseye
|
||||
@@ -19,16 +18,13 @@ buster: &buster
|
||||
- make cloudflared
|
||||
build-fips:
|
||||
build_dir: *build_dir
|
||||
builddeps: &build_deps_fips
|
||||
- *pinned_go_fips
|
||||
- build-essential
|
||||
- gotest-to-teamcity
|
||||
builddeps: *build_deps
|
||||
pre-cache: *build_pre_cache
|
||||
post-cache:
|
||||
- export GOOS=linux
|
||||
- export GOARCH=amd64
|
||||
- export FIPS=true
|
||||
- make cloudflared
|
||||
- export FIPS=true
|
||||
cover:
|
||||
build_dir: *build_dir
|
||||
builddeps: *build_deps
|
||||
@@ -72,7 +68,7 @@ buster: &buster
|
||||
github-fips-release-pkgs:
|
||||
build_dir: *build_dir
|
||||
builddeps:
|
||||
- *pinned_go_fips
|
||||
- *pinned_go
|
||||
- build-essential
|
||||
- fakeroot
|
||||
- rubygem-fpm
|
||||
@@ -111,7 +107,7 @@ buster: &buster
|
||||
build-fips-internal-deb:
|
||||
build_dir: *build_dir
|
||||
builddeps: &build_fips_deb_deps
|
||||
- *pinned_go_fips
|
||||
- *pinned_go
|
||||
- build-essential
|
||||
- fakeroot
|
||||
- rubygem-fpm
|
||||
@@ -195,7 +191,7 @@ buster: &buster
|
||||
- make test | gotest-to-teamcity
|
||||
test-fips:
|
||||
build_dir: *build_dir
|
||||
builddeps: *build_deps_fips
|
||||
builddeps: *build_deps
|
||||
pre-cache: *build_pre_cache
|
||||
post-cache:
|
||||
- export GOOS=linux
|
||||
@@ -227,7 +223,7 @@ buster: &buster
|
||||
component-test-fips:
|
||||
build_dir: *build_dir
|
||||
builddeps:
|
||||
- *pinned_go_fips
|
||||
- *pinned_go
|
||||
- python3.7
|
||||
- python3-pip
|
||||
- python3-setuptools
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@
|
||||
<!--Set the cloudflared bin location to the Path Environment Variable-->
|
||||
<Environment Id="ENV0"
|
||||
Name="PATH"
|
||||
Value="[INSTALLDIR]."
|
||||
Value="[INSTALLDIR]"
|
||||
Permanent="no"
|
||||
Part="last"
|
||||
Action="create"
|
||||
|
||||
@@ -70,14 +70,14 @@ func ssh(c *cli.Context) error {
|
||||
|
||||
// get the hostname from the cmdline and error out if its not provided
|
||||
rawHostName := c.String(sshHostnameFlag)
|
||||
hostname, err := validation.ValidateHostname(rawHostName)
|
||||
if err != nil || rawHostName == "" {
|
||||
url, err := parseURL(rawHostName)
|
||||
if err != nil {
|
||||
log.Err(err).Send()
|
||||
return cli.ShowCommandHelp(c, "ssh")
|
||||
}
|
||||
originURL := ensureURLScheme(hostname)
|
||||
|
||||
// get the headers from the cmdline and add them
|
||||
headers := buildRequestHeaders(c.StringSlice(sshHeaderFlag))
|
||||
headers := parseRequestHeaders(c.StringSlice(sshHeaderFlag))
|
||||
if c.IsSet(sshTokenIDFlag) {
|
||||
headers.Set(cfAccessClientIDHeader, c.String(sshTokenIDFlag))
|
||||
}
|
||||
@@ -89,9 +89,9 @@ func ssh(c *cli.Context) error {
|
||||
carrier.SetBastionDest(headers, c.String(sshDestinationFlag))
|
||||
|
||||
options := &carrier.StartOptions{
|
||||
OriginURL: originURL,
|
||||
OriginURL: url.String(),
|
||||
Headers: headers,
|
||||
Host: hostname,
|
||||
Host: url.Host,
|
||||
}
|
||||
|
||||
if connectTo := c.String(sshConnectTo); connectTo != "" {
|
||||
@@ -138,20 +138,9 @@ func ssh(c *cli.Context) error {
|
||||
// default to 10 if provided but unset
|
||||
maxMessages = 10
|
||||
}
|
||||
logger := log.With().Str("host", hostname).Logger()
|
||||
logger := log.With().Str("host", url.Host).Logger()
|
||||
s = stream.NewDebugStream(s, &logger, maxMessages)
|
||||
}
|
||||
carrier.StartClient(wsConn, s, options)
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildRequestHeaders(values []string) http.Header {
|
||||
headers := make(http.Header)
|
||||
for _, valuePair := range values {
|
||||
header, value, found := strings.Cut(valuePair, ":")
|
||||
if found {
|
||||
headers.Add(strings.TrimSpace(header), strings.TrimSpace(value))
|
||||
}
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package access
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBuildRequestHeaders(t *testing.T) {
|
||||
headers := make(http.Header)
|
||||
headers.Add("client", "value")
|
||||
headers.Add("secret", "safe-value")
|
||||
|
||||
values := buildRequestHeaders([]string{"client: value", "secret: safe-value", "trash", "cf-trace-id: 000:000:0:1:asd"})
|
||||
assert.Equal(t, headers.Get("client"), values.Get("client"))
|
||||
assert.Equal(t, headers.Get("secret"), values.Get("secret"))
|
||||
assert.Equal(t, headers.Get("cf-trace-id"), values.Get("000:000:0:1:asd"))
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
loginQuietFlag = "quiet"
|
||||
sshHostnameFlag = "hostname"
|
||||
sshDestinationFlag = "destination"
|
||||
sshURLFlag = "url"
|
||||
@@ -90,6 +91,13 @@ func Commands() []*cli.Command {
|
||||
Once authenticated with your identity provider, the login command will generate a JSON Web Token (JWT)
|
||||
scoped to your identity, the application you intend to reach, and valid for a session duration set by your
|
||||
administrator. cloudflared stores the token in local storage.`,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: loginQuietFlag,
|
||||
Aliases: []string{"q"},
|
||||
Usage: "do not print the jwt to the command line",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "curl",
|
||||
@@ -222,8 +230,7 @@ func login(c *cli.Context) error {
|
||||
log := logger.CreateLoggerFromContext(c, logger.EnableTerminalLog)
|
||||
|
||||
args := c.Args()
|
||||
rawURL := ensureURLScheme(args.First())
|
||||
appURL, err := url.Parse(rawURL)
|
||||
appURL, err := parseURL(args.First())
|
||||
if args.Len() < 1 || err != nil {
|
||||
log.Error().Msg("Please provide the url of the Access application")
|
||||
return err
|
||||
@@ -247,21 +254,15 @@ func login(c *cli.Context) error {
|
||||
fmt.Fprintln(os.Stderr, "token for provided application was empty.")
|
||||
return errors.New("empty application token")
|
||||
}
|
||||
|
||||
if c.Bool(loginQuietFlag) {
|
||||
return nil
|
||||
}
|
||||
fmt.Fprintf(os.Stdout, "Successfully fetched your token:\n\n%s\n\n", cfdToken)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ensureURLScheme prepends a URL with https:// if it doesn't have a scheme. http:// URLs will not be converted.
|
||||
func ensureURLScheme(url string) string {
|
||||
url = strings.Replace(strings.ToLower(url), "http://", "https://", 1)
|
||||
if !strings.HasPrefix(url, "https://") {
|
||||
url = fmt.Sprintf("https://%s", url)
|
||||
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
// curl provides a wrapper around curl, passing Access JWT along in request
|
||||
func curl(c *cli.Context) error {
|
||||
err := sentry.Init(sentry.ClientOptions{
|
||||
@@ -345,7 +346,7 @@ func generateToken(c *cli.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appURL, err := url.Parse(ensureURLScheme(c.String("app")))
|
||||
appURL, err := parseURL(c.String("app"))
|
||||
if err != nil || c.NumFlags() < 1 {
|
||||
fmt.Fprintln(os.Stderr, "Please provide a url.")
|
||||
return err
|
||||
@@ -398,7 +399,7 @@ func sshGen(c *cli.Context) error {
|
||||
return cli.ShowCommandHelp(c, "ssh-gen")
|
||||
}
|
||||
|
||||
originURL, err := url.Parse(ensureURLScheme(hostname))
|
||||
originURL, err := parseURL(hostname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -477,6 +478,11 @@ func processURL(s string) (*url.URL, error) {
|
||||
|
||||
// cloudflaredPath pulls the full path of cloudflared on disk
|
||||
func cloudflaredPath() string {
|
||||
path, err := os.Executable()
|
||||
if err == nil && isFileThere(path) {
|
||||
return path
|
||||
}
|
||||
|
||||
for _, p := range strings.Split(os.Getenv("PATH"), ":") {
|
||||
path := fmt.Sprintf("%s/%s", p, "cloudflared")
|
||||
if isFileThere(path) {
|
||||
@@ -499,7 +505,7 @@ func isFileThere(candidate string) bool {
|
||||
// Then makes a request to to the origin with the token to ensure it is valid.
|
||||
// Returns nil if token is valid.
|
||||
func verifyTokenAtEdge(appUrl *url.URL, appInfo *token.AppInfo, c *cli.Context, log *zerolog.Logger) error {
|
||||
headers := buildRequestHeaders(c.StringSlice(sshHeaderFlag))
|
||||
headers := parseRequestHeaders(c.StringSlice(sshHeaderFlag))
|
||||
if c.IsSet(sshTokenIDFlag) {
|
||||
headers.Add(cfAccessClientIDHeader, c.String(sshTokenIDFlag))
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package access
|
||||
|
||||
import "testing"
|
||||
|
||||
func Test_ensureURLScheme(t *testing.T) {
|
||||
type args struct {
|
||||
url string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
{"no scheme", args{"localhost:123"}, "https://localhost:123"},
|
||||
{"http scheme", args{"http://test"}, "https://test"},
|
||||
{"https scheme", args{"https://test"}, "https://test"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := ensureURLScheme(tt.args.url); got != tt.want {
|
||||
t.Errorf("ensureURLScheme() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package access
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/http/httpguts"
|
||||
)
|
||||
|
||||
// parseRequestHeaders will take user-provided header values as strings "Content-Type: application/json" and create
|
||||
// a http.Header object.
|
||||
func parseRequestHeaders(values []string) http.Header {
|
||||
headers := make(http.Header)
|
||||
for _, valuePair := range values {
|
||||
header, value, found := strings.Cut(valuePair, ":")
|
||||
if found {
|
||||
headers.Add(strings.TrimSpace(header), strings.TrimSpace(value))
|
||||
}
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
// parseHostname will attempt to convert a user provided URL string into a string with some light error checking on
|
||||
// certain expectations from the URL.
|
||||
// Will convert all HTTP URLs to HTTPS
|
||||
func parseURL(input string) (*url.URL, error) {
|
||||
if input == "" {
|
||||
return nil, errors.New("no input provided")
|
||||
}
|
||||
if !strings.HasPrefix(input, "https://") && !strings.HasPrefix(input, "http://") {
|
||||
input = fmt.Sprintf("https://%s", input)
|
||||
}
|
||||
url, err := url.ParseRequestURI(input)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse as URL: %w", err)
|
||||
}
|
||||
if url.Scheme != "https" {
|
||||
url.Scheme = "https"
|
||||
}
|
||||
if url.Host == "" {
|
||||
return nil, errors.New("failed to parse Host")
|
||||
}
|
||||
host, err := httpguts.PunycodeHostPort(url.Host)
|
||||
if err != nil || host == "" {
|
||||
return nil, err
|
||||
}
|
||||
if !httpguts.ValidHostHeader(host) {
|
||||
return nil, errors.New("invalid Host provided")
|
||||
}
|
||||
url.Host = host
|
||||
return url, nil
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package access
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseRequestHeaders(t *testing.T) {
|
||||
values := parseRequestHeaders([]string{"client: value", "secret: safe-value", "trash", "cf-trace-id: 000:000:0:1:asd"})
|
||||
assert.Len(t, values, 3)
|
||||
assert.Equal(t, "value", values.Get("client"))
|
||||
assert.Equal(t, "safe-value", values.Get("secret"))
|
||||
assert.Equal(t, "000:000:0:1:asd", values.Get("cf-trace-id"))
|
||||
}
|
||||
|
||||
func TestParseURL(t *testing.T) {
|
||||
schemes := []string{
|
||||
"http://",
|
||||
"https://",
|
||||
"",
|
||||
}
|
||||
hosts := []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{"localhost", "localhost"},
|
||||
{"127.0.0.1", "127.0.0.1"},
|
||||
{"127.0.0.1:9090", "127.0.0.1:9090"},
|
||||
{"::1", "::1"},
|
||||
{"::1:8080", "::1:8080"},
|
||||
{"[::1]", "[::1]"},
|
||||
{"[::1]:8080", "[::1]:8080"},
|
||||
{":8080", ":8080"},
|
||||
{"example.com", "example.com"},
|
||||
{"hello.example.com", "hello.example.com"},
|
||||
{"bücher.example.com", "xn--bcher-kva.example.com"},
|
||||
}
|
||||
paths := []string{
|
||||
"",
|
||||
"/test",
|
||||
"/example.com?qwe=123",
|
||||
}
|
||||
for i, scheme := range schemes {
|
||||
for j, host := range hosts {
|
||||
for k, path := range paths {
|
||||
t.Run(fmt.Sprintf("%d_%d_%d", i, j, k), func(t *testing.T) {
|
||||
input := fmt.Sprintf("%s%s%s", scheme, host.input, path)
|
||||
expected := fmt.Sprintf("%s%s%s", "https://", host.expected, path)
|
||||
url, err := parseURL(input)
|
||||
assert.NoError(t, err, "input: %s\texpected: %s", input, expected)
|
||||
assert.Equal(t, expected, url.String())
|
||||
assert.Equal(t, host.expected, url.Host)
|
||||
assert.Equal(t, "https", url.Scheme)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("no input", func(t *testing.T) {
|
||||
_, err := parseURL("")
|
||||
assert.ErrorContains(t, err, "no input provided")
|
||||
})
|
||||
|
||||
t.Run("missing host", func(t *testing.T) {
|
||||
_, err := parseURL("https:///host")
|
||||
assert.ErrorContains(t, err, "failed to parse Host")
|
||||
})
|
||||
|
||||
t.Run("invalid path only", func(t *testing.T) {
|
||||
_, err := parseURL("/host")
|
||||
assert.ErrorContains(t, err, "failed to parse Host")
|
||||
})
|
||||
|
||||
t.Run("invalid parse URL", func(t *testing.T) {
|
||||
_, err := parseURL("https://host\\host")
|
||||
assert.ErrorContains(t, err, "failed to parse as URL")
|
||||
})
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !windows && !darwin && !linux
|
||||
// +build !windows,!darwin,!linux
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package main
|
||||
|
||||
@@ -370,7 +369,7 @@ func uninstallSystemd(log *zerolog.Logger) error {
|
||||
// Get only the installed services
|
||||
installedServices := make(map[string]ServiceTemplate)
|
||||
for serviceName, serviceTemplate := range systemdAllTemplates {
|
||||
if err := runCommand("systemctl", "status", serviceName); err == nil {
|
||||
if err := runCommand("systemctl", "list-units", "--all", "|", "grep", serviceName); err == nil {
|
||||
installedServices[serviceName] = serviceTemplate
|
||||
} else {
|
||||
log.Info().Msgf("Service '%s' not installed, skipping its uninstall", serviceName)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -340,7 +340,7 @@ func StartServer(
|
||||
logClientOptions(c, log)
|
||||
|
||||
// this context drives the server, when it's cancelled tunnel and all other components (origins, dns, etc...) should stop
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(c.Context)
|
||||
defer cancel()
|
||||
|
||||
go waitForSignal(graceShutdownC, log)
|
||||
@@ -392,7 +392,7 @@ func StartServer(
|
||||
observer.SendURL(quickTunnelURL)
|
||||
}
|
||||
|
||||
tunnelConfig, orchestratorConfig, err := prepareTunnelConfig(c, info, log, logTransport, observer, namedTunnel)
|
||||
tunnelConfig, orchestratorConfig, err := prepareTunnelConfig(ctx, c, info, log, logTransport, observer, namedTunnel)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("Couldn't start tunnel")
|
||||
return err
|
||||
|
||||
@@ -4,10 +4,12 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cloudflare/cloudflared/features"
|
||||
)
|
||||
|
||||
func TestDedup(t *testing.T) {
|
||||
expected := []string{"a", "b"}
|
||||
actual := dedup([]string{"a", "b", "a"})
|
||||
actual := features.Dedup([]string{"a", "b", "a"})
|
||||
require.ElementsMatch(t, expected, actual)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
mathRand "math/rand"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
@@ -33,9 +33,9 @@ import (
|
||||
const secretValue = "*****"
|
||||
|
||||
var (
|
||||
developerPortal = "https://developers.cloudflare.com/argo-tunnel"
|
||||
serviceUrl = developerPortal + "/reference/service/"
|
||||
argumentsUrl = developerPortal + "/reference/arguments/"
|
||||
developerPortal = "https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup"
|
||||
serviceUrl = developerPortal + "/tunnel-guide/local/as-a-service/"
|
||||
argumentsUrl = developerPortal + "/tunnel-guide/local/local-management/arguments/"
|
||||
|
||||
secretFlags = [2]*altsrc.StringFlag{credentialsContentsFlag, tunnelTokenFlag}
|
||||
|
||||
@@ -113,6 +113,7 @@ func dnsProxyStandAlone(c *cli.Context, namedTunnel *connection.NamedTunnelPrope
|
||||
}
|
||||
|
||||
func prepareTunnelConfig(
|
||||
ctx context.Context,
|
||||
c *cli.Context,
|
||||
info *cliutil.BuildInfo,
|
||||
log, logTransport *zerolog.Logger,
|
||||
@@ -132,22 +133,36 @@ func prepareTunnelConfig(
|
||||
tags = append(tags, tunnelpogs.Tag{Name: "ID", Value: clientID.String()})
|
||||
|
||||
transportProtocol := c.String("protocol")
|
||||
needPQ := c.Bool("post-quantum")
|
||||
if needPQ {
|
||||
|
||||
clientFeatures := features.Dedup(append(c.StringSlice("features"), features.DefaultFeatures...))
|
||||
|
||||
staticFeatures := features.StaticFeatures{}
|
||||
if c.Bool("post-quantum") {
|
||||
if FipsEnabled {
|
||||
return nil, nil, fmt.Errorf("post-quantum not supported in FIPS mode")
|
||||
}
|
||||
pqMode := features.PostQuantumStrict
|
||||
staticFeatures.PostQuantumMode = &pqMode
|
||||
}
|
||||
featureSelector, err := features.NewFeatureSelector(ctx, namedTunnel.Credentials.AccountTag, staticFeatures, log)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "Failed to create feature selector")
|
||||
}
|
||||
pqMode := featureSelector.PostQuantumMode()
|
||||
if pqMode == features.PostQuantumStrict {
|
||||
// Error if the user tries to force a non-quic transport protocol
|
||||
if transportProtocol != connection.AutoSelectFlag && transportProtocol != connection.QUIC.String() {
|
||||
return nil, nil, fmt.Errorf("post-quantum is only supported with the quic transport")
|
||||
}
|
||||
transportProtocol = connection.QUIC.String()
|
||||
clientFeatures = append(clientFeatures, features.FeaturePostQuantum)
|
||||
|
||||
log.Info().Msgf(
|
||||
"Using hybrid post-quantum key agreement %s",
|
||||
supervisor.PQKexName,
|
||||
)
|
||||
}
|
||||
|
||||
clientFeatures := dedup(append(c.StringSlice("features"), features.DefaultFeatures...))
|
||||
if needPQ {
|
||||
clientFeatures = append(clientFeatures, features.FeaturePostQuantum)
|
||||
}
|
||||
namedTunnel.Client = tunnelpogs.ClientInfo{
|
||||
ClientID: clientID[:],
|
||||
Features: clientFeatures,
|
||||
@@ -203,15 +218,6 @@ func prepareTunnelConfig(
|
||||
log.Warn().Str("edgeIPVersion", edgeIPVersion.String()).Err(err).Msg("Overriding edge-ip-version")
|
||||
}
|
||||
|
||||
var pqKexIdx int
|
||||
if needPQ {
|
||||
pqKexIdx = mathRand.Intn(len(supervisor.PQKexes))
|
||||
log.Info().Msgf(
|
||||
"Using experimental hybrid post-quantum key agreement %s",
|
||||
supervisor.PQKexNames[supervisor.PQKexes[pqKexIdx]],
|
||||
)
|
||||
}
|
||||
|
||||
tunnelConfig := &supervisor.TunnelConfig{
|
||||
GracePeriod: gracePeriod,
|
||||
ReplaceExisting: c.Bool("force"),
|
||||
@@ -222,7 +228,6 @@ func prepareTunnelConfig(
|
||||
EdgeIPVersion: edgeIPVersion,
|
||||
EdgeBindAddr: edgeBindAddr,
|
||||
HAConnections: c.Int(haConnectionsFlag),
|
||||
IncidentLookup: supervisor.NewIncidentLookup(),
|
||||
IsAutoupdated: c.Bool("is-autoupdated"),
|
||||
LBPool: c.String("lb-pool"),
|
||||
Tags: tags,
|
||||
@@ -236,8 +241,7 @@ func prepareTunnelConfig(
|
||||
NamedTunnel: namedTunnel,
|
||||
ProtocolSelector: protocolSelector,
|
||||
EdgeTLSConfigs: edgeTLSConfigs,
|
||||
NeedPQ: needPQ,
|
||||
PQKexIdx: pqKexIdx,
|
||||
FeatureSelector: featureSelector,
|
||||
MaxEdgeAddrRetries: uint8(c.Int("max-edge-addr-retries")),
|
||||
UDPUnregisterSessionTimeout: c.Duration(udpUnregisterSessionTimeoutFlag),
|
||||
DisableQUICPathMTUDiscovery: c.Bool(quicDisablePathMTUDiscovery),
|
||||
@@ -280,25 +284,6 @@ func isRunningFromTerminal() bool {
|
||||
return term.IsTerminal(int(os.Stdout.Fd()))
|
||||
}
|
||||
|
||||
// Remove any duplicates from the slice
|
||||
func dedup(slice []string) []string {
|
||||
|
||||
// Convert the slice into a set
|
||||
set := make(map[string]bool, 0)
|
||||
for _, str := range slice {
|
||||
set[str] = true
|
||||
}
|
||||
|
||||
// Convert the set back into a slice
|
||||
keys := make([]string, len(set))
|
||||
i := 0
|
||||
for str := range set {
|
||||
keys[i] = str
|
||||
i++
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// ParseConfigIPVersion returns the IP version from possible expected values from config
|
||||
func parseConfigIPVersion(version string) (v allregions.ConfigIPVersion, err error) {
|
||||
switch version {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
// TODO: Remove the above build tag and include this test when we start compiling with Golang 1.10.0+
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ func testURLCommand(c *cli.Context) error {
|
||||
}
|
||||
|
||||
_, i := ing.FindMatchingRule(requestURL.Hostname(), requestURL.Path)
|
||||
fmt.Printf("Matched rule #%d\n", i+1)
|
||||
fmt.Printf("Matched rule #%d\n", i)
|
||||
fmt.Println(ing.Rules[i].MultiLineString())
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package tunnel
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ func (sc *subcommandContext) create(name string, credentialsFilePath string, sec
|
||||
var errorLines []string
|
||||
errorLines = append(errorLines, fmt.Sprintf("Your tunnel '%v' was created with ID %v. However, cloudflared couldn't write tunnel credentials to %s.", tunnel.Name, tunnel.ID, credentialsFilePath))
|
||||
errorLines = append(errorLines, fmt.Sprintf("The file-writing error is: %v", writeFileErr))
|
||||
if deleteErr := client.DeleteTunnel(tunnel.ID); deleteErr != nil {
|
||||
if deleteErr := client.DeleteTunnel(tunnel.ID, true); deleteErr != nil {
|
||||
errorLines = append(errorLines, fmt.Sprintf("Cloudflared tried to delete the tunnel for you, but encountered an error. You should use `cloudflared tunnel delete %v` to delete the tunnel yourself, because the tunnel can't be run without the tunnelfile.", tunnel.ID))
|
||||
errorLines = append(errorLines, fmt.Sprintf("The delete tunnel error is: %v", deleteErr))
|
||||
} else {
|
||||
@@ -206,13 +206,8 @@ func (sc *subcommandContext) delete(tunnelIDs []uuid.UUID) error {
|
||||
if !tunnel.DeletedAt.IsZero() {
|
||||
return fmt.Errorf("Tunnel %s has already been deleted", tunnel.ID)
|
||||
}
|
||||
if forceFlagSet {
|
||||
if err := client.CleanupConnections(tunnel.ID, cfapi.NewCleanupParams()); err != nil {
|
||||
return errors.Wrapf(err, "Error cleaning up connections for tunnel %s", tunnel.ID)
|
||||
}
|
||||
}
|
||||
|
||||
if err := client.DeleteTunnel(tunnel.ID); err != nil {
|
||||
if err := client.DeleteTunnel(tunnel.ID, forceFlagSet); err != nil {
|
||||
return errors.Wrapf(err, "Error deleting tunnel %s", tunnel.ID)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/cloudflare/cloudflared/cfapi"
|
||||
@@ -24,12 +27,12 @@ func (sc *subcommandContext) addRoute(newRoute cfapi.NewRoute) (cfapi.Route, err
|
||||
return client.AddRoute(newRoute)
|
||||
}
|
||||
|
||||
func (sc *subcommandContext) deleteRoute(params cfapi.DeleteRouteParams) error {
|
||||
func (sc *subcommandContext) deleteRoute(id uuid.UUID) error {
|
||||
client, err := sc.client()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, noClientMsg)
|
||||
}
|
||||
return client.DeleteRoute(params)
|
||||
return client.DeleteRoute(id)
|
||||
}
|
||||
|
||||
func (sc *subcommandContext) getRouteByIP(params cfapi.GetRouteByIpParams) (cfapi.DetailedRoute, error) {
|
||||
@@ -39,3 +42,25 @@ func (sc *subcommandContext) getRouteByIP(params cfapi.GetRouteByIpParams) (cfap
|
||||
}
|
||||
return client.GetByIP(params)
|
||||
}
|
||||
|
||||
func (sc *subcommandContext) getRouteId(network net.IPNet, vnetId *uuid.UUID) (uuid.UUID, error) {
|
||||
filters := cfapi.NewIPRouteFilter()
|
||||
filters.NotDeleted()
|
||||
filters.NetworkIsSubsetOf(network)
|
||||
filters.NetworkIsSupersetOf(network)
|
||||
|
||||
if vnetId != nil {
|
||||
filters.VNetID(*vnetId)
|
||||
}
|
||||
|
||||
result, err := sc.listRoutes(filters)
|
||||
if err != nil {
|
||||
return uuid.Nil, err
|
||||
}
|
||||
|
||||
if len(result) != 1 {
|
||||
return uuid.Nil, errors.New("unable to find route for provided network and vnet")
|
||||
}
|
||||
|
||||
return result[0].ID, nil
|
||||
}
|
||||
|
||||
@@ -219,7 +219,7 @@ func (d *deleteMockTunnelStore) GetTunnelToken(tunnelID uuid.UUID) (string, erro
|
||||
return "token", nil
|
||||
}
|
||||
|
||||
func (d *deleteMockTunnelStore) DeleteTunnel(tunnelID uuid.UUID) error {
|
||||
func (d *deleteMockTunnelStore) DeleteTunnel(tunnelID uuid.UUID, cascade bool) error {
|
||||
tunnel, ok := d.mockTunnels[tunnelID]
|
||||
if !ok {
|
||||
return fmt.Errorf("Couldn't find tunnel: %v", tunnelID)
|
||||
|
||||
@@ -119,8 +119,8 @@ var (
|
||||
forceDeleteFlag = &cli.BoolFlag{
|
||||
Name: "force",
|
||||
Aliases: []string{"f"},
|
||||
Usage: "Cleans up any stale connections before the tunnel is deleted. cloudflared will not " +
|
||||
"delete a tunnel with connections without this flag.",
|
||||
Usage: "Deletes a tunnel even if tunnel is connected and it has dependencies associated to it. (eg. IP routes)." +
|
||||
" It is not possible to delete tunnels that have connections or non-deleted dependencies, without this flag.",
|
||||
EnvVars: []string{"TUNNEL_RUN_FORCE_OVERWRITE"},
|
||||
}
|
||||
selectProtocolFlag = altsrc.NewStringFlag(&cli.StringFlag{
|
||||
|
||||
@@ -21,6 +21,8 @@ var (
|
||||
Aliases: []string{"vn"},
|
||||
Usage: "The ID or name of the virtual network to which the route is associated to.",
|
||||
}
|
||||
|
||||
routeAddError = errors.New("You must supply exactly one argument, the ID or CIDR of the route you want to delete")
|
||||
)
|
||||
|
||||
func buildRouteIPSubcommand() *cli.Command {
|
||||
@@ -68,11 +70,9 @@ which virtual network's routing table you want to add the route to with:
|
||||
Name: "delete",
|
||||
Action: cliutil.ConfiguredAction(deleteRouteCommand),
|
||||
Usage: "Delete a row from your organization's private routing table",
|
||||
UsageText: "cloudflared tunnel [--config FILEPATH] route ip delete [flags] [CIDR]",
|
||||
Description: `Deletes the row for a given CIDR from your routing table. That portion of your network
|
||||
will no longer be reachable by the WARP clients. Note that if you use virtual
|
||||
networks, then you have to tell which virtual network whose routing table you
|
||||
have a row deleted from.`,
|
||||
UsageText: "cloudflared tunnel [--config FILEPATH] route ip delete [flags] [Route ID or CIDR]",
|
||||
Description: `Deletes the row for the given route ID from your routing table. That portion of your network
|
||||
will no longer be reachable.`,
|
||||
Flags: []cli.Flag{vnetFlag},
|
||||
},
|
||||
{
|
||||
@@ -187,33 +187,36 @@ func deleteRouteCommand(c *cli.Context) error {
|
||||
}
|
||||
|
||||
if c.NArg() != 1 {
|
||||
return errors.New("You must supply exactly one argument, the network whose route you want to delete (in CIDR form e.g. 1.2.3.4/32)")
|
||||
return routeAddError
|
||||
}
|
||||
|
||||
_, network, err := net.ParseCIDR(c.Args().First())
|
||||
var routeId uuid.UUID
|
||||
routeId, err = uuid.Parse(c.Args().First())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Invalid network CIDR")
|
||||
}
|
||||
if network == nil {
|
||||
return errors.New("Invalid network CIDR")
|
||||
}
|
||||
_, network, err := net.ParseCIDR(c.Args().First())
|
||||
if err != nil || network == nil {
|
||||
return routeAddError
|
||||
}
|
||||
|
||||
params := cfapi.DeleteRouteParams{
|
||||
Network: *network,
|
||||
}
|
||||
var vnetId *uuid.UUID
|
||||
if c.IsSet(vnetFlag.Name) {
|
||||
id, err := getVnetId(sc, c.String(vnetFlag.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
vnetId = &id
|
||||
}
|
||||
|
||||
if c.IsSet(vnetFlag.Name) {
|
||||
vnetId, err := getVnetId(sc, c.String(vnetFlag.Name))
|
||||
routeId, err = sc.getRouteId(*network, vnetId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.VNetID = &vnetId
|
||||
}
|
||||
|
||||
if err := sc.deleteRoute(params); err != nil {
|
||||
if err := sc.deleteRoute(routeId); err != nil {
|
||||
return errors.Wrap(err, "API error")
|
||||
}
|
||||
fmt.Printf("Successfully deleted route for %s\n", network)
|
||||
fmt.Printf("Successfully deleted route with ID %s\n", routeId)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -269,7 +272,7 @@ func formatAndPrintRouteList(routes []*cfapi.DetailedRoute) {
|
||||
defer writer.Flush()
|
||||
|
||||
// Print column headers with tabbed columns
|
||||
_, _ = fmt.Fprintln(writer, "NETWORK\tVIRTUAL NET ID\tCOMMENT\tTUNNEL ID\tTUNNEL NAME\tCREATED\tDELETED\t")
|
||||
_, _ = fmt.Fprintln(writer, "ID\tNETWORK\tVIRTUAL NET ID\tCOMMENT\tTUNNEL ID\tTUNNEL NAME\tCREATED\tDELETED\t")
|
||||
|
||||
// Loop through routes, create formatted string for each, and print using tabwriter
|
||||
for _, route := range routes {
|
||||
|
||||
@@ -56,6 +56,9 @@ func (s *WorkersService) Check() (CheckResult, error) {
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, s.url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
q := req.URL.Query()
|
||||
q.Add(OSKeyName, runtime.GOOS)
|
||||
q.Add(ArchitectureKeyName, runtime.GOARCH)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package updater
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
cloudflare==2.8.15
|
||||
cloudflare==2.14.3
|
||||
flaky==3.7.0
|
||||
pytest==7.3.1
|
||||
pytest-asyncio==0.21.0
|
||||
pyyaml==5.4.1
|
||||
pyyaml==6.0.1
|
||||
requests==2.28.2
|
||||
retrying==1.3.4
|
||||
websockets==11.0.1
|
||||
|
||||
@@ -74,7 +74,7 @@ def delete_tunnel(config):
|
||||
|
||||
@retry(stop_max_attempt_number=MAX_RETRIES, wait_fixed=BACKOFF_SECS * 1000)
|
||||
def create_dns(config, hostname, type, content):
|
||||
cf = CloudFlare.CloudFlare(debug=True, token=get_env("DNS_API_TOKEN"))
|
||||
cf = CloudFlare.CloudFlare(debug=False, token=get_env("DNS_API_TOKEN"))
|
||||
cf.zones.dns_records.post(
|
||||
config["zone_tag"],
|
||||
data={'name': hostname, 'type': type, 'content': content, 'proxied': True}
|
||||
@@ -89,7 +89,7 @@ def create_named_dns(config, random_uuid):
|
||||
|
||||
@retry(stop_max_attempt_number=MAX_RETRIES, wait_fixed=BACKOFF_SECS * 1000)
|
||||
def delete_dns(config, hostname):
|
||||
cf = CloudFlare.CloudFlare(debug=True, token=get_env("DNS_API_TOKEN"))
|
||||
cf = CloudFlare.CloudFlare(debug=False, token=get_env("DNS_API_TOKEN"))
|
||||
zone_tag = config["zone_tag"]
|
||||
dns_records = cf.zones.dns_records.get(zone_tag, params={'name': hostname})
|
||||
if len(dns_records) > 0:
|
||||
|
||||
@@ -36,17 +36,17 @@ class TestConfig:
|
||||
_ = start_cloudflared(tmp_path, config, validate_args)
|
||||
|
||||
self.match_rule(tmp_path, config,
|
||||
"http://example.com/index.html", 1)
|
||||
"http://example.com/index.html", 0)
|
||||
self.match_rule(tmp_path, config,
|
||||
"https://example.com/index.html", 1)
|
||||
"https://example.com/index.html", 0)
|
||||
self.match_rule(tmp_path, config,
|
||||
"https://api.example.com/login", 2)
|
||||
"https://api.example.com/login", 1)
|
||||
self.match_rule(tmp_path, config,
|
||||
"https://wss.example.com", 3)
|
||||
"https://wss.example.com", 2)
|
||||
self.match_rule(tmp_path, config,
|
||||
"https://ssh.example.com", 4)
|
||||
"https://ssh.example.com", 3)
|
||||
self.match_rule(tmp_path, config,
|
||||
"https://api.example.com", 5)
|
||||
"https://api.example.com", 4)
|
||||
|
||||
# This is used to check that the command tunnel ingress url <url> matches rule number <rule_num>. Note that rule number uses 1-based indexing
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import platform
|
||||
import subprocess
|
||||
from contextlib import contextmanager
|
||||
from time import sleep
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -14,8 +15,14 @@ from retrying import retry
|
||||
|
||||
from constants import METRICS_PORT, MAX_RETRIES, BACKOFF_SECS
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
def configure_logger():
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
handler = logging.StreamHandler(sys.stdout)
|
||||
logger.addHandler(handler)
|
||||
return logger
|
||||
|
||||
LOGGER = configure_logger()
|
||||
|
||||
def select_platform(plat):
|
||||
return pytest.mark.skipif(
|
||||
|
||||
@@ -257,7 +257,6 @@ type Configuration struct {
|
||||
}
|
||||
|
||||
type WarpRoutingConfig struct {
|
||||
Enabled bool `yaml:"enabled" json:"enabled"`
|
||||
ConnectTimeout *CustomDuration `yaml:"connectTimeout" json:"connectTimeout,omitempty"`
|
||||
TCPKeepAlive *CustomDuration `yaml:"tcpKeepAlive" json:"tcpKeepAlive,omitempty"`
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ func TestConfigFileSettings(t *testing.T) {
|
||||
Service: "https://localhost:8001",
|
||||
}
|
||||
warpRouting = WarpRoutingConfig{
|
||||
Enabled: true,
|
||||
ConnectTimeout: &CustomDuration{Duration: 2 * time.Second},
|
||||
TCPKeepAlive: &CustomDuration{Duration: 10 * time.Second},
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ type Orchestrator interface {
|
||||
UpdateConfig(version int32, config []byte) *pogs.UpdateConfigurationResponse
|
||||
GetConfigJSON() ([]byte, error)
|
||||
GetOriginProxy() (OriginProxy, error)
|
||||
WarpRoutingEnabled() (enabled bool)
|
||||
}
|
||||
|
||||
type NamedTunnelProperties struct {
|
||||
|
||||
+14
-3
@@ -9,6 +9,7 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -103,7 +104,7 @@ func NewQUICConnection(
|
||||
sessionDemuxChan := make(chan *packet.Session, demuxChanCapacity)
|
||||
datagramMuxer := quicpogs.NewDatagramMuxerV2(session, logger, sessionDemuxChan)
|
||||
sessionManager := datagramsession.NewManager(logger, datagramMuxer.SendToSession, sessionDemuxChan)
|
||||
packetRouter := ingress.NewPacketRouter(packetRouterConfig, datagramMuxer, logger, orchestrator.WarpRoutingEnabled)
|
||||
packetRouter := ingress.NewPacketRouter(packetRouterConfig, datagramMuxer, logger)
|
||||
|
||||
return &QUICConnection{
|
||||
session: session,
|
||||
@@ -623,9 +624,19 @@ func createUDPConnForConnIndex(connIndex uint8, localIP net.IP, logger *zerolog.
|
||||
localIP = net.IPv4zero
|
||||
}
|
||||
|
||||
listenNetwork := "udp"
|
||||
// https://github.com/quic-go/quic-go/issues/3793 DF bit cannot be set for dual stack listener on OSX
|
||||
if runtime.GOOS == "darwin" {
|
||||
if localIP.To4() != nil {
|
||||
listenNetwork = "udp4"
|
||||
} else {
|
||||
listenNetwork = "udp6"
|
||||
}
|
||||
}
|
||||
|
||||
// if port was not set yet, it will be zero, so bind will randomly allocate one.
|
||||
if port, ok := portForConnIndex[connIndex]; ok {
|
||||
udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: localIP, Port: port})
|
||||
udpConn, err := net.ListenUDP(listenNetwork, &net.UDPAddr{IP: localIP, Port: port})
|
||||
// if there wasn't an error, or if port was 0 (independently of error or not, just return)
|
||||
if err == nil {
|
||||
return udpConn, nil
|
||||
@@ -635,7 +646,7 @@ func createUDPConnForConnIndex(connIndex uint8, localIP net.IP, logger *zerolog.
|
||||
}
|
||||
|
||||
// if we reached here, then there was an error or port as not been allocated it.
|
||||
udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: localIP, Port: 0})
|
||||
udpConn, err := net.ListenUDP(listenNetwork, &net.UDPAddr{IP: localIP, Port: 0})
|
||||
if err == nil {
|
||||
udpAddr, ok := (udpConn.LocalAddr()).(*net.UDPAddr)
|
||||
if !ok {
|
||||
|
||||
@@ -621,7 +621,7 @@ func serveSession(ctx context.Context, qc *QUICConnection, edgeQUICSession quic.
|
||||
muxedPayload, err = quicpogs.SuffixType(muxedPayload, quicpogs.DatagramTypeUDP)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = edgeQUICSession.SendMessage(muxedPayload)
|
||||
err = edgeQUICSession.SendDatagram(muxedPayload)
|
||||
require.NoError(t, err)
|
||||
|
||||
readBuffer := make([]byte, len(payload)+1)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.19 as builder
|
||||
FROM golang:1.21.5 as builder
|
||||
ENV GO111MODULE=on \
|
||||
CGO_ENABLED=0
|
||||
WORKDIR /go/src/github.com/cloudflare/cloudflared/
|
||||
|
||||
@@ -28,3 +28,22 @@ func Contains(feature string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Remove any duplicates from the slice
|
||||
func Dedup(slice []string) []string {
|
||||
|
||||
// Convert the slice into a set
|
||||
set := make(map[string]bool, 0)
|
||||
for _, str := range slice {
|
||||
set[str] = true
|
||||
}
|
||||
|
||||
// Convert the set back into a slice
|
||||
keys := make([]string, len(set))
|
||||
i := 0
|
||||
for str := range set {
|
||||
keys[i] = str
|
||||
i++
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
package features
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
const (
|
||||
featureSelectorHostname = "cfd-features.argotunnel.com"
|
||||
defaultRefreshFreq = time.Hour * 6
|
||||
lookupTimeout = time.Second * 10
|
||||
)
|
||||
|
||||
type PostQuantumMode uint8
|
||||
|
||||
const (
|
||||
// Prefer post quantum, but fallback if connection cannot be established
|
||||
PostQuantumPrefer PostQuantumMode = iota
|
||||
// If the user passes the --post-quantum flag, we override
|
||||
// CurvePreferences to only support hybrid post-quantum key agreements.
|
||||
PostQuantumStrict
|
||||
)
|
||||
|
||||
// If the TXT record adds other fields, the umarshal logic will ignore those keys
|
||||
// If the TXT record is missing a key, the field will unmarshal to the default Go value
|
||||
// pq was removed in TUN-7970
|
||||
type featuresRecord struct{}
|
||||
|
||||
func NewFeatureSelector(ctx context.Context, accountTag string, staticFeatures StaticFeatures, logger *zerolog.Logger) (*FeatureSelector, error) {
|
||||
return newFeatureSelector(ctx, accountTag, logger, newDNSResolver(), staticFeatures, defaultRefreshFreq)
|
||||
}
|
||||
|
||||
// FeatureSelector determines if this account will try new features. It preiodically queries a DNS TXT record
|
||||
// to see which features are turned on
|
||||
type FeatureSelector struct {
|
||||
accountHash int32
|
||||
logger *zerolog.Logger
|
||||
resolver resolver
|
||||
|
||||
staticFeatures StaticFeatures
|
||||
|
||||
// lock protects concurrent access to dynamic features
|
||||
lock sync.RWMutex
|
||||
features featuresRecord
|
||||
}
|
||||
|
||||
// Features set by user provided flags
|
||||
type StaticFeatures struct {
|
||||
PostQuantumMode *PostQuantumMode
|
||||
}
|
||||
|
||||
func newFeatureSelector(ctx context.Context, accountTag string, logger *zerolog.Logger, resolver resolver, staticFeatures StaticFeatures, refreshFreq time.Duration) (*FeatureSelector, error) {
|
||||
selector := &FeatureSelector{
|
||||
accountHash: switchThreshold(accountTag),
|
||||
logger: logger,
|
||||
resolver: resolver,
|
||||
staticFeatures: staticFeatures,
|
||||
}
|
||||
|
||||
if err := selector.refresh(ctx); err != nil {
|
||||
logger.Err(err).Msg("Failed to fetch features, default to disable")
|
||||
}
|
||||
|
||||
// Run refreshLoop next time we have a new feature to rollout
|
||||
|
||||
return selector, nil
|
||||
}
|
||||
|
||||
func (fs *FeatureSelector) PostQuantumMode() PostQuantumMode {
|
||||
if fs.staticFeatures.PostQuantumMode != nil {
|
||||
return *fs.staticFeatures.PostQuantumMode
|
||||
}
|
||||
|
||||
return PostQuantumPrefer
|
||||
}
|
||||
|
||||
func (fs *FeatureSelector) refreshLoop(ctx context.Context, refreshFreq time.Duration) {
|
||||
ticker := time.NewTicker(refreshFreq)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
err := fs.refresh(ctx)
|
||||
if err != nil {
|
||||
fs.logger.Err(err).Msg("Failed to refresh feature selector")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (fs *FeatureSelector) refresh(ctx context.Context) error {
|
||||
record, err := fs.resolver.lookupRecord(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var features featuresRecord
|
||||
if err := json.Unmarshal(record, &features); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fs.lock.Lock()
|
||||
defer fs.lock.Unlock()
|
||||
|
||||
fs.features = features
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// resolver represents an object that can look up featuresRecord
|
||||
type resolver interface {
|
||||
lookupRecord(ctx context.Context) ([]byte, error)
|
||||
}
|
||||
|
||||
type dnsResolver struct {
|
||||
resolver *net.Resolver
|
||||
}
|
||||
|
||||
func newDNSResolver() *dnsResolver {
|
||||
return &dnsResolver{
|
||||
resolver: net.DefaultResolver,
|
||||
}
|
||||
}
|
||||
|
||||
func (dr *dnsResolver) lookupRecord(ctx context.Context) ([]byte, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, lookupTimeout)
|
||||
defer cancel()
|
||||
|
||||
records, err := dr.resolver.LookupTXT(ctx, featureSelectorHostname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(records) == 0 {
|
||||
return nil, fmt.Errorf("No TXT record found for %s to determine which features to opt-in", featureSelectorHostname)
|
||||
}
|
||||
|
||||
return []byte(records[0]), nil
|
||||
}
|
||||
|
||||
func switchThreshold(accountTag string) int32 {
|
||||
h := fnv.New32a()
|
||||
_, _ = h.Write([]byte(accountTag))
|
||||
return int32(h.Sum32() % 100)
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package features
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestUnmarshalFeaturesRecord(t *testing.T) {
|
||||
tests := []struct {
|
||||
record []byte
|
||||
}{
|
||||
{
|
||||
record: []byte(`{"pq":0}`),
|
||||
},
|
||||
{
|
||||
record: []byte(`{"pq":39}`),
|
||||
},
|
||||
{
|
||||
record: []byte(`{"pq":100}`),
|
||||
},
|
||||
{
|
||||
record: []byte(`{}`), // Unmarshal to default struct if key is not present
|
||||
},
|
||||
{
|
||||
record: []byte(`{"kyber":768}`), // Unmarshal to default struct if key is not present
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
var features featuresRecord
|
||||
err := json.Unmarshal(test.record, &features)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, featuresRecord{}, features)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStaticFeatures(t *testing.T) {
|
||||
pqMode := PostQuantumStrict
|
||||
selector := newTestSelector(t, &pqMode, time.Millisecond*10)
|
||||
require.Equal(t, PostQuantumStrict, selector.PostQuantumMode())
|
||||
|
||||
// No StaticFeatures configured
|
||||
selector = newTestSelector(t, nil, time.Millisecond*10)
|
||||
require.Equal(t, PostQuantumPrefer, selector.PostQuantumMode())
|
||||
}
|
||||
|
||||
func newTestSelector(t *testing.T, pqMode *PostQuantumMode, refreshFreq time.Duration) *FeatureSelector {
|
||||
accountTag := t.Name()
|
||||
logger := zerolog.Nop()
|
||||
|
||||
resolver := &mockResolver{}
|
||||
|
||||
staticFeatures := StaticFeatures{
|
||||
PostQuantumMode: pqMode,
|
||||
}
|
||||
selector, err := newFeatureSelector(context.Background(), accountTag, &logger, resolver, staticFeatures, refreshFreq)
|
||||
require.NoError(t, err)
|
||||
|
||||
return selector
|
||||
}
|
||||
|
||||
type mockResolver struct{}
|
||||
|
||||
func (mr *mockResolver) lookupRecord(ctx context.Context) ([]byte, error) {
|
||||
return nil, fmt.Errorf("mockResolver hasn't implement lookupRecord")
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
module github.com/cloudflare/cloudflared
|
||||
|
||||
go 1.19
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/cloudflare/golibs v0.0.0-20170913112048-333127dbecfc
|
||||
github.com/coredns/coredns v1.10.0
|
||||
github.com/coreos/go-oidc/v3 v3.6.0
|
||||
github.com/coreos/go-systemd/v22 v22.5.0
|
||||
@@ -16,7 +15,7 @@ require (
|
||||
github.com/gobwas/ws v1.0.4
|
||||
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
|
||||
github.com/google/gopacket v1.1.19
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/google/uuid v1.3.1
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/mattn/go-colorable v0.1.13
|
||||
@@ -25,23 +24,23 @@ require (
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.13.0
|
||||
github.com/prometheus/client_model v0.2.0
|
||||
github.com/quic-go/quic-go v0.0.0-00010101000000-000000000000
|
||||
github.com/quic-go/quic-go v0.40.1-0.20240101045026-22b7f7744eb6
|
||||
github.com/rs/zerolog v1.20.0
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/urfave/cli/v2 v2.3.0
|
||||
go.opentelemetry.io/contrib/propagators v0.22.0
|
||||
go.opentelemetry.io/otel v1.6.3
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.3
|
||||
go.opentelemetry.io/otel/sdk v1.6.3
|
||||
go.opentelemetry.io/otel/trace v1.6.3
|
||||
go.opentelemetry.io/proto/otlp v0.15.0
|
||||
go.opentelemetry.io/otel v1.21.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0
|
||||
go.opentelemetry.io/otel/sdk v1.21.0
|
||||
go.opentelemetry.io/otel/trace v1.21.0
|
||||
go.opentelemetry.io/proto/otlp v1.0.0
|
||||
go.uber.org/automaxprocs v1.4.0
|
||||
golang.org/x/crypto v0.8.0
|
||||
golang.org/x/net v0.9.0
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/sys v0.7.0
|
||||
golang.org/x/term v0.7.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
golang.org/x/crypto v0.16.0
|
||||
golang.org/x/net v0.19.0
|
||||
golang.org/x/sync v0.4.0
|
||||
golang.org/x/sys v0.15.0
|
||||
golang.org/x/term v0.15.0
|
||||
google.golang.org/protobuf v1.31.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
nhooyr.io/websocket v1.8.7
|
||||
@@ -52,8 +51,7 @@ require (
|
||||
github.com/BurntSushi/toml v1.2.0 // indirect
|
||||
github.com/apparentlymart/go-cidr v1.1.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cloudflare/circl v1.2.1-0.20220809205628-0a9554f37a47 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/coredns/caddy v1.1.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
@@ -62,15 +60,14 @@ require (
|
||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
|
||||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/logr v1.3.0 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/gobwas/httphead v0.0.0-20200921212729-da3d93bc3c58 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect
|
||||
github.com/klauspost/compress v1.15.11 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
@@ -79,24 +76,24 @@ require (
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.4.0 // indirect
|
||||
github.com/onsi/gomega v1.23.0 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.21.0 // indirect
|
||||
go.uber.org/mock v0.3.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
golang.org/x/oauth2 v0.6.0 // indirect
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd // indirect
|
||||
google.golang.org/grpc v1.51.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
golang.org/x/mod v0.11.0 // indirect
|
||||
golang.org/x/oauth2 v0.13.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.9.1 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect
|
||||
google.golang.org/grpc v1.60.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
@@ -106,12 +103,3 @@ replace github.com/urfave/cli/v2 => github.com/ipostelnik/cli/v2 v2.3.1-0.202103
|
||||
replace github.com/prometheus/golang_client => github.com/prometheus/golang_client v1.12.1
|
||||
|
||||
replace gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1
|
||||
|
||||
replace github.com/quic-go/quic-go => github.com/devincarr/quic-go v0.0.0-20230502200822-d1f4edacbee7
|
||||
|
||||
// Post-quantum tunnel RTG-1339
|
||||
replace (
|
||||
// Branches go1.19 go1.20 on github.com/cloudflare/qtls-pq
|
||||
github.com/quic-go/qtls-go1-19 => github.com/cloudflare/qtls-pq v0.0.0-20230320123031-3faac1a945b2
|
||||
github.com/quic-go/qtls-go1-20 => github.com/cloudflare/qtls-pq v0.0.0-20230320122459-4ed280d0d633
|
||||
)
|
||||
|
||||
@@ -35,45 +35,27 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
||||
github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
|
||||
github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU=
|
||||
github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
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/bwesterb/go-ristretto v1.2.2/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.2.1-0.20220809205628-0a9554f37a47 h1:YzpECHxZ9TzO7LpnKmPxItSd79lLgrR5heIlnqU4dTU=
|
||||
github.com/cloudflare/circl v1.2.1-0.20220809205628-0a9554f37a47/go.mod h1:qhx8gBILsYlbam7h09SvHDSkjpe3TfLA7b/z4rxJvkE=
|
||||
github.com/cloudflare/golibs v0.0.0-20170913112048-333127dbecfc h1:Dvk3ySBsOm5EviLx6VCyILnafPcQinXGP5jbTdHUJgE=
|
||||
github.com/cloudflare/golibs v0.0.0-20170913112048-333127dbecfc/go.mod h1:HlgKKR8V5a1wroIDDIz3/A+T+9Janfq+7n1P5sEFdi0=
|
||||
github.com/cloudflare/qtls-pq v0.0.0-20230320122459-4ed280d0d633 h1:ZTub2XMOBpxyBiJf6Q+UKqAi07yt1rZmFitriHvFd8M=
|
||||
github.com/cloudflare/qtls-pq v0.0.0-20230320122459-4ed280d0d633/go.mod h1:j/igSUc4PgBMayIsBGjAFu2i7g663rm6kZrKy4htb7E=
|
||||
github.com/cloudflare/qtls-pq v0.0.0-20230320123031-3faac1a945b2 h1:0/KuLjh9lBMiXlooAdwoo+FbLVD5DABtquB0ImEFOK0=
|
||||
github.com/cloudflare/qtls-pq v0.0.0-20230320123031-3faac1a945b2/go.mod h1:XzuZIjv4mF5cM205RHHW1d60PQtWGwMR6jx38YKuYHs=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/coredns/caddy v1.1.1 h1:2eYKZT7i6yxIfGP3qLJoJ7HAsDJqYB+X68g4NYjSrE0=
|
||||
github.com/coredns/caddy v1.1.1/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4=
|
||||
github.com/coredns/coredns v1.10.0 h1:jCfuWsBjTs0dapkkhISfPCzn5LqvSRtrFtaf/Tjj4DI=
|
||||
@@ -90,14 +72,9 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/devincarr/quic-go v0.0.0-20230502200822-d1f4edacbee7 h1:qxyoKKPXmPsbvT7SZTcvhEgUaZhEttk4f6u8rIawKj0=
|
||||
github.com/devincarr/quic-go v0.0.0-20230502200822-d1f4edacbee7/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g=
|
||||
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/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
|
||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
|
||||
@@ -115,16 +92,17 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/getsentry/sentry-go v0.16.0 h1:owk+S+5XcgJLlGR/3+3s6N4d+uKwqYvh/eS0AIMjPWo=
|
||||
github.com/getsentry/sentry-go v0.16.0/go.mod h1:ZXCloQLj0pG7mja5NK6NPf2V4A88YJ4pNlc2mOHwh6Y=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
|
||||
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
||||
github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
|
||||
github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
||||
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@@ -139,20 +117,23 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
||||
github.com/go-logr/logr v1.3.0/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-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
|
||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
|
||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
|
||||
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||
github.com/gobwas/httphead v0.0.0-20200921212729-da3d93bc3c58 h1:YyrUZvJaU8Q0QsoVo+xLFBgWDTam29PKea6GYmwvSiQ=
|
||||
github.com/gobwas/httphead v0.0.0-20200921212729-da3d93bc3c58/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||
@@ -163,13 +144,14 @@ github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/E
|
||||
github.com/gobwas/ws v1.0.4 h1:5eXU1CZhpQdq5kXbKb+sECH5Ia5KiO6CYzIzdlVx6Bs=
|
||||
github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
|
||||
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4=
|
||||
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.mod h1:nPpo7qLxd6XL3hWJG/O60sR8ZKfMCiIoNap5GvD12KU=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
|
||||
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
|
||||
github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
|
||||
github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
@@ -180,8 +162,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@@ -197,8 +177,9 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
@@ -211,8 +192,8 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
@@ -229,17 +210,15 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJY
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
|
||||
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 v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
@@ -267,8 +246,8 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
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=
|
||||
@@ -277,6 +256,7 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
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.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
@@ -297,15 +277,18 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs=
|
||||
github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo=
|
||||
github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys=
|
||||
github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
|
||||
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
||||
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
||||
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.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
|
||||
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
|
||||
github.com/philhofer/fwd v1.1.1 h1:GdGcTjf5RNAxwS4QLsiMzJYj5KEvPJD3Abr261yRQXQ=
|
||||
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
||||
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
@@ -337,8 +320,15 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
|
||||
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/quic-go/quic-go v0.40.1-0.20231203135336-87ef8ec48d55 h1:I4N3ZRnkZPbDN935Tg8QDf8fRpHp3bZ0U0/L42jBgNE=
|
||||
github.com/quic-go/quic-go v0.40.1-0.20231203135336-87ef8ec48d55/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
|
||||
github.com/quic-go/quic-go v0.40.1-0.20240101045026-22b7f7744eb6 h1:OI4WiysowCcxLtcZMGBZildo12di3ljcMN4vWdUQpoU=
|
||||
github.com/quic-go/quic-go v0.40.1-0.20240101045026-22b7f7744eb6/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
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/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.20.0 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs=
|
||||
github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
|
||||
@@ -349,30 +339,27 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
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=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
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.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ=
|
||||
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
|
||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
@@ -381,21 +368,23 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/contrib/propagators v0.22.0 h1:KGdv58M2//veiYLIhb31mofaI2LgkIPXXAZVeYVyfd8=
|
||||
go.opentelemetry.io/contrib/propagators v0.22.0/go.mod h1:xGOuXr6lLIF9BXipA4pm6UuOSI0M98U6tsI3khbOiwU=
|
||||
go.opentelemetry.io/otel v1.0.0-RC2/go.mod h1:w1thVQ7qbAy8MHb0IFj8a5Q2QU0l2ksf8u/CN8m3NOM=
|
||||
go.opentelemetry.io/otel v1.6.3 h1:FLOfo8f9JzFVFVyU+MSRJc2HdEAXQgm7pIv2uFKRSZE=
|
||||
go.opentelemetry.io/otel v1.6.3/go.mod h1:7BgNga5fNlF/iZjG06hM3yofffp0ofKCDwSXx1GC4dI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.3/go.mod h1:NEu79Xo32iVb+0gVNV8PMd7GoWqnyDXRlj04yFjqz40=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.3 h1:4/UjHWMVVc5VwX/KAtqJOHErKigMCH8NexChMuanb/o=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.3/go.mod h1:UJmXdiVVBaZ63umRUTwJuCMAV//GCMvDiQwn703/GoY=
|
||||
go.opentelemetry.io/otel/sdk v1.6.3 h1:prSHYdwCQOX5DrsEzxowH3nLhoAzEBdZhvrR79scfLs=
|
||||
go.opentelemetry.io/otel/sdk v1.6.3/go.mod h1:A4iWF7HTXa+GWL/AaqESz28VuSBIcZ+0CV+IzJ5NMiQ=
|
||||
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
|
||||
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg=
|
||||
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
|
||||
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
|
||||
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
|
||||
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
|
||||
go.opentelemetry.io/otel/trace v1.0.0-RC2/go.mod h1:JPQ+z6nNw9mqEGT8o3eoPTdnNI+Aj5JcxEsVGREIAy4=
|
||||
go.opentelemetry.io/otel/trace v1.6.3 h1:IqN4L+5b0mPNjdXIiZ90Ni4Bl5BRkDQywePLWemd9bc=
|
||||
go.opentelemetry.io/otel/trace v1.6.3/go.mod h1:GNJQusJlUgZl9/TQBPKU/Y/ty+0iVB5fjhKeJGZPGFs=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.opentelemetry.io/proto/otlp v0.15.0 h1:h0bKrvdrT/9sBwEJ6iWUqT/N/xPcS66bL4u3isneJ6w=
|
||||
go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
|
||||
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
|
||||
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
|
||||
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
|
||||
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
||||
go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0=
|
||||
go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
|
||||
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
|
||||
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@@ -403,9 +392,9 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
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.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
|
||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
|
||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -439,8 +428,9 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
|
||||
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.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -469,24 +459,24 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
|
||||
golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
|
||||
golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY=
|
||||
golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0=
|
||||
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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -497,8 +487,9 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
|
||||
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -536,31 +527,31 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -605,10 +596,10 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
|
||||
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||
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=
|
||||
@@ -635,8 +626,8 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
@@ -660,16 +651,18 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd h1:OjndDrsik+Gt+e6fs45z9AxiewiKyLKYpA45W5Kpkks=
|
||||
google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE=
|
||||
google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0=
|
||||
google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 h1:W18sezcAYs+3tDZX4F80yctqa12jcP1PUS2gQu1zTPU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 h1:6GQBEOdGkX6MMTLT9V+TjtIRZCw9VPD5Z+yHY9wMgS0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
@@ -682,13 +675,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
|
||||
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
|
||||
google.golang.org/grpc v1.60.0 h1:6FQAR0kM31P6MRdeluor2w2gPaS4SVNrD/DNTxrQ15k=
|
||||
google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -701,10 +689,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
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=
|
||||
|
||||
+1
-5
@@ -44,14 +44,12 @@ const (
|
||||
)
|
||||
|
||||
type WarpRoutingConfig struct {
|
||||
Enabled bool `yaml:"enabled" json:"enabled"`
|
||||
ConnectTimeout config.CustomDuration `yaml:"connectTimeout" json:"connectTimeout,omitempty"`
|
||||
TCPKeepAlive config.CustomDuration `yaml:"tcpKeepAlive" json:"tcpKeepAlive,omitempty"`
|
||||
}
|
||||
|
||||
func NewWarpRoutingConfig(raw *config.WarpRoutingConfig) WarpRoutingConfig {
|
||||
cfg := WarpRoutingConfig{
|
||||
Enabled: raw.Enabled,
|
||||
ConnectTimeout: defaultWarpRoutingConnectTimeout,
|
||||
TCPKeepAlive: defaultTCPKeepAlive,
|
||||
}
|
||||
@@ -65,9 +63,7 @@ func NewWarpRoutingConfig(raw *config.WarpRoutingConfig) WarpRoutingConfig {
|
||||
}
|
||||
|
||||
func (c *WarpRoutingConfig) RawConfig() config.WarpRoutingConfig {
|
||||
raw := config.WarpRoutingConfig{
|
||||
Enabled: c.Enabled,
|
||||
}
|
||||
raw := config.WarpRoutingConfig{}
|
||||
if c.ConnectTimeout.Duration != defaultWarpRoutingConnectTimeout.Duration {
|
||||
raw.ConnectTimeout = &c.ConnectTimeout
|
||||
}
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@ type Ingress struct {
|
||||
|
||||
// ParseIngress parses ingress rules, but does not send HTTP requests to the origins.
|
||||
func ParseIngress(conf *config.Configuration) (Ingress, error) {
|
||||
if len(conf.Ingress) == 0 {
|
||||
if conf == nil || len(conf.Ingress) == 0 {
|
||||
return Ingress{}, ErrNoIngressRules
|
||||
}
|
||||
return validateIngress(conf.Ingress, originRequestFromConfig(conf.OriginRequest))
|
||||
|
||||
@@ -43,6 +43,11 @@ ingress:
|
||||
require.Equal(t, "https", s.scheme)
|
||||
}
|
||||
|
||||
func TestParseIngressNilConfig(t *testing.T) {
|
||||
_, err := ParseIngress(nil)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestParseIngress(t *testing.T) {
|
||||
localhost8000 := MustParseURL(t, "https://localhost:8000")
|
||||
localhost8001 := MustParseURL(t, "https://localhost:8001")
|
||||
|
||||
+11
-17
@@ -23,12 +23,11 @@ type muxer interface {
|
||||
|
||||
// PacketRouter routes packets between Upstream and ICMPRouter. Currently it rejects all other type of ICMP packets
|
||||
type PacketRouter struct {
|
||||
globalConfig *GlobalRouterConfig
|
||||
muxer muxer
|
||||
logger *zerolog.Logger
|
||||
checkRouterEnabledFunc func() bool
|
||||
icmpDecoder *packet.ICMPDecoder
|
||||
encoder *packet.Encoder
|
||||
globalConfig *GlobalRouterConfig
|
||||
muxer muxer
|
||||
logger *zerolog.Logger
|
||||
icmpDecoder *packet.ICMPDecoder
|
||||
encoder *packet.Encoder
|
||||
}
|
||||
|
||||
// GlobalRouterConfig is the configuration shared by all instance of Router.
|
||||
@@ -40,14 +39,13 @@ type GlobalRouterConfig struct {
|
||||
}
|
||||
|
||||
// NewPacketRouter creates a PacketRouter that handles ICMP packets. Packets are read from muxer but dropped if globalConfig is nil.
|
||||
func NewPacketRouter(globalConfig *GlobalRouterConfig, muxer muxer, logger *zerolog.Logger, checkRouterEnabledFunc func() bool) *PacketRouter {
|
||||
func NewPacketRouter(globalConfig *GlobalRouterConfig, muxer muxer, logger *zerolog.Logger) *PacketRouter {
|
||||
return &PacketRouter{
|
||||
globalConfig: globalConfig,
|
||||
muxer: muxer,
|
||||
logger: logger,
|
||||
checkRouterEnabledFunc: checkRouterEnabledFunc,
|
||||
icmpDecoder: packet.NewICMPDecoder(),
|
||||
encoder: packet.NewEncoder(),
|
||||
globalConfig: globalConfig,
|
||||
muxer: muxer,
|
||||
logger: logger,
|
||||
icmpDecoder: packet.NewICMPDecoder(),
|
||||
encoder: packet.NewEncoder(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,10 +90,6 @@ func (r *PacketRouter) handlePacket(ctx context.Context, rawPacket packet.RawPac
|
||||
return
|
||||
}
|
||||
|
||||
if enabled := r.checkRouterEnabledFunc(); !enabled {
|
||||
return
|
||||
}
|
||||
|
||||
icmpPacket, err := r.icmpDecoder.Decode(rawPacket)
|
||||
if err != nil {
|
||||
r.logger.Err(err).Msg("Failed to decode ICMP packet from quic datagram")
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"net/netip"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -29,9 +28,7 @@ var (
|
||||
|
||||
func TestRouterReturnTTLExceed(t *testing.T) {
|
||||
muxer := newMockMuxer(0)
|
||||
routerEnabled := &routerEnabledChecker{}
|
||||
routerEnabled.set(true)
|
||||
router := NewPacketRouter(packetConfig, muxer, &noopLogger, routerEnabled.isEnabled)
|
||||
router := NewPacketRouter(packetConfig, muxer, &noopLogger)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
routerStopped := make(chan struct{})
|
||||
go func() {
|
||||
@@ -80,65 +77,6 @@ func TestRouterReturnTTLExceed(t *testing.T) {
|
||||
<-routerStopped
|
||||
}
|
||||
|
||||
func TestRouterCheckEnabled(t *testing.T) {
|
||||
muxer := newMockMuxer(0)
|
||||
routerEnabled := &routerEnabledChecker{}
|
||||
router := NewPacketRouter(packetConfig, muxer, &noopLogger, routerEnabled.isEnabled)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
routerStopped := make(chan struct{})
|
||||
go func() {
|
||||
router.Serve(ctx)
|
||||
close(routerStopped)
|
||||
}()
|
||||
|
||||
pk := packet.ICMP{
|
||||
IP: &packet.IP{
|
||||
Src: netip.MustParseAddr("192.168.1.1"),
|
||||
Dst: netip.MustParseAddr("10.0.0.1"),
|
||||
Protocol: layers.IPProtocolICMPv4,
|
||||
TTL: 1,
|
||||
},
|
||||
Message: &icmp.Message{
|
||||
Type: ipv4.ICMPTypeEcho,
|
||||
Code: 0,
|
||||
Body: &icmp.Echo{
|
||||
ID: 12481,
|
||||
Seq: 8036,
|
||||
Data: []byte(t.Name()),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// router is disabled
|
||||
encoder := packet.NewEncoder()
|
||||
encodedPacket, err := encoder.Encode(&pk)
|
||||
require.NoError(t, err)
|
||||
sendPacket := quicpogs.RawPacket(encodedPacket)
|
||||
|
||||
muxer.edgeToCfd <- sendPacket
|
||||
select {
|
||||
case <-time.After(time.Millisecond * 10):
|
||||
case <-muxer.cfdToEdge:
|
||||
t.Error("Unexpected reply when router is disabled")
|
||||
}
|
||||
routerEnabled.set(true)
|
||||
// router is enabled, expects reply
|
||||
muxer.edgeToCfd <- sendPacket
|
||||
<-muxer.cfdToEdge
|
||||
|
||||
routerEnabled.set(false)
|
||||
// router is disabled
|
||||
muxer.edgeToCfd <- sendPacket
|
||||
select {
|
||||
case <-time.After(time.Millisecond * 10):
|
||||
case <-muxer.cfdToEdge:
|
||||
t.Error("Unexpected reply when router is disabled")
|
||||
}
|
||||
|
||||
cancel()
|
||||
<-routerStopped
|
||||
}
|
||||
|
||||
func assertTTLExceed(t *testing.T, originalPacket *packet.ICMP, expectedSrc netip.Addr, muxer *mockMuxer) {
|
||||
encoder := packet.NewEncoder()
|
||||
rawPacket, err := encoder.Encode(originalPacket)
|
||||
|
||||
@@ -60,7 +60,6 @@ func TestNewLocalConfig_MarshalJSON(t *testing.T) {
|
||||
}
|
||||
],
|
||||
"warp-routing": {
|
||||
"enabled": true,
|
||||
"connectTimeout": 1
|
||||
}
|
||||
}
|
||||
@@ -83,7 +82,6 @@ func TestNewLocalConfig_MarshalJSON(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, remoteConfig.WarpRouting, ingress.WarpRoutingConfig{
|
||||
Enabled: true,
|
||||
ConnectTimeout: config.CustomDuration{
|
||||
Duration: time.Second,
|
||||
},
|
||||
|
||||
@@ -29,11 +29,10 @@ type Orchestrator struct {
|
||||
// Underlying value is proxy.Proxy, can be read without the lock, but still needs the lock to update
|
||||
proxy atomic.Value
|
||||
// Set of internal ingress rules defined at cloudflared startup (separate from user-defined ingress rules)
|
||||
internalRules []ingress.Rule
|
||||
warpRoutingEnabled atomic.Bool
|
||||
config *Config
|
||||
tags []tunnelpogs.Tag
|
||||
log *zerolog.Logger
|
||||
internalRules []ingress.Rule
|
||||
config *Config
|
||||
tags []tunnelpogs.Tag
|
||||
log *zerolog.Logger
|
||||
|
||||
// orchestrator must not handle any more updates after shutdownC is closed
|
||||
shutdownC <-chan struct{}
|
||||
@@ -136,11 +135,6 @@ func (o *Orchestrator) updateIngress(ingressRules ingress.Ingress, warpRouting i
|
||||
o.proxy.Store(proxy)
|
||||
o.config.Ingress = &ingressRules
|
||||
o.config.WarpRouting = warpRouting
|
||||
if warpRouting.Enabled {
|
||||
o.warpRoutingEnabled.Store(true)
|
||||
} else {
|
||||
o.warpRoutingEnabled.Store(false)
|
||||
}
|
||||
|
||||
// If proxyShutdownC is nil, there is no previous running proxy
|
||||
if o.proxyShutdownC != nil {
|
||||
@@ -209,10 +203,6 @@ func (o *Orchestrator) GetOriginProxy() (connection.OriginProxy, error) {
|
||||
return proxy, nil
|
||||
}
|
||||
|
||||
func (o *Orchestrator) WarpRoutingEnabled() bool {
|
||||
return o.warpRoutingEnabled.Load()
|
||||
}
|
||||
|
||||
func (o *Orchestrator) waitToCloseLastProxy() {
|
||||
<-o.shutdownC
|
||||
o.lock.Lock()
|
||||
|
||||
@@ -55,7 +55,6 @@ func TestUpdateConfiguration(t *testing.T) {
|
||||
initOriginProxy, err := orchestrator.GetOriginProxy()
|
||||
require.NoError(t, err)
|
||||
require.Implements(t, (*connection.OriginProxy)(nil), initOriginProxy)
|
||||
require.False(t, orchestrator.WarpRoutingEnabled())
|
||||
|
||||
configJSONV2 := []byte(`
|
||||
{
|
||||
@@ -87,7 +86,6 @@ func TestUpdateConfiguration(t *testing.T) {
|
||||
}
|
||||
],
|
||||
"warp-routing": {
|
||||
"enabled": true,
|
||||
"connectTimeout": 10
|
||||
}
|
||||
}
|
||||
@@ -126,8 +124,6 @@ func TestUpdateConfiguration(t *testing.T) {
|
||||
require.Equal(t, config.CustomDuration{Duration: time.Second * 90}, configV2.Ingress.Rules[2].Config.ConnectTimeout)
|
||||
require.Equal(t, false, configV2.Ingress.Rules[2].Config.NoTLSVerify)
|
||||
require.Equal(t, true, configV2.Ingress.Rules[2].Config.NoHappyEyeballs)
|
||||
require.True(t, configV2.WarpRouting.Enabled)
|
||||
require.Equal(t, configV2.WarpRouting.Enabled, orchestrator.WarpRoutingEnabled())
|
||||
require.Equal(t, configV2.WarpRouting.ConnectTimeout.Duration, 10*time.Second)
|
||||
|
||||
originProxyV2, err := orchestrator.GetOriginProxy()
|
||||
@@ -162,7 +158,6 @@ func TestUpdateConfiguration(t *testing.T) {
|
||||
}
|
||||
],
|
||||
"warp-routing": {
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
`)
|
||||
@@ -171,8 +166,6 @@ func TestUpdateConfiguration(t *testing.T) {
|
||||
require.Len(t, configV10.Ingress.Rules, 1)
|
||||
require.True(t, configV10.Ingress.Rules[0].Matches("blogs.tunnel.io", "/2022/02/10"))
|
||||
require.Equal(t, ingress.HelloWorldService, configV10.Ingress.Rules[0].Service.String())
|
||||
require.False(t, configV10.WarpRouting.Enabled)
|
||||
require.Equal(t, configV10.WarpRouting.Enabled, orchestrator.WarpRoutingEnabled())
|
||||
|
||||
originProxyV10, err := orchestrator.GetOriginProxy()
|
||||
require.NoError(t, err)
|
||||
@@ -191,7 +184,6 @@ func TestUpdateConfiguration_FromMigration(t *testing.T) {
|
||||
initOriginProxy, err := orchestrator.GetOriginProxy()
|
||||
require.NoError(t, err)
|
||||
require.Implements(t, (*connection.OriginProxy)(nil), initOriginProxy)
|
||||
require.False(t, orchestrator.WarpRoutingEnabled())
|
||||
|
||||
configJSONV2 := []byte(`
|
||||
{
|
||||
@@ -201,7 +193,6 @@ func TestUpdateConfiguration_FromMigration(t *testing.T) {
|
||||
}
|
||||
],
|
||||
"warp-routing": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
`)
|
||||
@@ -271,7 +262,6 @@ func TestConcurrentUpdateAndRead(t *testing.T) {
|
||||
}
|
||||
],
|
||||
"warp-routing": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
`, hostname, httpOrigin.URL, expectedHost))
|
||||
@@ -283,7 +273,6 @@ func TestConcurrentUpdateAndRead(t *testing.T) {
|
||||
}
|
||||
],
|
||||
"warp-routing": {
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
`)
|
||||
@@ -296,7 +285,6 @@ func TestConcurrentUpdateAndRead(t *testing.T) {
|
||||
}
|
||||
],
|
||||
"warp-routing": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
`)
|
||||
@@ -516,7 +504,6 @@ func TestClosePreviousProxies(t *testing.T) {
|
||||
}
|
||||
],
|
||||
"warp-routing": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
`, hostname))
|
||||
@@ -529,7 +516,6 @@ func TestClosePreviousProxies(t *testing.T) {
|
||||
}
|
||||
],
|
||||
"warp-routing": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
`)
|
||||
@@ -612,7 +598,6 @@ func TestPersistentConnection(t *testing.T) {
|
||||
}
|
||||
],
|
||||
"warp-routing": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
`, wsOrigin.URL))
|
||||
@@ -679,7 +664,6 @@ func TestPersistentConnection(t *testing.T) {
|
||||
}
|
||||
],
|
||||
"warp-routing": {
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
+2
-4
@@ -57,10 +57,8 @@ func NewOriginProxy(
|
||||
tags: tags,
|
||||
log: log,
|
||||
}
|
||||
if warpRouting.Enabled {
|
||||
proxy.warpRouting = ingress.NewWarpRoutingService(warpRouting)
|
||||
log.Info().Msgf("Warp-routing is enabled")
|
||||
}
|
||||
|
||||
proxy.warpRouting = ingress.NewWarpRoutingService(warpRouting)
|
||||
|
||||
return proxy
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package proxy
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ var (
|
||||
testTags = []tunnelpogs.Tag{{Name: "Name", Value: "value"}}
|
||||
noWarpRouting = ingress.WarpRoutingConfig{}
|
||||
testWarpRouting = ingress.WarpRoutingConfig{
|
||||
Enabled: true,
|
||||
ConnectTimeout: config.CustomDuration{Duration: time.Second},
|
||||
}
|
||||
)
|
||||
|
||||
+2
-2
@@ -53,7 +53,7 @@ func (dm *DatagramMuxer) SendToSession(session *packet.Session) error {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to suffix session ID to datagram, it will be dropped")
|
||||
}
|
||||
if err := dm.session.SendMessage(payloadWithMetadata); err != nil {
|
||||
if err := dm.session.SendDatagram(payloadWithMetadata); err != nil {
|
||||
return errors.Wrap(err, "Failed to send datagram back to edge")
|
||||
}
|
||||
return nil
|
||||
@@ -64,7 +64,7 @@ func (dm *DatagramMuxer) ServeReceive(ctx context.Context) error {
|
||||
// Extracts datagram session ID, then sends the session ID and payload to receiver
|
||||
// which determines how to proxy to the origin. It assumes the datagram session has already been
|
||||
// registered with receiver through other side channel
|
||||
msg, err := dm.session.ReceiveMessage()
|
||||
msg, err := dm.session.ReceiveDatagram(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/netip"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -114,9 +115,8 @@ func TestDatagram(t *testing.T) {
|
||||
|
||||
func testDatagram(t *testing.T, version uint8, sessionToPayloads []*packet.Session, packets []packet.ICMP) {
|
||||
quicConfig := &quic.Config{
|
||||
KeepAlivePeriod: 5 * time.Millisecond,
|
||||
EnableDatagrams: true,
|
||||
MaxDatagramFrameSize: MaxDatagramFrameSize,
|
||||
KeepAlivePeriod: 5 * time.Millisecond,
|
||||
EnableDatagrams: true,
|
||||
}
|
||||
quicListener := newQUICListener(t, quicConfig)
|
||||
defer quicListener.Close()
|
||||
@@ -182,8 +182,12 @@ func testDatagram(t *testing.T, version uint8, sessionToPayloads []*packet.Sessi
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// https://github.com/quic-go/quic-go/issues/3793 MTU discovery is disabled on OSX for dual stack listeners
|
||||
udpConn, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
||||
require.NoError(t, err)
|
||||
// Establish quic connection
|
||||
quicSession, err := quic.DialAddrEarly(ctx, quicListener.Addr().String(), tlsClientConfig, quicConfig)
|
||||
quicSession, err := quic.DialEarly(ctx, udpConn, quicListener.Addr(), tlsClientConfig, quicConfig)
|
||||
require.NoError(t, err)
|
||||
defer quicSession.CloseWithError(0, "")
|
||||
|
||||
|
||||
+3
-3
@@ -86,7 +86,7 @@ func (dm *DatagramMuxerV2) SendToSession(session *packet.Session) error {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to suffix datagram type, it will be dropped")
|
||||
}
|
||||
if err := dm.session.SendMessage(msgWithIDAndType); err != nil {
|
||||
if err := dm.session.SendDatagram(msgWithIDAndType); err != nil {
|
||||
return errors.Wrap(err, "Failed to send datagram back to edge")
|
||||
}
|
||||
return nil
|
||||
@@ -104,7 +104,7 @@ func (dm *DatagramMuxerV2) SendPacket(pk Packet) error {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to suffix datagram type, it will be dropped")
|
||||
}
|
||||
if err := dm.session.SendMessage(payloadWithMetadataAndType); err != nil {
|
||||
if err := dm.session.SendDatagram(payloadWithMetadataAndType); err != nil {
|
||||
return errors.Wrap(err, "Failed to send datagram back to edge")
|
||||
}
|
||||
return nil
|
||||
@@ -113,7 +113,7 @@ func (dm *DatagramMuxerV2) SendPacket(pk Packet) error {
|
||||
// Demux reads datagrams from the QUIC connection and demuxes depending on whether it's a session or packet
|
||||
func (dm *DatagramMuxerV2) ServeReceive(ctx context.Context) error {
|
||||
for {
|
||||
msg, err := dm.session.ReceiveMessage()
|
||||
msg, err := dm.session.ReceiveDatagram(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -109,63 +109,6 @@ func TestConnectResponseMeta(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnregisterUdpSession(t *testing.T) {
|
||||
unregisterMessage := "closed by eyeball"
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
sessionRPCServer mockSessionRPCServer
|
||||
timeout time.Duration
|
||||
}{
|
||||
|
||||
{
|
||||
name: "UnregisterUdpSessionTimesout if the RPC server does not respond",
|
||||
sessionRPCServer: mockSessionRPCServer{
|
||||
sessionID: uuid.New(),
|
||||
dstIP: net.IP{172, 16, 0, 1},
|
||||
dstPort: 8000,
|
||||
closeIdleAfter: testCloseIdleAfterHint,
|
||||
unregisterMessage: unregisterMessage,
|
||||
traceContext: "1241ce3ecdefc68854e8514e69ba42ca:b38f1bf5eae406f3:0:1",
|
||||
},
|
||||
// very very low value so we trigger the timeout every time.
|
||||
timeout: time.Nanosecond * 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
logger := zerolog.Nop()
|
||||
clientStream, serverStream := newMockRPCStreams()
|
||||
sessionRegisteredChan := make(chan struct{})
|
||||
go func() {
|
||||
protocol, err := DetermineProtocol(serverStream)
|
||||
assert.NoError(t, err)
|
||||
rpcServerStream, err := NewRPCServerStream(serverStream, protocol)
|
||||
assert.NoError(t, err)
|
||||
err = rpcServerStream.Serve(test.sessionRPCServer, nil, &logger)
|
||||
assert.NoError(t, err)
|
||||
|
||||
serverStream.Close()
|
||||
close(sessionRegisteredChan)
|
||||
}()
|
||||
|
||||
rpcClientStream, err := NewRPCClientStream(context.Background(), clientStream, test.timeout, &logger)
|
||||
assert.NoError(t, err)
|
||||
|
||||
reg, err := rpcClientStream.RegisterUdpSession(context.Background(), test.sessionRPCServer.sessionID, test.sessionRPCServer.dstIP, test.sessionRPCServer.dstPort, testCloseIdleAfterHint, test.sessionRPCServer.traceContext)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, reg.Err)
|
||||
|
||||
assert.Error(t, rpcClientStream.UnregisterUdpSession(context.Background(), test.sessionRPCServer.sessionID, unregisterMessage))
|
||||
|
||||
rpcClientStream.Close()
|
||||
<-sessionRegisteredChan
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestRegisterUdpSession(t *testing.T) {
|
||||
unregisterMessage := "closed by eyeball"
|
||||
|
||||
|
||||
+49
-26
@@ -21,7 +21,7 @@ type tracerConfig struct {
|
||||
index uint8
|
||||
}
|
||||
|
||||
func NewClientTracer(logger *zerolog.Logger, index uint8) func(context.Context, logging.Perspective, logging.ConnectionID) logging.ConnectionTracer {
|
||||
func NewClientTracer(logger *zerolog.Logger, index uint8) func(context.Context, logging.Perspective, logging.ConnectionID) *logging.ConnectionTracer {
|
||||
t := &tracer{
|
||||
logger: logger,
|
||||
config: &tracerConfig{
|
||||
@@ -32,42 +32,61 @@ func NewClientTracer(logger *zerolog.Logger, index uint8) func(context.Context,
|
||||
return t.TracerForConnection
|
||||
}
|
||||
|
||||
func NewServerTracer(logger *zerolog.Logger) logging.Tracer {
|
||||
return &tracer{
|
||||
logger: logger,
|
||||
config: &tracerConfig{
|
||||
isClient: false,
|
||||
},
|
||||
func NewServerTracer(logger *zerolog.Logger) *logging.Tracer {
|
||||
return &logging.Tracer{
|
||||
SentPacket: func(net.Addr, *logging.Header, logging.ByteCount, []logging.Frame) {},
|
||||
SentVersionNegotiationPacket: func(_ net.Addr, dest, src logging.ArbitraryLenConnectionID, _ []logging.VersionNumber) {},
|
||||
DroppedPacket: func(net.Addr, logging.PacketType, logging.ByteCount, logging.PacketDropReason) {},
|
||||
}
|
||||
}
|
||||
|
||||
func (t *tracer) TracerForConnection(_ctx context.Context, _p logging.Perspective, _odcid logging.ConnectionID) logging.ConnectionTracer {
|
||||
func (t *tracer) TracerForConnection(_ctx context.Context, _p logging.Perspective, _odcid logging.ConnectionID) *logging.ConnectionTracer {
|
||||
if t.config.isClient {
|
||||
return newConnTracer(newClientCollector(t.config.index))
|
||||
}
|
||||
return newConnTracer(newServiceCollector())
|
||||
}
|
||||
|
||||
func (*tracer) SentPacket(net.Addr, *logging.Header, logging.ByteCount, []logging.Frame) {
|
||||
}
|
||||
func (*tracer) SentVersionNegotiationPacket(_ net.Addr, dest, src logging.ArbitraryLenConnectionID, _ []logging.VersionNumber) {
|
||||
}
|
||||
func (*tracer) DroppedPacket(net.Addr, logging.PacketType, logging.ByteCount, logging.PacketDropReason) {
|
||||
}
|
||||
|
||||
var _ logging.Tracer = (*tracer)(nil)
|
||||
|
||||
// connTracer collects connection level metrics
|
||||
type connTracer struct {
|
||||
metricsCollector MetricsCollector
|
||||
}
|
||||
|
||||
var _ logging.ConnectionTracer = (*connTracer)(nil)
|
||||
|
||||
func newConnTracer(metricsCollector MetricsCollector) logging.ConnectionTracer {
|
||||
return &connTracer{
|
||||
func newConnTracer(metricsCollector MetricsCollector) *logging.ConnectionTracer {
|
||||
tracer := connTracer{
|
||||
metricsCollector: metricsCollector,
|
||||
}
|
||||
return &logging.ConnectionTracer{
|
||||
StartedConnection: tracer.StartedConnection,
|
||||
NegotiatedVersion: tracer.NegotiatedVersion,
|
||||
ClosedConnection: tracer.ClosedConnection,
|
||||
SentTransportParameters: tracer.SentTransportParameters,
|
||||
ReceivedTransportParameters: tracer.ReceivedTransportParameters,
|
||||
RestoredTransportParameters: tracer.RestoredTransportParameters,
|
||||
SentLongHeaderPacket: tracer.SentLongHeaderPacket,
|
||||
SentShortHeaderPacket: tracer.SentShortHeaderPacket,
|
||||
ReceivedVersionNegotiationPacket: tracer.ReceivedVersionNegotiationPacket,
|
||||
ReceivedRetry: tracer.ReceivedRetry,
|
||||
ReceivedLongHeaderPacket: tracer.ReceivedLongHeaderPacket,
|
||||
ReceivedShortHeaderPacket: tracer.ReceivedShortHeaderPacket,
|
||||
BufferedPacket: tracer.BufferedPacket,
|
||||
DroppedPacket: tracer.DroppedPacket,
|
||||
UpdatedMetrics: tracer.UpdatedMetrics,
|
||||
AcknowledgedPacket: tracer.AcknowledgedPacket,
|
||||
LostPacket: tracer.LostPacket,
|
||||
UpdatedCongestionState: tracer.UpdatedCongestionState,
|
||||
UpdatedPTOCount: tracer.UpdatedPTOCount,
|
||||
UpdatedKeyFromTLS: tracer.UpdatedKeyFromTLS,
|
||||
UpdatedKey: tracer.UpdatedKey,
|
||||
DroppedEncryptionLevel: tracer.DroppedEncryptionLevel,
|
||||
DroppedKey: tracer.DroppedKey,
|
||||
SetLossTimer: tracer.SetLossTimer,
|
||||
LossTimerExpired: tracer.LossTimerExpired,
|
||||
LossTimerCanceled: tracer.LossTimerCanceled,
|
||||
ECNStateUpdated: tracer.ECNStateUpdated,
|
||||
Close: tracer.Close,
|
||||
Debug: tracer.Debug,
|
||||
}
|
||||
}
|
||||
|
||||
func (ct *connTracer) StartedConnection(local, remote net.Addr, srcConnID, destConnID logging.ConnectionID) {
|
||||
@@ -90,7 +109,7 @@ func (ct *connTracer) BufferedPacket(pt logging.PacketType, size logging.ByteCou
|
||||
ct.metricsCollector.bufferedPackets(pt)
|
||||
}
|
||||
|
||||
func (ct *connTracer) DroppedPacket(pt logging.PacketType, size logging.ByteCount, reason logging.PacketDropReason) {
|
||||
func (ct *connTracer) DroppedPacket(pt logging.PacketType, number logging.PacketNumber, size logging.ByteCount, reason logging.PacketDropReason) {
|
||||
ct.metricsCollector.droppedPackets(pt, size, reason)
|
||||
}
|
||||
|
||||
@@ -114,10 +133,10 @@ func (ct *connTracer) ReceivedTransportParameters(parameters *logging.TransportP
|
||||
func (ct *connTracer) RestoredTransportParameters(parameters *logging.TransportParameters) {
|
||||
}
|
||||
|
||||
func (ct *connTracer) SentLongHeaderPacket(hdr *logging.ExtendedHeader, size logging.ByteCount, ack *logging.AckFrame, frames []logging.Frame) {
|
||||
func (ct *connTracer) SentLongHeaderPacket(hdr *logging.ExtendedHeader, size logging.ByteCount, ecn logging.ECN, ack *logging.AckFrame, frames []logging.Frame) {
|
||||
}
|
||||
|
||||
func (ct *connTracer) SentShortHeaderPacket(hdr *logging.ShortHeader, size logging.ByteCount, ack *logging.AckFrame, frames []logging.Frame) {
|
||||
func (ct *connTracer) SentShortHeaderPacket(hdr *logging.ShortHeader, size logging.ByteCount, ecn logging.ECN, ack *logging.AckFrame, frames []logging.Frame) {
|
||||
}
|
||||
|
||||
func (ct *connTracer) ReceivedVersionNegotiationPacket(dest, src logging.ArbitraryLenConnectionID, _ []logging.VersionNumber) {
|
||||
@@ -126,10 +145,10 @@ func (ct *connTracer) ReceivedVersionNegotiationPacket(dest, src logging.Arbitra
|
||||
func (ct *connTracer) ReceivedRetry(header *logging.Header) {
|
||||
}
|
||||
|
||||
func (ct *connTracer) ReceivedLongHeaderPacket(hdr *logging.ExtendedHeader, size logging.ByteCount, frames []logging.Frame) {
|
||||
func (ct *connTracer) ReceivedLongHeaderPacket(hdr *logging.ExtendedHeader, size logging.ByteCount, ecn logging.ECN, frames []logging.Frame) {
|
||||
}
|
||||
|
||||
func (ct *connTracer) ReceivedShortHeaderPacket(hdr *logging.ShortHeader, size logging.ByteCount, frames []logging.Frame) {
|
||||
func (ct *connTracer) ReceivedShortHeaderPacket(hdr *logging.ShortHeader, size logging.ByteCount, ecn logging.ECN, frames []logging.Frame) {
|
||||
}
|
||||
|
||||
func (ct *connTracer) AcknowledgedPacket(level logging.EncryptionLevel, number logging.PacketNumber) {
|
||||
@@ -162,6 +181,10 @@ func (ct *connTracer) LossTimerExpired(timerType logging.TimerType, level loggin
|
||||
func (ct *connTracer) LossTimerCanceled() {
|
||||
}
|
||||
|
||||
func (ct *connTracer) ECNStateUpdated(state logging.ECNState, trigger logging.ECNStateTrigger) {
|
||||
|
||||
}
|
||||
|
||||
func (ct *connTracer) Close() {
|
||||
}
|
||||
|
||||
|
||||
+1
-3
@@ -13,7 +13,6 @@ import base64
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
from hashlib import sha256
|
||||
from pathlib import Path
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
@@ -35,7 +34,6 @@ class PkgUploader:
|
||||
|
||||
def upload_pkg_to_r2(self, filename, upload_file_path):
|
||||
endpoint_url = f"https://{self.account_id}.r2.cloudflarestorage.com"
|
||||
token_secret_hash = sha256(self.client_secret.encode()).hexdigest()
|
||||
|
||||
config = Config(
|
||||
region_name='auto',
|
||||
@@ -48,7 +46,7 @@ class PkgUploader:
|
||||
"s3",
|
||||
endpoint_url=endpoint_url,
|
||||
aws_access_key_id=self.client_id,
|
||||
aws_secret_access_key=token_secret_hash,
|
||||
aws_secret_access_key=self.client_secret,
|
||||
config=config,
|
||||
)
|
||||
|
||||
|
||||
@@ -91,10 +91,12 @@ func (b *BackoffHandler) Backoff(ctx context.Context) bool {
|
||||
|
||||
// Sets a grace period within which the the backoff timer is maintained. After the grace
|
||||
// period expires, the number of retries & backoff duration is reset.
|
||||
func (b *BackoffHandler) SetGracePeriod() {
|
||||
func (b *BackoffHandler) SetGracePeriod() time.Duration {
|
||||
maxTimeToWait := b.GetBaseTime() * 2 << (b.retries + 1)
|
||||
timeToWait := time.Duration(rand.Int63n(maxTimeToWait.Nanoseconds()))
|
||||
b.resetDeadline = Clock.Now().Add(timeToWait)
|
||||
|
||||
return timeToWait
|
||||
}
|
||||
|
||||
func (b BackoffHandler) GetBaseTime() time.Duration {
|
||||
|
||||
@@ -57,9 +57,9 @@ func TestBackoffGracePeriod(t *testing.T) {
|
||||
t.Fatalf("backoff failed immediately")
|
||||
}
|
||||
// the next call to Backoff would fail unless it's after the grace period
|
||||
backoff.SetGracePeriod()
|
||||
// advance time to after the grace period (~4 seconds) and see what happens
|
||||
currentTime = currentTime.Add(time.Second * 5)
|
||||
gracePeriod := backoff.SetGracePeriod()
|
||||
// advance time to after the grace period, which at most will be 8 seconds, but we will advance +1 second.
|
||||
currentTime = currentTime.Add(gracePeriod + time.Second)
|
||||
if !backoff.Backoff(ctx) {
|
||||
t.Fatalf("backoff failed after the grace period expired")
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package sshgen
|
||||
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
package supervisor
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/golibs/lrucache"
|
||||
)
|
||||
|
||||
// StatusPage.io API docs:
|
||||
// https://www.cloudflarestatus.com/api/v2/#incidents-unresolved
|
||||
const (
|
||||
activeIncidentsURL = "https://yh6f0r4529hb.statuspage.io/api/v2/incidents/unresolved.json"
|
||||
argoTunnelKeyword = "argo tunnel"
|
||||
incidentDetailsPrefix = "https://www.cloudflarestatus.com/incidents/"
|
||||
)
|
||||
|
||||
// IncidentLookup is an object that checks for active incidents in
|
||||
// the Cloudflare infrastructure.
|
||||
type IncidentLookup interface {
|
||||
ActiveIncidents() []Incident
|
||||
}
|
||||
|
||||
// NewIncidentLookup returns a new IncidentLookup instance that caches its
|
||||
// results with a 1-minute TTL.
|
||||
func NewIncidentLookup() IncidentLookup {
|
||||
return newCachedIncidentLookup(fetchActiveIncidents)
|
||||
}
|
||||
|
||||
type IncidentUpdate struct {
|
||||
Body string
|
||||
}
|
||||
|
||||
type Incident struct {
|
||||
Name string
|
||||
ID string `json:"id"`
|
||||
Updates []IncidentUpdate `json:"incident_updates"`
|
||||
}
|
||||
|
||||
type StatusPage struct {
|
||||
Incidents []Incident
|
||||
}
|
||||
|
||||
func (i Incident) URL() string {
|
||||
return incidentDetailsPrefix + i.ID
|
||||
}
|
||||
|
||||
func parseStatusPage(data []byte) (*StatusPage, error) {
|
||||
var result StatusPage
|
||||
err := json.Unmarshal(data, &result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func isArgoTunnelIncident(i Incident) bool {
|
||||
if strings.Contains(strings.ToLower(i.Name), argoTunnelKeyword) {
|
||||
return true
|
||||
}
|
||||
for _, u := range i.Updates {
|
||||
if strings.Contains(strings.ToLower(u.Body), argoTunnelKeyword) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func fetchActiveIncidents() (incidents []Incident) {
|
||||
resp, err := http.Get(activeIncidentsURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
statusPage, err := parseStatusPage(body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, i := range statusPage.Incidents {
|
||||
if isArgoTunnelIncident(i) {
|
||||
incidents = append(incidents, i)
|
||||
}
|
||||
}
|
||||
return incidents
|
||||
}
|
||||
|
||||
type cachedIncidentLookup struct {
|
||||
cache *lrucache.LRUCache
|
||||
ttl time.Duration
|
||||
uncachedLookup func() []Incident
|
||||
}
|
||||
|
||||
func newCachedIncidentLookup(uncachedLookup func() []Incident) *cachedIncidentLookup {
|
||||
return &cachedIncidentLookup{
|
||||
cache: lrucache.NewLRUCache(1),
|
||||
ttl: time.Minute,
|
||||
uncachedLookup: uncachedLookup,
|
||||
}
|
||||
}
|
||||
|
||||
// We only need one cache entry. Always use the empty string as its key.
|
||||
const cacheKey = ""
|
||||
|
||||
func (c *cachedIncidentLookup) ActiveIncidents() []Incident {
|
||||
if cached, ok := c.cache.GetNotStale(cacheKey); ok {
|
||||
if incidents, ok := cached.([]Incident); ok {
|
||||
return incidents
|
||||
}
|
||||
}
|
||||
incidents := c.uncachedLookup()
|
||||
c.cache.Set(cacheKey, incidents, time.Now().Add(c.ttl))
|
||||
return incidents
|
||||
}
|
||||
@@ -1,384 +0,0 @@
|
||||
package supervisor
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/golibs/lrucache"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseStatusPage(t *testing.T) {
|
||||
testCases := []struct {
|
||||
input []byte
|
||||
output *StatusPage
|
||||
fail bool
|
||||
}{
|
||||
{
|
||||
input: []byte(`<html>
|
||||
<head><title>504 Gateway Time-out</title></head>
|
||||
<body><center><h1>504 Gateway Time-out</h1></center></body>
|
||||
</html>`),
|
||||
output: nil,
|
||||
fail: true,
|
||||
},
|
||||
{
|
||||
input: []byte(`{
|
||||
"page": {
|
||||
"id": "yh6f0r4529hb",
|
||||
"name": "Cloudflare",
|
||||
"url": "https://www.cloudflarestatus.com",
|
||||
"time_zone": "Etc/UTC",
|
||||
"updated_at": "2019-01-10T20:11:38.750Z"
|
||||
},
|
||||
"incidents": [
|
||||
{
|
||||
"name": "Cloudflare API service issues",
|
||||
"status": "resolved",
|
||||
"created_at": "2018-09-17T19:29:21.132Z",
|
||||
"updated_at": "2018-09-18T07:45:41.313Z",
|
||||
"monitoring_at": "2018-09-17T21:35:06.492Z",
|
||||
"resolved_at": "2018-09-18T07:45:41.290Z",
|
||||
"shortlink": "http://stspg.io/7f079791e",
|
||||
"id": "q746ybtyb6q0",
|
||||
"page_id": "yh6f0r4529hb",
|
||||
"incident_updates": [
|
||||
{
|
||||
"status": "resolved",
|
||||
"body": "Cloudflare has resolved the issue and the service have resumed normal operation.",
|
||||
"created_at": "2018-09-18T07:45:41.290Z",
|
||||
"updated_at": "2018-09-18T07:45:41.290Z",
|
||||
"display_at": "2018-09-18T07:45:41.290Z",
|
||||
"affected_components": [
|
||||
{
|
||||
"code": "g4tb35rs9yw7",
|
||||
"name": "Cloudflare customer dashboard and APIs - Cloudflare APIs",
|
||||
"old_status": "operational",
|
||||
"new_status": "operational"
|
||||
}
|
||||
],
|
||||
"deliver_notifications": true,
|
||||
"tweet_id": null,
|
||||
"id": "zl5g2pl5zhfs",
|
||||
"incident_id": "q746ybtyb6q0",
|
||||
"custom_tweet": null
|
||||
},
|
||||
{
|
||||
"status": "monitoring",
|
||||
"body": "Cloudflare has implemented a fix for this issue and is currently monitoring the results.\r\n\r\nWe will update the status once the issue is resolved.",
|
||||
"created_at": "2018-09-17T21:35:06.492Z",
|
||||
"updated_at": "2018-09-17T21:35:06.492Z",
|
||||
"display_at": "2018-09-17T21:35:06.492Z",
|
||||
"affected_components": [
|
||||
{
|
||||
"code": "g4tb35rs9yw7",
|
||||
"name": "Cloudflare customer dashboard and APIs - Cloudflare APIs",
|
||||
"old_status": "degraded_performance",
|
||||
"new_status": "operational"
|
||||
}
|
||||
],
|
||||
"deliver_notifications": false,
|
||||
"tweet_id": null,
|
||||
"id": "0001sv3chdnx",
|
||||
"incident_id": "q746ybtyb6q0",
|
||||
"custom_tweet": null
|
||||
},
|
||||
{
|
||||
"status": "investigating",
|
||||
"body": "We are continuing to investigate this issue.",
|
||||
"created_at": "2018-09-17T19:30:08.049Z",
|
||||
"updated_at": "2018-09-17T19:30:08.049Z",
|
||||
"display_at": "2018-09-17T19:30:08.049Z",
|
||||
"affected_components": [
|
||||
{
|
||||
"code": "g4tb35rs9yw7",
|
||||
"name": "Cloudflare customer dashboard and APIs - Cloudflare APIs",
|
||||
"old_status": "operational",
|
||||
"new_status": "degraded_performance"
|
||||
}
|
||||
],
|
||||
"deliver_notifications": false,
|
||||
"tweet_id": null,
|
||||
"id": "qdr164tfpq7m",
|
||||
"incident_id": "q746ybtyb6q0",
|
||||
"custom_tweet": null
|
||||
},
|
||||
{
|
||||
"status": "investigating",
|
||||
"body": "Cloudflare is investigating issues with APIs and Page Rule delays for Page Rule updates. Cloudflare Page Rule service delivery is unaffected and is operating normally. Also, these issues do not affect the Cloudflare CDN and therefore, do not impact customer websites.",
|
||||
"created_at": "2018-09-17T19:29:21.201Z",
|
||||
"updated_at": "2018-09-17T19:29:21.201Z",
|
||||
"display_at": "2018-09-17T19:29:21.201Z",
|
||||
"affected_components": [
|
||||
{
|
||||
"code": "g4tb35rs9yw7",
|
||||
"name": "Cloudflare customer dashboard and APIs - Cloudflare APIs",
|
||||
"old_status": "operational",
|
||||
"new_status": "operational"
|
||||
}
|
||||
],
|
||||
"deliver_notifications": false,
|
||||
"tweet_id": null,
|
||||
"id": "qzl2n0q8tskg",
|
||||
"incident_id": "q746ybtyb6q0",
|
||||
"custom_tweet": null
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"status": "operational",
|
||||
"name": "Cloudflare APIs",
|
||||
"created_at": "2014-10-09T03:32:07.158Z",
|
||||
"updated_at": "2019-01-01T22:58:30.846Z",
|
||||
"position": 2,
|
||||
"description": null,
|
||||
"showcase": false,
|
||||
"id": "g4tb35rs9yw7",
|
||||
"page_id": "yh6f0r4529hb",
|
||||
"group_id": "1km35smx8p41",
|
||||
"group": false,
|
||||
"only_show_if_degraded": false
|
||||
}
|
||||
],
|
||||
"impact": "minor"
|
||||
},
|
||||
{
|
||||
"name": "Web Analytics Delays",
|
||||
"status": "resolved",
|
||||
"created_at": "2018-09-17T18:05:39.907Z",
|
||||
"updated_at": "2018-09-17T22:53:05.078Z",
|
||||
"monitoring_at": null,
|
||||
"resolved_at": "2018-09-17T22:53:05.057Z",
|
||||
"shortlink": "http://stspg.io/cb208928c",
|
||||
"id": "wqfk9mzs5qt1",
|
||||
"page_id": "yh6f0r4529hb",
|
||||
"incident_updates": [
|
||||
{
|
||||
"status": "resolved",
|
||||
"body": "Cloudflare has resolved the issue and Web Analytics have resumed normal operation.",
|
||||
"created_at": "2018-09-17T22:53:05.057Z",
|
||||
"updated_at": "2018-09-17T22:53:05.057Z",
|
||||
"display_at": "2018-09-17T22:53:05.057Z",
|
||||
"affected_components": [
|
||||
{
|
||||
"code": "4c231tkdlpcl",
|
||||
"name": "Cloudflare customer dashboard and APIs - Analytics",
|
||||
"old_status": "degraded_performance",
|
||||
"new_status": "operational"
|
||||
}
|
||||
],
|
||||
"deliver_notifications": false,
|
||||
"tweet_id": null,
|
||||
"id": "93y1w00yqzk4",
|
||||
"incident_id": "wqfk9mzs5qt1",
|
||||
"custom_tweet": null
|
||||
},
|
||||
{
|
||||
"status": "investigating",
|
||||
"body": "There is a delay in processing Cloudflare Web Analytics. This affects timely delivery of customer data.\n\nThese delays do not impact analytics for DNS and Rate Limiting.",
|
||||
"created_at": "2018-09-17T18:05:40.033Z",
|
||||
"updated_at": "2018-09-17T18:05:40.033Z",
|
||||
"display_at": "2018-09-17T18:05:40.033Z",
|
||||
"affected_components": [
|
||||
{
|
||||
"code": "4c231tkdlpcl",
|
||||
"name": "Cloudflare customer dashboard and APIs - Analytics",
|
||||
"old_status": "operational",
|
||||
"new_status": "degraded_performance"
|
||||
}
|
||||
],
|
||||
"deliver_notifications": false,
|
||||
"tweet_id": null,
|
||||
"id": "362t6lv0vrpk",
|
||||
"incident_id": "wqfk9mzs5qt1",
|
||||
"custom_tweet": null
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"status": "operational",
|
||||
"name": "Analytics",
|
||||
"created_at": "2014-11-13T11:54:10.191Z",
|
||||
"updated_at": "2018-12-31T08:20:52.349Z",
|
||||
"position": 3,
|
||||
"description": "Customer data",
|
||||
"showcase": false,
|
||||
"id": "4c231tkdlpcl",
|
||||
"page_id": "yh6f0r4529hb",
|
||||
"group_id": "1km35smx8p41",
|
||||
"group": false,
|
||||
"only_show_if_degraded": false
|
||||
}
|
||||
],
|
||||
"impact": "minor"
|
||||
}
|
||||
]
|
||||
}`),
|
||||
output: &StatusPage{
|
||||
Incidents: []Incident{
|
||||
Incident{
|
||||
Name: "Cloudflare API service issues",
|
||||
ID: "q746ybtyb6q0",
|
||||
Updates: []IncidentUpdate{
|
||||
IncidentUpdate{
|
||||
Body: "Cloudflare has resolved the issue and the service have resumed normal operation.",
|
||||
},
|
||||
IncidentUpdate{
|
||||
Body: "Cloudflare has implemented a fix for this issue and is currently monitoring the results.\r\n\r\nWe will update the status once the issue is resolved.",
|
||||
},
|
||||
IncidentUpdate{
|
||||
Body: "We are continuing to investigate this issue.",
|
||||
},
|
||||
IncidentUpdate{
|
||||
Body: "Cloudflare is investigating issues with APIs and Page Rule delays for Page Rule updates. Cloudflare Page Rule service delivery is unaffected and is operating normally. Also, these issues do not affect the Cloudflare CDN and therefore, do not impact customer websites.",
|
||||
},
|
||||
},
|
||||
},
|
||||
Incident{
|
||||
Name: "Web Analytics Delays",
|
||||
ID: "wqfk9mzs5qt1",
|
||||
Updates: []IncidentUpdate{
|
||||
IncidentUpdate{
|
||||
Body: "Cloudflare has resolved the issue and Web Analytics have resumed normal operation.",
|
||||
},
|
||||
IncidentUpdate{
|
||||
Body: "There is a delay in processing Cloudflare Web Analytics. This affects timely delivery of customer data.\n\nThese delays do not impact analytics for DNS and Rate Limiting.",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
output, err := parseStatusPage(testCase.input)
|
||||
if testCase.fail {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, testCase.output, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsArgoTunnelIncident(t *testing.T) {
|
||||
testCases := []struct {
|
||||
input Incident
|
||||
output bool
|
||||
}{
|
||||
{
|
||||
input: Incident{},
|
||||
output: false,
|
||||
},
|
||||
{
|
||||
input: Incident{Name: "An Argo Tunnel incident"},
|
||||
output: true,
|
||||
},
|
||||
{
|
||||
input: Incident{Name: "an argo tunnel incident"},
|
||||
output: true,
|
||||
},
|
||||
{
|
||||
input: Incident{Name: "an aRgO TuNnEl incident"},
|
||||
output: true,
|
||||
},
|
||||
{
|
||||
input: Incident{Name: "an argotunnel incident"},
|
||||
output: false,
|
||||
},
|
||||
{
|
||||
input: Incident{Name: "irrelevant"},
|
||||
output: false,
|
||||
},
|
||||
{
|
||||
input: Incident{
|
||||
Name: "irrelevant",
|
||||
Updates: []IncidentUpdate{
|
||||
IncidentUpdate{Body: "irrelevant"},
|
||||
IncidentUpdate{Body: "an Argo Tunnel incident"},
|
||||
IncidentUpdate{Body: "irrelevant"},
|
||||
},
|
||||
},
|
||||
output: true,
|
||||
},
|
||||
{
|
||||
input: Incident{
|
||||
Name: "an Argo Tunnel incident",
|
||||
Updates: []IncidentUpdate{
|
||||
IncidentUpdate{Body: "irrelevant"},
|
||||
IncidentUpdate{Body: "irrelevant"},
|
||||
IncidentUpdate{Body: "irrelevant"},
|
||||
},
|
||||
},
|
||||
output: true,
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
actual := isArgoTunnelIncident(testCase.input)
|
||||
assert.Equal(t, testCase.output, actual, "Test case failed: %v", testCase.input)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIncidentURL(t *testing.T) {
|
||||
incident := Incident{
|
||||
ID: "s6k0dnn5347b",
|
||||
}
|
||||
assert.Equal(t, "https://www.cloudflarestatus.com/incidents/s6k0dnn5347b", incident.URL())
|
||||
}
|
||||
|
||||
func TestNewCachedIncidentLookup(t *testing.T) {
|
||||
c := newCachedIncidentLookup(func() []Incident { return nil })
|
||||
assert.Equal(t, time.Minute, c.ttl)
|
||||
assert.Equal(t, 1, c.cache.Capacity())
|
||||
}
|
||||
|
||||
func TestCachedIncidentLookup(t *testing.T) {
|
||||
expected := []Incident{
|
||||
Incident{
|
||||
Name: "An incident",
|
||||
ID: "incidentID",
|
||||
},
|
||||
}
|
||||
|
||||
var shouldCallUncachedLookup bool
|
||||
c := &cachedIncidentLookup{
|
||||
cache: lrucache.NewLRUCache(1),
|
||||
ttl: 50 * time.Millisecond,
|
||||
uncachedLookup: func() []Incident {
|
||||
if !shouldCallUncachedLookup {
|
||||
t.Fatal("uncachedLookup shouldn't have been called")
|
||||
}
|
||||
return expected
|
||||
},
|
||||
}
|
||||
|
||||
shouldCallUncachedLookup = true
|
||||
assert.Equal(t, expected, c.ActiveIncidents())
|
||||
|
||||
shouldCallUncachedLookup = false
|
||||
assert.Equal(t, expected, c.ActiveIncidents())
|
||||
assert.Equal(t, expected, c.ActiveIncidents())
|
||||
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
shouldCallUncachedLookup = true
|
||||
assert.Equal(t, expected, c.ActiveIncidents())
|
||||
}
|
||||
|
||||
func TestCachedIncidentLookupDoesntPanic(t *testing.T) {
|
||||
expected := []Incident{
|
||||
Incident{
|
||||
Name: "An incident",
|
||||
ID: "incidentID",
|
||||
},
|
||||
}
|
||||
c := &cachedIncidentLookup{
|
||||
cache: lrucache.NewLRUCache(1),
|
||||
ttl: 50 * time.Millisecond,
|
||||
uncachedLookup: func() []Incident { return expected },
|
||||
}
|
||||
c.cache.Set(cacheKey, 42, time.Now().Add(30*time.Minute))
|
||||
actual := c.ActiveIncidents()
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
+22
-85
@@ -1,100 +1,37 @@
|
||||
package supervisor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"sync"
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudflare/cloudflared/features"
|
||||
)
|
||||
|
||||
// When experimental post-quantum tunnels are enabled, and we're hitting an
|
||||
// issue creating the tunnel, we'll report the first error
|
||||
// to https://pqtunnels.cloudflareresearch.com.
|
||||
|
||||
var (
|
||||
PQKexes = [...]tls.CurveID{
|
||||
tls.CurveID(0xfe30), // X25519Kyber512Draft00
|
||||
tls.CurveID(0xfe31), // X25519Kyber768Draft00
|
||||
}
|
||||
PQKexNames map[tls.CurveID]string = map[tls.CurveID]string{
|
||||
tls.CurveID(0xfe30): "X25519Kyber512Draft00",
|
||||
tls.CurveID(0xfe31): "X25519Kyber768Draft00",
|
||||
}
|
||||
|
||||
pqtMux sync.Mutex // protects pqtSubmitted and pqtWaitForMessage
|
||||
pqtSubmitted bool // whether an error has already been submitted
|
||||
|
||||
// Number of errors to ignore before printing elaborate instructions.
|
||||
pqtWaitForMessage int
|
||||
const (
|
||||
PQKex = tls.CurveID(0xfe31) // X25519Kyber768Draft00
|
||||
PQKexName = "X25519Kyber768Draft00"
|
||||
)
|
||||
|
||||
func handlePQTunnelError(rep error, config *TunnelConfig) {
|
||||
needToMessage := false
|
||||
func curvePreference(pqMode features.PostQuantumMode, currentCurve []tls.CurveID) ([]tls.CurveID, error) {
|
||||
switch pqMode {
|
||||
case features.PostQuantumStrict:
|
||||
// If the user passes the -post-quantum flag, we override
|
||||
// CurvePreferences to only support hybrid post-quantum key agreements.
|
||||
return []tls.CurveID{PQKex}, nil
|
||||
case features.PostQuantumPrefer:
|
||||
if len(currentCurve) == 0 {
|
||||
return []tls.CurveID{PQKex}, nil
|
||||
}
|
||||
|
||||
pqtMux.Lock()
|
||||
needToSubmit := !pqtSubmitted
|
||||
if needToSubmit {
|
||||
pqtSubmitted = true
|
||||
}
|
||||
pqtWaitForMessage--
|
||||
if pqtWaitForMessage < 0 {
|
||||
pqtWaitForMessage = 5
|
||||
needToMessage = true
|
||||
}
|
||||
pqtMux.Unlock()
|
||||
|
||||
if needToMessage {
|
||||
config.Log.Info().Msgf(
|
||||
"\n\n" +
|
||||
"===================================================================================\n" +
|
||||
"You are hitting an error while using the experimental post-quantum tunnels feature.\n" +
|
||||
"\n" +
|
||||
"Please check:\n" +
|
||||
"\n" +
|
||||
" https://pqtunnels.cloudflareresearch.com\n" +
|
||||
"\n" +
|
||||
"for known problems.\n" +
|
||||
"===================================================================================\n\n",
|
||||
)
|
||||
}
|
||||
|
||||
if needToSubmit {
|
||||
go submitPQTunnelError(rep, config)
|
||||
if currentCurve[0] != PQKex {
|
||||
return append([]tls.CurveID{PQKex}, currentCurve...), nil
|
||||
}
|
||||
return currentCurve, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Unexpected post quantum mode")
|
||||
}
|
||||
}
|
||||
|
||||
func submitPQTunnelError(rep error, config *TunnelConfig) {
|
||||
body, err := json.Marshal(struct {
|
||||
Group int `json:"g"`
|
||||
Message string `json:"m"`
|
||||
Version string `json:"v"`
|
||||
}{
|
||||
Group: int(PQKexes[config.PQKexIdx]),
|
||||
Message: rep.Error(),
|
||||
Version: config.ReportedVersion,
|
||||
})
|
||||
if err != nil {
|
||||
config.Log.Err(err).Msg("Failed to create error report")
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := http.Post(
|
||||
"https://pqtunnels.cloudflareresearch.com",
|
||||
"application/json",
|
||||
bytes.NewBuffer(body),
|
||||
)
|
||||
if err != nil {
|
||||
config.Log.Err(err).Msg(
|
||||
"Failed to submit post-quantum tunnel error report",
|
||||
)
|
||||
return
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
config.Log.Error().Msgf(
|
||||
"Failed to submit post-quantum tunnel error report: status %d",
|
||||
resp.StatusCode,
|
||||
)
|
||||
}
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
+15
-40
@@ -47,7 +47,6 @@ type TunnelConfig struct {
|
||||
EdgeIPVersion allregions.ConfigIPVersion
|
||||
EdgeBindAddr net.IP
|
||||
HAConnections int
|
||||
IncidentLookup IncidentLookup
|
||||
IsAutoupdated bool
|
||||
LBPool string
|
||||
Tags []tunnelpogs.Tag
|
||||
@@ -61,9 +60,6 @@ type TunnelConfig struct {
|
||||
|
||||
NeedPQ bool
|
||||
|
||||
// Index into PQKexes of post-quantum kex to use if NeedPQ is set.
|
||||
PQKexIdx int
|
||||
|
||||
NamedTunnel *connection.NamedTunnelProperties
|
||||
ProtocolSelector connection.ProtocolSelector
|
||||
EdgeTLSConfigs map[connection.Protocol]*tls.Config
|
||||
@@ -72,6 +68,8 @@ type TunnelConfig struct {
|
||||
UDPUnregisterSessionTimeout time.Duration
|
||||
|
||||
DisableQUICPathMTUDiscovery bool
|
||||
|
||||
FeatureSelector *features.FeatureSelector
|
||||
}
|
||||
|
||||
func (c *TunnelConfig) registrationOptions(connectionID uint8, OriginLocalIP string, uuid uuid.UUID) *tunnelpogs.RegistrationOptions {
|
||||
@@ -354,7 +352,7 @@ func selectNextProtocol(
|
||||
"Cloudflare Network with `quic` protocol, then most likely your machine/network is getting its egress " +
|
||||
"UDP to port 7844 (or others) blocked or dropped. Make sure to allow egress connectivity as per " +
|
||||
"https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/configuration/ports-and-ips/\n" +
|
||||
"If you are using private routing to this Tunnel, then UDP (and Private DNS Resolution) will not work " +
|
||||
"If you are using private routing to this Tunnel, then ICMP, UDP (and Private DNS Resolution) will not work " +
|
||||
"unless your cloudflared can connect with Cloudflare Network with `quic`.")
|
||||
}
|
||||
|
||||
@@ -437,9 +435,6 @@ func (e *EdgeTunnelServer) serveTunnel(
|
||||
connLog.ConnAwareLogger().Err(err).Msg("Register tunnel error from server side")
|
||||
// Don't send registration error return from server to Sentry. They are
|
||||
// logged on server side
|
||||
if incidents := e.config.IncidentLookup.ActiveIncidents(); len(incidents) > 0 {
|
||||
connLog.ConnAwareLogger().Msg(activeIncidentsMsg(incidents))
|
||||
}
|
||||
return err.Cause, !err.Permanent
|
||||
case *connection.EdgeQuicDialError:
|
||||
return err, false
|
||||
@@ -539,7 +534,8 @@ func (e *EdgeTunnelServer) serveHTTP2(
|
||||
controlStreamHandler connection.ControlStreamHandler,
|
||||
connIndex uint8,
|
||||
) error {
|
||||
if e.config.NeedPQ {
|
||||
pqMode := e.config.FeatureSelector.PostQuantumMode()
|
||||
if pqMode == features.PostQuantumStrict {
|
||||
return unrecoverableError{errors.New("HTTP/2 transport does not support post-quantum")}
|
||||
}
|
||||
|
||||
@@ -582,21 +578,18 @@ func (e *EdgeTunnelServer) serveQUIC(
|
||||
) (err error, recoverable bool) {
|
||||
tlsConfig := e.config.EdgeTLSConfigs[connection.QUIC]
|
||||
|
||||
if e.config.NeedPQ {
|
||||
// If the user passes the -post-quantum flag, we override
|
||||
// CurvePreferences to only support hybrid post-quantum key agreements.
|
||||
cs := make([]tls.CurveID, len(PQKexes))
|
||||
copy(cs, PQKexes[:])
|
||||
|
||||
// It is unclear whether Kyber512 or Kyber768 will become the standard.
|
||||
// Kyber768 is a bit bigger (and doesn't fit in one initial
|
||||
// datagram anymore). We're enabling both, but pick randomly which
|
||||
// one to put first. (TLS will use the first one in the list
|
||||
// and allows a fallback to the second.)
|
||||
cs[0], cs[e.config.PQKexIdx] = cs[e.config.PQKexIdx], cs[0]
|
||||
tlsConfig.CurvePreferences = cs
|
||||
pqMode := e.config.FeatureSelector.PostQuantumMode()
|
||||
if pqMode == features.PostQuantumStrict || pqMode == features.PostQuantumPrefer {
|
||||
connOptions.Client.Features = features.Dedup(append(connOptions.Client.Features, features.FeaturePostQuantum))
|
||||
}
|
||||
|
||||
curvePref, err := curvePreference(pqMode, tlsConfig.CurvePreferences)
|
||||
if err != nil {
|
||||
return err, true
|
||||
}
|
||||
|
||||
tlsConfig.CurvePreferences = curvePref
|
||||
|
||||
quicConfig := &quic.Config{
|
||||
HandshakeIdleTimeout: quicpogs.HandshakeIdleTimeout,
|
||||
MaxIdleTimeout: quicpogs.MaxIdleTimeout,
|
||||
@@ -604,7 +597,6 @@ func (e *EdgeTunnelServer) serveQUIC(
|
||||
MaxIncomingStreams: quicpogs.MaxIncomingStreams,
|
||||
MaxIncomingUniStreams: quicpogs.MaxIncomingStreams,
|
||||
EnableDatagrams: true,
|
||||
MaxDatagramFrameSize: quicpogs.MaxDatagramFrameSize,
|
||||
Tracer: quicpogs.NewClientTracer(connLogger.Logger(), connIndex),
|
||||
DisablePathMTUDiscovery: e.config.DisableQUICPathMTUDiscovery,
|
||||
}
|
||||
@@ -624,10 +616,6 @@ func (e *EdgeTunnelServer) serveQUIC(
|
||||
e.config.UDPUnregisterSessionTimeout,
|
||||
)
|
||||
if err != nil {
|
||||
if e.config.NeedPQ {
|
||||
handlePQTunnelError(err, e.config)
|
||||
}
|
||||
|
||||
connLogger.ConnAwareLogger().Err(err).Msgf("Failed to create new quic connection")
|
||||
return err, true
|
||||
}
|
||||
@@ -678,16 +666,3 @@ func (cf *connectedFuse) Connected() {
|
||||
func (cf *connectedFuse) IsConnected() bool {
|
||||
return cf.fuse.Value()
|
||||
}
|
||||
|
||||
func activeIncidentsMsg(incidents []Incident) string {
|
||||
preamble := "There is an active Cloudflare incident that may be related:"
|
||||
if len(incidents) > 1 {
|
||||
preamble = "There are active Cloudflare incidents that may be related:"
|
||||
}
|
||||
incidentStrings := []string{}
|
||||
for _, incident := range incidents {
|
||||
incidentString := fmt.Sprintf("%s (%s)", incident.Name, incident.URL())
|
||||
incidentStrings = append(incidentStrings, incidentString)
|
||||
}
|
||||
return preamble + " " + strings.Join(incidentStrings, "; ")
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package token
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !windows && !darwin && !linux && !netbsd && !freebsd && !openbsd
|
||||
// +build !windows,!darwin,!linux,!netbsd,!freebsd,!openbsd
|
||||
|
||||
package token
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build linux || freebsd || openbsd || netbsd
|
||||
// +build linux freebsd openbsd netbsd
|
||||
|
||||
package token
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package token
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
//go:build linux || darwin
|
||||
|
||||
package token
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSignalHandler(t *testing.T) {
|
||||
sigHandler := signalHandler{signals: []os.Signal{syscall.SIGUSR1}}
|
||||
handlerRan := false
|
||||
done := make(chan struct{})
|
||||
timer := time.NewTimer(time.Second)
|
||||
sigHandler.register(func() {
|
||||
handlerRan = true
|
||||
done <- struct{}{}
|
||||
})
|
||||
|
||||
p, err := os.FindProcess(os.Getpid())
|
||||
require.Nil(t, err)
|
||||
p.Signal(syscall.SIGUSR1)
|
||||
|
||||
// Blocks for up to one second to make sure the handler callback runs before the assert.
|
||||
select {
|
||||
case <-done:
|
||||
assert.True(t, handlerRan)
|
||||
case <-timer.C:
|
||||
t.Fail()
|
||||
}
|
||||
sigHandler.deregister()
|
||||
}
|
||||
|
||||
func TestSignalHandlerClose(t *testing.T) {
|
||||
sigHandler := signalHandler{signals: []os.Signal{syscall.SIGUSR1}}
|
||||
done := make(chan struct{})
|
||||
timer := time.NewTimer(time.Second)
|
||||
sigHandler.register(func() { done <- struct{}{} })
|
||||
sigHandler.deregister()
|
||||
|
||||
p, err := os.FindProcess(os.Getpid())
|
||||
require.Nil(t, err)
|
||||
p.Signal(syscall.SIGUSR1)
|
||||
select {
|
||||
case <-done:
|
||||
t.Fail()
|
||||
case <-timer.C:
|
||||
}
|
||||
}
|
||||
+37
-14
@@ -21,11 +21,13 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
keyName = "token"
|
||||
tokenCookie = "CF_Authorization"
|
||||
appDomainHeader = "CF-Access-Domain"
|
||||
appAUDHeader = "CF-Access-Aud"
|
||||
AccessLoginWorkerPath = "/cdn-cgi/access/login"
|
||||
keyName = "token"
|
||||
tokenCookie = "CF_Authorization"
|
||||
appSessionCookie = "CF_AppSession"
|
||||
appDomainHeader = "CF-Access-Domain"
|
||||
appAUDHeader = "CF-Access-Aud"
|
||||
AccessLoginWorkerPath = "/cdn-cgi/access/login"
|
||||
AccessAuthorizedWorkerPath = "/cdn-cgi/access/authorized"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -297,20 +299,41 @@ func GetAppInfo(reqURL *url.URL) (*AppInfo, error) {
|
||||
return &AppInfo{location.Hostname(), aud, domain}, nil
|
||||
}
|
||||
|
||||
func handleRedirects(req *http.Request, via []*http.Request, orgToken string) error {
|
||||
// attach org token to login request
|
||||
if strings.Contains(req.URL.Path, AccessLoginWorkerPath) {
|
||||
req.AddCookie(&http.Cookie{Name: tokenCookie, Value: orgToken})
|
||||
}
|
||||
|
||||
// attach app session cookie to authorized request
|
||||
if strings.Contains(req.URL.Path, AccessAuthorizedWorkerPath) {
|
||||
// We need to check and see if the CF_APP_SESSION cookie was set
|
||||
for _, prevReq := range via {
|
||||
if prevReq != nil && prevReq.Response != nil {
|
||||
for _, c := range prevReq.Response.Cookies() {
|
||||
if c.Name == appSessionCookie {
|
||||
req.AddCookie(&http.Cookie{Name: appSessionCookie, Value: c.Value})
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// stop after hitting authorized endpoint since it will contain the app token
|
||||
if len(via) > 0 && strings.Contains(via[len(via)-1].URL.Path, AccessAuthorizedWorkerPath) {
|
||||
return http.ErrUseLastResponse
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// exchangeOrgToken attaches an org token to a request to the appURL and returns an app token. This uses the Access SSO
|
||||
// flow to automatically generate and return an app token without the login page.
|
||||
func exchangeOrgToken(appURL *url.URL, orgToken string) (string, error) {
|
||||
client := &http.Client{
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
// attach org token to login request
|
||||
if strings.Contains(req.URL.Path, AccessLoginWorkerPath) {
|
||||
req.AddCookie(&http.Cookie{Name: tokenCookie, Value: orgToken})
|
||||
}
|
||||
// stop after hitting authorized endpoint since it will contain the app token
|
||||
if strings.Contains(via[len(via)-1].URL.Path, "cdn-cgi/access/authorized") {
|
||||
return http.ErrUseLastResponse
|
||||
}
|
||||
return nil
|
||||
return handleRedirects(req, via, orgToken)
|
||||
},
|
||||
Timeout: time.Second * 7,
|
||||
}
|
||||
|
||||
+70
-43
@@ -1,55 +1,82 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package token
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSignalHandler(t *testing.T) {
|
||||
sigHandler := signalHandler{signals: []os.Signal{syscall.SIGUSR1}}
|
||||
handlerRan := false
|
||||
done := make(chan struct{})
|
||||
timer := time.NewTimer(time.Second)
|
||||
sigHandler.register(func() {
|
||||
handlerRan = true
|
||||
done <- struct{}{}
|
||||
})
|
||||
func TestHandleRedirects_AttachOrgToken(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", "http://example.com/cdn-cgi/access/login", nil)
|
||||
via := []*http.Request{}
|
||||
orgToken := "orgTokenValue"
|
||||
|
||||
p, err := os.FindProcess(os.Getpid())
|
||||
require.Nil(t, err)
|
||||
p.Signal(syscall.SIGUSR1)
|
||||
handleRedirects(req, via, orgToken)
|
||||
|
||||
// Blocks for up to one second to make sure the handler callback runs before the assert.
|
||||
select {
|
||||
case <-done:
|
||||
assert.True(t, handlerRan)
|
||||
case <-timer.C:
|
||||
t.Fail()
|
||||
// Check if the orgToken cookie is attached
|
||||
cookies := req.Cookies()
|
||||
found := false
|
||||
for _, cookie := range cookies {
|
||||
if cookie.Name == tokenCookie && cookie.Value == orgToken {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
sigHandler.deregister()
|
||||
}
|
||||
|
||||
func TestSignalHandlerClose(t *testing.T) {
|
||||
sigHandler := signalHandler{signals: []os.Signal{syscall.SIGUSR1}}
|
||||
done := make(chan struct{})
|
||||
timer := time.NewTimer(time.Second)
|
||||
sigHandler.register(func() { done <- struct{}{} })
|
||||
sigHandler.deregister()
|
||||
|
||||
p, err := os.FindProcess(os.Getpid())
|
||||
require.Nil(t, err)
|
||||
p.Signal(syscall.SIGUSR1)
|
||||
select {
|
||||
case <-done:
|
||||
t.Fail()
|
||||
case <-timer.C:
|
||||
if !found {
|
||||
t.Errorf("OrgToken cookie not attached to the request.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleRedirects_AttachAppSessionCookie(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", "http://example.com/cdn-cgi/access/authorized", nil)
|
||||
via := []*http.Request{
|
||||
{
|
||||
URL: &url.URL{Path: "/cdn-cgi/access/login"},
|
||||
Response: &http.Response{
|
||||
Header: http.Header{"Set-Cookie": {"CF_AppSession=appSessionValue"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
orgToken := "orgTokenValue"
|
||||
|
||||
err := handleRedirects(req, via, orgToken)
|
||||
|
||||
// Check if the appSessionCookie is attached to the request
|
||||
cookies := req.Cookies()
|
||||
found := false
|
||||
for _, cookie := range cookies {
|
||||
if cookie.Name == appSessionCookie && cookie.Value == "appSessionValue" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("AppSessionCookie not attached to the request.")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleRedirects_StopAtAuthorizedEndpoint(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", "http://example.com/cdn-cgi/access/authorized", nil)
|
||||
via := []*http.Request{
|
||||
{
|
||||
URL: &url.URL{Path: "other"},
|
||||
},
|
||||
{
|
||||
URL: &url.URL{Path: AccessAuthorizedWorkerPath},
|
||||
},
|
||||
}
|
||||
orgToken := "orgTokenValue"
|
||||
|
||||
err := handleRedirects(req, via, orgToken)
|
||||
|
||||
// Check if ErrUseLastResponse is returned
|
||||
if err != http.ErrUseLastResponse {
|
||||
t.Errorf("Expected ErrUseLastResponse, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,8 +132,7 @@ func createResourceSpan(spans []*tracepb.Span) *tracepb.ResourceSpans {
|
||||
SchemaUrl: instrumentSchemaUrl,
|
||||
},
|
||||
},
|
||||
InstrumentationLibrarySpans: nil,
|
||||
SchemaUrl: resourceSchemaUrl,
|
||||
SchemaUrl: resourceSchemaUrl,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -118,6 +118,7 @@ func TestSerializeAuthenticationResponse(t *testing.T) {
|
||||
|
||||
for i, testCase := range tests {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
assert.NoError(t, err)
|
||||
capnpEntity, err := tunnelrpc.NewAuthenticateResponse(seg)
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fatal("Couldn't initialize a new message")
|
||||
|
||||
@@ -38,6 +38,7 @@ func TestTunnelRegistration(t *testing.T) {
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
assert.NoError(t, err)
|
||||
capnpEntity, err := tunnelrpc.NewTunnelRegistration(seg)
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fatal("Couldn't initialize a new message")
|
||||
|
||||
@@ -168,68 +168,6 @@ func validateIP(scheme, host, port string) (string, error) {
|
||||
return fmt.Sprintf("%s://%s", scheme, host), nil
|
||||
}
|
||||
|
||||
// originURL shouldn't be a pointer, because this function might change the scheme
|
||||
func ValidateHTTPService(originURL string, hostname string, transport http.RoundTripper) error {
|
||||
parsedURL, err := url.Parse(originURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Transport: transport,
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
Timeout: validationTimeout,
|
||||
}
|
||||
|
||||
initialRequest, err := http.NewRequest("GET", parsedURL.String(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
initialRequest.Host = hostname
|
||||
resp, initialErr := client.Do(initialRequest)
|
||||
if initialErr == nil {
|
||||
resp.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Attempt the same endpoint via the other protocol (http/https); maybe we have better luck?
|
||||
oldScheme := parsedURL.Scheme
|
||||
parsedURL.Scheme = toggleProtocol(oldScheme)
|
||||
|
||||
secondRequest, err := http.NewRequest("GET", parsedURL.String(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
secondRequest.Host = hostname
|
||||
resp, secondErr := client.Do(secondRequest)
|
||||
if secondErr == nil { // Worked this time--advise the user to switch protocols
|
||||
_ = resp.Body.Close()
|
||||
return errors.Errorf(
|
||||
"%s doesn't seem to work over %s, but does seem to work over %s. Reason: %v. Consider changing the origin URL to %v",
|
||||
parsedURL.Host,
|
||||
oldScheme,
|
||||
parsedURL.Scheme,
|
||||
initialErr,
|
||||
originURL,
|
||||
)
|
||||
}
|
||||
|
||||
return initialErr
|
||||
}
|
||||
|
||||
func toggleProtocol(httpProtocol string) string {
|
||||
switch httpProtocol {
|
||||
case "http":
|
||||
return "https"
|
||||
case "https":
|
||||
return "http"
|
||||
default:
|
||||
return httpProtocol
|
||||
}
|
||||
}
|
||||
|
||||
// Access checks if a JWT from Cloudflare Access is valid.
|
||||
type Access struct {
|
||||
verifier *oidc.IDTokenVerifier
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"context"
|
||||
"crypto/tls"
|
||||
@@ -114,179 +113,6 @@ func TestValidateUrl(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestToggleProtocol(t *testing.T) {
|
||||
assert.Equal(t, "https", toggleProtocol("http"))
|
||||
assert.Equal(t, "http", toggleProtocol("https"))
|
||||
assert.Equal(t, "random", toggleProtocol("random"))
|
||||
assert.Equal(t, "", toggleProtocol(""))
|
||||
}
|
||||
|
||||
// Happy path 1: originURL is HTTP, and HTTP connections work
|
||||
func TestValidateHTTPService_HTTP2HTTP(t *testing.T) {
|
||||
originURL := "http://127.0.0.1/"
|
||||
hostname := "example.com"
|
||||
|
||||
assert.Nil(t, ValidateHTTPService(originURL, hostname, testRoundTripper(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Equal(t, req.Host, hostname)
|
||||
if req.URL.Scheme == "http" {
|
||||
return emptyResponse(200), nil
|
||||
}
|
||||
if req.URL.Scheme == "https" {
|
||||
t.Fatal("http works, shouldn't have tried with https")
|
||||
}
|
||||
panic("Shouldn't reach here")
|
||||
})))
|
||||
|
||||
assert.Nil(t, ValidateHTTPService(originURL, hostname, testRoundTripper(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Equal(t, req.Host, hostname)
|
||||
if req.URL.Scheme == "http" {
|
||||
return emptyResponse(503), nil
|
||||
}
|
||||
if req.URL.Scheme == "https" {
|
||||
t.Fatal("http works, shouldn't have tried with https")
|
||||
}
|
||||
panic("Shouldn't reach here")
|
||||
})))
|
||||
}
|
||||
|
||||
// Happy path 2: originURL is HTTPS, and HTTPS connections work
|
||||
func TestValidateHTTPService_HTTPS2HTTPS(t *testing.T) {
|
||||
originURL := "https://127.0.0.1:1234/"
|
||||
hostname := "example.com"
|
||||
|
||||
assert.Nil(t, ValidateHTTPService(originURL, hostname, testRoundTripper(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Equal(t, req.Host, hostname)
|
||||
if req.URL.Scheme == "http" {
|
||||
t.Fatal("https works, shouldn't have tried with http")
|
||||
}
|
||||
if req.URL.Scheme == "https" {
|
||||
return emptyResponse(200), nil
|
||||
}
|
||||
panic("Shouldn't reach here")
|
||||
})))
|
||||
|
||||
assert.Nil(t, ValidateHTTPService(originURL, hostname, testRoundTripper(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Equal(t, req.Host, hostname)
|
||||
if req.URL.Scheme == "http" {
|
||||
t.Fatal("https works, shouldn't have tried with http")
|
||||
}
|
||||
if req.URL.Scheme == "https" {
|
||||
return emptyResponse(503), nil
|
||||
}
|
||||
panic("Shouldn't reach here")
|
||||
})))
|
||||
}
|
||||
|
||||
// Error path 1: originURL is HTTPS, but HTTP connections work
|
||||
func TestValidateHTTPService_HTTPS2HTTP(t *testing.T) {
|
||||
originURL := "https://127.0.0.1:1234/"
|
||||
hostname := "example.com"
|
||||
|
||||
assert.Error(t, ValidateHTTPService(originURL, hostname, testRoundTripper(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Equal(t, req.Host, hostname)
|
||||
if req.URL.Scheme == "http" {
|
||||
return emptyResponse(200), nil
|
||||
}
|
||||
if req.URL.Scheme == "https" {
|
||||
return nil, assert.AnError
|
||||
}
|
||||
panic("Shouldn't reach here")
|
||||
})))
|
||||
|
||||
assert.Error(t, ValidateHTTPService(originURL, hostname, testRoundTripper(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Equal(t, req.Host, hostname)
|
||||
if req.URL.Scheme == "http" {
|
||||
return emptyResponse(503), nil
|
||||
}
|
||||
if req.URL.Scheme == "https" {
|
||||
return nil, assert.AnError
|
||||
}
|
||||
panic("Shouldn't reach here")
|
||||
})))
|
||||
}
|
||||
|
||||
// Error path 2: originURL is HTTP, but HTTPS connections work
|
||||
func TestValidateHTTPService_HTTP2HTTPS(t *testing.T) {
|
||||
originURL := "http://127.0.0.1:1234/"
|
||||
hostname := "example.com"
|
||||
|
||||
assert.Error(t, ValidateHTTPService(originURL, hostname, testRoundTripper(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Equal(t, req.Host, hostname)
|
||||
if req.URL.Scheme == "http" {
|
||||
return nil, assert.AnError
|
||||
}
|
||||
if req.URL.Scheme == "https" {
|
||||
return emptyResponse(200), nil
|
||||
}
|
||||
panic("Shouldn't reach here")
|
||||
})))
|
||||
|
||||
assert.Error(t, ValidateHTTPService(originURL, hostname, testRoundTripper(func(req *http.Request) (*http.Response, error) {
|
||||
assert.Equal(t, req.Host, hostname)
|
||||
if req.URL.Scheme == "http" {
|
||||
return nil, assert.AnError
|
||||
}
|
||||
if req.URL.Scheme == "https" {
|
||||
return emptyResponse(503), nil
|
||||
}
|
||||
panic("Shouldn't reach here")
|
||||
})))
|
||||
}
|
||||
|
||||
// Ensure the client does not follow 302 responses
|
||||
func TestValidateHTTPService_NoFollowRedirects(t *testing.T) {
|
||||
hostname := "example.com"
|
||||
redirectServer, redirectClient, err := createSecureMockServerAndClient(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/followedRedirect" {
|
||||
t.Fatal("shouldn't have followed the 302")
|
||||
}
|
||||
if r.Method == "CONNECT" {
|
||||
assert.Equal(t, "127.0.0.1:443", r.Host)
|
||||
} else {
|
||||
assert.Equal(t, hostname, r.Host)
|
||||
}
|
||||
w.Header().Set("Location", "/followedRedirect")
|
||||
w.WriteHeader(302)
|
||||
}))
|
||||
assert.NoError(t, err)
|
||||
defer redirectServer.Close()
|
||||
assert.NoError(t, ValidateHTTPService(redirectServer.URL, hostname, redirectClient.Transport))
|
||||
}
|
||||
|
||||
// Ensure validation times out when origin URL is nonresponsive
|
||||
func TestValidateHTTPService_NonResponsiveOrigin(t *testing.T) {
|
||||
originURL := "http://127.0.0.1/"
|
||||
hostname := "example.com"
|
||||
oldValidationTimeout := validationTimeout
|
||||
defer func() {
|
||||
validationTimeout = oldValidationTimeout
|
||||
}()
|
||||
validationTimeout = 500 * time.Millisecond
|
||||
|
||||
// Use createMockServerAndClient, not createSecureMockServerAndClient.
|
||||
// The latter will bail with HTTP 400 immediately on an http:// request,
|
||||
// which defeats the purpose of a 'nonresponsive origin' test.
|
||||
server, client, err := createMockServerAndClient(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "CONNECT" {
|
||||
assert.Equal(t, "127.0.0.1:443", r.Host)
|
||||
} else {
|
||||
assert.Equal(t, hostname, r.Host)
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
w.WriteHeader(200)
|
||||
}))
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
defer server.Close()
|
||||
|
||||
err = ValidateHTTPService(originURL, hostname, client.Transport)
|
||||
fmt.Println(err)
|
||||
if err, ok := err.(net.Error); assert.True(t, ok) {
|
||||
assert.True(t, err.Timeout())
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewAccessValidatorOk(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
url := "test.cloudflareaccess.com"
|
||||
|
||||
+17
-14
@@ -3,8 +3,7 @@
|
||||
[](https://pkg.go.dev/github.com/cespare/xxhash/v2)
|
||||
[](https://github.com/cespare/xxhash/actions/workflows/test.yml)
|
||||
|
||||
xxhash is a Go implementation of the 64-bit
|
||||
[xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a
|
||||
xxhash is a Go implementation of the 64-bit [xxHash] algorithm, XXH64. This is a
|
||||
high-quality hashing algorithm that is much faster than anything in the Go
|
||||
standard library.
|
||||
|
||||
@@ -25,8 +24,11 @@ func (*Digest) WriteString(string) (int, error)
|
||||
func (*Digest) Sum64() uint64
|
||||
```
|
||||
|
||||
This implementation provides a fast pure-Go implementation and an even faster
|
||||
assembly implementation for amd64.
|
||||
The package is written with optimized pure Go and also contains even faster
|
||||
assembly implementations for amd64 and arm64. If desired, the `purego` build tag
|
||||
opts into using the Go code even on those architectures.
|
||||
|
||||
[xxHash]: http://cyan4973.github.io/xxHash/
|
||||
|
||||
## Compatibility
|
||||
|
||||
@@ -45,19 +47,20 @@ I recommend using the latest release of Go.
|
||||
Here are some quick benchmarks comparing the pure-Go and assembly
|
||||
implementations of Sum64.
|
||||
|
||||
| input size | purego | asm |
|
||||
| --- | --- | --- |
|
||||
| 5 B | 979.66 MB/s | 1291.17 MB/s |
|
||||
| 100 B | 7475.26 MB/s | 7973.40 MB/s |
|
||||
| 4 KB | 17573.46 MB/s | 17602.65 MB/s |
|
||||
| 10 MB | 17131.46 MB/s | 17142.16 MB/s |
|
||||
| input size | purego | asm |
|
||||
| ---------- | --------- | --------- |
|
||||
| 4 B | 1.3 GB/s | 1.2 GB/s |
|
||||
| 16 B | 2.9 GB/s | 3.5 GB/s |
|
||||
| 100 B | 6.9 GB/s | 8.1 GB/s |
|
||||
| 4 KB | 11.7 GB/s | 16.7 GB/s |
|
||||
| 10 MB | 12.0 GB/s | 17.3 GB/s |
|
||||
|
||||
These numbers were generated on Ubuntu 18.04 with an Intel i7-8700K CPU using
|
||||
the following commands under Go 1.11.2:
|
||||
These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C
|
||||
CPU using the following commands under Go 1.19.2:
|
||||
|
||||
```
|
||||
$ go test -tags purego -benchtime 10s -bench '/xxhash,direct,bytes'
|
||||
$ go test -benchtime 10s -bench '/xxhash,direct,bytes'
|
||||
benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$')
|
||||
benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')
|
||||
```
|
||||
|
||||
## Projects using this package
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
set -eu -o pipefail
|
||||
|
||||
# Small convenience script for running the tests with various combinations of
|
||||
# arch/tags. This assumes we're running on amd64 and have qemu available.
|
||||
|
||||
go test ./...
|
||||
go test -tags purego ./...
|
||||
GOARCH=arm64 go test
|
||||
GOARCH=arm64 go test -tags purego
|
||||
+20
-27
@@ -16,19 +16,11 @@ const (
|
||||
prime5 uint64 = 2870177450012600261
|
||||
)
|
||||
|
||||
// NOTE(caleb): I'm using both consts and vars of the primes. Using consts where
|
||||
// possible in the Go code is worth a small (but measurable) performance boost
|
||||
// by avoiding some MOVQs. Vars are needed for the asm and also are useful for
|
||||
// convenience in the Go code in a few places where we need to intentionally
|
||||
// avoid constant arithmetic (e.g., v1 := prime1 + prime2 fails because the
|
||||
// result overflows a uint64).
|
||||
var (
|
||||
prime1v = prime1
|
||||
prime2v = prime2
|
||||
prime3v = prime3
|
||||
prime4v = prime4
|
||||
prime5v = prime5
|
||||
)
|
||||
// Store the primes in an array as well.
|
||||
//
|
||||
// The consts are used when possible in Go code to avoid MOVs but we need a
|
||||
// contiguous array of the assembly code.
|
||||
var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5}
|
||||
|
||||
// Digest implements hash.Hash64.
|
||||
type Digest struct {
|
||||
@@ -50,10 +42,10 @@ func New() *Digest {
|
||||
|
||||
// Reset clears the Digest's state so that it can be reused.
|
||||
func (d *Digest) Reset() {
|
||||
d.v1 = prime1v + prime2
|
||||
d.v1 = primes[0] + prime2
|
||||
d.v2 = prime2
|
||||
d.v3 = 0
|
||||
d.v4 = -prime1v
|
||||
d.v4 = -primes[0]
|
||||
d.total = 0
|
||||
d.n = 0
|
||||
}
|
||||
@@ -69,21 +61,23 @@ func (d *Digest) Write(b []byte) (n int, err error) {
|
||||
n = len(b)
|
||||
d.total += uint64(n)
|
||||
|
||||
memleft := d.mem[d.n&(len(d.mem)-1):]
|
||||
|
||||
if d.n+n < 32 {
|
||||
// This new data doesn't even fill the current block.
|
||||
copy(d.mem[d.n:], b)
|
||||
copy(memleft, b)
|
||||
d.n += n
|
||||
return
|
||||
}
|
||||
|
||||
if d.n > 0 {
|
||||
// Finish off the partial block.
|
||||
copy(d.mem[d.n:], b)
|
||||
c := copy(memleft, b)
|
||||
d.v1 = round(d.v1, u64(d.mem[0:8]))
|
||||
d.v2 = round(d.v2, u64(d.mem[8:16]))
|
||||
d.v3 = round(d.v3, u64(d.mem[16:24]))
|
||||
d.v4 = round(d.v4, u64(d.mem[24:32]))
|
||||
b = b[32-d.n:]
|
||||
b = b[c:]
|
||||
d.n = 0
|
||||
}
|
||||
|
||||
@@ -133,21 +127,20 @@ func (d *Digest) Sum64() uint64 {
|
||||
|
||||
h += d.total
|
||||
|
||||
i, end := 0, d.n
|
||||
for ; i+8 <= end; i += 8 {
|
||||
k1 := round(0, u64(d.mem[i:i+8]))
|
||||
b := d.mem[:d.n&(len(d.mem)-1)]
|
||||
for ; len(b) >= 8; b = b[8:] {
|
||||
k1 := round(0, u64(b[:8]))
|
||||
h ^= k1
|
||||
h = rol27(h)*prime1 + prime4
|
||||
}
|
||||
if i+4 <= end {
|
||||
h ^= uint64(u32(d.mem[i:i+4])) * prime1
|
||||
if len(b) >= 4 {
|
||||
h ^= uint64(u32(b[:4])) * prime1
|
||||
h = rol23(h)*prime2 + prime3
|
||||
i += 4
|
||||
b = b[4:]
|
||||
}
|
||||
for i < end {
|
||||
h ^= uint64(d.mem[i]) * prime5
|
||||
for ; len(b) > 0; b = b[1:] {
|
||||
h ^= uint64(b[0]) * prime5
|
||||
h = rol11(h) * prime1
|
||||
i++
|
||||
}
|
||||
|
||||
h ^= h >> 33
|
||||
|
||||
+151
-157
@@ -1,215 +1,209 @@
|
||||
//go:build !appengine && gc && !purego
|
||||
// +build !appengine
|
||||
// +build gc
|
||||
// +build !purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// Register allocation:
|
||||
// AX h
|
||||
// SI pointer to advance through b
|
||||
// DX n
|
||||
// BX loop end
|
||||
// R8 v1, k1
|
||||
// R9 v2
|
||||
// R10 v3
|
||||
// R11 v4
|
||||
// R12 tmp
|
||||
// R13 prime1v
|
||||
// R14 prime2v
|
||||
// DI prime4v
|
||||
// Registers:
|
||||
#define h AX
|
||||
#define d AX
|
||||
#define p SI // pointer to advance through b
|
||||
#define n DX
|
||||
#define end BX // loop end
|
||||
#define v1 R8
|
||||
#define v2 R9
|
||||
#define v3 R10
|
||||
#define v4 R11
|
||||
#define x R12
|
||||
#define prime1 R13
|
||||
#define prime2 R14
|
||||
#define prime4 DI
|
||||
|
||||
// round reads from and advances the buffer pointer in SI.
|
||||
// It assumes that R13 has prime1v and R14 has prime2v.
|
||||
#define round(r) \
|
||||
MOVQ (SI), R12 \
|
||||
ADDQ $8, SI \
|
||||
IMULQ R14, R12 \
|
||||
ADDQ R12, r \
|
||||
ROLQ $31, r \
|
||||
IMULQ R13, r
|
||||
#define round(acc, x) \
|
||||
IMULQ prime2, x \
|
||||
ADDQ x, acc \
|
||||
ROLQ $31, acc \
|
||||
IMULQ prime1, acc
|
||||
|
||||
// mergeRound applies a merge round on the two registers acc and val.
|
||||
// It assumes that R13 has prime1v, R14 has prime2v, and DI has prime4v.
|
||||
#define mergeRound(acc, val) \
|
||||
IMULQ R14, val \
|
||||
ROLQ $31, val \
|
||||
IMULQ R13, val \
|
||||
XORQ val, acc \
|
||||
IMULQ R13, acc \
|
||||
ADDQ DI, acc
|
||||
// round0 performs the operation x = round(0, x).
|
||||
#define round0(x) \
|
||||
IMULQ prime2, x \
|
||||
ROLQ $31, x \
|
||||
IMULQ prime1, x
|
||||
|
||||
// mergeRound applies a merge round on the two registers acc and x.
|
||||
// It assumes that prime1, prime2, and prime4 have been loaded.
|
||||
#define mergeRound(acc, x) \
|
||||
round0(x) \
|
||||
XORQ x, acc \
|
||||
IMULQ prime1, acc \
|
||||
ADDQ prime4, acc
|
||||
|
||||
// blockLoop processes as many 32-byte blocks as possible,
|
||||
// updating v1, v2, v3, and v4. It assumes that there is at least one block
|
||||
// to process.
|
||||
#define blockLoop() \
|
||||
loop: \
|
||||
MOVQ +0(p), x \
|
||||
round(v1, x) \
|
||||
MOVQ +8(p), x \
|
||||
round(v2, x) \
|
||||
MOVQ +16(p), x \
|
||||
round(v3, x) \
|
||||
MOVQ +24(p), x \
|
||||
round(v4, x) \
|
||||
ADDQ $32, p \
|
||||
CMPQ p, end \
|
||||
JLE loop
|
||||
|
||||
// func Sum64(b []byte) uint64
|
||||
TEXT ·Sum64(SB), NOSPLIT, $0-32
|
||||
TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
|
||||
// Load fixed primes.
|
||||
MOVQ ·prime1v(SB), R13
|
||||
MOVQ ·prime2v(SB), R14
|
||||
MOVQ ·prime4v(SB), DI
|
||||
MOVQ ·primes+0(SB), prime1
|
||||
MOVQ ·primes+8(SB), prime2
|
||||
MOVQ ·primes+24(SB), prime4
|
||||
|
||||
// Load slice.
|
||||
MOVQ b_base+0(FP), SI
|
||||
MOVQ b_len+8(FP), DX
|
||||
LEAQ (SI)(DX*1), BX
|
||||
MOVQ b_base+0(FP), p
|
||||
MOVQ b_len+8(FP), n
|
||||
LEAQ (p)(n*1), end
|
||||
|
||||
// The first loop limit will be len(b)-32.
|
||||
SUBQ $32, BX
|
||||
SUBQ $32, end
|
||||
|
||||
// Check whether we have at least one block.
|
||||
CMPQ DX, $32
|
||||
CMPQ n, $32
|
||||
JLT noBlocks
|
||||
|
||||
// Set up initial state (v1, v2, v3, v4).
|
||||
MOVQ R13, R8
|
||||
ADDQ R14, R8
|
||||
MOVQ R14, R9
|
||||
XORQ R10, R10
|
||||
XORQ R11, R11
|
||||
SUBQ R13, R11
|
||||
MOVQ prime1, v1
|
||||
ADDQ prime2, v1
|
||||
MOVQ prime2, v2
|
||||
XORQ v3, v3
|
||||
XORQ v4, v4
|
||||
SUBQ prime1, v4
|
||||
|
||||
// Loop until SI > BX.
|
||||
blockLoop:
|
||||
round(R8)
|
||||
round(R9)
|
||||
round(R10)
|
||||
round(R11)
|
||||
blockLoop()
|
||||
|
||||
CMPQ SI, BX
|
||||
JLE blockLoop
|
||||
MOVQ v1, h
|
||||
ROLQ $1, h
|
||||
MOVQ v2, x
|
||||
ROLQ $7, x
|
||||
ADDQ x, h
|
||||
MOVQ v3, x
|
||||
ROLQ $12, x
|
||||
ADDQ x, h
|
||||
MOVQ v4, x
|
||||
ROLQ $18, x
|
||||
ADDQ x, h
|
||||
|
||||
MOVQ R8, AX
|
||||
ROLQ $1, AX
|
||||
MOVQ R9, R12
|
||||
ROLQ $7, R12
|
||||
ADDQ R12, AX
|
||||
MOVQ R10, R12
|
||||
ROLQ $12, R12
|
||||
ADDQ R12, AX
|
||||
MOVQ R11, R12
|
||||
ROLQ $18, R12
|
||||
ADDQ R12, AX
|
||||
|
||||
mergeRound(AX, R8)
|
||||
mergeRound(AX, R9)
|
||||
mergeRound(AX, R10)
|
||||
mergeRound(AX, R11)
|
||||
mergeRound(h, v1)
|
||||
mergeRound(h, v2)
|
||||
mergeRound(h, v3)
|
||||
mergeRound(h, v4)
|
||||
|
||||
JMP afterBlocks
|
||||
|
||||
noBlocks:
|
||||
MOVQ ·prime5v(SB), AX
|
||||
MOVQ ·primes+32(SB), h
|
||||
|
||||
afterBlocks:
|
||||
ADDQ DX, AX
|
||||
ADDQ n, h
|
||||
|
||||
// Right now BX has len(b)-32, and we want to loop until SI > len(b)-8.
|
||||
ADDQ $24, BX
|
||||
ADDQ $24, end
|
||||
CMPQ p, end
|
||||
JG try4
|
||||
|
||||
CMPQ SI, BX
|
||||
JG fourByte
|
||||
loop8:
|
||||
MOVQ (p), x
|
||||
ADDQ $8, p
|
||||
round0(x)
|
||||
XORQ x, h
|
||||
ROLQ $27, h
|
||||
IMULQ prime1, h
|
||||
ADDQ prime4, h
|
||||
|
||||
wordLoop:
|
||||
// Calculate k1.
|
||||
MOVQ (SI), R8
|
||||
ADDQ $8, SI
|
||||
IMULQ R14, R8
|
||||
ROLQ $31, R8
|
||||
IMULQ R13, R8
|
||||
CMPQ p, end
|
||||
JLE loop8
|
||||
|
||||
XORQ R8, AX
|
||||
ROLQ $27, AX
|
||||
IMULQ R13, AX
|
||||
ADDQ DI, AX
|
||||
try4:
|
||||
ADDQ $4, end
|
||||
CMPQ p, end
|
||||
JG try1
|
||||
|
||||
CMPQ SI, BX
|
||||
JLE wordLoop
|
||||
MOVL (p), x
|
||||
ADDQ $4, p
|
||||
IMULQ prime1, x
|
||||
XORQ x, h
|
||||
|
||||
fourByte:
|
||||
ADDQ $4, BX
|
||||
CMPQ SI, BX
|
||||
JG singles
|
||||
ROLQ $23, h
|
||||
IMULQ prime2, h
|
||||
ADDQ ·primes+16(SB), h
|
||||
|
||||
MOVL (SI), R8
|
||||
ADDQ $4, SI
|
||||
IMULQ R13, R8
|
||||
XORQ R8, AX
|
||||
|
||||
ROLQ $23, AX
|
||||
IMULQ R14, AX
|
||||
ADDQ ·prime3v(SB), AX
|
||||
|
||||
singles:
|
||||
ADDQ $4, BX
|
||||
CMPQ SI, BX
|
||||
try1:
|
||||
ADDQ $4, end
|
||||
CMPQ p, end
|
||||
JGE finalize
|
||||
|
||||
singlesLoop:
|
||||
MOVBQZX (SI), R12
|
||||
ADDQ $1, SI
|
||||
IMULQ ·prime5v(SB), R12
|
||||
XORQ R12, AX
|
||||
loop1:
|
||||
MOVBQZX (p), x
|
||||
ADDQ $1, p
|
||||
IMULQ ·primes+32(SB), x
|
||||
XORQ x, h
|
||||
ROLQ $11, h
|
||||
IMULQ prime1, h
|
||||
|
||||
ROLQ $11, AX
|
||||
IMULQ R13, AX
|
||||
|
||||
CMPQ SI, BX
|
||||
JL singlesLoop
|
||||
CMPQ p, end
|
||||
JL loop1
|
||||
|
||||
finalize:
|
||||
MOVQ AX, R12
|
||||
SHRQ $33, R12
|
||||
XORQ R12, AX
|
||||
IMULQ R14, AX
|
||||
MOVQ AX, R12
|
||||
SHRQ $29, R12
|
||||
XORQ R12, AX
|
||||
IMULQ ·prime3v(SB), AX
|
||||
MOVQ AX, R12
|
||||
SHRQ $32, R12
|
||||
XORQ R12, AX
|
||||
MOVQ h, x
|
||||
SHRQ $33, x
|
||||
XORQ x, h
|
||||
IMULQ prime2, h
|
||||
MOVQ h, x
|
||||
SHRQ $29, x
|
||||
XORQ x, h
|
||||
IMULQ ·primes+16(SB), h
|
||||
MOVQ h, x
|
||||
SHRQ $32, x
|
||||
XORQ x, h
|
||||
|
||||
MOVQ AX, ret+24(FP)
|
||||
MOVQ h, ret+24(FP)
|
||||
RET
|
||||
|
||||
// writeBlocks uses the same registers as above except that it uses AX to store
|
||||
// the d pointer.
|
||||
|
||||
// func writeBlocks(d *Digest, b []byte) int
|
||||
TEXT ·writeBlocks(SB), NOSPLIT, $0-40
|
||||
TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
|
||||
// Load fixed primes needed for round.
|
||||
MOVQ ·prime1v(SB), R13
|
||||
MOVQ ·prime2v(SB), R14
|
||||
MOVQ ·primes+0(SB), prime1
|
||||
MOVQ ·primes+8(SB), prime2
|
||||
|
||||
// Load slice.
|
||||
MOVQ b_base+8(FP), SI
|
||||
MOVQ b_len+16(FP), DX
|
||||
LEAQ (SI)(DX*1), BX
|
||||
SUBQ $32, BX
|
||||
MOVQ b_base+8(FP), p
|
||||
MOVQ b_len+16(FP), n
|
||||
LEAQ (p)(n*1), end
|
||||
SUBQ $32, end
|
||||
|
||||
// Load vN from d.
|
||||
MOVQ d+0(FP), AX
|
||||
MOVQ 0(AX), R8 // v1
|
||||
MOVQ 8(AX), R9 // v2
|
||||
MOVQ 16(AX), R10 // v3
|
||||
MOVQ 24(AX), R11 // v4
|
||||
MOVQ s+0(FP), d
|
||||
MOVQ 0(d), v1
|
||||
MOVQ 8(d), v2
|
||||
MOVQ 16(d), v3
|
||||
MOVQ 24(d), v4
|
||||
|
||||
// We don't need to check the loop condition here; this function is
|
||||
// always called with at least one block of data to process.
|
||||
blockLoop:
|
||||
round(R8)
|
||||
round(R9)
|
||||
round(R10)
|
||||
round(R11)
|
||||
|
||||
CMPQ SI, BX
|
||||
JLE blockLoop
|
||||
blockLoop()
|
||||
|
||||
// Copy vN back to d.
|
||||
MOVQ R8, 0(AX)
|
||||
MOVQ R9, 8(AX)
|
||||
MOVQ R10, 16(AX)
|
||||
MOVQ R11, 24(AX)
|
||||
MOVQ v1, 0(d)
|
||||
MOVQ v2, 8(d)
|
||||
MOVQ v3, 16(d)
|
||||
MOVQ v4, 24(d)
|
||||
|
||||
// The number of bytes written is SI minus the old base pointer.
|
||||
SUBQ b_base+8(FP), SI
|
||||
MOVQ SI, ret+32(FP)
|
||||
// The number of bytes written is p minus the old base pointer.
|
||||
SUBQ b_base+8(FP), p
|
||||
MOVQ p, ret+32(FP)
|
||||
|
||||
RET
|
||||
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
//go:build !appengine && gc && !purego
|
||||
// +build !appengine
|
||||
// +build gc
|
||||
// +build !purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// Registers:
|
||||
#define digest R1
|
||||
#define h R2 // return value
|
||||
#define p R3 // input pointer
|
||||
#define n R4 // input length
|
||||
#define nblocks R5 // n / 32
|
||||
#define prime1 R7
|
||||
#define prime2 R8
|
||||
#define prime3 R9
|
||||
#define prime4 R10
|
||||
#define prime5 R11
|
||||
#define v1 R12
|
||||
#define v2 R13
|
||||
#define v3 R14
|
||||
#define v4 R15
|
||||
#define x1 R20
|
||||
#define x2 R21
|
||||
#define x3 R22
|
||||
#define x4 R23
|
||||
|
||||
#define round(acc, x) \
|
||||
MADD prime2, acc, x, acc \
|
||||
ROR $64-31, acc \
|
||||
MUL prime1, acc
|
||||
|
||||
// round0 performs the operation x = round(0, x).
|
||||
#define round0(x) \
|
||||
MUL prime2, x \
|
||||
ROR $64-31, x \
|
||||
MUL prime1, x
|
||||
|
||||
#define mergeRound(acc, x) \
|
||||
round0(x) \
|
||||
EOR x, acc \
|
||||
MADD acc, prime4, prime1, acc
|
||||
|
||||
// blockLoop processes as many 32-byte blocks as possible,
|
||||
// updating v1, v2, v3, and v4. It assumes that n >= 32.
|
||||
#define blockLoop() \
|
||||
LSR $5, n, nblocks \
|
||||
PCALIGN $16 \
|
||||
loop: \
|
||||
LDP.P 16(p), (x1, x2) \
|
||||
LDP.P 16(p), (x3, x4) \
|
||||
round(v1, x1) \
|
||||
round(v2, x2) \
|
||||
round(v3, x3) \
|
||||
round(v4, x4) \
|
||||
SUB $1, nblocks \
|
||||
CBNZ nblocks, loop
|
||||
|
||||
// func Sum64(b []byte) uint64
|
||||
TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
|
||||
LDP b_base+0(FP), (p, n)
|
||||
|
||||
LDP ·primes+0(SB), (prime1, prime2)
|
||||
LDP ·primes+16(SB), (prime3, prime4)
|
||||
MOVD ·primes+32(SB), prime5
|
||||
|
||||
CMP $32, n
|
||||
CSEL LT, prime5, ZR, h // if n < 32 { h = prime5 } else { h = 0 }
|
||||
BLT afterLoop
|
||||
|
||||
ADD prime1, prime2, v1
|
||||
MOVD prime2, v2
|
||||
MOVD $0, v3
|
||||
NEG prime1, v4
|
||||
|
||||
blockLoop()
|
||||
|
||||
ROR $64-1, v1, x1
|
||||
ROR $64-7, v2, x2
|
||||
ADD x1, x2
|
||||
ROR $64-12, v3, x3
|
||||
ROR $64-18, v4, x4
|
||||
ADD x3, x4
|
||||
ADD x2, x4, h
|
||||
|
||||
mergeRound(h, v1)
|
||||
mergeRound(h, v2)
|
||||
mergeRound(h, v3)
|
||||
mergeRound(h, v4)
|
||||
|
||||
afterLoop:
|
||||
ADD n, h
|
||||
|
||||
TBZ $4, n, try8
|
||||
LDP.P 16(p), (x1, x2)
|
||||
|
||||
round0(x1)
|
||||
|
||||
// NOTE: here and below, sequencing the EOR after the ROR (using a
|
||||
// rotated register) is worth a small but measurable speedup for small
|
||||
// inputs.
|
||||
ROR $64-27, h
|
||||
EOR x1 @> 64-27, h, h
|
||||
MADD h, prime4, prime1, h
|
||||
|
||||
round0(x2)
|
||||
ROR $64-27, h
|
||||
EOR x2 @> 64-27, h, h
|
||||
MADD h, prime4, prime1, h
|
||||
|
||||
try8:
|
||||
TBZ $3, n, try4
|
||||
MOVD.P 8(p), x1
|
||||
|
||||
round0(x1)
|
||||
ROR $64-27, h
|
||||
EOR x1 @> 64-27, h, h
|
||||
MADD h, prime4, prime1, h
|
||||
|
||||
try4:
|
||||
TBZ $2, n, try2
|
||||
MOVWU.P 4(p), x2
|
||||
|
||||
MUL prime1, x2
|
||||
ROR $64-23, h
|
||||
EOR x2 @> 64-23, h, h
|
||||
MADD h, prime3, prime2, h
|
||||
|
||||
try2:
|
||||
TBZ $1, n, try1
|
||||
MOVHU.P 2(p), x3
|
||||
AND $255, x3, x1
|
||||
LSR $8, x3, x2
|
||||
|
||||
MUL prime5, x1
|
||||
ROR $64-11, h
|
||||
EOR x1 @> 64-11, h, h
|
||||
MUL prime1, h
|
||||
|
||||
MUL prime5, x2
|
||||
ROR $64-11, h
|
||||
EOR x2 @> 64-11, h, h
|
||||
MUL prime1, h
|
||||
|
||||
try1:
|
||||
TBZ $0, n, finalize
|
||||
MOVBU (p), x4
|
||||
|
||||
MUL prime5, x4
|
||||
ROR $64-11, h
|
||||
EOR x4 @> 64-11, h, h
|
||||
MUL prime1, h
|
||||
|
||||
finalize:
|
||||
EOR h >> 33, h
|
||||
MUL prime2, h
|
||||
EOR h >> 29, h
|
||||
MUL prime3, h
|
||||
EOR h >> 32, h
|
||||
|
||||
MOVD h, ret+24(FP)
|
||||
RET
|
||||
|
||||
// func writeBlocks(d *Digest, b []byte) int
|
||||
TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
|
||||
LDP ·primes+0(SB), (prime1, prime2)
|
||||
|
||||
// Load state. Assume v[1-4] are stored contiguously.
|
||||
MOVD d+0(FP), digest
|
||||
LDP 0(digest), (v1, v2)
|
||||
LDP 16(digest), (v3, v4)
|
||||
|
||||
LDP b_base+8(FP), (p, n)
|
||||
|
||||
blockLoop()
|
||||
|
||||
// Store updated state.
|
||||
STP (v1, v2), 0(digest)
|
||||
STP (v3, v4), 16(digest)
|
||||
|
||||
BIC $31, n
|
||||
MOVD n, ret+32(FP)
|
||||
RET
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user