Compare commits

...

36 Commits

Author SHA1 Message Date
Sudarsan Reddy 2519aec733 Release 2022.12.0 2022-12-15 08:19:39 +00:00
Sudarsan Reddy 99b3736cc7 TUN-6999: cloudflared should attempt other edge addresses before falling back on protocol
This PR does two things:
It changes how we fallback to a lower protocol: The current state
is to try connecting with a protocol. If it fails, fall back to a
lower protocol. And try connecting with that and so on. With this PR,
if we fail to connect with a protocol, we will try to connect to other
edge addresses first. Only if we fail to connect to those will we
fall back to a lower protocol.
It fixes a behaviour where if we fail to connect to an edge addr,
we keep re-trying the same address over and over again.
This PR now switches between edge addresses on subsequent connecton attempts.
Note that through these switches, it still respects the backoff time.
(We are connecting to a different edge, but this helps to not bombard an edge
address with connect requests if a particular edge addresses stops working).
2022-12-14 13:17:21 +00:00
João Oliveirinha e517242194 TUN-6995: Disable quick-tunnels spin up by default
Before this change when running cloudflare tunnel command without any
subcommand and without any additional flag, we would spin up a
QuickTunnel.

This is really a strange behaviour because we can easily create unwanted
tunnels and results in bad user experience.
This also has the side effect on putting more burden in our services
that are probably just mistakes.

This commit fixes that by requiring  user to specify the url command
flag.
Running cloudflared tunnel alone will result in an error message
instead.
2022-12-13 12:03:32 +00:00
Sudarsan Reddy 7dee179652 TUN-7004: Dont show local config dirs for remotely configured tuns
cloudflared shows possible directories for config files to be present if
it doesn't see one when starting up. For remotely configured files, it
may not be necessary to have a config file present. This PR looks to see
if a token flag was provided, and if yes, does not log this message.
2022-12-13 11:03:00 +00:00
Sudarsan Reddy 78ca8002d2 TUN-7003: Add back a missing fi 2022-12-12 13:21:14 +00:00
Sudarsan Reddy c13b6df0a7 TUN-7003: Tempoarily disable erroneous notarize-app
This PR temporarily disables the xcrun notarize-app feature since this
is soemthing we've historically had broken. However, what changed now is
we set -e for the mac os scripts. We'll need to remove this to unblock
mac builds.

We could spend time as part of https://jira.cfdata.org/browse/TUN-5789
to look into this.
2022-12-12 13:06:06 +00:00
Sudarsan Reddy b8b35d99fa TUN-7002: Randomise first region selection
We previously always preferred region2 as the first region to connect
to if both the regions cloudflared connects to have the same number of
availabe addresses. This change randomises that choice. The first
connection, conn index: 0, can now either connect to region 1 or region
2.

More importantly, conn 0 and 2 and 1 and 3 need not belong to the same
region.
2022-12-07 17:46:15 +00:00
João Oliveirinha 61ccc0b303 TUN-6994: Improve logging config file not found 2022-12-07 13:13:44 +00:00
João Oliveirinha 7ef9bb89d3 TUN-7000: Reduce metric cardinality of closedConnections metric by removing error as tag 2022-12-07 11:09:16 +00:00
Sudarsan Reddy 45e8eb7275 TUN-6984: [CI] Don't fail on unset.
Dont fail on bash unset (set -u) because we initialise to machine
defaults if the variables are unset within this script.
2022-12-05 17:50:49 +00:00
Sudarsan Reddy 72503eeaaa TUN-6984: [CI] Ignore security import errors for code_sigining
This PR lets the script skip if the `security import`
command exits with a 1. This is okay becuase this script manually checks
this exit code to validate if its a duplicate error and if its not,
returns.
2022-12-05 16:23:15 +00:00
Sudarsan Reddy 09e33a0b17 TUN-6984: Add bash set x to improve visibility during builds 2022-12-05 13:59:38 +00:00
Sudarsan Reddy 4c10f68e2d TUN-6984: Set euo pipefile for homebrew builds 2022-11-30 15:05:21 +00:00
João Oliveirinha cf87ec7969 Release 2022.11.1 2022-11-30 10:12:03 +00:00
João Oliveirinha 64f15d9992 TUN-6981: We should close UDP socket if failed to connecto to edge 2022-11-29 15:13:34 +00:00
João Oliveirinha e3d35570e6 CUSTESC-23757: Fix a bug where a wildcard ingress rule would match an host without starting with a dot 2022-11-25 17:00:59 +00:00
João Oliveirinha b0663dce33 TUN-6970: Print newline when printing tunnel token 2022-11-24 16:03:47 +00:00
João Oliveirinha af59851f33 TUN-6963: Refactor Metrics service setup 2022-11-22 11:35:48 +00:00
João Oliveirinha c49621c723 Release 2022.11.0 2022-11-18 10:07:13 +00:00
Sudarsan Reddy 9339bb9485 TUN-6929: Use same protocol for other connections as first one
This PR changes protocol initialization of the other N connections to be
the same as the one we know the initial tunnel connected with. This is
so we homogenize connections and not lead to some connections being
QUIC-able and the others not.

There's also an improvement to the connection registered log so we know
what protocol every individual connection connected with from the
cloudflared side.
2022-11-17 10:28:04 +00:00
João Oliveirinha 19106cd609 TUN-6935: Cloudflared should use APIToken instead of serviceKey
This commit makes cloudflared use the API token provided during login
instead of service key.
In addition, it eliminates some of the old formats since those are
legacy and we only support cloudflared versions newer than 6 months.
2022-11-16 17:07:16 +00:00
João Oliveirinha b50f172bdb Revert "TUN-6935: Cloudflared should use APIToken instead of serviceKey"
This reverts commit 1c6316c1c9.
2022-11-16 12:05:09 +00:00
João Oliveirinha 1c6316c1c9 TUN-6935: Cloudflared should use APIToken instead of serviceKey
This commit makes cloudflared use the API token provided during login
instead of service key.
In addition, it eliminates some of the old formats since those are
legacy and we only support cloudflared versions newer than 6 months.
2022-11-16 10:04:17 +00:00
Devin Carr 1fe4878264 TUN-6937: Bump golang.org/x/* packages to new release tags 2022-11-14 17:25:11 +00:00
João Oliveirinha 85b44695f0 TUN-6941: Reduce log level to debug when failing to proxy ICMP reply 2022-11-14 11:22:38 +00:00
Joel May 6a1dad0ce2 ZTC-234: macOS tests 2022-11-11 19:43:26 +00:00
Joel May 2baea15387 ZTC-234: Replace ICMP funnels when ingress connection changes
Origintunneld has been observed to continue sending reply packets to the first incoming connection it received, even if a newer connection is observed to be sending the requests.

OTD uses the funnel library from cloudflared, which is why the changes are here.

In theory, cloudflared has the same type of bug where a ping session switching between quic connections will continue sending replies to the first connection.  This bug has not been tested or confirmed though, but this PR will fix if it exists.
2022-11-11 19:43:26 +00:00
João Oliveirinha a1d88a6cdd TUN-6927: Refactor validate access configuration to allow empty audTags only 2022-11-09 12:28:58 +00:00
Devin Carr 515ad7cbee TUN-6917: Bump go to 1.19.3 2022-11-07 09:19:19 -08:00
n0k0m3 1b5313cc28 Issue #574: Better ssh config for short-lived cert (#763)
This PR is made using suggestion from #574. The pros for this config is that it will work both Windows and Linux (tested), as well as in VSCode, which normally can't be done with the current generated ssh config (refers to #734)
2022-11-02 10:44:34 +00:00
João Oliveirinha dde83d5a7c TUN-6898: Refactor addPortIfMissing 2022-10-28 15:48:10 +01:00
João Oliveirinha e14238224d TUN-6898: Fix bug handling IPv6 based ingresses with missing port 2022-10-28 12:47:59 +01:00
João Oliveirinha 66d1f27507 Release 2022.10.3 2022-10-26 10:40:17 +01:00
João Oliveirinha e6c9ec0b39 TUN-6871: Add default feature to cloudflared to support EOF on QUIC connections 2022-10-24 13:14:47 +01:00
cthuang c3c050aa79 TUN-6867: Clear spans right after they are serialized to avoid returning duplicate spans 2022-10-19 16:20:40 +01:00
Chung-Ting b1de2a74fa TUN-6876: Fix flaky TestTraceICMPRouterEcho by taking account request span can return before reply 2022-10-19 15:01:24 +01:00
299 changed files with 25560 additions and 4150 deletions
+11 -14
View File
@@ -1,5 +1,7 @@
#!/bin/bash
set -exo pipefail
if [[ "$(uname)" != "Darwin" ]] ; then
echo "This should be run on macOS"
exit 1
@@ -33,7 +35,9 @@ if [[ ! -z "$CFD_CODE_SIGN_KEY" ]]; then
if [[ ! -z "$CFD_CODE_SIGN_PASS" ]]; then
# write private key to disk and then import it keychain
echo -n -e ${CFD_CODE_SIGN_KEY} | base64 -D > ${CODE_SIGN_PRIV}
out=$(security import ${CODE_SIGN_PRIV} -A -P "${CFD_CODE_SIGN_PASS}" 2>&1)
# we set || true here and for every `security import invoke` because the "duplicate SecKeychainItemImport" error
# will cause set -e to exit 1. It is okay we do this because we deliberately handle this error in the lines below.
out=$(security import ${CODE_SIGN_PRIV} -A -P "${CFD_CODE_SIGN_PASS}" 2>&1) || true
exitcode=$?
if [ -n "$out" ]; then
if [ $exitcode -eq 0 ]; then
@@ -53,7 +57,7 @@ fi
if [[ ! -z "$CFD_CODE_SIGN_CERT" ]]; then
# write certificate to disk and then import it keychain
echo -n -e ${CFD_CODE_SIGN_CERT} | base64 -D > ${CODE_SIGN_CERT}
out1=$(security import ${CODE_SIGN_CERT} -A 2>&1)
out1=$(security import ${CODE_SIGN_CERT} -A 2>&1) || true
exitcode1=$?
if [ -n "$out1" ]; then
if [ $exitcode1 -eq 0 ]; then
@@ -75,7 +79,7 @@ if [[ ! -z "$CFD_INSTALLER_KEY" ]]; then
if [[ ! -z "$CFD_INSTALLER_PASS" ]]; then
# write private key to disk and then import it into the keychain
echo -n -e ${CFD_INSTALLER_KEY} | base64 -D > ${INSTALLER_PRIV}
out2=$(security import ${INSTALLER_PRIV} -A -P "${CFD_INSTALLER_PASS}" 2>&1)
out2=$(security import ${INSTALLER_PRIV} -A -P "${CFD_INSTALLER_PASS}" 2>&1) || true
exitcode2=$?
if [ -n "$out2" ]; then
if [ $exitcode2 -eq 0 ]; then
@@ -95,7 +99,7 @@ fi
if [[ ! -z "$CFD_INSTALLER_CERT" ]]; then
# write certificate to disk and then import it keychain
echo -n -e ${CFD_INSTALLER_CERT} | base64 -D > ${INSTALLER_CERT}
out3=$(security import ${INSTALLER_CERT} -A 2>&1)
out3=$(security import ${INSTALLER_CERT} -A 2>&1) || true
exitcode3=$?
if [ -n "$out3" ]; then
if [ $exitcode3 -eq 0 ]; then
@@ -138,14 +142,10 @@ fi
if [[ ! -z "$CODE_SIGN_NAME" ]]; then
codesign -s "${CODE_SIGN_NAME}" -f -v --timestamp --options runtime ${BINARY_NAME}
# notarize the binary
if [[ ! -z "$CFD_NOTE_PASSWORD" ]]; then
zip "${BINARY_NAME}.zip" ${BINARY_NAME}
xcrun altool --notarize-app -f "${BINARY_NAME}.zip" -t osx -u ${CFD_NOTE_USERNAME} -p ${CFD_NOTE_PASSWORD} --primary-bundle-id ${BUNDLE_ID}
fi
# notarize the binary
# TODO: https://jira.cfdata.org/browse/TUN-5789
fi
# creating build directory
rm -rf $TARGET_DIRECTORY
mkdir "${TARGET_DIRECTORY}"
@@ -169,10 +169,7 @@ if [[ ! -z "$PKG_SIGN_NAME" ]]; then
${PKGNAME}
# notarize the package
if [[ ! -z "$CFD_NOTE_PASSWORD" ]]; then
xcrun altool --notarize-app -f ${PKGNAME} -t osx -u ${CFD_NOTE_USERNAME} -p ${CFD_NOTE_PASSWORD} --primary-bundle-id ${BUNDLE_ID}
xcrun stapler staple ${PKGNAME}
fi
# TODO: https://jira.cfdata.org/browse/TUN-5789
else
pkgbuild --identifier com.cloudflare.${PRODUCT} \
--version ${VERSION} \
+4 -4
View File
@@ -297,8 +297,8 @@ quic-deps:
.PHONY: vet
vet:
go vet -v -mod=vendor ./...
go vet -v -mod=vendor github.com/cloudflare/cloudflared/...
.PHONY: goimports
goimports:
for d in $$(go list -mod=readonly -f '{{.Dir}}' -a ./... | fgrep -v tunnelrpc) ; do goimports -format-only -local github.com/cloudflare/cloudflared -w $$d ; done
.PHONY: fmt
fmt:
goimports -l -w -local github.com/cloudflare/cloudflared $$(go list -mod=vendor -f '{{.Dir}}' -a ./... | fgrep -v tunnelrpc)
+37
View File
@@ -1,3 +1,40 @@
2022.12.0
- 2022-12-14 TUN-6999: cloudflared should attempt other edge addresses before falling back on protocol
- 2022-12-13 TUN-7004: Dont show local config dirs for remotely configured tuns
- 2022-12-12 TUN-7003: Tempoarily disable erroneous notarize-app
- 2022-12-12 TUN-7003: Add back a missing fi
- 2022-12-07 TUN-7000: Reduce metric cardinality of closedConnections metric by removing error as tag
- 2022-12-07 TUN-6994: Improve logging config file not found
- 2022-12-07 TUN-7002: Randomise first region selection
- 2022-12-07 TUN-6995: Disable quick-tunnels spin up by default
- 2022-12-05 TUN-6984: Add bash set x to improve visibility during builds
- 2022-12-05 TUN-6984: [CI] Ignore security import errors for code_sigining
- 2022-12-05 TUN-6984: [CI] Don't fail on unset.
- 2022-11-30 TUN-6984: Set euo pipefile for homebrew builds
2022.11.1
- 2022-11-29 TUN-6981: We should close UDP socket if failed to connecto to edge
- 2022-11-25 CUSTESC-23757: Fix a bug where a wildcard ingress rule would match an host without starting with a dot
- 2022-11-24 TUN-6970: Print newline when printing tunnel token
- 2022-11-22 TUN-6963: Refactor Metrics service setup
2022.11.0
- 2022-11-16 Revert "TUN-6935: Cloudflared should use APIToken instead of serviceKey"
- 2022-11-16 TUN-6929: Use same protocol for other connections as first one
- 2022-11-14 TUN-6941: Reduce log level to debug when failing to proxy ICMP reply
- 2022-11-14 TUN-6935: Cloudflared should use APIToken instead of serviceKey
- 2022-11-14 TUN-6935: Cloudflared should use APIToken instead of serviceKey
- 2022-11-11 TUN-6937: Bump golang.org/x/* packages to new release tags
- 2022-11-10 ZTC-234: macOS tests
- 2022-11-09 TUN-6927: Refactor validate access configuration to allow empty audTags only
- 2022-11-08 ZTC-234: Replace ICMP funnels when ingress connection changes
- 2022-11-04 TUN-6917: Bump go to 1.19.3
- 2022-11-02 Issue #574: Better ssh config for short-lived cert (#763)
- 2022-10-28 TUN-6898: Fix bug handling IPv6 based ingresses with missing port
- 2022-10-28 TUN-6898: Refactor addPortIfMissing
2022.10.3
- 2022-10-24 TUN-6871: Add default feature to cloudflared to support EOF on QUIC connections
- 2022-10-19 TUN-6876: Fix flaky TestTraceICMPRouterEcho by taking account request span can return before reply
- 2022-10-18 TUN-6867: Clear spans right after they are serialized to avoid returning duplicate spans
2022.10.2
- 2022-10-18 TUN-6869: Fix Makefile complaining about missing GO packages
- 2022-10-18 TUN-6864: Don't reuse port in quic unit tests
+3 -3
View File
@@ -1,6 +1,6 @@
//Package carrier provides a WebSocket proxy to carry or proxy a connection
//from the local client to the edge. See it as a wrapper around any protocol
//that it packages up in a WebSocket connection to the edge.
// Package carrier provides a WebSocket proxy to carry or proxy a connection
// from the local client to the edge. See it as a wrapper around any protocol
// that it packages up in a WebSocket connection to the edge.
package carrier
import (
+13 -49
View File
@@ -1,25 +1,21 @@
package certutil
import (
"crypto/x509"
"encoding/json"
"encoding/pem"
"fmt"
"strings"
)
type namedTunnelToken struct {
ZoneID string `json:"zoneID"`
AccountID string `json:"accountID"`
ServiceKey string `json:"serviceKey"`
ZoneID string `json:"zoneID"`
AccountID string `json:"accountID"`
APIToken string `json:"apiToken"`
}
type OriginCert struct {
PrivateKey interface{}
Cert *x509.Certificate
ZoneID string
ServiceKey string
AccountID string
ZoneID string
APIToken string
AccountID string
}
func DecodeOriginCert(blocks []byte) (*OriginCert, error) {
@@ -33,29 +29,11 @@ func DecodeOriginCert(blocks []byte) (*OriginCert, error) {
break
}
switch block.Type {
case "PRIVATE KEY":
if originCert.PrivateKey != nil {
return nil, fmt.Errorf("Found multiple private key in the certificate")
}
// RSA private key
privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("Cannot parse private key")
}
originCert.PrivateKey = privateKey
case "CERTIFICATE":
if originCert.Cert != nil {
return nil, fmt.Errorf("Found multiple certificates in the certificate")
}
cert, err := x509.ParseCertificates(block.Bytes)
if err != nil {
return nil, fmt.Errorf("Cannot parse certificate")
} else if len(cert) > 1 {
return nil, fmt.Errorf("Found multiple certificates in the certificate")
}
originCert.Cert = cert[0]
case "WARP TOKEN", "ARGO TUNNEL TOKEN":
if originCert.ZoneID != "" || originCert.ServiceKey != "" {
case "PRIVATE KEY", "CERTIFICATE":
// this is for legacy purposes.
break
case "ARGO TUNNEL TOKEN":
if originCert.ZoneID != "" || originCert.APIToken != "" {
return nil, fmt.Errorf("Found multiple tokens in the certificate")
}
// The token is a string,
@@ -63,18 +41,8 @@ func DecodeOriginCert(blocks []byte) (*OriginCert, error) {
ntt := namedTunnelToken{}
if err := json.Unmarshal(block.Bytes, &ntt); err == nil {
originCert.ZoneID = ntt.ZoneID
originCert.ServiceKey = ntt.ServiceKey
originCert.APIToken = ntt.APIToken
originCert.AccountID = ntt.AccountID
} else {
// Try the older format, where the zoneID and service key are separated by
// a new line character
token := string(block.Bytes)
s := strings.Split(token, "\n")
if len(s) != 2 {
return nil, fmt.Errorf("Cannot parse token")
}
originCert.ZoneID = s[0]
originCert.ServiceKey = s[1]
}
default:
return nil, fmt.Errorf("Unknown block %s in the certificate", block.Type)
@@ -82,11 +50,7 @@ func DecodeOriginCert(blocks []byte) (*OriginCert, error) {
block, rest = pem.Decode(rest)
}
if originCert.PrivateKey == nil {
return nil, fmt.Errorf("Missing private key in the certificate")
} else if originCert.Cert == nil {
return nil, fmt.Errorf("Missing certificate in the certificate")
} else if originCert.ZoneID == "" || originCert.ServiceKey == "" {
if originCert.ZoneID == "" || originCert.APIToken == "" {
return nil, fmt.Errorf("Missing token in the certificate")
}
+12 -28
View File
@@ -13,49 +13,33 @@ func TestLoadOriginCert(t *testing.T) {
assert.Equal(t, fmt.Errorf("Cannot decode empty certificate"), err)
assert.Nil(t, cert)
blocks, err := ioutil.ReadFile("test-cert-no-key.pem")
assert.Nil(t, err)
cert, err = DecodeOriginCert(blocks)
assert.Equal(t, fmt.Errorf("Missing private key in the certificate"), err)
assert.Nil(t, cert)
blocks, err = ioutil.ReadFile("test-cert-two-certificates.pem")
assert.Nil(t, err)
cert, err = DecodeOriginCert(blocks)
assert.Equal(t, fmt.Errorf("Found multiple certificates in the certificate"), err)
assert.Nil(t, cert)
blocks, err = ioutil.ReadFile("test-cert-unknown-block.pem")
blocks, err := ioutil.ReadFile("test-cert-unknown-block.pem")
assert.Nil(t, err)
cert, err = DecodeOriginCert(blocks)
assert.Equal(t, fmt.Errorf("Unknown block RSA PRIVATE KEY in the certificate"), err)
assert.Nil(t, cert)
blocks, err = ioutil.ReadFile("test-cert.pem")
assert.Nil(t, err)
cert, err = DecodeOriginCert(blocks)
assert.Nil(t, err)
assert.NotNil(t, cert)
assert.Equal(t, "7b0a4d77dfb881c1a3b7d61ea9443e19", cert.ZoneID)
key := "v1.0-58bd4f9e28f7b3c28e05a35ff3e80ab4fd9644ef3fece537eb0d12e2e9258217-183442fbb0bbdb3e571558fec9b5589ebd77aafc87498ee3f09f64a4ad79ffe8791edbae08b36c1d8f1d70a8670de56922dff92b15d214a524f4ebfa1958859e-7ce80f79921312a6022c5d25e2d380f82ceaefe3fbdc43dd13b080e3ef1e26f7"
assert.Equal(t, key, cert.ServiceKey)
}
func TestNewlineArgoTunnelToken(t *testing.T) {
ArgoTunnelTokenTest(t, "test-argo-tunnel-cert.pem")
func TestJSONArgoTunnelTokenEmpty(t *testing.T) {
cert, err := DecodeOriginCert([]byte{})
blocks, err := ioutil.ReadFile("test-cert-no-token.pem")
assert.Nil(t, err)
cert, err = DecodeOriginCert(blocks)
assert.Equal(t, fmt.Errorf("Missing token in the certificate"), err)
assert.Nil(t, cert)
}
func TestJSONArgoTunnelToken(t *testing.T) {
// The given cert's Argo Tunnel Token was generated by base64 encoding this JSON:
// {
// "zoneID": "7b0a4d77dfb881c1a3b7d61ea9443e19",
// "serviceKey": "test-service-key",
// "apiToken": "test-service-key",
// "accountID": "abcdabcdabcdabcd1234567890abcdef"
// }
ArgoTunnelTokenTest(t, "test-argo-tunnel-cert-json.pem")
CloudflareTunnelTokenTest(t, "test-cloudflare-tunnel-cert-json.pem")
}
func ArgoTunnelTokenTest(t *testing.T, path string) {
func CloudflareTunnelTokenTest(t *testing.T, path string) {
blocks, err := ioutil.ReadFile(path)
assert.Nil(t, err)
cert, err := DecodeOriginCert(blocks)
@@ -63,5 +47,5 @@ func ArgoTunnelTokenTest(t *testing.T, path string) {
assert.NotNil(t, cert)
assert.Equal(t, "7b0a4d77dfb881c1a3b7d61ea9443e19", cert.ZoneID)
key := "test-service-key"
assert.Equal(t, key, cert.ServiceKey)
assert.Equal(t, key, cert.APIToken)
}
-33
View File
@@ -1,33 +0,0 @@
-----BEGIN CERTIFICATE-----
MIID+jCCA6CgAwIBAgIUJhFxUKEGvTRc3CjCok6dbPGH/P4wCgYIKoZIzj0EAwIw
gagxCzAJBgNVBAYTAlVTMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMTgwNgYD
VQQLEy9DbG91ZEZsYXJlIE9yaWdpbiBTU0wgRUNDIENlcnRpZmljYXRlIEF1dGhv
cml0eTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5p
YTEXMBUGA1UEAxMOKGRldiB1c2Ugb25seSkwHhcNMTcxMDEzMTM1OTAwWhcNMzIx
MDA5MTM1OTAwWjBiMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMR0wGwYDVQQL
ExRDbG91ZEZsYXJlIE9yaWdpbiBDQTEmMCQGA1UEAxMdQ2xvdWRGbGFyZSBPcmln
aW4gQ2VydGlmaWNhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCf
GswL16Fz9Ei3sAg5AmBizoN2nZdyXHP8T57UxUMcrlJXEEXCVS5RR4m9l+EmK0ng
6yHR1H5oX1Lg1WKyXgWwr0whwmdTD+qWFJW2M8HyefyBKLrsGPuxw4CVYT0h72bx
tG0uyrXYh7Mtz0lHjGV90qrFpq5o0jx0sLbDlDvpFPbIO58uYzKG4Sn2VTC4rOyX
PE6SuDvMHIeX6Ekw4wSVQ9eTbksLQqTyxSqM3zp2ygc56SjGjy1nGQT8ZBGFzSbZ
AzNOxVKrUsySx7LzZVl+zCGCPlQwaYLKObKXadZJmrqSFmErC5jcbVgBz7oJQOgl
HJ2n0sMcZ+Ja1Y649mPVAgMBAAGjggEgMIIBHDAOBgNVHQ8BAf8EBAMCBaAwEwYD
VR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUzA6f2Ajq
zhX67c6piY2a1uTiUkwwHwYDVR0jBBgwFoAU2qfBlqxKMZnf0QeTeYiMelfqJfgw
RAYIKwYBBQUHAQEEODA2MDQGCCsGAQUFBzABhihodHRwOi8vb2NzcC5jbG91ZGZs
YXJlLmNvbS9vcmlnaW5fZWNjX2NhMCMGA1UdEQQcMBqCDCouYXJub2xkLmNvbYIK
YXJub2xkLmNvbTA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3JsLmNsb3VkZmxh
cmUuY29tL29yaWdpbl9lY2NfY2EuY3JsMAoGCCqGSM49BAMCA0gAMEUCIDV7HoMj
K5rShE/l+90YAOzHC89OH/wUz3I5KYOFuehoAiEA8e92aIf9XBkr0K6EvFCiSsD+
x+Yo/cL8fGfVpPt4UM8=
-----END CERTIFICATE-----
-----BEGIN WARP TOKEN-----
N2IwYTRkNzdkZmI4ODFjMWEzYjdkNjFlYTk0NDNlMTkKdjEuMC01OGJkNGY5ZTI4
ZjdiM2MyOGUwNWEzNWZmM2U4MGFiNGZkOTY0NGVmM2ZlY2U1MzdlYjBkMTJlMmU5
MjU4MjE3LTE4MzQ0MmZiYjBiYmRiM2U1NzE1NThmZWM5YjU1ODllYmQ3N2FhZmM4
NzQ5OGVlM2YwOWY2NGE0YWQ3OWZmZTg3OTFlZGJhZTA4YjM2YzFkOGYxZDcwYTg2
NzBkZTU2OTIyZGZmOTJiMTVkMjE0YTUyNGY0ZWJmYTE5NTg4NTllLTdjZTgwZjc5
OTIxMzEyYTYwMjJjNWQyNWUyZDM4MGY4MmNlYWVmZTNmYmRjNDNkZDEzYjA4MGUz
ZWYxZTI2Zjc=
-----END WARP TOKEN-----
@@ -51,7 +51,6 @@ K5rShE/l+90YAOzHC89OH/wUz3I5KYOFuehoAiEA8e92aIf9XBkr0K6EvFCiSsD+
x+Yo/cL8fGfVpPt4UM8=
-----END CERTIFICATE-----
-----BEGIN ARGO TUNNEL TOKEN-----
eyJ6b25lSUQiOiAiN2IwYTRkNzdkZmI4ODFjMWEzYjdkNjFlYTk0NDNlMTkiLCAi
c2VydmljZUtleSI6ICJ0ZXN0LXNlcnZpY2Uta2V5IiwgImFjY291bnRJRCI6ICJh
YmNkYWJjZGFiY2RhYmNkMTIzNDU2Nzg5MGFiY2RlZiJ9
eyJ6b25lSUQiOiAiN2IwYTRkNzdkZmI4ODFjMWEzYjdkNjFlYTk0NDNlMTkiLCAiYWNjb3VudElE
IjogImFiY2RhYmNkYWJjZGFiY2QxMjM0NTY3ODkwYWJjZGVmIn0=
-----END ARGO TUNNEL TOKEN-----
-85
View File
@@ -1,85 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCfGswL16Fz9Ei3
sAg5AmBizoN2nZdyXHP8T57UxUMcrlJXEEXCVS5RR4m9l+EmK0ng6yHR1H5oX1Lg
1WKyXgWwr0whwmdTD+qWFJW2M8HyefyBKLrsGPuxw4CVYT0h72bxtG0uyrXYh7Mt
z0lHjGV90qrFpq5o0jx0sLbDlDvpFPbIO58uYzKG4Sn2VTC4rOyXPE6SuDvMHIeX
6Ekw4wSVQ9eTbksLQqTyxSqM3zp2ygc56SjGjy1nGQT8ZBGFzSbZAzNOxVKrUsyS
x7LzZVl+zCGCPlQwaYLKObKXadZJmrqSFmErC5jcbVgBz7oJQOglHJ2n0sMcZ+Ja
1Y649mPVAgMBAAECggEAEbPF0ah9fH0IzTU/CPbIeh3flyY8GDuMpR1HvwUurSWB
IFI9bLyVAXKb8vYP1TMaTnXi5qmFof+/JShgyZc3+1tZtWTfoaiC8Y1bRfE2yk+D
xmwddhDmijYGG7i8uEaeddSdFEh2GKAqkbV/QgBvN2Nl4EVmIOAJXXNe9l5LFyjy
sR10aNVJRYV1FahrCTwZ3SovHP4d4AUvHh/3FFZDukHc37CFA0+CcR4uehp5yedi
2UdqaszXqunFo/3h+Tn9dW2C7gTTZx4+mfyaws3p3YOmdYArXvpejxHIc0FGwLBm
sb9K7wGVUiF0Bt0ch+C1mdYrCaFNHnPuDswjmm3FwQKBgQDYtxOwwSLA6ZyppozX
Doyx9a7PhiMHCFKSdVB4l8rpK545a+AmpG6LRScTtBsMTHBhT3IQ3QPWlVm1AhjF
AvXMa1rOeaGbCbDn1xqEoEVPtj4tys8eTfyWmtU73jWTFauOt4/xpf/urEpg91xj
m+Gl/8qgBrpm5rQxV5Y4MysRlQKBgQC78jzzlhocXGNvw0wT/K2NsknyeoZXqpIE
QYL60FMl4geZn6w9hwxaL1r+g/tUjTnpBPQtS1r2Ed2gXby5zspN1g/PW8U3t3to
P7zHIJ/sLBXrCh5RJko3hUgGhDNOOCIQj4IaKUfvHYvEIbIxlyI0vdsXsgXgMuQ8
pb9Yifn5QQKBgQCmGu0EtYQlyOlDP10EGSrN3Dm45l9CrKZdi326cN4eCkikSoLs
G2x/YumouItiydP5QiNzuXOPrbmse4bwumwb2s0nJSMw6iSmDsFMlmuJxW2zO5e0
6qGH7fUyhgcaTanJIfk6hrm7/mKkH/S4hGpYCc8NCRsmc/35M+D4AoAoYQKBgQC0
LWpZaxDlF30MbAHHN3l6We2iU+vup0sMYXGb2ZOcwa/fir+ozIr++l8VmJmdWTan
OWSM96zgMghx8Os4hhJTxF+rvqK242OfcVsc2x31X94zUaP2z+peh5uhA6Pb3Nxr
W+iyA9k+Vujiwhr+h5D3VvtvH++aG6/KpGtoCf5nAQKBgQDXX2+d7bd5CLNLLFNd
M2i4QoOFcSKIG+v4SuvgEJHgG8vGvxh2qlSxnMWuPV+7/1P5ATLqDj1PlKms+BNR
y7sc5AT9PclkL3Y9MNzOu0LXyBkGYcl8M0EQfLv9VPbWT+NXiMg/O2CHiT02pAAz
uQicoQq3yzeQh20wtrtaXzTNmA==
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIID+jCCA6CgAwIBAgIUJhFxUKEGvTRc3CjCok6dbPGH/P4wCgYIKoZIzj0EAwIw
gagxCzAJBgNVBAYTAlVTMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMTgwNgYD
VQQLEy9DbG91ZEZsYXJlIE9yaWdpbiBTU0wgRUNDIENlcnRpZmljYXRlIEF1dGhv
cml0eTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5p
YTEXMBUGA1UEAxMOKGRldiB1c2Ugb25seSkwHhcNMTcxMDEzMTM1OTAwWhcNMzIx
MDA5MTM1OTAwWjBiMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMR0wGwYDVQQL
ExRDbG91ZEZsYXJlIE9yaWdpbiBDQTEmMCQGA1UEAxMdQ2xvdWRGbGFyZSBPcmln
aW4gQ2VydGlmaWNhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCf
GswL16Fz9Ei3sAg5AmBizoN2nZdyXHP8T57UxUMcrlJXEEXCVS5RR4m9l+EmK0ng
6yHR1H5oX1Lg1WKyXgWwr0whwmdTD+qWFJW2M8HyefyBKLrsGPuxw4CVYT0h72bx
tG0uyrXYh7Mtz0lHjGV90qrFpq5o0jx0sLbDlDvpFPbIO58uYzKG4Sn2VTC4rOyX
PE6SuDvMHIeX6Ekw4wSVQ9eTbksLQqTyxSqM3zp2ygc56SjGjy1nGQT8ZBGFzSbZ
AzNOxVKrUsySx7LzZVl+zCGCPlQwaYLKObKXadZJmrqSFmErC5jcbVgBz7oJQOgl
HJ2n0sMcZ+Ja1Y649mPVAgMBAAGjggEgMIIBHDAOBgNVHQ8BAf8EBAMCBaAwEwYD
VR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUzA6f2Ajq
zhX67c6piY2a1uTiUkwwHwYDVR0jBBgwFoAU2qfBlqxKMZnf0QeTeYiMelfqJfgw
RAYIKwYBBQUHAQEEODA2MDQGCCsGAQUFBzABhihodHRwOi8vb2NzcC5jbG91ZGZs
YXJlLmNvbS9vcmlnaW5fZWNjX2NhMCMGA1UdEQQcMBqCDCouYXJub2xkLmNvbYIK
YXJub2xkLmNvbTA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3JsLmNsb3VkZmxh
cmUuY29tL29yaWdpbl9lY2NfY2EuY3JsMAoGCCqGSM49BAMCA0gAMEUCIDV7HoMj
K5rShE/l+90YAOzHC89OH/wUz3I5KYOFuehoAiEA8e92aIf9XBkr0K6EvFCiSsD+
x+Yo/cL8fGfVpPt4UM8=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID+jCCA6CgAwIBAgIUJhFxUKEGvTRc3CjCok6dbPGH/P4wCgYIKoZIzj0EAwIw
gagxCzAJBgNVBAYTAlVTMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMTgwNgYD
VQQLEy9DbG91ZEZsYXJlIE9yaWdpbiBTU0wgRUNDIENlcnRpZmljYXRlIEF1dGhv
cml0eTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5p
YTEXMBUGA1UEAxMOKGRldiB1c2Ugb25seSkwHhcNMTcxMDEzMTM1OTAwWhcNMzIx
MDA5MTM1OTAwWjBiMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMR0wGwYDVQQL
ExRDbG91ZEZsYXJlIE9yaWdpbiBDQTEmMCQGA1UEAxMdQ2xvdWRGbGFyZSBPcmln
aW4gQ2VydGlmaWNhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCf
GswL16Fz9Ei3sAg5AmBizoN2nZdyXHP8T57UxUMcrlJXEEXCVS5RR4m9l+EmK0ng
6yHR1H5oX1Lg1WKyXgWwr0whwmdTD+qWFJW2M8HyefyBKLrsGPuxw4CVYT0h72bx
tG0uyrXYh7Mtz0lHjGV90qrFpq5o0jx0sLbDlDvpFPbIO58uYzKG4Sn2VTC4rOyX
PE6SuDvMHIeX6Ekw4wSVQ9eTbksLQqTyxSqM3zp2ygc56SjGjy1nGQT8ZBGFzSbZ
AzNOxVKrUsySx7LzZVl+zCGCPlQwaYLKObKXadZJmrqSFmErC5jcbVgBz7oJQOgl
HJ2n0sMcZ+Ja1Y649mPVAgMBAAGjggEgMIIBHDAOBgNVHQ8BAf8EBAMCBaAwEwYD
VR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUzA6f2Ajq
zhX67c6piY2a1uTiUkwwHwYDVR0jBBgwFoAU2qfBlqxKMZnf0QeTeYiMelfqJfgw
RAYIKwYBBQUHAQEEODA2MDQGCCsGAQUFBzABhihodHRwOi8vb2NzcC5jbG91ZGZs
YXJlLmNvbS9vcmlnaW5fZWNjX2NhMCMGA1UdEQQcMBqCDCouYXJub2xkLmNvbYIK
YXJub2xkLmNvbTA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3JsLmNsb3VkZmxh
cmUuY29tL29yaWdpbl9lY2NfY2EuY3JsMAoGCCqGSM49BAMCA0gAMEUCIDV7HoMj
K5rShE/l+90YAOzHC89OH/wUz3I5KYOFuehoAiEA8e92aIf9XBkr0K6EvFCiSsD+
x+Yo/cL8fGfVpPt4UM8=
-----END CERTIFICATE-----
-----BEGIN WARP TOKEN-----
N2IwYTRkNzdkZmI4ODFjMWEzYjdkNjFlYTk0NDNlMTkKdjEuMC01OGJkNGY5ZTI4
ZjdiM2MyOGUwNWEzNWZmM2U4MGFiNGZkOTY0NGVmM2ZlY2U1MzdlYjBkMTJlMmU5
MjU4MjE3LTE4MzQ0MmZiYjBiYmRiM2U1NzE1NThmZWM5YjU1ODllYmQ3N2FhZmM4
NzQ5OGVlM2YwOWY2NGE0YWQ3OWZmZTg3OTFlZGJhZTA4YjM2YzFkOGYxZDcwYTg2
NzBkZTU2OTIyZGZmOTJiMTVkMjE0YTUyNGY0ZWJmYTE5NTg4NTllLTdjZTgwZjc5
OTIxMzEyYTYwMjJjNWQyNWUyZDM4MGY4MmNlYWVmZTNmYmRjNDNkZDEzYjA4MGUz
ZWYxZTI2Zjc=
-----END WARP TOKEN-----
+2 -2
View File
@@ -50,7 +50,7 @@ cmUuY29tL29yaWdpbl9lY2NfY2EuY3JsMAoGCCqGSM49BAMCA0gAMEUCIDV7HoMj
K5rShE/l+90YAOzHC89OH/wUz3I5KYOFuehoAiEA8e92aIf9XBkr0K6EvFCiSsD+
x+Yo/cL8fGfVpPt4UM8=
-----END CERTIFICATE-----
-----BEGIN WARP TOKEN-----
-----BEGIN ARGO TUNNEL TOKEN-----
N2IwYTRkNzdkZmI4ODFjMWEzYjdkNjFlYTk0NDNlMTkKdjEuMC01OGJkNGY5ZTI4
ZjdiM2MyOGUwNWEzNWZmM2U4MGFiNGZkOTY0NGVmM2ZlY2U1MzdlYjBkMTJlMmU5
MjU4MjE3LTE4MzQ0MmZiYjBiYmRiM2U1NzE1NThmZWM5YjU1ODllYmQ3N2FhZmM4
@@ -58,7 +58,7 @@ NzQ5OGVlM2YwOWY2NGE0YWQ3OWZmZTg3OTFlZGJhZTA4YjM2YzFkOGYxZDcwYTg2
NzBkZTU2OTIyZGZmOTJiMTVkMjE0YTUyNGY0ZWJmYTE5NTg4NTllLTdjZTgwZjc5
OTIxMzEyYTYwMjJjNWQyNWUyZDM4MGY4MmNlYWVmZTNmYmRjNDNkZDEzYjA4MGUz
ZWYxZTI2Zjc=
-----END WARP TOKEN-----
-----END ARGO TUNNEL TOKEN-----
-----BEGIN RSA PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCfGswL16Fz9Ei3
sAg5AmBizoN2nZdyXHP8T57UxUMcrlJXEEXCVS5RR4m9l+EmK0ng6yHR1H5oX1Lg
-61
View File
@@ -1,61 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCfGswL16Fz9Ei3
sAg5AmBizoN2nZdyXHP8T57UxUMcrlJXEEXCVS5RR4m9l+EmK0ng6yHR1H5oX1Lg
1WKyXgWwr0whwmdTD+qWFJW2M8HyefyBKLrsGPuxw4CVYT0h72bxtG0uyrXYh7Mt
z0lHjGV90qrFpq5o0jx0sLbDlDvpFPbIO58uYzKG4Sn2VTC4rOyXPE6SuDvMHIeX
6Ekw4wSVQ9eTbksLQqTyxSqM3zp2ygc56SjGjy1nGQT8ZBGFzSbZAzNOxVKrUsyS
x7LzZVl+zCGCPlQwaYLKObKXadZJmrqSFmErC5jcbVgBz7oJQOglHJ2n0sMcZ+Ja
1Y649mPVAgMBAAECggEAEbPF0ah9fH0IzTU/CPbIeh3flyY8GDuMpR1HvwUurSWB
IFI9bLyVAXKb8vYP1TMaTnXi5qmFof+/JShgyZc3+1tZtWTfoaiC8Y1bRfE2yk+D
xmwddhDmijYGG7i8uEaeddSdFEh2GKAqkbV/QgBvN2Nl4EVmIOAJXXNe9l5LFyjy
sR10aNVJRYV1FahrCTwZ3SovHP4d4AUvHh/3FFZDukHc37CFA0+CcR4uehp5yedi
2UdqaszXqunFo/3h+Tn9dW2C7gTTZx4+mfyaws3p3YOmdYArXvpejxHIc0FGwLBm
sb9K7wGVUiF0Bt0ch+C1mdYrCaFNHnPuDswjmm3FwQKBgQDYtxOwwSLA6ZyppozX
Doyx9a7PhiMHCFKSdVB4l8rpK545a+AmpG6LRScTtBsMTHBhT3IQ3QPWlVm1AhjF
AvXMa1rOeaGbCbDn1xqEoEVPtj4tys8eTfyWmtU73jWTFauOt4/xpf/urEpg91xj
m+Gl/8qgBrpm5rQxV5Y4MysRlQKBgQC78jzzlhocXGNvw0wT/K2NsknyeoZXqpIE
QYL60FMl4geZn6w9hwxaL1r+g/tUjTnpBPQtS1r2Ed2gXby5zspN1g/PW8U3t3to
P7zHIJ/sLBXrCh5RJko3hUgGhDNOOCIQj4IaKUfvHYvEIbIxlyI0vdsXsgXgMuQ8
pb9Yifn5QQKBgQCmGu0EtYQlyOlDP10EGSrN3Dm45l9CrKZdi326cN4eCkikSoLs
G2x/YumouItiydP5QiNzuXOPrbmse4bwumwb2s0nJSMw6iSmDsFMlmuJxW2zO5e0
6qGH7fUyhgcaTanJIfk6hrm7/mKkH/S4hGpYCc8NCRsmc/35M+D4AoAoYQKBgQC0
LWpZaxDlF30MbAHHN3l6We2iU+vup0sMYXGb2ZOcwa/fir+ozIr++l8VmJmdWTan
OWSM96zgMghx8Os4hhJTxF+rvqK242OfcVsc2x31X94zUaP2z+peh5uhA6Pb3Nxr
W+iyA9k+Vujiwhr+h5D3VvtvH++aG6/KpGtoCf5nAQKBgQDXX2+d7bd5CLNLLFNd
M2i4QoOFcSKIG+v4SuvgEJHgG8vGvxh2qlSxnMWuPV+7/1P5ATLqDj1PlKms+BNR
y7sc5AT9PclkL3Y9MNzOu0LXyBkGYcl8M0EQfLv9VPbWT+NXiMg/O2CHiT02pAAz
uQicoQq3yzeQh20wtrtaXzTNmA==
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIID+jCCA6CgAwIBAgIUJhFxUKEGvTRc3CjCok6dbPGH/P4wCgYIKoZIzj0EAwIw
gagxCzAJBgNVBAYTAlVTMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMTgwNgYD
VQQLEy9DbG91ZEZsYXJlIE9yaWdpbiBTU0wgRUNDIENlcnRpZmljYXRlIEF1dGhv
cml0eTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5p
YTEXMBUGA1UEAxMOKGRldiB1c2Ugb25seSkwHhcNMTcxMDEzMTM1OTAwWhcNMzIx
MDA5MTM1OTAwWjBiMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMR0wGwYDVQQL
ExRDbG91ZEZsYXJlIE9yaWdpbiBDQTEmMCQGA1UEAxMdQ2xvdWRGbGFyZSBPcmln
aW4gQ2VydGlmaWNhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCf
GswL16Fz9Ei3sAg5AmBizoN2nZdyXHP8T57UxUMcrlJXEEXCVS5RR4m9l+EmK0ng
6yHR1H5oX1Lg1WKyXgWwr0whwmdTD+qWFJW2M8HyefyBKLrsGPuxw4CVYT0h72bx
tG0uyrXYh7Mtz0lHjGV90qrFpq5o0jx0sLbDlDvpFPbIO58uYzKG4Sn2VTC4rOyX
PE6SuDvMHIeX6Ekw4wSVQ9eTbksLQqTyxSqM3zp2ygc56SjGjy1nGQT8ZBGFzSbZ
AzNOxVKrUsySx7LzZVl+zCGCPlQwaYLKObKXadZJmrqSFmErC5jcbVgBz7oJQOgl
HJ2n0sMcZ+Ja1Y649mPVAgMBAAGjggEgMIIBHDAOBgNVHQ8BAf8EBAMCBaAwEwYD
VR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUzA6f2Ajq
zhX67c6piY2a1uTiUkwwHwYDVR0jBBgwFoAU2qfBlqxKMZnf0QeTeYiMelfqJfgw
RAYIKwYBBQUHAQEEODA2MDQGCCsGAQUFBzABhihodHRwOi8vb2NzcC5jbG91ZGZs
YXJlLmNvbS9vcmlnaW5fZWNjX2NhMCMGA1UdEQQcMBqCDCouYXJub2xkLmNvbYIK
YXJub2xkLmNvbTA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3JsLmNsb3VkZmxh
cmUuY29tL29yaWdpbl9lY2NfY2EuY3JsMAoGCCqGSM49BAMCA0gAMEUCIDV7HoMj
K5rShE/l+90YAOzHC89OH/wUz3I5KYOFuehoAiEA8e92aIf9XBkr0K6EvFCiSsD+
x+Yo/cL8fGfVpPt4UM8=
-----END CERTIFICATE-----
-----BEGIN WARP TOKEN-----
N2IwYTRkNzdkZmI4ODFjMWEzYjdkNjFlYTk0NDNlMTkKdjEuMC01OGJkNGY5ZTI4
ZjdiM2MyOGUwNWEzNWZmM2U4MGFiNGZkOTY0NGVmM2ZlY2U1MzdlYjBkMTJlMmU5
MjU4MjE3LTE4MzQ0MmZiYjBiYmRiM2U1NzE1NThmZWM5YjU1ODllYmQ3N2FhZmM4
NzQ5OGVlM2YwOWY2NGE0YWQ3OWZmZTg3OTFlZGJhZTA4YjM2YzFkOGYxZDcwYTg2
NzBkZTU2OTIyZGZmOTJiMTVkMjE0YTUyNGY0ZWJmYTE5NTg4NTllLTdjZTgwZjc5
OTIxMzEyYTYwMjJjNWQyNWUyZDM4MGY4MmNlYWVmZTNmYmRjNDNkZDEzYjA4MGUz
ZWYxZTI2Zjc=
-----END WARP TOKEN-----
@@ -51,6 +51,7 @@ K5rShE/l+90YAOzHC89OH/wUz3I5KYOFuehoAiEA8e92aIf9XBkr0K6EvFCiSsD+
x+Yo/cL8fGfVpPt4UM8=
-----END CERTIFICATE-----
-----BEGIN ARGO TUNNEL TOKEN-----
N2IwYTRkNzdkZmI4ODFjMWEzYjdkNjFlYTk0NDNlMTkKdGVzdC1zZXJ2aWNlLWtl
eQ==
eyJ6b25lSUQiOiAiN2IwYTRkNzdkZmI4ODFjMWEzYjdkNjFlYTk0NDNlMTkiLCAiYXBpVG9rZW4i
OiAidGVzdC1zZXJ2aWNlLWtleSIsICJhY2NvdW50SUQiOiAiYWJjZGFiY2RhYmNkYWJjZDEyMzQ1
Njc4OTBhYmNkZWYifQ==
-----END ARGO TUNNEL TOKEN-----
+1 -1
View File
@@ -104,7 +104,7 @@ func (r *RESTClient) sendRequest(method string, url url.URL, body interface{}) (
if bodyReader != nil {
req.Header.Set("Content-Type", jsonContentType)
}
req.Header.Add("X-Auth-User-Service-Key", r.authToken)
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", r.authToken))
req.Header.Add("Accept", "application/json;version=1")
return r.client.Do(req)
}
+14 -15
View File
@@ -1,23 +1,29 @@
pinned_go: &pinned_go go=1.18.6-1
pinned_go_fips: &pinned_go_fips go-boring=1.18.6-1
pinned_go: &pinned_go go=1.19.3-1
pinned_go_fips: &pinned_go_fips go-boring=1.19.3-1
build_dir: &build_dir /cfsetup_build
default-flavor: bullseye
stretch: &stretch
build:
build_dir: *build_dir
builddeps:
builddeps: &build_deps
- *pinned_go
- build-essential
- gotest-to-teamcity
pre-cache: &build_pre_cache
- export GOCACHE=/cfsetup_build/.cache/go-build
- go install golang.org/x/tools/cmd/goimports@latest
post-cache:
- export GOOS=linux
- export GOARCH=amd64
- make cloudflared
build-fips:
build_dir: *build_dir
builddeps:
builddeps: &build_deps_fips
- *pinned_go_fips
- build-essential
- gotest-to-teamcity
pre-cache: *build_pre_cache
post-cache:
- export GOOS=linux
- export GOARCH=amd64
@@ -163,12 +169,8 @@ stretch: &stretch
- make github-windows-upload
test:
build_dir: *build_dir
builddeps:
- *pinned_go
- build-essential
- gotest-to-teamcity
pre-cache: &test_pre_cache
- go install golang.org/x/tools/cmd/goimports@latest
builddeps: *build_deps
pre-cache: *build_pre_cache
post-cache:
- export GOOS=linux
- export GOARCH=amd64
@@ -177,11 +179,8 @@ stretch: &stretch
- make test | gotest-to-teamcity
test-fips:
build_dir: *build_dir
builddeps:
- *pinned_go_fips
- build-essential
- gotest-to-teamcity
pre-cache: *test_pre_cache
builddeps: *build_deps_fips
pre-cache: *build_pre_cache
post-cache:
- export GOOS=linux
- export GOARCH=amd64
+4 -7
View File
@@ -37,16 +37,13 @@ const (
sshConfigTemplate = `
Add to your {{.Home}}/.ssh/config:
Host {{.Hostname}}
{{- if .ShortLivedCerts}}
ProxyCommand bash -c '{{.Cloudflared}} access ssh-gen --hostname %h; ssh -tt %r@cfpipe-{{.Hostname}} >&2 <&1'
Host cfpipe-{{.Hostname}}
HostName {{.Hostname}}
Match host {{.Hostname}} exec "{{.Cloudflared}} access ssh-gen --hostname %h"
ProxyCommand {{.Cloudflared}} access ssh --hostname %h
IdentityFile ~/.cloudflared/{{.Hostname}}-cf_key
CertificateFile ~/.cloudflared/{{.Hostname}}-cf_key-cert.pub
IdentityFile ~/.cloudflared/%h-cf_key
CertificateFile ~/.cloudflared/%h-cf_key-cert.pub
{{- else}}
Host {{.Hostname}}
ProxyCommand {{.Cloudflared}} access ssh --hostname %h
{{end}}
`
+2 -1
View File
@@ -1,6 +1,7 @@
package proxydns
import (
"context"
"net"
"os"
"os/signal"
@@ -73,7 +74,7 @@ func Run(c *cli.Context) error {
log.Fatal().Err(err).Msg("Failed to open the metrics listener")
}
go metrics.ServeMetrics(metricsListener, nil, nil, "", nil, log)
go metrics.ServeMetrics(metricsListener, context.Background(), metrics.Config{}, log)
listener, err := tunneldns.CreateListener(
c.String("address"),
+35 -8
View File
@@ -82,6 +82,15 @@ const (
LogFieldPIDPathname = "pidPathname"
LogFieldTmpTraceFilename = "tmpTraceFilename"
LogFieldTraceOutputFilepath = "traceOutputFilepath"
tunnelCmdErrorMessage = `You did not specify any valid additional argument to the cloudflared tunnel command.
If you are trying to run a Quick Tunnel then you need to explicitly pass the --url flag.
Eg. cloudflared tunnel --url localhost:8080/.
Please note that Quick Tunnels are meant to be ephemeral and should only be used for testing purposes.
For production usage, we recommend creating Named Tunnels. (https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/tunnel-guide/)
`
)
var (
@@ -166,21 +175,27 @@ func TunnelCommand(c *cli.Context) error {
if err != nil {
return err
}
if name := c.String("name"); name != "" { // Start a named tunnel
return runAdhocNamedTunnel(sc, name, c.String(CredFileFlag))
}
// Unauthenticated named tunnel on <random>.<quick-tunnels-service>.com
shouldRunQuickTunnel := c.IsSet("url") || c.IsSet("hello-world")
if !dnsProxyStandAlone(c, nil) && c.String("hostname") == "" && c.String("quick-service") != "" && shouldRunQuickTunnel {
return RunQuickTunnel(sc)
}
if ref := config.GetConfiguration().TunnelID; ref != "" {
return fmt.Errorf("Use `cloudflared tunnel run` to start tunnel %s", ref)
}
// Unauthenticated named tunnel on <random>.<quick-tunnels-service>.com
// For now, default to legacy setup unless quick-service is specified
if !dnsProxyStandAlone(c, nil) && c.String("hostname") == "" && c.String("quick-service") != "" {
return RunQuickTunnel(sc)
// Start a classic tunnel if hostname is specified.
if c.String("hostname") != "" {
return runClassicTunnel(sc)
}
// Start a classic tunnel
return runClassicTunnel(sc)
return errors.New(tunnelCmdErrorMessage)
}
func Init(info *cliutil.BuildInfo, gracefulShutdown chan struct{}) {
@@ -241,7 +256,8 @@ func StartServer(
listeners := gracenet.Net{}
errC := make(chan error)
if config.GetConfiguration().Source() == "" {
// Only log for locally configured tunnels (Token is blank).
if config.GetConfiguration().Source() == "" && c.String(TunnelTokenFlag) == "" {
log.Info().Msg(config.ErrNoConfigFile.Error())
}
@@ -372,7 +388,12 @@ func StartServer(
defer wg.Done()
readinessServer := metrics.NewReadyServer(log, clientID)
observer.RegisterSink(readinessServer)
errC <- metrics.ServeMetrics(metricsListener, ctx.Done(), readinessServer, quickTunnelURL, orchestrator, log)
metricsConfig := metrics.Config{
ReadyServer: readinessServer,
QuickTunnelHostname: quickTunnelURL,
Orchestrator: orchestrator,
}
errC <- metrics.ServeMetrics(metricsListener, ctx, metricsConfig, log)
}()
reconnectCh := make(chan supervisor.ReconnectSignal, c.Int("ha-connections"))
@@ -591,6 +612,12 @@ func tunnelFlags(shouldHide bool) []cli.Flag {
Value: 5,
Hidden: true,
}),
altsrc.NewIntFlag(&cli.IntFlag{
Name: "max-edge-addr-retries",
Usage: "Maximum number of times to retry on edge addrs before falling back to a lower protocol",
Value: 8,
Hidden: true,
}),
// Note TUN-3758 , we use Int because UInt is not supported with altsrc
altsrc.NewIntFlag(&cli.IntFlag{
Name: "retries",
+11 -10
View File
@@ -46,7 +46,7 @@ var (
LogFieldHostname = "hostname"
secretFlags = [2]*altsrc.StringFlag{credentialsContentsFlag, tunnelTokenFlag}
defaultFeatures = []string{supervisor.FeatureAllowRemoteConfig, supervisor.FeatureSerializedHeaders, supervisor.FeatureDatagramV2}
defaultFeatures = []string{supervisor.FeatureAllowRemoteConfig, supervisor.FeatureSerializedHeaders, supervisor.FeatureDatagramV2, supervisor.FeatureQUICSupportEOF}
configFlags = []string{"autoupdate-freq", "no-autoupdate", "retries", "protocol", "loglevel", "transport-loglevel", "origincert", "metrics", "metrics-update-freq", "edge-ip-version"}
)
@@ -376,15 +376,16 @@ func prepareTunnelConfig(
Observer: observer,
ReportedVersion: info.Version(),
// Note TUN-3758 , we use Int because UInt is not supported with altsrc
Retries: uint(c.Int("retries")),
RunFromTerminal: isRunningFromTerminal(),
NamedTunnel: namedTunnel,
ClassicTunnel: classicTunnel,
MuxerConfig: muxerConfig,
ProtocolSelector: protocolSelector,
EdgeTLSConfigs: edgeTLSConfigs,
NeedPQ: needPQ,
PQKexIdx: pqKexIdx,
Retries: uint(c.Int("retries")),
RunFromTerminal: isRunningFromTerminal(),
NamedTunnel: namedTunnel,
ClassicTunnel: classicTunnel,
MuxerConfig: muxerConfig,
ProtocolSelector: protocolSelector,
EdgeTLSConfigs: edgeTLSConfigs,
NeedPQ: needPQ,
PQKexIdx: pqKexIdx,
MaxEdgeAddrRetries: uint8(c.Int("max-edge-addr-retries")),
}
packetConfig, err := newPacketConfig(c, log)
if err != nil {
+1 -1
View File
@@ -74,7 +74,7 @@ func (sc *subcommandContext) client() (cfapi.Client, error) {
sc.c.String("api-url"),
credential.cert.AccountID,
credential.cert.ZoneID,
credential.cert.ServiceKey,
credential.cert.APIToken,
userAgent,
sc.log,
)
+1 -1
View File
@@ -783,7 +783,7 @@ func tokenCommand(c *cli.Context) error {
return err
}
fmt.Printf("%s", encodedToken)
fmt.Println(encodedToken)
return nil
}
+2 -1
View File
@@ -391,7 +391,8 @@ func ReadConfigFile(c *cli.Context, log *zerolog.Logger) (settings *configFileSe
log.Debug().Msgf("Loading configuration from %s", configFile)
file, err := os.Open(configFile)
if err != nil {
if os.IsNotExist(err) {
// If does not exist and config file was not specificly specified then return ErrNoConfigFile found.
if os.IsNotExist(err) && !c.IsSet("config") {
err = ErrNoConfigFile
}
return nil, "", err
+1 -1
View File
@@ -85,7 +85,7 @@ func (c *controlStream) ServeControlStream(
return err
}
c.observer.logServerInfo(c.connIndex, registrationDetails.Location, c.edgeAddress, fmt.Sprintf("Connection %s registered", registrationDetails.UUID))
c.observer.logServerInfo(c.connIndex, registrationDetails.Location, c.edgeAddress, fmt.Sprintf("Connection %s registered with protocol: %s", registrationDetails.UUID, c.protocol))
c.observer.sendConnectedEvent(c.connIndex, c.protocol, registrationDetails.Location)
c.connectedFuse.Connected()
+2
View File
@@ -81,6 +81,8 @@ func NewQUICConnection(
session, err := quic.Dial(udpConn, edgeAddr, edgeAddr.String(), tlsConfig, quicConfig)
if err != nil {
// close the udp server socket in case of error connecting to the edge
udpConn.Close()
return nil, &EdgeQuicDialError{Cause: err}
}
+1 -1
View File
@@ -1,4 +1,4 @@
FROM golang:1.18 as builder
FROM golang:1.19 as builder
ENV GO111MODULE=on \
CGO_ENABLED=0
WORKDIR /go/src/github.com/cloudflare/cloudflared/
+7 -4
View File
@@ -71,11 +71,14 @@ type EdgeAddr struct {
// If the call to net.LookupSRV fails, try to fall back to DoT from Cloudflare directly.
//
// Note: Instead of DoT, we could also have used DoH. Either of these:
// - directly via the JSON API (https://1.1.1.1/dns-query?ct=application/dns-json&name=_origintunneld._tcp.argotunnel.com&type=srv)
// - indirectly via `tunneldns.NewUpstreamHTTPS()`
// - directly via the JSON API (https://1.1.1.1/dns-query?ct=application/dns-json&name=_origintunneld._tcp.argotunnel.com&type=srv)
// - indirectly via `tunneldns.NewUpstreamHTTPS()`
//
// But both of these cases miss out on a key feature from the stdlib:
// "The returned records are sorted by priority and randomized by weight within a priority."
// (https://golang.org/pkg/net/#Resolver.LookupSRV)
//
// "The returned records are sorted by priority and randomized by weight within a priority."
// (https://golang.org/pkg/net/#Resolver.LookupSRV)
//
// Does this matter? I don't know. It may someday. Let's use DoT so we don't need to worry about it.
// See also: Go feature request for stdlib-supported DoH: https://github.com/golang/go/issues/27552
var fallbackLookupSRV = lookupSRVWithDOT
+10
View File
@@ -2,6 +2,7 @@ package allregions
import (
"fmt"
"math/rand"
"github.com/rs/zerolog"
)
@@ -85,6 +86,15 @@ func (rs *Regions) AddrUsedBy(connID int) *EdgeAddr {
// GetUnusedAddr gets an unused addr from the edge, excluding the given addr. Prefer to use addresses
// evenly across both regions.
func (rs *Regions) GetUnusedAddr(excluding *EdgeAddr, connID int) *EdgeAddr {
// If both regions have the same number of available addrs, lets randomise which one
// we pick. The rest of this algorithm will continue to make sure we always use addresses
// evenly across both regions.
if rs.region1.AvailableAddrs() == rs.region2.AvailableAddrs() {
regions := []Region{rs.region1, rs.region2}
firstChoice := rand.Intn(2)
return getAddrs(excluding, connID, &regions[firstChoice], &regions[1-firstChoice])
}
if rs.region1.AvailableAddrs() > rs.region2.AvailableAddrs() {
return getAddrs(excluding, connID, &rs.region1, &rs.region2)
}
+2 -2
View File
@@ -2,12 +2,12 @@
set -e -o pipefail
OUTPUT=$(for d in $(go list -mod=vendor -f '{{.Dir}}' -a ./... | fgrep -v tunnelrpc) ; do goimports -format-only -local github.com/cloudflare/cloudflared -d $d ; done)
OUTPUT=$(goimports -l -d -local github.com/cloudflare/cloudflared $(go list -mod=vendor -f '{{.Dir}}' -a ./... | fgrep -v tunnelrpc))
if [ -n "$OUTPUT" ] ; then
PAGER=$(which colordiff || echo cat)
echo
echo "Code formatting issues found, use 'goimports -format-only -local github.com/cloudflare/cloudflared' to correct them"
echo "Code formatting issues found, use 'make fmt' to correct them"
echo
echo "$OUTPUT" | $PAGER
exit 1
+9 -10
View File
@@ -1,6 +1,6 @@
module github.com/cloudflare/cloudflared
go 1.18
go 1.19
require (
github.com/cloudflare/brotli-go v0.0.0-20191101163834-d34379f7ff93
@@ -35,11 +35,11 @@ require (
go.opentelemetry.io/otel/trace v1.6.3
go.opentelemetry.io/proto/otlp v0.15.0
go.uber.org/automaxprocs v1.4.0
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
golang.org/x/net v0.0.0-20220909164309-bea034e7d591
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
golang.org/x/crypto v0.2.0
golang.org/x/net v0.2.0
golang.org/x/sync v0.1.0
golang.org/x/sys v0.2.0
golang.org/x/term v0.2.0
google.golang.org/protobuf v1.28.0
gopkg.in/coreos/go-oidc.v2 v2.2.1
gopkg.in/natefinch/lumberjack.v2 v2.0.0
@@ -89,11 +89,10 @@ require (
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
golang.org/x/text v0.4.0 // indirect
golang.org/x/tools v0.1.12 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90 // indirect
google.golang.org/grpc v1.47.0 // indirect
+16 -10
View File
@@ -644,8 +644,9 @@ golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.2.0 h1:BRXPfhNivWL5Yq0BGQ39a2sW6t44aODpfxkWjYdzewE=
golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
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=
@@ -681,8 +682,9 @@ 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.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -742,8 +744,8 @@ golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI=
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -780,8 +782,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/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/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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -865,12 +868,14 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 h1:v1W7bwXHsnLLloWYTVEdvGvA7BHMeBYsPcF0GLDxIRs=
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
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=
@@ -879,8 +884,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/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 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
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=
@@ -945,15 +951,15 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 h1:BonxutuHCTL0rBDnZlKjpGIQFTjyUVTexFOdWkB6Fg0=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
+5 -4
View File
@@ -435,10 +435,11 @@ func (defaults *OriginRequestConfig) setAccess(overrides config.OriginRequestCon
// SetConfig gets config for the requests that cloudflared sends to origins.
// Each field has a setter method which sets a value for the field by trying to find:
// 1. The user config for this rule
// 2. The user config for the overall ingress config
// 3. Defaults chosen by the cloudflared team
// 4. Golang zero values for that type
// 1. The user config for this rule
// 2. The user config for the overall ingress config
// 3. Defaults chosen by the cloudflared team
// 4. Golang zero values for that type
//
// If an earlier option isn't set, it will try the next option down.
func setConfig(defaults OriginRequestConfig, overrides config.OriginRequestConfig) OriginRequestConfig {
cfg := defaults
+3 -3
View File
@@ -148,7 +148,6 @@ func (ip *icmpProxy) Request(ctx context.Context, pk *packet.ICMP, responder *pa
dstIP: pk.Dst,
originalEchoID: originalEcho.ID,
}
// TODO: TUN-6744 assign unique flow per (src, echo ID)
assignedEchoID, success := ip.echoIDTracker.getOrAssign(echoIDTrackerKey)
if !success {
err := fmt.Errorf("failed to assign unique echo ID")
@@ -157,6 +156,7 @@ func (ip *icmpProxy) Request(ctx context.Context, pk *packet.ICMP, responder *pa
}
span.SetAttributes(attribute.Int("assignedEchoID", int(assignedEchoID)))
shouldReplaceFunnelFunc := createShouldReplaceFunnelFunc(ip.logger, responder.datagramMuxer, pk, originalEcho.ID)
newFunnelFunc := func() (packet.Funnel, error) {
originalEcho, err := getICMPEcho(pk.Message)
if err != nil {
@@ -170,7 +170,7 @@ func (ip *icmpProxy) Request(ctx context.Context, pk *packet.ICMP, responder *pa
return icmpFlow, nil
}
funnelID := echoFunnelID(assignedEchoID)
funnel, isNew, err := ip.srcFunnelTracker.GetOrRegister(funnelID, newFunnelFunc)
funnel, isNew, err := ip.srcFunnelTracker.GetOrRegister(funnelID, shouldReplaceFunnelFunc, newFunnelFunc)
if err != nil {
tracing.EndWithErrorStatus(span, err)
return err
@@ -229,7 +229,7 @@ func (ip *icmpProxy) Serve(ctx context.Context) error {
continue
}
if err := ip.sendReply(ctx, reply); err != nil {
ip.logger.Error().Err(err).Str("dst", from.String()).Msg("Failed to send ICMP reply")
ip.logger.Debug().Err(err).Str("dst", from.String()).Msg("Failed to send ICMP reply")
continue
}
}
+8
View File
@@ -8,6 +8,8 @@ import (
"testing"
"github.com/stretchr/testify/require"
"github.com/cloudflare/cloudflared/packet"
)
func TestSingleEchoIDTracker(t *testing.T) {
@@ -119,3 +121,9 @@ func (eit *echoIDTracker) get(key flow3Tuple) (id uint16, exist bool) {
id, exists := eit.mapping[key]
return id, exists
}
func getFunnel(t *testing.T, proxy *icmpProxy, tuple flow3Tuple) (packet.Funnel, bool) {
assignedEchoID, success := proxy.echoIDTracker.getOrAssign(tuple)
require.True(t, success)
return proxy.srcFunnelTracker.Get(echoFunnelID(assignedEchoID))
}
+3 -2
View File
@@ -112,6 +112,7 @@ func (ip *icmpProxy) Request(ctx context.Context, pk *packet.ICMP, responder *pa
attribute.Int("seq", originalEcho.Seq),
)
shouldReplaceFunnelFunc := createShouldReplaceFunnelFunc(ip.logger, responder.datagramMuxer, pk, originalEcho.ID)
newFunnelFunc := func() (packet.Funnel, error) {
conn, err := newICMPConn(ip.listenIP, ip.ipv6Zone)
if err != nil {
@@ -137,7 +138,7 @@ func (ip *icmpProxy) Request(ctx context.Context, pk *packet.ICMP, responder *pa
dstIP: pk.Dst,
originalEchoID: originalEcho.ID,
}
funnel, isNew, err := ip.srcFunnelTracker.GetOrRegister(funnelID, newFunnelFunc)
funnel, isNew, err := ip.srcFunnelTracker.GetOrRegister(funnelID, shouldReplaceFunnelFunc, newFunnelFunc)
if err != nil {
tracing.EndWithErrorStatus(span, err)
return err
@@ -219,7 +220,7 @@ func (ip *icmpProxy) handleResponse(ctx context.Context, flow *icmpEchoFlow, buf
attribute.Int("seq", reply.echo.Seq),
)
if err := flow.returnToSrc(reply); err != nil {
ip.logger.Err(err).Str("dst", from.String()).Msg("Failed to send ICMP reply")
ip.logger.Debug().Err(err).Str("dst", from.String()).Msg("Failed to send ICMP reply")
tracing.EndWithErrorStatus(span, err)
return true, err
}
+13
View File
@@ -0,0 +1,13 @@
//go:build linux
package ingress
import (
"testing"
"github.com/cloudflare/cloudflared/packet"
)
func getFunnel(t *testing.T, proxy *icmpProxy, tuple flow3Tuple) (packet.Funnel, bool) {
return proxy.srcFunnelTracker.Get(tuple)
}
+28
View File
@@ -10,6 +10,7 @@ import (
"net/netip"
"github.com/google/gopacket/layers"
"github.com/rs/zerolog"
"golang.org/x/net/icmp"
"github.com/cloudflare/cloudflared/packet"
@@ -174,3 +175,30 @@ func toICMPEchoFlow(funnel packet.Funnel) (*icmpEchoFlow, error) {
}
return icmpFlow, nil
}
func createShouldReplaceFunnelFunc(logger *zerolog.Logger, muxer muxer, pk *packet.ICMP, originalEchoID int) func(packet.Funnel) bool {
return func(existing packet.Funnel) bool {
existingFlow, err := toICMPEchoFlow(existing)
if err != nil {
logger.Err(err).
Str("src", pk.Src.String()).
Str("dst", pk.Dst.String()).
Int("originalEchoID", originalEchoID).
Msg("Funnel of wrong type found")
return true
}
// Each quic connection should have a unique muxer.
// If the existing flow has a different muxer, there's a new quic connection where return packets should be
// routed. Otherwise, return packets will be send to the first observed incoming connection, rather than the
// most recently observed connection.
if existingFlow.responder.datagramMuxer != muxer {
logger.Debug().
Str("src", pk.Src.String()).
Str("dst", pk.Dst.String()).
Int("originalEchoID", originalEchoID).
Msg("Replacing funnel with new responder")
return true
}
return false
}
}
+66 -4
View File
@@ -57,13 +57,13 @@ func TestFunnelIdleTimeout(t *testing.T) {
datagramMuxer: muxer,
}
require.NoError(t, proxy.Request(ctx, &pk, &responder))
validateEchoFlow(t, muxer, &pk)
validateEchoFlow(t, <-muxer.cfdToEdge, &pk)
// Send second request, should reuse the funnel
require.NoError(t, proxy.Request(ctx, &pk, &packetResponder{
datagramMuxer: nil,
datagramMuxer: muxer,
}))
validateEchoFlow(t, muxer, &pk)
validateEchoFlow(t, <-muxer.cfdToEdge, &pk)
time.Sleep(idleTimeout * 2)
newMuxer := newMockMuxer(0)
@@ -71,7 +71,69 @@ func TestFunnelIdleTimeout(t *testing.T) {
datagramMuxer: newMuxer,
}
require.NoError(t, proxy.Request(ctx, &pk, &newResponder))
validateEchoFlow(t, newMuxer, &pk)
validateEchoFlow(t, <-newMuxer.cfdToEdge, &pk)
cancel()
<-proxyDone
}
func TestReuseFunnel(t *testing.T) {
const (
idleTimeout = time.Second
echoID = 42573
startSeq = 8129
)
logger := zerolog.New(os.Stderr)
proxy, err := newICMPProxy(localhostIP, "", &logger, idleTimeout)
require.NoError(t, err)
ctx, cancel := context.WithCancel(context.Background())
proxyDone := make(chan struct{})
go func() {
proxy.Serve(ctx)
close(proxyDone)
}()
// Send a packet to register the flow
pk := packet.ICMP{
IP: &packet.IP{
Src: localhostIP,
Dst: localhostIP,
Protocol: layers.IPProtocolICMPv4,
},
Message: &icmp.Message{
Type: ipv4.ICMPTypeEcho,
Code: 0,
Body: &icmp.Echo{
ID: echoID,
Seq: startSeq,
Data: []byte(t.Name()),
},
},
}
tuple := flow3Tuple{
srcIP: pk.Src,
dstIP: pk.Dst,
originalEchoID: echoID,
}
muxer := newMockMuxer(0)
responder := packetResponder{
datagramMuxer: muxer,
}
require.NoError(t, proxy.Request(ctx, &pk, &responder))
validateEchoFlow(t, <-muxer.cfdToEdge, &pk)
funnel1, found := getFunnel(t, proxy, tuple)
require.True(t, found)
// Send second request, should reuse the funnel
require.NoError(t, proxy.Request(ctx, &pk, &packetResponder{
datagramMuxer: muxer,
}))
validateEchoFlow(t, <-muxer.cfdToEdge, &pk)
funnel2, found := getFunnel(t, proxy, tuple)
require.True(t, found)
require.Equal(t, funnel1, funnel2)
cancel()
<-proxyDone
+14 -14
View File
@@ -376,20 +376,20 @@ func (ip *icmpProxy) icmpEchoRoundtrip(dst netip.Addr, echo *icmp.Echo) (echoRes
}
/*
Wrapper to call https://docs.microsoft.com/en-us/windows/win32/api/icmpapi/nf-icmpapi-icmpsendecho
Parameters:
- IcmpHandle: Handle created by IcmpCreateFile
- DestinationAddress: IPv4 in the form of https://docs.microsoft.com/en-us/windows/win32/api/inaddr/ns-inaddr-in_addr#syntax
- RequestData: A pointer to echo data
- RequestSize: Number of bytes in buffer pointed by echo data
- RequestOptions: IP header options
- ReplyBuffer: A pointer to the buffer for echoReply, options and data
- ReplySize: Number of bytes allocated for ReplyBuffer
- Timeout: Timeout in milliseconds to wait for a reply
Returns:
- the number of replies in uint32 https://docs.microsoft.com/en-us/windows/win32/api/icmpapi/nf-icmpapi-icmpsendecho#return-value
To retain the reference allocated objects, conversion from pointer to uintptr must happen as arguments to the
syscall function
Wrapper to call https://docs.microsoft.com/en-us/windows/win32/api/icmpapi/nf-icmpapi-icmpsendecho
Parameters:
- IcmpHandle: Handle created by IcmpCreateFile
- DestinationAddress: IPv4 in the form of https://docs.microsoft.com/en-us/windows/win32/api/inaddr/ns-inaddr-in_addr#syntax
- RequestData: A pointer to echo data
- RequestSize: Number of bytes in buffer pointed by echo data
- RequestOptions: IP header options
- ReplyBuffer: A pointer to the buffer for echoReply, options and data
- ReplySize: Number of bytes allocated for ReplyBuffer
- Timeout: Timeout in milliseconds to wait for a reply
Returns:
- the number of replies in uint32 https://docs.microsoft.com/en-us/windows/win32/api/icmpapi/nf-icmpapi-icmpsendecho#return-value
To retain the reference allocated objects, conversion from pointer to uintptr must happen as arguments to the
syscall function
*/
func (ip *icmpProxy) icmpSendEcho(dst netip.Addr, echo *icmp.Echo) (*echoV4Resp, error) {
dataSize := len(echo.Data)
+1 -1
View File
@@ -125,7 +125,7 @@ func TestParseEchoV6Reply(t *testing.T) {
}
}
// TestSendEchoErrors makes sure icmpSendEcho handles error cases
// TestSendEchoErrors makes sure icmpSendEcho handles error cases
func TestSendEchoErrors(t *testing.T) {
testSendEchoErrors(t, netip.IPv4Unspecified())
testSendEchoErrors(t, netip.IPv6Unspecified())
+5 -13
View File
@@ -58,7 +58,7 @@ func matchHost(ruleHost, reqHost string) bool {
// Validate hostnames that use wildcards at the start
if strings.HasPrefix(ruleHost, "*.") {
toMatch := strings.TrimPrefix(ruleHost, "*.")
toMatch := strings.TrimPrefix(ruleHost, "*")
return strings.HasSuffix(reqHost, toMatch)
}
return false
@@ -175,18 +175,10 @@ func validateAccessConfiguration(cfg *config.AccessConfig) error {
return nil
}
// It is possible to set `required:true` and not have these two configured yet.
// But if one of them is configured, we'd validate for correctness.
if len(cfg.AudTag) == 0 && cfg.TeamName == "" {
return nil
}
if len(cfg.AudTag) == 0 {
return errors.New("access audtag cannot be empty")
}
if cfg.TeamName == "" {
return errors.New("access.TeamName cannot be blank")
// we allow for an initial setup where user can force Access but not configure the rest of the keys.
// however, if the user specified audTags but forgot teamName, we should alert it.
if cfg.TeamName == "" && len(cfg.AudTag) > 0 {
return errors.New("access.TeamName cannot be blank when access.audTags are present")
}
return nil
+40
View File
@@ -674,6 +674,46 @@ ingress:
}
}
func TestParseAccessConfig(t *testing.T) {
tests := []struct {
name string
cfg config.AccessConfig
expectError bool
}{
{
name: "Config required with teamName only",
cfg: config.AccessConfig{Required: true, TeamName: "team"},
expectError: false,
},
{
name: "required false",
cfg: config.AccessConfig{Required: false},
expectError: false,
},
{
name: "required true but empty config",
cfg: config.AccessConfig{Required: true},
expectError: false,
},
{
name: "complete config",
cfg: config.AccessConfig{Required: true, TeamName: "team", AudTag: []string{"a"}},
expectError: false,
},
{
name: "required true with audTags but no teamName",
cfg: config.AccessConfig{Required: true, AudTag: []string{"a"}},
expectError: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := validateAccessConfiguration(&test.cfg)
require.Equal(t, err != nil, test.expectError)
})
}
}
func MustReadIngress(s string) *config.Configuration {
var conf config.Configuration
err := yaml.Unmarshal([]byte(s), &conf)
+31 -45
View File
@@ -6,7 +6,6 @@ import (
"fmt"
"net"
"net/netip"
"runtime"
"strings"
"sync"
"testing"
@@ -95,7 +94,7 @@ func testICMPRouterEcho(t *testing.T, sendIPv4 bool) {
},
}
require.NoError(t, router.Request(ctx, &pk, &responder))
validateEchoFlow(t, muxer, &pk)
validateEchoFlow(t, <-muxer.cfdToEdge, &pk)
}
}
cancel()
@@ -148,25 +147,35 @@ func TestTraceICMPRouterEcho(t *testing.T) {
}
require.NoError(t, router.Request(ctx, &pk, &responder))
// On Windows, request span is returned before reply
if runtime.GOOS != "windows" {
validateEchoFlow(t, muxer, &pk)
firstPK := <-muxer.cfdToEdge
var requestSpan *quicpogs.TracingSpanPacket
// The order of receiving reply or request span is not deterministic
switch firstPK.Type() {
case quicpogs.DatagramTypeIP:
// reply packet
validateEchoFlow(t, firstPK, &pk)
case quicpogs.DatagramTypeTracingSpan:
// Request span
requestSpan = firstPK.(*quicpogs.TracingSpanPacket)
require.NotEmpty(t, requestSpan.Spans)
require.True(t, bytes.Equal(serializedIdentity, requestSpan.TracingIdentity))
default:
panic(fmt.Sprintf("received unexpected packet type %d", firstPK.Type()))
}
// Request span
receivedPacket := <-muxer.cfdToEdge
requestSpan, ok := receivedPacket.(*quicpogs.TracingSpanPacket)
require.True(t, ok)
require.NotEmpty(t, requestSpan.Spans)
require.True(t, bytes.Equal(serializedIdentity, requestSpan.TracingIdentity))
if runtime.GOOS == "windows" {
validateEchoFlow(t, muxer, &pk)
secondPK := <-muxer.cfdToEdge
if requestSpan != nil {
// If first packet is request span, second packet should be the reply
validateEchoFlow(t, secondPK, &pk)
} else {
requestSpan = secondPK.(*quicpogs.TracingSpanPacket)
require.NotEmpty(t, requestSpan.Spans)
require.True(t, bytes.Equal(serializedIdentity, requestSpan.TracingIdentity))
}
// Reply span
receivedPacket = <-muxer.cfdToEdge
replySpan, ok := receivedPacket.(*quicpogs.TracingSpanPacket)
thirdPacket := <-muxer.cfdToEdge
replySpan, ok := thirdPacket.(*quicpogs.TracingSpanPacket)
require.True(t, ok)
require.NotEmpty(t, replySpan.Spans)
require.True(t, bytes.Equal(serializedIdentity, replySpan.TracingIdentity))
@@ -179,10 +188,10 @@ func TestTraceICMPRouterEcho(t *testing.T) {
datagramMuxer: muxer,
}
require.NoError(t, router.Request(ctx, &pk, &newResponder))
validateEchoFlow(t, muxer, &pk)
validateEchoFlow(t, <-muxer.cfdToEdge, &pk)
select {
case receivedPacket = <-muxer.cfdToEdge:
case receivedPacket := <-muxer.cfdToEdge:
panic(fmt.Sprintf("Receive unexpected packet %+v", receivedPacket))
default:
}
@@ -240,7 +249,7 @@ func TestConcurrentRequestsToSameDst(t *testing.T) {
},
}
require.NoError(t, router.Request(ctx, pk, &responder))
validateEchoFlow(t, muxer, pk)
validateEchoFlow(t, <-muxer.cfdToEdge, pk)
}
}()
go func() {
@@ -268,7 +277,7 @@ func TestConcurrentRequestsToSameDst(t *testing.T) {
},
}
require.NoError(t, router.Request(ctx, pk, &responder))
validateEchoFlow(t, muxer, pk)
validateEchoFlow(t, <-muxer.cfdToEdge, pk)
}
}()
}
@@ -357,33 +366,10 @@ func testICMPRouterRejectNotEcho(t *testing.T, srcDstIP netip.Addr, msgs []icmp.
}
}
type echoFlowResponder struct {
lock sync.Mutex
decoder *packet.ICMPDecoder
respChan chan []byte
}
func (efr *echoFlowResponder) SendPacket(dst netip.Addr, pk packet.RawPacket) error {
efr.lock.Lock()
defer efr.lock.Unlock()
copiedPacket := make([]byte, len(pk.Data))
copy(copiedPacket, pk.Data)
efr.respChan <- copiedPacket
return nil
}
func (efr *echoFlowResponder) Close() error {
efr.lock.Lock()
defer efr.lock.Unlock()
close(efr.respChan)
return nil
}
func validateEchoFlow(t *testing.T, muxer *mockMuxer, echoReq *packet.ICMP) {
pk := <-muxer.cfdToEdge
func validateEchoFlow(t *testing.T, pk quicpogs.Packet, echoReq *packet.ICMP) {
decoder := packet.NewICMPDecoder()
decoded, err := decoder.Decode(packet.RawPacket{Data: pk.Payload()})
require.NoError(t, err)
require.NoError(t, err, pk)
require.Equal(t, decoded.Src, echoReq.Dst)
require.Equal(t, decoded.Dst, echoReq.Src)
require.Equal(t, echoReq.Protocol, decoded.Protocol)
+4 -1
View File
@@ -9,6 +9,7 @@ import (
"net"
"net/http"
"net/url"
"strconv"
"time"
"github.com/pkg/errors"
@@ -155,8 +156,10 @@ func newSocksProxyOverWSService(accessPolicy *ipaccess.Policy) *socksProxyOverWS
}
func addPortIfMissing(uri *url.URL, port int) {
hostname := uri.Hostname()
if uri.Port() == "" {
uri.Host = fmt.Sprintf("%s:%d", uri.Hostname(), port)
uri.Host = net.JoinHostPort(hostname, strconv.FormatInt(int64(port), 10))
}
}
+29
View File
@@ -0,0 +1,29 @@
package ingress
import (
"net/url"
"testing"
"github.com/stretchr/testify/require"
)
func TestAddPortIfMissing(t *testing.T) {
testCases := []struct {
input string
expected string
}{
{"ssh://[::1]", "[::1]:22"},
{"ssh://[::1]:38", "[::1]:38"},
{"ssh://abc:38", "abc:38"},
{"ssh://127.0.0.1:38", "127.0.0.1:38"},
{"ssh://127.0.0.1", "127.0.0.1:22"},
}
for _, tc := range testCases {
t.Run(tc.input, func(t *testing.T) {
url1, _ := url.Parse(tc.input)
addPortIfMissing(url1, 22)
require.Equal(t, tc.expected, url1.Host)
})
}
}
-2
View File
@@ -176,8 +176,6 @@ func (pr *packetResponder) exportSpan() {
}
spans := pr.tracedCtx.GetProtoSpans()
if len(spans) > 0 {
// Make sure spans are cleared after they are sent
defer pr.tracedCtx.ClearSpans()
pr.datagramMuxer.SendPacket(&quicpogs.TracingSpanPacket{
Spans: spans,
TracingIdentity: pr.serializedIdentity,
+10
View File
@@ -148,6 +148,16 @@ func Test_rule_matches(t *testing.T) {
},
want: true,
},
{
name: "Hostname with wildcard should not match if no dot present",
rule: Rule{
Hostname: "*.api.abc.cloud",
},
args: args{
requestURL: MustParseURL(t, "https://testing-api.abc.cloud"),
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
+25 -16
View File
@@ -18,18 +18,24 @@ import (
)
const (
shutdownTimeout = time.Second * 15
startupTime = time.Millisecond * 500
startupTime = time.Millisecond * 500
defaultShutdownTimeout = time.Second * 15
)
type Config struct {
ReadyServer *ReadyServer
QuickTunnelHostname string
Orchestrator orchestrator
ShutdownTimeout time.Duration
}
type orchestrator interface {
GetVersionedConfigJSON() ([]byte, error)
}
func newMetricsHandler(
readyServer *ReadyServer,
quickTunnelHostname string,
orchestrator orchestrator,
config Config,
log *zerolog.Logger,
) *mux.Router {
router := mux.NewRouter()
@@ -39,15 +45,15 @@ func newMetricsHandler(
router.HandleFunc("/healthcheck", func(w http.ResponseWriter, r *http.Request) {
_, _ = fmt.Fprintf(w, "OK\n")
})
if readyServer != nil {
router.Handle("/ready", readyServer)
if config.ReadyServer != nil {
router.Handle("/ready", config.ReadyServer)
}
router.HandleFunc("/quicktunnel", func(w http.ResponseWriter, r *http.Request) {
_, _ = fmt.Fprintf(w, `{"hostname":"%s"}`, quickTunnelHostname)
_, _ = fmt.Fprintf(w, `{"hostname":"%s"}`, config.QuickTunnelHostname)
})
if orchestrator != nil {
if config.Orchestrator != nil {
router.HandleFunc("/config", func(w http.ResponseWriter, r *http.Request) {
json, err := orchestrator.GetVersionedConfigJSON()
json, err := config.Orchestrator.GetVersionedConfigJSON()
if err != nil {
w.WriteHeader(500)
_, _ = fmt.Fprintf(w, "ERR: %v", err)
@@ -63,10 +69,8 @@ func newMetricsHandler(
func ServeMetrics(
l net.Listener,
shutdownC <-chan struct{},
readyServer *ReadyServer,
quickTunnelHostname string,
orchestrator orchestrator,
ctx context.Context,
config Config,
log *zerolog.Logger,
) (err error) {
var wg sync.WaitGroup
@@ -74,7 +78,7 @@ func ServeMetrics(
trace.AuthRequest = func(*http.Request) (bool, bool) { return true, true }
// TODO: parameterize ReadTimeout and WriteTimeout. The maximum time we can
// profile CPU usage depends on WriteTimeout
h := newMetricsHandler(readyServer, quickTunnelHostname, orchestrator, log)
h := newMetricsHandler(config, log)
server := &http.Server{
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
@@ -91,7 +95,12 @@ func ServeMetrics(
// fully started up. So add artificial delay.
time.Sleep(startupTime)
<-shutdownC
<-ctx.Done()
shutdownTimeout := config.ShutdownTimeout
if shutdownTimeout == 0 {
shutdownTimeout = defaultShutdownTimeout
}
ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
_ = server.Shutdown(ctx)
cancel()
+14 -4
View File
@@ -108,13 +108,23 @@ func (ft *FunnelTracker) Get(id FunnelID) (Funnel, bool) {
return funnel, ok
}
// Registers a funnel. It replaces the current funnel.
func (ft *FunnelTracker) GetOrRegister(id FunnelID, newFunnelFunc func() (Funnel, error)) (funnel Funnel, new bool, err error) {
// Registers a funnel. If the `id` is already registered and `shouldReplaceFunc` returns true, it closes and replaces
// the current funnel. If `newFunnelFunc` returns an error, the `id` will remain unregistered, even if it was registered
// when calling this function.
func (ft *FunnelTracker) GetOrRegister(
id FunnelID,
shouldReplaceFunc func(Funnel) bool,
newFunnelFunc func() (Funnel, error),
) (funnel Funnel, new bool, err error) {
ft.lock.Lock()
defer ft.lock.Unlock()
currentFunnel, exists := ft.funnels[id]
if exists {
return currentFunnel, false, nil
if !shouldReplaceFunc(currentFunnel) {
return currentFunnel, false, nil
}
currentFunnel.Close()
delete(ft.funnels, id)
}
newFunnel, err := newFunnelFunc()
if err != nil {
@@ -124,7 +134,7 @@ func (ft *FunnelTracker) GetOrRegister(id FunnelID, newFunnelFunc func() (Funnel
return newFunnel, true, nil
}
// Unregisters a funnel if the funnel equals to the current funnel
// Unregisters and closes a funnel if the funnel equals to the current funnel
func (ft *FunnelTracker) Unregister(id FunnelID, funnel Funnel) (deleted bool) {
ft.lock.Lock()
defer ft.lock.Unlock()
+123 -1
View File
@@ -1,6 +1,13 @@
package packet
import "net/netip"
import (
"fmt"
"net/netip"
"testing"
"time"
"github.com/stretchr/testify/require"
)
type mockFunnelUniPipe struct {
uniPipe chan RawPacket
@@ -14,3 +21,118 @@ func (mfui *mockFunnelUniPipe) SendPacket(dst netip.Addr, pk RawPacket) error {
func (mfui *mockFunnelUniPipe) Close() error {
return nil
}
func TestFunnelRegistration(t *testing.T) {
id := testFunnelID{"id1"}
funnelErr := fmt.Errorf("expected error")
newFunnelFuncErr := func() (Funnel, error) { return nil, funnelErr }
newFunnelFuncUncalled := func() (Funnel, error) {
require.FailNow(t, "a new funnel should not be created")
panic("unreached")
}
funnel1, newFunnelFunc1 := newFunnelAndFunc("funnel1")
funnel2, newFunnelFunc2 := newFunnelAndFunc("funnel2")
ft := NewFunnelTracker()
// Register funnel1
funnel, new, err := ft.GetOrRegister(id, shouldReplaceFalse, newFunnelFunc1)
require.NoError(t, err)
require.True(t, new)
require.Equal(t, funnel1, funnel)
// Register funnel, no replace
funnel, new, err = ft.GetOrRegister(id, shouldReplaceFalse, newFunnelFuncUncalled)
require.NoError(t, err)
require.False(t, new)
require.Equal(t, funnel1, funnel)
// Register funnel2, replace
funnel, new, err = ft.GetOrRegister(id, shouldReplaceTrue, newFunnelFunc2)
require.NoError(t, err)
require.True(t, new)
require.Equal(t, funnel2, funnel)
require.True(t, funnel1.closed)
// Register funnel error, replace
funnel, new, err = ft.GetOrRegister(id, shouldReplaceTrue, newFunnelFuncErr)
require.ErrorIs(t, err, funnelErr)
require.False(t, new)
require.Nil(t, funnel)
require.True(t, funnel2.closed)
}
func TestFunnelUnregister(t *testing.T) {
id := testFunnelID{"id1"}
funnel1, newFunnelFunc1 := newFunnelAndFunc("funnel1")
funnel2, newFunnelFunc2 := newFunnelAndFunc("funnel2")
funnel3, newFunnelFunc3 := newFunnelAndFunc("funnel3")
ft := NewFunnelTracker()
// Register & unregister
_, _, err := ft.GetOrRegister(id, shouldReplaceFalse, newFunnelFunc1)
require.NoError(t, err)
require.True(t, ft.Unregister(id, funnel1))
require.True(t, funnel1.closed)
require.True(t, ft.Unregister(id, funnel1))
// Register, replace, and unregister
_, _, err = ft.GetOrRegister(id, shouldReplaceFalse, newFunnelFunc2)
require.NoError(t, err)
_, _, err = ft.GetOrRegister(id, shouldReplaceTrue, newFunnelFunc3)
require.NoError(t, err)
require.True(t, funnel2.closed)
require.False(t, ft.Unregister(id, funnel2))
require.True(t, ft.Unregister(id, funnel3))
require.True(t, funnel3.closed)
}
func shouldReplaceFalse(_ Funnel) bool {
return false
}
func shouldReplaceTrue(_ Funnel) bool {
return true
}
func newFunnelAndFunc(id string) (*testFunnel, func() (Funnel, error)) {
funnel := newTestFunnel(id)
funnelFunc := func() (Funnel, error) {
return funnel, nil
}
return funnel, funnelFunc
}
type testFunnelID struct {
id string
}
func (t testFunnelID) Type() string {
return "testFunnelID"
}
func (t testFunnelID) String() string {
return t.id
}
type testFunnel struct {
id string
closed bool
}
func newTestFunnel(id string) *testFunnel {
return &testFunnel{
id,
false,
}
}
func (tf *testFunnel) Close() error {
tf.closed = true
return nil
}
func (tf *testFunnel) Equal(other Funnel) bool {
return tf.id == other.(*testFunnel).id
}
func (tf *testFunnel) LastActive() time.Time {
return time.Now()
}
func (tf *testFunnel) UpdateLastActive() {}
+3 -4
View File
@@ -15,7 +15,7 @@ var (
clientConnLabels = []string{"conn_index"}
clientMetrics = struct {
totalConnections prometheus.Counter
closedConnections *prometheus.CounterVec
closedConnections prometheus.Counter
sentPackets *prometheus.CounterVec
sentBytes *prometheus.CounterVec
receivePackets *prometheus.CounterVec
@@ -30,9 +30,8 @@ var (
totalConnections: prometheus.NewCounter(
totalConnectionsOpts(logging.PerspectiveClient),
),
closedConnections: prometheus.NewCounterVec(
closedConnections: prometheus.NewCounter(
closedConnectionsOpts(logging.PerspectiveClient),
[]string{"error"},
),
sentPackets: prometheus.NewCounterVec(
sentPacketsOpts(logging.PerspectiveClient),
@@ -284,7 +283,7 @@ func (cc *clientCollector) startedConnection() {
}
func (cc *clientCollector) closedConnection(err error) {
clientMetrics.closedConnections.WithLabelValues(err.Error()).Inc()
clientMetrics.closedConnections.Inc()
}
func (cc *clientCollector) sentPackets(size logging.ByteCount) {
+4 -11
View File
@@ -14,7 +14,6 @@ import (
"github.com/cloudflare/cloudflared/connection"
"github.com/cloudflare/cloudflared/edgediscovery"
"github.com/cloudflare/cloudflared/edgediscovery/allregions"
"github.com/cloudflare/cloudflared/h2mux"
"github.com/cloudflare/cloudflared/orchestration"
"github.com/cloudflare/cloudflared/retry"
@@ -45,7 +44,7 @@ type Supervisor struct {
config *TunnelConfig
orchestrator *orchestration.Orchestrator
edgeIPs *edgediscovery.Edge
edgeTunnelServer *EdgeTunnelServer
edgeTunnelServer TunnelServer
tunnelErrors chan tunnelError
tunnelsConnecting map[int]chan struct{}
tunnelsProtocolFallback map[int]*protocolFallback
@@ -94,14 +93,7 @@ func NewSupervisor(config *TunnelConfig, orchestrator *orchestration.Orchestrato
tracker := tunnelstate.NewConnTracker(config.Log)
log := NewConnAwareLogger(config.Log, tracker, config.Observer)
var edgeAddrHandler EdgeAddrHandler
if isStaticEdge { // static edge addresses
edgeAddrHandler = &IPAddrFallback{}
} else if config.EdgeIPVersion == allregions.IPv6Only || config.EdgeIPVersion == allregions.Auto {
edgeAddrHandler = &IPAddrFallback{}
} else { // IPv4Only
edgeAddrHandler = &DefaultAddrFallback{}
}
edgeAddrHandler := NewIPAddrFallback(config.MaxEdgeAddrRetries)
edgeTunnelServer := EdgeTunnelServer{
config: config,
@@ -285,7 +277,8 @@ func (s *Supervisor) initialize(
for i := 1; i < s.config.HAConnections; i++ {
s.tunnelsProtocolFallback[i] = &protocolFallback{
retry.BackoffHandler{MaxRetries: s.config.Retries, RetryForever: true},
s.config.ProtocolSelector.Current(),
// Set the protocol we know the first tunnel connected with.
s.tunnelsProtocolFallback[0].protocol,
false,
}
go s.startTunnel(ctx, i, s.newConnectedTunnelSignal(i))
+74
View File
@@ -0,0 +1,74 @@
package supervisor
import (
"context"
"testing"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"github.com/cloudflare/cloudflared/connection"
"github.com/cloudflare/cloudflared/edgediscovery"
"github.com/cloudflare/cloudflared/edgediscovery/allregions"
"github.com/cloudflare/cloudflared/signal"
)
type mockProtocolSelector struct {
protocols []connection.Protocol
index int
}
func (m *mockProtocolSelector) Current() connection.Protocol {
return m.protocols[m.index]
}
func (m *mockProtocolSelector) Fallback() (connection.Protocol, bool) {
m.index++
if m.index == len(m.protocols) {
return m.protocols[len(m.protocols)-1], false
}
return m.protocols[m.index], true
}
type mockEdgeTunnelServer struct {
config *TunnelConfig
}
func (m *mockEdgeTunnelServer) Serve(ctx context.Context, connIndex uint8, protocolFallback *protocolFallback, connectedSignal *signal.Signal) error {
// This is to mock the first connection falling back because of connectivity issues.
protocolFallback.protocol, _ = m.config.ProtocolSelector.Fallback()
connectedSignal.Notify()
return nil
}
// Test to check if initialize sets all the different connections to the same protocol should the first
// tunnel fall back.
func Test_Initialize_Same_Protocol(t *testing.T) {
edgeIPs, err := edgediscovery.ResolveEdge(&zerolog.Logger{}, "us", allregions.Auto)
assert.Nil(t, err)
s := Supervisor{
edgeIPs: edgeIPs,
config: &TunnelConfig{
ProtocolSelector: &mockProtocolSelector{protocols: []connection.Protocol{connection.QUIC, connection.HTTP2, connection.H2mux}},
},
tunnelsProtocolFallback: make(map[int]*protocolFallback),
edgeTunnelServer: &mockEdgeTunnelServer{
config: &TunnelConfig{
ProtocolSelector: &mockProtocolSelector{protocols: []connection.Protocol{connection.QUIC, connection.HTTP2, connection.H2mux}},
},
},
}
ctx := context.Background()
connectedSignal := signal.New(make(chan struct{}))
s.initialize(ctx, connectedSignal)
// Make sure we fell back to http2 as the mock Serve is wont to do.
assert.Equal(t, s.tunnelsProtocolFallback[0].protocol, connection.HTTP2)
// Ensure all the protocols we set to try are the same as what the first tunnel has fallen back to.
for _, protocolFallback := range s.tunnelsProtocolFallback {
assert.Equal(t, protocolFallback.protocol, s.tunnelsProtocolFallback[0].protocol)
}
}
+89 -68
View File
@@ -37,28 +37,30 @@ const (
FeatureAllowRemoteConfig = "allow_remote_config"
FeatureDatagramV2 = "support_datagram_v2"
FeaturePostQuantum = "postquantum"
FeatureQUICSupportEOF = "support_quic_eof"
)
type TunnelConfig struct {
GracePeriod time.Duration
ReplaceExisting bool
OSArch string
ClientID string
CloseConnOnce *sync.Once // Used to close connectedSignal no more than once
EdgeAddrs []string
Region string
EdgeIPVersion allregions.ConfigIPVersion
HAConnections int
IncidentLookup IncidentLookup
IsAutoupdated bool
LBPool string
Tags []tunnelpogs.Tag
Log *zerolog.Logger
LogTransport *zerolog.Logger
Observer *connection.Observer
ReportedVersion string
Retries uint
RunFromTerminal bool
GracePeriod time.Duration
ReplaceExisting bool
OSArch string
ClientID string
CloseConnOnce *sync.Once // Used to close connectedSignal no more than once
EdgeAddrs []string
Region string
EdgeIPVersion allregions.ConfigIPVersion
HAConnections int
IncidentLookup IncidentLookup
IsAutoupdated bool
LBPool string
Tags []tunnelpogs.Tag
Log *zerolog.Logger
LogTransport *zerolog.Logger
Observer *connection.Observer
ReportedVersion string
Retries uint
MaxEdgeAddrRetries uint8
RunFromTerminal bool
NeedPQ bool
@@ -132,6 +134,24 @@ func StartTunnelDaemon(
return s.Run(ctx, connectedSignal)
}
type ConnectivityError struct {
reachedMaxRetries bool
}
func NewConnectivityError(hasReachedMaxRetries bool) *ConnectivityError {
return &ConnectivityError{
reachedMaxRetries: hasReachedMaxRetries,
}
}
func (e *ConnectivityError) Error() string {
return fmt.Sprintf("connectivity error - reached max retries: %t", e.HasReachedMaxRetries())
}
func (e *ConnectivityError) HasReachedMaxRetries() bool {
return e.reachedMaxRetries
}
// EdgeAddrHandler provides a mechanism switch between behaviors in ServeTunnel
// for handling the errors when attempting to make edge connections.
type EdgeAddrHandler interface {
@@ -139,56 +159,47 @@ type EdgeAddrHandler interface {
// the edge address should be replaced with a new one. Also, will return if the
// error should be recognized as a connectivity error, or otherwise, a general
// application error.
ShouldGetNewAddress(err error) (needsNewAddress bool, isConnectivityError bool)
ShouldGetNewAddress(connIndex uint8, err error) (needsNewAddress bool, connectivityError error)
}
// DefaultAddrFallback will always return false for isConnectivityError since this
// handler is a way to provide the legacy behavior in the new edge discovery algorithm.
type DefaultAddrFallback struct {
edgeErrors int
}
func (f DefaultAddrFallback) ShouldGetNewAddress(err error) (needsNewAddress bool, isConnectivityError bool) {
switch err.(type) {
case nil: // maintain current IP address
// DupConnRegisterTunnelError should indicate to get a new address immediately
case connection.DupConnRegisterTunnelError:
return true, false
// Try the next address if it was a quic.IdleTimeoutError
case *quic.IdleTimeoutError,
edgediscovery.DialError,
*connection.EdgeQuicDialError:
// Wait for two failures before falling back to a new address
f.edgeErrors++
if f.edgeErrors >= 2 {
f.edgeErrors = 0
return true, false
}
default: // maintain current IP address
func NewIPAddrFallback(maxRetries uint8) *ipAddrFallback {
return &ipAddrFallback{
retriesByConnIndex: make(map[uint8]uint8),
maxRetries: maxRetries,
}
return false, false
}
// IPAddrFallback will have more conditions to fall back to a new address for certain
// ipAddrFallback will have more conditions to fall back to a new address for certain
// edge connection errors. This means that this handler will return true for isConnectivityError
// for more cases like duplicate connection register and edge quic dial errors.
type IPAddrFallback struct{}
type ipAddrFallback struct {
m sync.Mutex
retriesByConnIndex map[uint8]uint8
maxRetries uint8
}
func (f IPAddrFallback) ShouldGetNewAddress(err error) (needsNewAddress bool, isConnectivityError bool) {
func (f *ipAddrFallback) ShouldGetNewAddress(connIndex uint8, err error) (needsNewAddress bool, connectivityError error) {
f.m.Lock()
defer f.m.Unlock()
switch err.(type) {
case nil: // maintain current IP address
// Try the next address if it was a quic.IdleTimeoutError
// DupConnRegisterTunnelError needs to also receive a new ip address
case connection.DupConnRegisterTunnelError,
*quic.IdleTimeoutError:
return true, false
return true, nil
// Network problems should be retried with new address immediately and report
// as connectivity error
case edgediscovery.DialError, *connection.EdgeQuicDialError:
return true, true
if f.retriesByConnIndex[connIndex] >= f.maxRetries {
f.retriesByConnIndex[connIndex] = 0
return true, NewConnectivityError(true)
}
f.retriesByConnIndex[connIndex]++
return true, NewConnectivityError(false)
default: // maintain current IP address
}
return false, false
return false, nil
}
type EdgeTunnelServer struct {
@@ -205,6 +216,10 @@ type EdgeTunnelServer struct {
connAwareLogger *ConnAwareLogger
}
type TunnelServer interface {
Serve(ctx context.Context, connIndex uint8, protocolFallback *protocolFallback, connectedSignal *signal.Signal) error
}
func (e *EdgeTunnelServer) Serve(ctx context.Context, connIndex uint8, protocolFallback *protocolFallback, connectedSignal *signal.Signal) error {
haConnections.Inc()
defer haConnections.Dec()
@@ -233,11 +248,12 @@ func (e *EdgeTunnelServer) Serve(ctx context.Context, connIndex uint8, protocolF
Uint8(connection.LogFieldConnIndex, connIndex).
Logger()
connLog := e.connAwareLogger.ReplaceLogger(&logger)
// Each connection to keep its own copy of protocol, because individual connections might fallback
// to another protocol when a particular metal doesn't support new protocol
// Each connection can also have it's own IP version because individual connections might fallback
// to another IP version.
err, recoverable := e.serveTunnel(
err, shouldFallbackProtocol := e.serveTunnel(
ctx,
connLog,
addr,
@@ -247,34 +263,39 @@ func (e *EdgeTunnelServer) Serve(ctx context.Context, connIndex uint8, protocolF
protocolFallback.protocol,
)
// If the connection is recoverable, we want to maintain the same IP
// but backoff a reconnect with some duration.
if recoverable {
duration, ok := protocolFallback.GetMaxBackoffDuration(ctx)
if !ok {
return err
}
e.config.Observer.SendReconnect(connIndex)
connLog.Logger().Info().Msgf("Retrying connection in up to %s", duration)
}
// Check if the connection error was from an IP issue with the host or
// establishing a connection to the edge and if so, rotate the IP address.
yes, hasConnectivityError := e.edgeAddrHandler.ShouldGetNewAddress(err)
if yes {
if _, err := e.edgeAddrs.GetDifferentAddr(int(connIndex), hasConnectivityError); err != nil {
shouldRotateEdgeIP, cErr := e.edgeAddrHandler.ShouldGetNewAddress(connIndex, err)
if shouldRotateEdgeIP {
// rotate IP, but forcing internal state to assign a new IP to connection index.
if _, err := e.edgeAddrs.GetDifferentAddr(int(connIndex), true); err != nil {
return err
}
// In addition, if it is a connectivity error, and we have exhausted the configurable maximum edge IPs to rotate,
// then just fallback protocol on next iteration run.
connectivityErr, ok := cErr.(*ConnectivityError)
if ok {
shouldFallbackProtocol = connectivityErr.HasReachedMaxRetries()
}
}
// set connection has re-connecting and log the next retrying backoff
duration, ok := protocolFallback.GetMaxBackoffDuration(ctx)
if !ok {
return err
}
e.config.Observer.SendReconnect(connIndex)
connLog.Logger().Info().Msgf("Retrying connection in up to %s", duration)
select {
case <-ctx.Done():
return ctx.Err()
case <-e.gracefulShutdownC:
return nil
case <-protocolFallback.BackoffTimer():
if !recoverable {
// should we fallback protocol? If not, just return. Otherwise, set new protocol for next method call.
if !shouldFallbackProtocol {
return err
}
@@ -421,7 +442,7 @@ func (e *EdgeTunnelServer) serveTunnel(
}
return err.Cause, !err.Permanent
case *connection.EdgeQuicDialError:
return err, true
return err, false
case ReconnectSignal:
connLog.Logger().Info().
IPAddr(connection.LogFieldIPAddress, addr.UDP.IP).
+18 -18
View File
@@ -3,26 +3,26 @@
// tldr is it uses Elliptic Curves (Curve25519) for the keys, XSalsa20 and Poly1305 for encryption.
// You can read more here https://godoc.org/golang.org/x/crypto/nacl/box.
//
// msg := []byte("super safe message.")
// alice, err := NewEncrypter("alice_priv_key.pem", "alice_pub_key.pem")
// if err != nil {
// log.Fatal(err)
// }
// msg := []byte("super safe message.")
// alice, err := NewEncrypter("alice_priv_key.pem", "alice_pub_key.pem")
// if err != nil {
// log.Fatal(err)
// }
//
// bob, err := NewEncrypter("bob_priv_key.pem", "bob_pub_key.pem")
// if err != nil {
// log.Fatal(err)
// }
// encrypted, err := alice.Encrypt(msg, bob.PublicKey())
// if err != nil {
// log.Fatal(err)
// }
// bob, err := NewEncrypter("bob_priv_key.pem", "bob_pub_key.pem")
// if err != nil {
// log.Fatal(err)
// }
// encrypted, err := alice.Encrypt(msg, bob.PublicKey())
// if err != nil {
// log.Fatal(err)
// }
//
// data, err := bob.Decrypt(encrypted, alice.PublicKey())
// if err != nil {
// log.Fatal(err)
// }
// fmt.Println(string(data))
// data, err := bob.Decrypt(encrypted, alice.PublicKey())
// if err != nil {
// log.Fatal(err)
// }
// fmt.Println(string(data))
package token
import (
+11 -14
View File
@@ -24,11 +24,9 @@ type InMemoryClient interface {
// Spans returns a copy of the list of in-memory stored spans as a base64
// encoded otlp protobuf string.
Spans() (string, error)
// ProtoSpans returns a copy of the list of in-memory stored spans as otlp
// protobuf byte array.
ProtoSpans() ([]byte, error)
// Clear spans removes all in-memory spans
ClearSpans()
// ExportProtoSpans returns a copy of the list of in-memory stored spans as otlp
// protobuf byte array and clears the in-memory spans.
ExportProtoSpans() ([]byte, error)
}
// InMemoryOtlpClient is a client implementation for otlptrace.Client
@@ -60,7 +58,7 @@ func (mc *InMemoryOtlpClient) UploadTraces(_ context.Context, protoSpans []*trac
// Spans returns the list of in-memory stored spans as a base64 encoded otlp protobuf string.
func (mc *InMemoryOtlpClient) Spans() (string, error) {
data, err := mc.ProtoSpans()
data, err := mc.ExportProtoSpans()
if err != nil {
return "", err
}
@@ -68,7 +66,7 @@ func (mc *InMemoryOtlpClient) Spans() (string, error) {
}
// ProtoSpans returns the list of in-memory stored spans as the protobuf byte array.
func (mc *InMemoryOtlpClient) ProtoSpans() ([]byte, error) {
func (mc *InMemoryOtlpClient) ExportProtoSpans() ([]byte, error) {
mc.mu.Lock()
defer mc.mu.Unlock()
if len(mc.spans) <= 0 {
@@ -77,13 +75,12 @@ func (mc *InMemoryOtlpClient) ProtoSpans() ([]byte, error) {
pbRequest := &coltracepb.ExportTraceServiceRequest{
ResourceSpans: mc.spans,
}
return proto.Marshal(pbRequest)
}
func (mc *InMemoryOtlpClient) ClearSpans() {
mc.mu.Lock()
defer mc.mu.Unlock()
serializedSpans, err := proto.Marshal(pbRequest)
if err != nil {
return nil, err
}
mc.spans = make([]*tracepb.ResourceSpans, 0)
return serializedSpans, nil
}
// NoopOtlpClient is a client implementation for otlptrace.Client that does nothing
@@ -107,7 +104,7 @@ func (mc *NoopOtlpClient) Spans() (string, error) {
}
// Spans always returns no traces error
func (mc *NoopOtlpClient) ProtoSpans() ([]byte, error) {
func (mc *NoopOtlpClient) ExportProtoSpans() ([]byte, error) {
return nil, errNoopTracer
}
+1 -5
View File
@@ -157,7 +157,7 @@ func (cft *cfdTracer) GetSpans() (enc string) {
// GetProtoSpans returns the spans as the otlp traces in protobuf byte array.
func (cft *cfdTracer) GetProtoSpans() (proto []byte) {
proto, err := cft.exporter.ProtoSpans()
proto, err := cft.exporter.ExportProtoSpans()
switch err {
case nil:
break
@@ -189,10 +189,6 @@ func (cft *cfdTracer) AddSpans(headers http.Header) {
headers[CanonicalCloudflaredTracingHeader] = []string{enc}
}
func (cft *cfdTracer) ClearSpans() {
cft.exporter.ClearSpans()
}
// End will set the OK status for the span and then end it.
func End(span trace.Span) {
endSpan(span, -1, codes.Ok, nil)
-1
View File
@@ -40,7 +40,6 @@ func (ar AuthenticateResponse) Outcome() AuthOutcome {
}
// AuthOutcome is a programmer-friendly sum type denoting the possible outcomes of Authenticate.
//go-sumtype:decl AuthOutcome
type AuthOutcome interface {
isAuthOutcome()
// Serialize into an AuthenticateResponse which can be sent via Capnp
+6 -2
View File
@@ -61,9 +61,13 @@ func ValidateHostname(hostname string) (string, error) {
// ValidateUrl returns a validated version of `originUrl` with a scheme prepended (by default http://).
// Note: when originUrl contains a scheme, the path is removed:
// ValidateUrl("https://localhost:8080/api/") => "https://localhost:8080"
//
// ValidateUrl("https://localhost:8080/api/") => "https://localhost:8080"
//
// but when it does not, the path is preserved:
// ValidateUrl("localhost:8080/api/") => "http://localhost:8080/api/"
//
// ValidateUrl("localhost:8080/api/") => "http://localhost:8080/api/"
//
// This is arguably a bug, but changing it might break some cloudflared users.
func ValidateUrl(originUrl string) (*url.URL, error) {
urlStr, err := validateUrlString(originUrl)
+2 -2
View File
@@ -12,7 +12,7 @@ import (
"errors"
"math/bits"
"golang.org/x/crypto/internal/subtle"
"golang.org/x/crypto/internal/alias"
)
const (
@@ -189,7 +189,7 @@ func (s *Cipher) XORKeyStream(dst, src []byte) {
panic("chacha20: output smaller than input")
}
dst = dst[:len(src)]
if subtle.InexactOverlap(dst, src) {
if alias.InexactOverlap(dst, src) {
panic("chacha20: invalid buffer overlap")
}
+3 -3
View File
@@ -10,7 +10,7 @@ package chacha20poly1305
import (
"encoding/binary"
"golang.org/x/crypto/internal/subtle"
"golang.org/x/crypto/internal/alias"
"golang.org/x/sys/cpu"
)
@@ -56,7 +56,7 @@ func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []
setupState(&state, &c.key, nonce)
ret, out := sliceForAppend(dst, len(plaintext)+16)
if subtle.InexactOverlap(out, plaintext) {
if alias.InexactOverlap(out, plaintext) {
panic("chacha20poly1305: invalid buffer overlap")
}
chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
@@ -73,7 +73,7 @@ func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) (
ciphertext = ciphertext[:len(ciphertext)-16]
ret, out := sliceForAppend(dst, len(ciphertext))
if subtle.InexactOverlap(out, ciphertext) {
if alias.InexactOverlap(out, ciphertext) {
panic("chacha20poly1305: invalid buffer overlap")
}
if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
+3 -3
View File
@@ -8,8 +8,8 @@ import (
"encoding/binary"
"golang.org/x/crypto/chacha20"
"golang.org/x/crypto/internal/alias"
"golang.org/x/crypto/internal/poly1305"
"golang.org/x/crypto/internal/subtle"
)
func writeWithPadding(p *poly1305.MAC, b []byte) {
@@ -30,7 +30,7 @@ func writeUint64(p *poly1305.MAC, n int) {
func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte {
ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
ciphertext, tag := out[:len(plaintext)], out[len(plaintext):]
if subtle.InexactOverlap(out, plaintext) {
if alias.InexactOverlap(out, plaintext) {
panic("chacha20poly1305: invalid buffer overlap")
}
@@ -66,7 +66,7 @@ func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []
writeUint64(p, len(ciphertext))
ret, out := sliceForAppend(dst, len(ciphertext))
if subtle.InexactOverlap(out, ciphertext) {
if alias.InexactOverlap(out, ciphertext) {
panic("chacha20poly1305: invalid buffer overlap")
}
if !p.Verify(tag) {
+5
View File
@@ -95,6 +95,11 @@ func (b *Builder) AddUint32(v uint32) {
b.add(byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}
// AddUint64 appends a big-endian, 64-bit value to the byte string.
func (b *Builder) AddUint64(v uint64) {
b.add(byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}
// AddBytes appends a sequence of bytes to the byte string.
func (b *Builder) AddBytes(v []byte) {
b.add(v...)
+11
View File
@@ -81,6 +81,17 @@ func (s *String) ReadUint32(out *uint32) bool {
return true
}
// ReadUint64 decodes a big-endian, 64-bit value into out and advances over it.
// It reports whether the read was successful.
func (s *String) ReadUint64(out *uint64) bool {
v := s.read(8)
if v == nil {
return false
}
*out = uint64(v[0])<<56 | uint64(v[1])<<48 | uint64(v[2])<<40 | uint64(v[3])<<32 | uint64(v[4])<<24 | uint64(v[5])<<16 | uint64(v[6])<<8 | uint64(v[7])
return true
}
func (s *String) readUnsigned(out *uint32, length int) bool {
v := s.read(length)
if v == nil {
@@ -5,9 +5,8 @@
//go:build !purego
// +build !purego
// Package subtle implements functions that are often useful in cryptographic
// code but require careful thought to use correctly.
package subtle // import "golang.org/x/crypto/internal/subtle"
// Package alias implements memory aliasing tests.
package alias
import "unsafe"
@@ -5,9 +5,8 @@
//go:build purego
// +build purego
// Package subtle implements functions that are often useful in cryptographic
// code but require careful thought to use correctly.
package subtle // import "golang.org/x/crypto/internal/subtle"
// Package alias implements memory aliasing tests.
package alias
// This is the Google App Engine standard variant based on reflect
// because the unsafe package and cgo are disallowed.
+3 -3
View File
@@ -35,8 +35,8 @@ This package is interoperable with NaCl: https://nacl.cr.yp.to/secretbox.html.
package secretbox // import "golang.org/x/crypto/nacl/secretbox"
import (
"golang.org/x/crypto/internal/alias"
"golang.org/x/crypto/internal/poly1305"
"golang.org/x/crypto/internal/subtle"
"golang.org/x/crypto/salsa20/salsa"
)
@@ -88,7 +88,7 @@ func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte {
copy(poly1305Key[:], firstBlock[:])
ret, out := sliceForAppend(out, len(message)+poly1305.TagSize)
if subtle.AnyOverlap(out, message) {
if alias.AnyOverlap(out, message) {
panic("nacl: invalid buffer overlap")
}
@@ -147,7 +147,7 @@ func Open(out, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) {
}
ret, out := sliceForAppend(out, len(box)-Overhead)
if subtle.AnyOverlap(out, box) {
if alias.AnyOverlap(out, box) {
panic("nacl: invalid buffer overlap")
}
+34 -32
View File
@@ -5,6 +5,8 @@
// Package salsa provides low-level access to functions in the Salsa family.
package salsa // import "golang.org/x/crypto/salsa20/salsa"
import "math/bits"
// Sigma is the Salsa20 constant for 256-bit keys.
var Sigma = [16]byte{'e', 'x', 'p', 'a', 'n', 'd', ' ', '3', '2', '-', 'b', 'y', 't', 'e', ' ', 'k'}
@@ -31,76 +33,76 @@ func HSalsa20(out *[32]byte, in *[16]byte, k *[32]byte, c *[16]byte) {
for i := 0; i < 20; i += 2 {
u := x0 + x12
x4 ^= u<<7 | u>>(32-7)
x4 ^= bits.RotateLeft32(u, 7)
u = x4 + x0
x8 ^= u<<9 | u>>(32-9)
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x4
x12 ^= u<<13 | u>>(32-13)
x12 ^= bits.RotateLeft32(u, 13)
u = x12 + x8
x0 ^= u<<18 | u>>(32-18)
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x1
x9 ^= u<<7 | u>>(32-7)
x9 ^= bits.RotateLeft32(u, 7)
u = x9 + x5
x13 ^= u<<9 | u>>(32-9)
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x9
x1 ^= u<<13 | u>>(32-13)
x1 ^= bits.RotateLeft32(u, 13)
u = x1 + x13
x5 ^= u<<18 | u>>(32-18)
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x6
x14 ^= u<<7 | u>>(32-7)
x14 ^= bits.RotateLeft32(u, 7)
u = x14 + x10
x2 ^= u<<9 | u>>(32-9)
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x14
x6 ^= u<<13 | u>>(32-13)
x6 ^= bits.RotateLeft32(u, 13)
u = x6 + x2
x10 ^= u<<18 | u>>(32-18)
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x11
x3 ^= u<<7 | u>>(32-7)
x3 ^= bits.RotateLeft32(u, 7)
u = x3 + x15
x7 ^= u<<9 | u>>(32-9)
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x3
x11 ^= u<<13 | u>>(32-13)
x11 ^= bits.RotateLeft32(u, 13)
u = x11 + x7
x15 ^= u<<18 | u>>(32-18)
x15 ^= bits.RotateLeft32(u, 18)
u = x0 + x3
x1 ^= u<<7 | u>>(32-7)
x1 ^= bits.RotateLeft32(u, 7)
u = x1 + x0
x2 ^= u<<9 | u>>(32-9)
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x1
x3 ^= u<<13 | u>>(32-13)
x3 ^= bits.RotateLeft32(u, 13)
u = x3 + x2
x0 ^= u<<18 | u>>(32-18)
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x4
x6 ^= u<<7 | u>>(32-7)
x6 ^= bits.RotateLeft32(u, 7)
u = x6 + x5
x7 ^= u<<9 | u>>(32-9)
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x6
x4 ^= u<<13 | u>>(32-13)
x4 ^= bits.RotateLeft32(u, 13)
u = x4 + x7
x5 ^= u<<18 | u>>(32-18)
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x9
x11 ^= u<<7 | u>>(32-7)
x11 ^= bits.RotateLeft32(u, 7)
u = x11 + x10
x8 ^= u<<9 | u>>(32-9)
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x11
x9 ^= u<<13 | u>>(32-13)
x9 ^= bits.RotateLeft32(u, 13)
u = x9 + x8
x10 ^= u<<18 | u>>(32-18)
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x14
x12 ^= u<<7 | u>>(32-7)
x12 ^= bits.RotateLeft32(u, 7)
u = x12 + x15
x13 ^= u<<9 | u>>(32-9)
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x12
x14 ^= u<<13 | u>>(32-13)
x14 ^= bits.RotateLeft32(u, 13)
u = x14 + x13
x15 ^= u<<18 | u>>(32-18)
x15 ^= bits.RotateLeft32(u, 18)
}
out[0] = byte(x0)
out[1] = byte(x0 >> 8)
+34 -32
View File
@@ -4,6 +4,8 @@
package salsa
import "math/bits"
// Core208 applies the Salsa20/8 core function to the 64-byte array in and puts
// the result into the 64-byte array out. The input and output may be the same array.
func Core208(out *[64]byte, in *[64]byte) {
@@ -29,76 +31,76 @@ func Core208(out *[64]byte, in *[64]byte) {
for i := 0; i < 8; i += 2 {
u := x0 + x12
x4 ^= u<<7 | u>>(32-7)
x4 ^= bits.RotateLeft32(u, 7)
u = x4 + x0
x8 ^= u<<9 | u>>(32-9)
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x4
x12 ^= u<<13 | u>>(32-13)
x12 ^= bits.RotateLeft32(u, 13)
u = x12 + x8
x0 ^= u<<18 | u>>(32-18)
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x1
x9 ^= u<<7 | u>>(32-7)
x9 ^= bits.RotateLeft32(u, 7)
u = x9 + x5
x13 ^= u<<9 | u>>(32-9)
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x9
x1 ^= u<<13 | u>>(32-13)
x1 ^= bits.RotateLeft32(u, 13)
u = x1 + x13
x5 ^= u<<18 | u>>(32-18)
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x6
x14 ^= u<<7 | u>>(32-7)
x14 ^= bits.RotateLeft32(u, 7)
u = x14 + x10
x2 ^= u<<9 | u>>(32-9)
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x14
x6 ^= u<<13 | u>>(32-13)
x6 ^= bits.RotateLeft32(u, 13)
u = x6 + x2
x10 ^= u<<18 | u>>(32-18)
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x11
x3 ^= u<<7 | u>>(32-7)
x3 ^= bits.RotateLeft32(u, 7)
u = x3 + x15
x7 ^= u<<9 | u>>(32-9)
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x3
x11 ^= u<<13 | u>>(32-13)
x11 ^= bits.RotateLeft32(u, 13)
u = x11 + x7
x15 ^= u<<18 | u>>(32-18)
x15 ^= bits.RotateLeft32(u, 18)
u = x0 + x3
x1 ^= u<<7 | u>>(32-7)
x1 ^= bits.RotateLeft32(u, 7)
u = x1 + x0
x2 ^= u<<9 | u>>(32-9)
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x1
x3 ^= u<<13 | u>>(32-13)
x3 ^= bits.RotateLeft32(u, 13)
u = x3 + x2
x0 ^= u<<18 | u>>(32-18)
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x4
x6 ^= u<<7 | u>>(32-7)
x6 ^= bits.RotateLeft32(u, 7)
u = x6 + x5
x7 ^= u<<9 | u>>(32-9)
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x6
x4 ^= u<<13 | u>>(32-13)
x4 ^= bits.RotateLeft32(u, 13)
u = x4 + x7
x5 ^= u<<18 | u>>(32-18)
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x9
x11 ^= u<<7 | u>>(32-7)
x11 ^= bits.RotateLeft32(u, 7)
u = x11 + x10
x8 ^= u<<9 | u>>(32-9)
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x11
x9 ^= u<<13 | u>>(32-13)
x9 ^= bits.RotateLeft32(u, 13)
u = x9 + x8
x10 ^= u<<18 | u>>(32-18)
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x14
x12 ^= u<<7 | u>>(32-7)
x12 ^= bits.RotateLeft32(u, 7)
u = x12 + x15
x13 ^= u<<9 | u>>(32-9)
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x12
x14 ^= u<<13 | u>>(32-13)
x14 ^= bits.RotateLeft32(u, 13)
u = x14 + x13
x15 ^= u<<18 | u>>(32-18)
x15 ^= bits.RotateLeft32(u, 18)
}
x0 += j0
x1 += j1
+34 -32
View File
@@ -4,6 +4,8 @@
package salsa
import "math/bits"
const rounds = 20
// core applies the Salsa20 core function to 16-byte input in, 32-byte key k,
@@ -31,76 +33,76 @@ func core(out *[64]byte, in *[16]byte, k *[32]byte, c *[16]byte) {
for i := 0; i < rounds; i += 2 {
u := x0 + x12
x4 ^= u<<7 | u>>(32-7)
x4 ^= bits.RotateLeft32(u, 7)
u = x4 + x0
x8 ^= u<<9 | u>>(32-9)
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x4
x12 ^= u<<13 | u>>(32-13)
x12 ^= bits.RotateLeft32(u, 13)
u = x12 + x8
x0 ^= u<<18 | u>>(32-18)
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x1
x9 ^= u<<7 | u>>(32-7)
x9 ^= bits.RotateLeft32(u, 7)
u = x9 + x5
x13 ^= u<<9 | u>>(32-9)
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x9
x1 ^= u<<13 | u>>(32-13)
x1 ^= bits.RotateLeft32(u, 13)
u = x1 + x13
x5 ^= u<<18 | u>>(32-18)
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x6
x14 ^= u<<7 | u>>(32-7)
x14 ^= bits.RotateLeft32(u, 7)
u = x14 + x10
x2 ^= u<<9 | u>>(32-9)
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x14
x6 ^= u<<13 | u>>(32-13)
x6 ^= bits.RotateLeft32(u, 13)
u = x6 + x2
x10 ^= u<<18 | u>>(32-18)
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x11
x3 ^= u<<7 | u>>(32-7)
x3 ^= bits.RotateLeft32(u, 7)
u = x3 + x15
x7 ^= u<<9 | u>>(32-9)
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x3
x11 ^= u<<13 | u>>(32-13)
x11 ^= bits.RotateLeft32(u, 13)
u = x11 + x7
x15 ^= u<<18 | u>>(32-18)
x15 ^= bits.RotateLeft32(u, 18)
u = x0 + x3
x1 ^= u<<7 | u>>(32-7)
x1 ^= bits.RotateLeft32(u, 7)
u = x1 + x0
x2 ^= u<<9 | u>>(32-9)
x2 ^= bits.RotateLeft32(u, 9)
u = x2 + x1
x3 ^= u<<13 | u>>(32-13)
x3 ^= bits.RotateLeft32(u, 13)
u = x3 + x2
x0 ^= u<<18 | u>>(32-18)
x0 ^= bits.RotateLeft32(u, 18)
u = x5 + x4
x6 ^= u<<7 | u>>(32-7)
x6 ^= bits.RotateLeft32(u, 7)
u = x6 + x5
x7 ^= u<<9 | u>>(32-9)
x7 ^= bits.RotateLeft32(u, 9)
u = x7 + x6
x4 ^= u<<13 | u>>(32-13)
x4 ^= bits.RotateLeft32(u, 13)
u = x4 + x7
x5 ^= u<<18 | u>>(32-18)
x5 ^= bits.RotateLeft32(u, 18)
u = x10 + x9
x11 ^= u<<7 | u>>(32-7)
x11 ^= bits.RotateLeft32(u, 7)
u = x11 + x10
x8 ^= u<<9 | u>>(32-9)
x8 ^= bits.RotateLeft32(u, 9)
u = x8 + x11
x9 ^= u<<13 | u>>(32-13)
x9 ^= bits.RotateLeft32(u, 13)
u = x9 + x8
x10 ^= u<<18 | u>>(32-18)
x10 ^= bits.RotateLeft32(u, 18)
u = x15 + x14
x12 ^= u<<7 | u>>(32-7)
x12 ^= bits.RotateLeft32(u, 7)
u = x12 + x15
x13 ^= u<<9 | u>>(32-9)
x13 ^= bits.RotateLeft32(u, 9)
u = x13 + x12
x14 ^= u<<13 | u>>(32-13)
x14 ^= bits.RotateLeft32(u, 13)
u = x14 + x13
x15 ^= u<<18 | u>>(32-18)
x15 ^= bits.RotateLeft32(u, 18)
}
x0 += j0
x1 += j1
+1 -1
View File
@@ -251,7 +251,7 @@ type algorithmOpenSSHCertSigner struct {
// private key is held by signer. It returns an error if the public key in cert
// doesn't match the key used by signer.
func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) {
if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 {
if !bytes.Equal(cert.Key.Marshal(), signer.PublicKey().Marshal()) {
return nil, errors.New("ssh: signer and cert have different public key")
}
+5 -6
View File
@@ -15,7 +15,6 @@ import (
"fmt"
"hash"
"io"
"io/ioutil"
"golang.org/x/crypto/chacha20"
"golang.org/x/crypto/internal/poly1305"
@@ -97,13 +96,13 @@ func streamCipherMode(skip int, createFunc func(key, iv []byte) (cipher.Stream,
// are not supported and will not be negotiated, even if explicitly requested in
// ClientConfig.Crypto.Ciphers.
var cipherModes = map[string]*cipherMode{
// Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms
// Ciphers from RFC 4344, which introduced many CTR-based ciphers. Algorithms
// are defined in the order specified in the RFC.
"aes128-ctr": {16, aes.BlockSize, streamCipherMode(0, newAESCTR)},
"aes192-ctr": {24, aes.BlockSize, streamCipherMode(0, newAESCTR)},
"aes256-ctr": {32, aes.BlockSize, streamCipherMode(0, newAESCTR)},
// Ciphers from RFC4345, which introduces security-improved arcfour ciphers.
// Ciphers from RFC 4345, which introduces security-improved arcfour ciphers.
// They are defined in the order specified in the RFC.
"arcfour128": {16, 0, streamCipherMode(1536, newRC4)},
"arcfour256": {32, 0, streamCipherMode(1536, newRC4)},
@@ -111,7 +110,7 @@ var cipherModes = map[string]*cipherMode{
// Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol.
// Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and
// RC4) has problems with weak keys, and should be used with caution."
// RFC4345 introduces improved versions of Arcfour.
// RFC 4345 introduces improved versions of Arcfour.
"arcfour": {16, 0, streamCipherMode(0, newRC4)},
// AEAD ciphers
@@ -497,7 +496,7 @@ func (c *cbcCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error)
// data, to make distinguishing between
// failing MAC and failing length check more
// difficult.
io.CopyN(ioutil.Discard, r, int64(c.oracleCamouflage))
io.CopyN(io.Discard, r, int64(c.oracleCamouflage))
}
}
return p, err
@@ -642,7 +641,7 @@ const chacha20Poly1305ID = "chacha20-poly1305@openssh.com"
//
// https://tools.ietf.org/html/draft-josefsson-ssh-chacha20-poly1305-openssh-00
//
// the methods here also implement padding, which RFC4253 Section 6
// the methods here also implement padding, which RFC 4253 Section 6
// also requires of stream ciphers.
type chacha20Poly1305Cipher struct {
lengthKey [32]byte
+2 -2
View File
@@ -149,7 +149,7 @@ type directionAlgorithms struct {
// rekeyBytes returns a rekeying intervals in bytes.
func (a *directionAlgorithms) rekeyBytes() int64 {
// According to RFC4344 block ciphers should rekey after
// According to RFC 4344 block ciphers should rekey after
// 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is
// 128.
switch a.Cipher {
@@ -158,7 +158,7 @@ func (a *directionAlgorithms) rekeyBytes() int64 {
}
// For others, stick with RFC4253 recommendation to rekey after 1 Gb of data.
// For others, stick with RFC 4253 recommendation to rekey after 1 Gb of data.
return 1 << 30
}
+1 -1
View File
@@ -52,7 +52,7 @@ type Conn interface {
// SendRequest sends a global request, and returns the
// reply. If wantReply is true, it returns the response status
// and payload. See also RFC4254, section 4.
// and payload. See also RFC 4254, section 4.
SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error)
// OpenChannel tries to open an channel. If the request is
+1 -1
View File
@@ -184,7 +184,7 @@ func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey
return "", nil, nil, "", nil, io.EOF
}
// ParseAuthorizedKeys parses a public key from an authorized_keys
// ParseAuthorizedKey parses a public key from an authorized_keys
// file used in OpenSSH according to the sshd(8) manual page.
func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error) {
for len(in) > 0 {
+1 -1
View File
@@ -68,7 +68,7 @@ type kexInitMsg struct {
// See RFC 4253, section 8.
// Diffie-Helman
// Diffie-Hellman
const msgKexDHInit = 30
type kexDHInitMsg struct {
+13 -1
View File
@@ -68,8 +68,16 @@ type ServerConfig struct {
// NoClientAuth is true if clients are allowed to connect without
// authenticating.
// To determine NoClientAuth at runtime, set NoClientAuth to true
// and the optional NoClientAuthCallback to a non-nil value.
NoClientAuth bool
// NoClientAuthCallback, if non-nil, is called when a user
// attempts to authenticate with auth method "none".
// NoClientAuth must also be set to true for this be used, or
// this func is unused.
NoClientAuthCallback func(ConnMetadata) (*Permissions, error)
// MaxAuthTries specifies the maximum number of authentication attempts
// permitted per connection. If set to a negative number, the number of
// attempts are unlimited. If set to zero, the number of attempts are limited
@@ -455,7 +463,11 @@ userAuthLoop:
switch userAuthReq.Method {
case "none":
if config.NoClientAuth {
authErr = nil
if config.NoClientAuthCallback != nil {
perms, authErr = config.NoClientAuthCallback(s)
} else {
authErr = nil
}
}
// allow initial attempt of 'none' without penalty
+3 -4
View File
@@ -13,7 +13,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"sync"
)
@@ -124,7 +123,7 @@ type Session struct {
// output and error.
//
// If either is nil, Run connects the corresponding file
// descriptor to an instance of ioutil.Discard. There is a
// descriptor to an instance of io.Discard. There is a
// fixed amount of buffering that is shared for the two streams.
// If either blocks it may eventually cause the remote
// command to block.
@@ -506,7 +505,7 @@ func (s *Session) stdout() {
return
}
if s.Stdout == nil {
s.Stdout = ioutil.Discard
s.Stdout = io.Discard
}
s.copyFuncs = append(s.copyFuncs, func() error {
_, err := io.Copy(s.Stdout, s.ch)
@@ -519,7 +518,7 @@ func (s *Session) stderr() {
return
}
if s.Stderr == nil {
s.Stderr = ioutil.Discard
s.Stderr = io.Discard
}
s.copyFuncs = append(s.copyFuncs, func() error {
_, err := io.Copy(s.Stderr, s.ch.Stderr())
+78
View File
@@ -0,0 +1,78 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package lazyregexp is a thin wrapper over regexp, allowing the use of global
// regexp variables without forcing them to be compiled at init.
package lazyregexp
import (
"os"
"regexp"
"strings"
"sync"
)
// Regexp is a wrapper around regexp.Regexp, where the underlying regexp will be
// compiled the first time it is needed.
type Regexp struct {
str string
once sync.Once
rx *regexp.Regexp
}
func (r *Regexp) re() *regexp.Regexp {
r.once.Do(r.build)
return r.rx
}
func (r *Regexp) build() {
r.rx = regexp.MustCompile(r.str)
r.str = ""
}
func (r *Regexp) FindSubmatch(s []byte) [][]byte {
return r.re().FindSubmatch(s)
}
func (r *Regexp) FindStringSubmatch(s string) []string {
return r.re().FindStringSubmatch(s)
}
func (r *Regexp) FindStringSubmatchIndex(s string) []int {
return r.re().FindStringSubmatchIndex(s)
}
func (r *Regexp) ReplaceAllString(src, repl string) string {
return r.re().ReplaceAllString(src, repl)
}
func (r *Regexp) FindString(s string) string {
return r.re().FindString(s)
}
func (r *Regexp) FindAllString(s string, n int) []string {
return r.re().FindAllString(s, n)
}
func (r *Regexp) MatchString(s string) bool {
return r.re().MatchString(s)
}
func (r *Regexp) SubexpNames() []string {
return r.re().SubexpNames()
}
var inTest = len(os.Args) > 0 && strings.HasSuffix(strings.TrimSuffix(os.Args[0], ".exe"), ".test")
// New creates a new lazy regexp, delaying the compiling work until it is first
// needed. If the code is being run as part of tests, the regexp compiling will
// happen immediately.
func New(str string) *Regexp {
lr := &Regexp{str: str}
if inTest {
// In tests, always compile the regexps early.
lr.re()
}
return lr
}
+44 -25
View File
@@ -15,7 +15,7 @@
// but additional checking functions, most notably Check, verify that
// a particular path, version pair is valid.
//
// Escaped Paths
// # Escaped Paths
//
// Module paths appear as substrings of file system paths
// (in the download cache) and of web server URLs in the proxy protocol.
@@ -55,7 +55,7 @@
// Import paths have never allowed exclamation marks, so there is no
// need to define how to escape a literal !.
//
// Unicode Restrictions
// # Unicode Restrictions
//
// Today, paths are disallowed from using Unicode.
//
@@ -102,9 +102,9 @@ import (
"strings"
"unicode"
"unicode/utf8"
"errors"
"golang.org/x/mod/semver"
errors "golang.org/x/xerrors"
)
// A Version (for clients, a module.Version) is defined by a module path and version pair.
@@ -192,6 +192,21 @@ func (e *InvalidVersionError) Error() string {
func (e *InvalidVersionError) Unwrap() error { return e.Err }
// An InvalidPathError indicates a module, import, or file path doesn't
// satisfy all naming constraints. See CheckPath, CheckImportPath,
// and CheckFilePath for specific restrictions.
type InvalidPathError struct {
Kind string // "module", "import", or "file"
Path string
Err error
}
func (e *InvalidPathError) Error() string {
return fmt.Sprintf("malformed %s path %q: %v", e.Kind, e.Path, e.Err)
}
func (e *InvalidPathError) Unwrap() error { return e.Err }
// Check checks that a given module path, version pair is valid.
// In addition to the path being a valid module path
// and the version being a valid semantic version,
@@ -271,12 +286,7 @@ func fileNameOK(r rune) bool {
if '0' <= r && r <= '9' || 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' {
return true
}
for i := 0; i < len(allowed); i++ {
if rune(allowed[i]) == r {
return true
}
}
return false
return strings.ContainsRune(allowed, r)
}
// It may be OK to add more ASCII punctuation here, but only carefully.
// For example Windows disallows < > \, and macOS disallows :, so we must not allow those.
@@ -296,30 +306,36 @@ func fileNameOK(r rune) bool {
// this second requirement is replaced by a requirement that the path
// follow the gopkg.in server's conventions.
// Third, no path element may begin with a dot.
func CheckPath(path string) error {
func CheckPath(path string) (err error) {
defer func() {
if err != nil {
err = &InvalidPathError{Kind: "module", Path: path, Err: err}
}
}()
if err := checkPath(path, modulePath); err != nil {
return fmt.Errorf("malformed module path %q: %v", path, err)
return err
}
i := strings.Index(path, "/")
if i < 0 {
i = len(path)
}
if i == 0 {
return fmt.Errorf("malformed module path %q: leading slash", path)
return fmt.Errorf("leading slash")
}
if !strings.Contains(path[:i], ".") {
return fmt.Errorf("malformed module path %q: missing dot in first path element", path)
return fmt.Errorf("missing dot in first path element")
}
if path[0] == '-' {
return fmt.Errorf("malformed module path %q: leading dash in first path element", path)
return fmt.Errorf("leading dash in first path element")
}
for _, r := range path[:i] {
if !firstPathOK(r) {
return fmt.Errorf("malformed module path %q: invalid char %q in first path element", path, r)
return fmt.Errorf("invalid char %q in first path element", r)
}
}
if _, _, ok := SplitPathVersion(path); !ok {
return fmt.Errorf("malformed module path %q: invalid version", path)
return fmt.Errorf("invalid version")
}
return nil
}
@@ -343,7 +359,7 @@ func CheckPath(path string) error {
// subtleties of Unicode.
func CheckImportPath(path string) error {
if err := checkPath(path, importPath); err != nil {
return fmt.Errorf("malformed import path %q: %v", path, err)
return &InvalidPathError{Kind: "import", Path: path, Err: err}
}
return nil
}
@@ -358,12 +374,13 @@ const (
filePath
)
// checkPath checks that a general path is valid.
// It returns an error describing why but not mentioning path.
// Because these checks apply to both module paths and import paths,
// the caller is expected to add the "malformed ___ path %q: " prefix.
// fileName indicates whether the final element of the path is a file name
// (as opposed to a directory name).
// checkPath checks that a general path is valid. kind indicates what
// specific constraints should be applied.
//
// checkPath returns an error describing why the path is not valid.
// Because these checks apply to module, import, and file paths,
// and because other checks may be applied, the caller is expected to wrap
// this error with InvalidPathError.
func checkPath(path string, kind pathKind) error {
if !utf8.ValidString(path) {
return fmt.Errorf("invalid UTF-8")
@@ -371,7 +388,7 @@ func checkPath(path string, kind pathKind) error {
if path == "" {
return fmt.Errorf("empty string")
}
if path[0] == '-' {
if path[0] == '-' && kind != filePath {
return fmt.Errorf("leading dash")
}
if strings.Contains(path, "//") {
@@ -477,7 +494,7 @@ func checkElem(elem string, kind pathKind) error {
// subtleties of Unicode.
func CheckFilePath(path string) error {
if err := checkPath(path, filePath); err != nil {
return fmt.Errorf("malformed file path %q: %v", path, err)
return &InvalidPathError{Kind: "file", Path: path, Err: err}
}
return nil
}
@@ -781,6 +798,7 @@ func unescapeString(escaped string) (string, bool) {
// GOPRIVATE environment variable, as described by 'go help module-private'.
//
// It ignores any empty or malformed patterns in the list.
// Trailing slashes on patterns are ignored.
func MatchPrefixPatterns(globs, target string) bool {
for globs != "" {
// Extract next non-empty glob in comma-separated list.
@@ -790,6 +808,7 @@ func MatchPrefixPatterns(globs, target string) bool {
} else {
glob, globs = globs, ""
}
glob = strings.TrimSuffix(glob, "/")
if glob == "" {
continue
}
+250
View File
@@ -0,0 +1,250 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Pseudo-versions
//
// Code authors are expected to tag the revisions they want users to use,
// including prereleases. However, not all authors tag versions at all,
// and not all commits a user might want to try will have tags.
// A pseudo-version is a version with a special form that allows us to
// address an untagged commit and order that version with respect to
// other versions we might encounter.
//
// A pseudo-version takes one of the general forms:
//
// (1) vX.0.0-yyyymmddhhmmss-abcdef123456
// (2) vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456
// (3) vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456+incompatible
// (4) vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456
// (5) vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456+incompatible
//
// If there is no recently tagged version with the right major version vX,
// then form (1) is used, creating a space of pseudo-versions at the bottom
// of the vX version range, less than any tagged version, including the unlikely v0.0.0.
//
// If the most recent tagged version before the target commit is vX.Y.Z or vX.Y.Z+incompatible,
// then the pseudo-version uses form (2) or (3), making it a prerelease for the next
// possible semantic version after vX.Y.Z. The leading 0 segment in the prerelease string
// ensures that the pseudo-version compares less than possible future explicit prereleases
// like vX.Y.(Z+1)-rc1 or vX.Y.(Z+1)-1.
//
// If the most recent tagged version before the target commit is vX.Y.Z-pre or vX.Y.Z-pre+incompatible,
// then the pseudo-version uses form (4) or (5), making it a slightly later prerelease.
package module
import (
"errors"
"fmt"
"strings"
"time"
"golang.org/x/mod/internal/lazyregexp"
"golang.org/x/mod/semver"
)
var pseudoVersionRE = lazyregexp.New(`^v[0-9]+\.(0\.0-|\d+\.\d+-([^+]*\.)?0\.)\d{14}-[A-Za-z0-9]+(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$`)
const PseudoVersionTimestampFormat = "20060102150405"
// PseudoVersion returns a pseudo-version for the given major version ("v1")
// preexisting older tagged version ("" or "v1.2.3" or "v1.2.3-pre"), revision time,
// and revision identifier (usually a 12-byte commit hash prefix).
func PseudoVersion(major, older string, t time.Time, rev string) string {
if major == "" {
major = "v0"
}
segment := fmt.Sprintf("%s-%s", t.UTC().Format(PseudoVersionTimestampFormat), rev)
build := semver.Build(older)
older = semver.Canonical(older)
if older == "" {
return major + ".0.0-" + segment // form (1)
}
if semver.Prerelease(older) != "" {
return older + ".0." + segment + build // form (4), (5)
}
// Form (2), (3).
// Extract patch from vMAJOR.MINOR.PATCH
i := strings.LastIndex(older, ".") + 1
v, patch := older[:i], older[i:]
// Reassemble.
return v + incDecimal(patch) + "-0." + segment + build
}
// ZeroPseudoVersion returns a pseudo-version with a zero timestamp and
// revision, which may be used as a placeholder.
func ZeroPseudoVersion(major string) string {
return PseudoVersion(major, "", time.Time{}, "000000000000")
}
// incDecimal returns the decimal string incremented by 1.
func incDecimal(decimal string) string {
// Scan right to left turning 9s to 0s until you find a digit to increment.
digits := []byte(decimal)
i := len(digits) - 1
for ; i >= 0 && digits[i] == '9'; i-- {
digits[i] = '0'
}
if i >= 0 {
digits[i]++
} else {
// digits is all zeros
digits[0] = '1'
digits = append(digits, '0')
}
return string(digits)
}
// decDecimal returns the decimal string decremented by 1, or the empty string
// if the decimal is all zeroes.
func decDecimal(decimal string) string {
// Scan right to left turning 0s to 9s until you find a digit to decrement.
digits := []byte(decimal)
i := len(digits) - 1
for ; i >= 0 && digits[i] == '0'; i-- {
digits[i] = '9'
}
if i < 0 {
// decimal is all zeros
return ""
}
if i == 0 && digits[i] == '1' && len(digits) > 1 {
digits = digits[1:]
} else {
digits[i]--
}
return string(digits)
}
// IsPseudoVersion reports whether v is a pseudo-version.
func IsPseudoVersion(v string) bool {
return strings.Count(v, "-") >= 2 && semver.IsValid(v) && pseudoVersionRE.MatchString(v)
}
// IsZeroPseudoVersion returns whether v is a pseudo-version with a zero base,
// timestamp, and revision, as returned by ZeroPseudoVersion.
func IsZeroPseudoVersion(v string) bool {
return v == ZeroPseudoVersion(semver.Major(v))
}
// PseudoVersionTime returns the time stamp of the pseudo-version v.
// It returns an error if v is not a pseudo-version or if the time stamp
// embedded in the pseudo-version is not a valid time.
func PseudoVersionTime(v string) (time.Time, error) {
_, timestamp, _, _, err := parsePseudoVersion(v)
if err != nil {
return time.Time{}, err
}
t, err := time.Parse("20060102150405", timestamp)
if err != nil {
return time.Time{}, &InvalidVersionError{
Version: v,
Pseudo: true,
Err: fmt.Errorf("malformed time %q", timestamp),
}
}
return t, nil
}
// PseudoVersionRev returns the revision identifier of the pseudo-version v.
// It returns an error if v is not a pseudo-version.
func PseudoVersionRev(v string) (rev string, err error) {
_, _, rev, _, err = parsePseudoVersion(v)
return
}
// PseudoVersionBase returns the canonical parent version, if any, upon which
// the pseudo-version v is based.
//
// If v has no parent version (that is, if it is "vX.0.0-[…]"),
// PseudoVersionBase returns the empty string and a nil error.
func PseudoVersionBase(v string) (string, error) {
base, _, _, build, err := parsePseudoVersion(v)
if err != nil {
return "", err
}
switch pre := semver.Prerelease(base); pre {
case "":
// vX.0.0-yyyymmddhhmmss-abcdef123456 → ""
if build != "" {
// Pseudo-versions of the form vX.0.0-yyyymmddhhmmss-abcdef123456+incompatible
// are nonsensical: the "vX.0.0-" prefix implies that there is no parent tag,
// but the "+incompatible" suffix implies that the major version of
// the parent tag is not compatible with the module's import path.
//
// There are a few such entries in the index generated by proxy.golang.org,
// but we believe those entries were generated by the proxy itself.
return "", &InvalidVersionError{
Version: v,
Pseudo: true,
Err: fmt.Errorf("lacks base version, but has build metadata %q", build),
}
}
return "", nil
case "-0":
// vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456 → vX.Y.Z
// vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456+incompatible → vX.Y.Z+incompatible
base = strings.TrimSuffix(base, pre)
i := strings.LastIndexByte(base, '.')
if i < 0 {
panic("base from parsePseudoVersion missing patch number: " + base)
}
patch := decDecimal(base[i+1:])
if patch == "" {
// vX.0.0-0 is invalid, but has been observed in the wild in the index
// generated by requests to proxy.golang.org.
//
// NOTE(bcmills): I cannot find a historical bug that accounts for
// pseudo-versions of this form, nor have I seen such versions in any
// actual go.mod files. If we find actual examples of this form and a
// reasonable theory of how they came into existence, it seems fine to
// treat them as equivalent to vX.0.0 (especially since the invalid
// pseudo-versions have lower precedence than the real ones). For now, we
// reject them.
return "", &InvalidVersionError{
Version: v,
Pseudo: true,
Err: fmt.Errorf("version before %s would have negative patch number", base),
}
}
return base[:i+1] + patch + build, nil
default:
// vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456 → vX.Y.Z-pre
// vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456+incompatible → vX.Y.Z-pre+incompatible
if !strings.HasSuffix(base, ".0") {
panic(`base from parsePseudoVersion missing ".0" before date: ` + base)
}
return strings.TrimSuffix(base, ".0") + build, nil
}
}
var errPseudoSyntax = errors.New("syntax error")
func parsePseudoVersion(v string) (base, timestamp, rev, build string, err error) {
if !IsPseudoVersion(v) {
return "", "", "", "", &InvalidVersionError{
Version: v,
Pseudo: true,
Err: errPseudoSyntax,
}
}
build = semver.Build(v)
v = strings.TrimSuffix(v, build)
j := strings.LastIndex(v, "-")
v, rev = v[:j], v[j+1:]
i := strings.LastIndex(v, "-")
if j := strings.LastIndex(v, "."); j > i {
base = v[:j] // "vX.Y.Z-pre.0" or "vX.Y.(Z+1)-0"
timestamp = v[j+1:]
} else {
base = v[:i] // "vX.0.0"
timestamp = v[i+1:]
}
return base, timestamp, rev, build, nil
}
+20 -10
View File
@@ -22,6 +22,8 @@
// as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0.
package semver
import "sort"
// parsed returns the parsed form of a semantic version string.
type parsed struct {
major string
@@ -30,7 +32,6 @@ type parsed struct {
short string
prerelease string
build string
err string
}
// IsValid reports whether v is a valid semantic version string.
@@ -150,14 +151,30 @@ func Max(v, w string) string {
return w
}
// ByVersion implements sort.Interface for sorting semantic version strings.
type ByVersion []string
func (vs ByVersion) Len() int { return len(vs) }
func (vs ByVersion) Swap(i, j int) { vs[i], vs[j] = vs[j], vs[i] }
func (vs ByVersion) Less(i, j int) bool {
cmp := Compare(vs[i], vs[j])
if cmp != 0 {
return cmp < 0
}
return vs[i] < vs[j]
}
// Sort sorts a list of semantic version strings using ByVersion.
func Sort(list []string) {
sort.Sort(ByVersion(list))
}
func parse(v string) (p parsed, ok bool) {
if v == "" || v[0] != 'v' {
p.err = "missing v prefix"
return
}
p.major, v, ok = parseInt(v[1:])
if !ok {
p.err = "bad major version"
return
}
if v == "" {
@@ -167,13 +184,11 @@ func parse(v string) (p parsed, ok bool) {
return
}
if v[0] != '.' {
p.err = "bad minor prefix"
ok = false
return
}
p.minor, v, ok = parseInt(v[1:])
if !ok {
p.err = "bad minor version"
return
}
if v == "" {
@@ -182,31 +197,26 @@ func parse(v string) (p parsed, ok bool) {
return
}
if v[0] != '.' {
p.err = "bad patch prefix"
ok = false
return
}
p.patch, v, ok = parseInt(v[1:])
if !ok {
p.err = "bad patch version"
return
}
if len(v) > 0 && v[0] == '-' {
p.prerelease, v, ok = parsePrerelease(v)
if !ok {
p.err = "bad prerelease"
return
}
}
if len(v) > 0 && v[0] == '+' {
p.build, v, ok = parseBuild(v)
if !ok {
p.err = "bad build"
return
}
}
if v != "" {
p.err = "junk on end"
ok = false
return
}
+18
View File
@@ -27,7 +27,14 @@ func buildCommonHeaderMaps() {
"accept-language",
"accept-ranges",
"age",
"access-control-allow-credentials",
"access-control-allow-headers",
"access-control-allow-methods",
"access-control-allow-origin",
"access-control-expose-headers",
"access-control-max-age",
"access-control-request-headers",
"access-control-request-method",
"allow",
"authorization",
"cache-control",
@@ -53,6 +60,7 @@ func buildCommonHeaderMaps() {
"link",
"location",
"max-forwards",
"origin",
"proxy-authenticate",
"proxy-authorization",
"range",
@@ -68,6 +76,8 @@ func buildCommonHeaderMaps() {
"vary",
"via",
"www-authenticate",
"x-forwarded-for",
"x-forwarded-proto",
}
commonLowerHeader = make(map[string]string, len(common))
commonCanonHeader = make(map[string]string, len(common))
@@ -85,3 +95,11 @@ func lowerHeader(v string) (lower string, ascii bool) {
}
return asciiToLower(v)
}
func canonicalHeader(v string) string {
buildCommonHeaderMapsOnce()
if s, ok := commonCanonHeader[v]; ok {
return s
}
return http.CanonicalHeaderKey(v)
}
+188
View File
@@ -0,0 +1,188 @@
// go generate gen.go
// Code generated by the command above; DO NOT EDIT.
package hpack
var staticTable = &headerFieldTable{
evictCount: 0,
byName: map[string]uint64{
":authority": 1,
":method": 3,
":path": 5,
":scheme": 7,
":status": 14,
"accept-charset": 15,
"accept-encoding": 16,
"accept-language": 17,
"accept-ranges": 18,
"accept": 19,
"access-control-allow-origin": 20,
"age": 21,
"allow": 22,
"authorization": 23,
"cache-control": 24,
"content-disposition": 25,
"content-encoding": 26,
"content-language": 27,
"content-length": 28,
"content-location": 29,
"content-range": 30,
"content-type": 31,
"cookie": 32,
"date": 33,
"etag": 34,
"expect": 35,
"expires": 36,
"from": 37,
"host": 38,
"if-match": 39,
"if-modified-since": 40,
"if-none-match": 41,
"if-range": 42,
"if-unmodified-since": 43,
"last-modified": 44,
"link": 45,
"location": 46,
"max-forwards": 47,
"proxy-authenticate": 48,
"proxy-authorization": 49,
"range": 50,
"referer": 51,
"refresh": 52,
"retry-after": 53,
"server": 54,
"set-cookie": 55,
"strict-transport-security": 56,
"transfer-encoding": 57,
"user-agent": 58,
"vary": 59,
"via": 60,
"www-authenticate": 61,
},
byNameValue: map[pairNameValue]uint64{
{name: ":authority", value: ""}: 1,
{name: ":method", value: "GET"}: 2,
{name: ":method", value: "POST"}: 3,
{name: ":path", value: "/"}: 4,
{name: ":path", value: "/index.html"}: 5,
{name: ":scheme", value: "http"}: 6,
{name: ":scheme", value: "https"}: 7,
{name: ":status", value: "200"}: 8,
{name: ":status", value: "204"}: 9,
{name: ":status", value: "206"}: 10,
{name: ":status", value: "304"}: 11,
{name: ":status", value: "400"}: 12,
{name: ":status", value: "404"}: 13,
{name: ":status", value: "500"}: 14,
{name: "accept-charset", value: ""}: 15,
{name: "accept-encoding", value: "gzip, deflate"}: 16,
{name: "accept-language", value: ""}: 17,
{name: "accept-ranges", value: ""}: 18,
{name: "accept", value: ""}: 19,
{name: "access-control-allow-origin", value: ""}: 20,
{name: "age", value: ""}: 21,
{name: "allow", value: ""}: 22,
{name: "authorization", value: ""}: 23,
{name: "cache-control", value: ""}: 24,
{name: "content-disposition", value: ""}: 25,
{name: "content-encoding", value: ""}: 26,
{name: "content-language", value: ""}: 27,
{name: "content-length", value: ""}: 28,
{name: "content-location", value: ""}: 29,
{name: "content-range", value: ""}: 30,
{name: "content-type", value: ""}: 31,
{name: "cookie", value: ""}: 32,
{name: "date", value: ""}: 33,
{name: "etag", value: ""}: 34,
{name: "expect", value: ""}: 35,
{name: "expires", value: ""}: 36,
{name: "from", value: ""}: 37,
{name: "host", value: ""}: 38,
{name: "if-match", value: ""}: 39,
{name: "if-modified-since", value: ""}: 40,
{name: "if-none-match", value: ""}: 41,
{name: "if-range", value: ""}: 42,
{name: "if-unmodified-since", value: ""}: 43,
{name: "last-modified", value: ""}: 44,
{name: "link", value: ""}: 45,
{name: "location", value: ""}: 46,
{name: "max-forwards", value: ""}: 47,
{name: "proxy-authenticate", value: ""}: 48,
{name: "proxy-authorization", value: ""}: 49,
{name: "range", value: ""}: 50,
{name: "referer", value: ""}: 51,
{name: "refresh", value: ""}: 52,
{name: "retry-after", value: ""}: 53,
{name: "server", value: ""}: 54,
{name: "set-cookie", value: ""}: 55,
{name: "strict-transport-security", value: ""}: 56,
{name: "transfer-encoding", value: ""}: 57,
{name: "user-agent", value: ""}: 58,
{name: "vary", value: ""}: 59,
{name: "via", value: ""}: 60,
{name: "www-authenticate", value: ""}: 61,
},
ents: []HeaderField{
{Name: ":authority", Value: "", Sensitive: false},
{Name: ":method", Value: "GET", Sensitive: false},
{Name: ":method", Value: "POST", Sensitive: false},
{Name: ":path", Value: "/", Sensitive: false},
{Name: ":path", Value: "/index.html", Sensitive: false},
{Name: ":scheme", Value: "http", Sensitive: false},
{Name: ":scheme", Value: "https", Sensitive: false},
{Name: ":status", Value: "200", Sensitive: false},
{Name: ":status", Value: "204", Sensitive: false},
{Name: ":status", Value: "206", Sensitive: false},
{Name: ":status", Value: "304", Sensitive: false},
{Name: ":status", Value: "400", Sensitive: false},
{Name: ":status", Value: "404", Sensitive: false},
{Name: ":status", Value: "500", Sensitive: false},
{Name: "accept-charset", Value: "", Sensitive: false},
{Name: "accept-encoding", Value: "gzip, deflate", Sensitive: false},
{Name: "accept-language", Value: "", Sensitive: false},
{Name: "accept-ranges", Value: "", Sensitive: false},
{Name: "accept", Value: "", Sensitive: false},
{Name: "access-control-allow-origin", Value: "", Sensitive: false},
{Name: "age", Value: "", Sensitive: false},
{Name: "allow", Value: "", Sensitive: false},
{Name: "authorization", Value: "", Sensitive: false},
{Name: "cache-control", Value: "", Sensitive: false},
{Name: "content-disposition", Value: "", Sensitive: false},
{Name: "content-encoding", Value: "", Sensitive: false},
{Name: "content-language", Value: "", Sensitive: false},
{Name: "content-length", Value: "", Sensitive: false},
{Name: "content-location", Value: "", Sensitive: false},
{Name: "content-range", Value: "", Sensitive: false},
{Name: "content-type", Value: "", Sensitive: false},
{Name: "cookie", Value: "", Sensitive: false},
{Name: "date", Value: "", Sensitive: false},
{Name: "etag", Value: "", Sensitive: false},
{Name: "expect", Value: "", Sensitive: false},
{Name: "expires", Value: "", Sensitive: false},
{Name: "from", Value: "", Sensitive: false},
{Name: "host", Value: "", Sensitive: false},
{Name: "if-match", Value: "", Sensitive: false},
{Name: "if-modified-since", Value: "", Sensitive: false},
{Name: "if-none-match", Value: "", Sensitive: false},
{Name: "if-range", Value: "", Sensitive: false},
{Name: "if-unmodified-since", Value: "", Sensitive: false},
{Name: "last-modified", Value: "", Sensitive: false},
{Name: "link", Value: "", Sensitive: false},
{Name: "location", Value: "", Sensitive: false},
{Name: "max-forwards", Value: "", Sensitive: false},
{Name: "proxy-authenticate", Value: "", Sensitive: false},
{Name: "proxy-authorization", Value: "", Sensitive: false},
{Name: "range", Value: "", Sensitive: false},
{Name: "referer", Value: "", Sensitive: false},
{Name: "refresh", Value: "", Sensitive: false},
{Name: "retry-after", Value: "", Sensitive: false},
{Name: "server", Value: "", Sensitive: false},
{Name: "set-cookie", Value: "", Sensitive: false},
{Name: "strict-transport-security", Value: "", Sensitive: false},
{Name: "transfer-encoding", Value: "", Sensitive: false},
{Name: "user-agent", Value: "", Sensitive: false},
{Name: "vary", Value: "", Sensitive: false},
{Name: "via", Value: "", Sensitive: false},
{Name: "www-authenticate", Value: "", Sensitive: false},
},
}
+1 -77
View File
@@ -96,8 +96,7 @@ func (t *headerFieldTable) evictOldest(n int) {
// meaning t.ents is reversed for dynamic tables. Hence, when t is a dynamic
// table, the return value i actually refers to the entry t.ents[t.len()-i].
//
// All tables are assumed to be a dynamic tables except for the global
// staticTable pointer.
// All tables are assumed to be a dynamic tables except for the global staticTable.
//
// See Section 2.3.3.
func (t *headerFieldTable) search(f HeaderField) (i uint64, nameValueMatch bool) {
@@ -125,81 +124,6 @@ func (t *headerFieldTable) idToIndex(id uint64) uint64 {
return k + 1
}
// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-B
var staticTable = newStaticTable()
var staticTableEntries = [...]HeaderField{
{Name: ":authority"},
{Name: ":method", Value: "GET"},
{Name: ":method", Value: "POST"},
{Name: ":path", Value: "/"},
{Name: ":path", Value: "/index.html"},
{Name: ":scheme", Value: "http"},
{Name: ":scheme", Value: "https"},
{Name: ":status", Value: "200"},
{Name: ":status", Value: "204"},
{Name: ":status", Value: "206"},
{Name: ":status", Value: "304"},
{Name: ":status", Value: "400"},
{Name: ":status", Value: "404"},
{Name: ":status", Value: "500"},
{Name: "accept-charset"},
{Name: "accept-encoding", Value: "gzip, deflate"},
{Name: "accept-language"},
{Name: "accept-ranges"},
{Name: "accept"},
{Name: "access-control-allow-origin"},
{Name: "age"},
{Name: "allow"},
{Name: "authorization"},
{Name: "cache-control"},
{Name: "content-disposition"},
{Name: "content-encoding"},
{Name: "content-language"},
{Name: "content-length"},
{Name: "content-location"},
{Name: "content-range"},
{Name: "content-type"},
{Name: "cookie"},
{Name: "date"},
{Name: "etag"},
{Name: "expect"},
{Name: "expires"},
{Name: "from"},
{Name: "host"},
{Name: "if-match"},
{Name: "if-modified-since"},
{Name: "if-none-match"},
{Name: "if-range"},
{Name: "if-unmodified-since"},
{Name: "last-modified"},
{Name: "link"},
{Name: "location"},
{Name: "max-forwards"},
{Name: "proxy-authenticate"},
{Name: "proxy-authorization"},
{Name: "range"},
{Name: "referer"},
{Name: "refresh"},
{Name: "retry-after"},
{Name: "server"},
{Name: "set-cookie"},
{Name: "strict-transport-security"},
{Name: "transfer-encoding"},
{Name: "user-agent"},
{Name: "vary"},
{Name: "via"},
{Name: "www-authenticate"},
}
func newStaticTable() *headerFieldTable {
t := &headerFieldTable{}
t.init()
for _, e := range staticTableEntries[:] {
t.addEntry(e)
}
return t
}
var huffmanCodes = [256]uint32{
0x1ff8,
0x7fffd8,
+129 -39
View File
@@ -143,7 +143,7 @@ type Server struct {
}
func (s *Server) initialConnRecvWindowSize() int32 {
if s.MaxUploadBufferPerConnection > initialWindowSize {
if s.MaxUploadBufferPerConnection >= initialWindowSize {
return s.MaxUploadBufferPerConnection
}
return 1 << 20
@@ -622,7 +622,9 @@ type stream struct {
resetQueued bool // RST_STREAM queued for write; set by sc.resetStream
gotTrailerHeader bool // HEADER frame for trailers was seen
wroteHeaders bool // whether we wrote headers (not status 100)
readDeadline *time.Timer // nil if unused
writeDeadline *time.Timer // nil if unused
closeErr error // set before cw is closed
trailer http.Header // accumulated trailers
reqTrailer http.Header // handler's Request.Trailer
@@ -948,6 +950,8 @@ func (sc *serverConn) serve() {
}
case *startPushRequest:
sc.startPush(v)
case func(*serverConn):
v(sc)
default:
panic(fmt.Sprintf("unexpected type %T", v))
}
@@ -1461,6 +1465,21 @@ func (sc *serverConn) processFrame(f Frame) error {
sc.sawFirstSettings = true
}
// Discard frames for streams initiated after the identified last
// stream sent in a GOAWAY, or all frames after sending an error.
// We still need to return connection-level flow control for DATA frames.
// RFC 9113 Section 6.8.
if sc.inGoAway && (sc.goAwayCode != ErrCodeNo || f.Header().StreamID > sc.maxClientStreamID) {
if f, ok := f.(*DataFrame); ok {
if sc.inflow.available() < int32(f.Length) {
return sc.countError("data_flow", streamError(f.Header().StreamID, ErrCodeFlowControl))
}
sc.sendWindowUpdate(nil, int(f.Length)) // conn-level
}
return nil
}
switch f := f.(type) {
case *SettingsFrame:
return sc.processSettings(f)
@@ -1503,9 +1522,6 @@ func (sc *serverConn) processPing(f *PingFrame) error {
// PROTOCOL_ERROR."
return sc.countError("ping_on_stream", ConnectionError(ErrCodeProtocol))
}
if sc.inGoAway && sc.goAwayCode != ErrCodeNo {
return nil
}
sc.writeFrame(FrameWriteRequest{write: writePingAck{f}})
return nil
}
@@ -1567,6 +1583,9 @@ func (sc *serverConn) closeStream(st *stream, err error) {
panic(fmt.Sprintf("invariant; can't close stream in state %v", st.state))
}
st.state = stateClosed
if st.readDeadline != nil {
st.readDeadline.Stop()
}
if st.writeDeadline != nil {
st.writeDeadline.Stop()
}
@@ -1592,6 +1611,14 @@ func (sc *serverConn) closeStream(st *stream, err error) {
p.CloseWithError(err)
}
if e, ok := err.(StreamError); ok {
if e.Cause != nil {
err = e.Cause
} else {
err = errStreamClosed
}
}
st.closeErr = err
st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc
sc.writeSched.CloseStream(st.id)
}
@@ -1688,16 +1715,6 @@ func (sc *serverConn) processSettingInitialWindowSize(val uint32) error {
func (sc *serverConn) processData(f *DataFrame) error {
sc.serveG.check()
id := f.Header().StreamID
if sc.inGoAway && (sc.goAwayCode != ErrCodeNo || id > sc.maxClientStreamID) {
// Discard all DATA frames if the GOAWAY is due to an
// error, or:
//
// Section 6.8: After sending a GOAWAY frame, the sender
// can discard frames for streams initiated by the
// receiver with identifiers higher than the identified
// last stream.
return nil
}
data := f.Data()
state, st := sc.state(id)
@@ -1840,19 +1857,27 @@ func (st *stream) copyTrailersToHandlerRequest() {
}
}
// onReadTimeout is run on its own goroutine (from time.AfterFunc)
// when the stream's ReadTimeout has fired.
func (st *stream) onReadTimeout() {
// Wrap the ErrDeadlineExceeded to avoid callers depending on us
// returning the bare error.
st.body.CloseWithError(fmt.Errorf("%w", os.ErrDeadlineExceeded))
}
// onWriteTimeout is run on its own goroutine (from time.AfterFunc)
// when the stream's WriteTimeout has fired.
func (st *stream) onWriteTimeout() {
st.sc.writeFrameFromHandler(FrameWriteRequest{write: streamError(st.id, ErrCodeInternal)})
st.sc.writeFrameFromHandler(FrameWriteRequest{write: StreamError{
StreamID: st.id,
Code: ErrCodeInternal,
Cause: os.ErrDeadlineExceeded,
}})
}
func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
sc.serveG.check()
id := f.StreamID
if sc.inGoAway {
// Ignore.
return nil
}
// http://tools.ietf.org/html/rfc7540#section-5.1.1
// Streams initiated by a client MUST use odd-numbered stream
// identifiers. [...] An endpoint that receives an unexpected
@@ -1955,6 +1980,9 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
// (in Go 1.8), though. That's a more sane option anyway.
if sc.hs.ReadTimeout != 0 {
sc.conn.SetReadDeadline(time.Time{})
if st.body != nil {
st.readDeadline = time.AfterFunc(sc.hs.ReadTimeout, st.onReadTimeout)
}
}
go sc.runHandler(rw, req, handler)
@@ -2023,9 +2051,6 @@ func (sc *serverConn) checkPriority(streamID uint32, p PriorityParam) error {
}
func (sc *serverConn) processPriority(f *PriorityFrame) error {
if sc.inGoAway {
return nil
}
if err := sc.checkPriority(f.StreamID, f.PriorityParam); err != nil {
return err
}
@@ -2099,12 +2124,6 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
return nil, nil, sc.countError("bad_path_method", streamError(f.StreamID, ErrCodeProtocol))
}
bodyOpen := !f.StreamEnded()
if rp.method == "HEAD" && bodyOpen {
// HEAD requests can't have bodies
return nil, nil, sc.countError("head_body", streamError(f.StreamID, ErrCodeProtocol))
}
rp.header = make(http.Header)
for _, hf := range f.RegularFields() {
rp.header.Add(sc.canonicalHeader(hf.Name), hf.Value)
@@ -2117,6 +2136,7 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
if err != nil {
return nil, nil, err
}
bodyOpen := !f.StreamEnded()
if bodyOpen {
if vv, ok := rp.header["Content-Length"]; ok {
if cl, err := strconv.ParseUint(vv[0], 10, 63); err == nil {
@@ -2346,7 +2366,7 @@ func (sc *serverConn) sendWindowUpdate(st *stream, n int) {
// a larger Read than this. Very unlikely, but we handle it here
// rather than elsewhere for now.
const maxUint31 = 1<<31 - 1
for n >= maxUint31 {
for n > maxUint31 {
sc.sendWindowUpdate32(st, maxUint31)
n -= maxUint31
}
@@ -2466,7 +2486,15 @@ type responseWriterState struct {
type chunkWriter struct{ rws *responseWriterState }
func (cw chunkWriter) Write(p []byte) (n int, err error) { return cw.rws.writeChunk(p) }
func (cw chunkWriter) Write(p []byte) (n int, err error) {
n, err = cw.rws.writeChunk(p)
if err == errStreamClosed {
// If writing failed because the stream has been closed,
// return the reason it was closed.
err = cw.rws.stream.closeErr
}
return n, err
}
func (rws *responseWriterState) hasTrailers() bool { return len(rws.trailers) > 0 }
@@ -2505,6 +2533,10 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
rws.writeHeader(200)
}
if rws.handlerDone {
rws.promoteUndeclaredTrailers()
}
isHeadResp := rws.req.Method == "HEAD"
if !rws.sentHeader {
rws.sentHeader = true
@@ -2576,10 +2608,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
return 0, nil
}
if rws.handlerDone {
rws.promoteUndeclaredTrailers()
}
// only send trailers if they have actually been defined by the
// server handler.
hasNonemptyTrailers := rws.hasNonemptyTrailers()
@@ -2660,23 +2688,85 @@ func (rws *responseWriterState) promoteUndeclaredTrailers() {
}
}
func (w *responseWriter) SetReadDeadline(deadline time.Time) error {
st := w.rws.stream
if !deadline.IsZero() && deadline.Before(time.Now()) {
// If we're setting a deadline in the past, reset the stream immediately
// so writes after SetWriteDeadline returns will fail.
st.onReadTimeout()
return nil
}
w.rws.conn.sendServeMsg(func(sc *serverConn) {
if st.readDeadline != nil {
if !st.readDeadline.Stop() {
// Deadline already exceeded, or stream has been closed.
return
}
}
if deadline.IsZero() {
st.readDeadline = nil
} else if st.readDeadline == nil {
st.readDeadline = time.AfterFunc(deadline.Sub(time.Now()), st.onReadTimeout)
} else {
st.readDeadline.Reset(deadline.Sub(time.Now()))
}
})
return nil
}
func (w *responseWriter) SetWriteDeadline(deadline time.Time) error {
st := w.rws.stream
if !deadline.IsZero() && deadline.Before(time.Now()) {
// If we're setting a deadline in the past, reset the stream immediately
// so writes after SetWriteDeadline returns will fail.
st.onWriteTimeout()
return nil
}
w.rws.conn.sendServeMsg(func(sc *serverConn) {
if st.writeDeadline != nil {
if !st.writeDeadline.Stop() {
// Deadline already exceeded, or stream has been closed.
return
}
}
if deadline.IsZero() {
st.writeDeadline = nil
} else if st.writeDeadline == nil {
st.writeDeadline = time.AfterFunc(deadline.Sub(time.Now()), st.onWriteTimeout)
} else {
st.writeDeadline.Reset(deadline.Sub(time.Now()))
}
})
return nil
}
func (w *responseWriter) Flush() {
w.FlushError()
}
func (w *responseWriter) FlushError() error {
rws := w.rws
if rws == nil {
panic("Header called after Handler finished")
}
var err error
if rws.bw.Buffered() > 0 {
if err := rws.bw.Flush(); err != nil {
// Ignore the error. The frame writer already knows.
return
}
err = rws.bw.Flush()
} else {
// The bufio.Writer won't call chunkWriter.Write
// (writeChunk with zero bytes, so we have to do it
// ourselves to force the HTTP response header and/or
// final DATA frame (with END_STREAM) to be sent.
rws.writeChunk(nil)
_, err = chunkWriter{rws}.Write(nil)
if err == nil {
select {
case <-rws.stream.cw:
err = rws.stream.closeErr
default:
}
}
}
return err
}
func (w *responseWriter) CloseNotify() <-chan bool {
+71 -33
View File
@@ -16,6 +16,7 @@ import (
"errors"
"fmt"
"io"
"io/fs"
"log"
"math"
mathrand "math/rand"
@@ -258,7 +259,8 @@ func (t *Transport) initConnPool() {
// HTTP/2 server.
type ClientConn struct {
t *Transport
tconn net.Conn // usually *tls.Conn, except specialized impls
tconn net.Conn // usually *tls.Conn, except specialized impls
tconnClosed bool
tlsState *tls.ConnectionState // nil only for specialized impls
reused uint32 // whether conn is being reused; atomic
singleUse bool // whether being used for a single http.Request
@@ -344,8 +346,8 @@ type clientStream struct {
readErr error // sticky read error; owned by transportResponseBody.Read
reqBody io.ReadCloser
reqBodyContentLength int64 // -1 means unknown
reqBodyClosed bool // body has been closed; guarded by cc.mu
reqBodyContentLength int64 // -1 means unknown
reqBodyClosed chan struct{} // guarded by cc.mu; non-nil on Close, closed when done
// owned by writeRequest:
sentEndStream bool // sent an END_STREAM flag to the peer
@@ -385,9 +387,8 @@ func (cs *clientStream) abortStreamLocked(err error) {
cs.abortErr = err
close(cs.abort)
})
if cs.reqBody != nil && !cs.reqBodyClosed {
cs.reqBody.Close()
cs.reqBodyClosed = true
if cs.reqBody != nil {
cs.closeReqBodyLocked()
}
// TODO(dneil): Clean up tests where cs.cc.cond is nil.
if cs.cc.cond != nil {
@@ -400,13 +401,24 @@ func (cs *clientStream) abortRequestBodyWrite() {
cc := cs.cc
cc.mu.Lock()
defer cc.mu.Unlock()
if cs.reqBody != nil && !cs.reqBodyClosed {
cs.reqBody.Close()
cs.reqBodyClosed = true
if cs.reqBody != nil && cs.reqBodyClosed == nil {
cs.closeReqBodyLocked()
cc.cond.Broadcast()
}
}
func (cs *clientStream) closeReqBodyLocked() {
if cs.reqBodyClosed != nil {
return
}
cs.reqBodyClosed = make(chan struct{})
reqBodyClosed := cs.reqBodyClosed
go func() {
cs.reqBody.Close()
close(reqBodyClosed)
}()
}
type stickyErrWriter struct {
conn net.Conn
timeout time.Duration
@@ -490,6 +502,15 @@ func authorityAddr(scheme string, authority string) (addr string) {
return net.JoinHostPort(host, port)
}
var retryBackoffHook func(time.Duration) *time.Timer
func backoffNewTimer(d time.Duration) *time.Timer {
if retryBackoffHook != nil {
return retryBackoffHook(d)
}
return time.NewTimer(d)
}
// RoundTripOpt is like RoundTrip, but takes options.
func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Response, error) {
if !(req.URL.Scheme == "https" || (req.URL.Scheme == "http" && t.AllowHTTP)) {
@@ -515,11 +536,14 @@ func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res
}
backoff := float64(uint(1) << (uint(retry) - 1))
backoff += backoff * (0.1 * mathrand.Float64())
d := time.Second * time.Duration(backoff)
timer := backoffNewTimer(d)
select {
case <-time.After(time.Second * time.Duration(backoff)):
case <-timer.C:
t.vlogf("RoundTrip retrying after failure: %v", err)
continue
case <-req.Context().Done():
timer.Stop()
err = req.Context().Err()
}
}
@@ -921,10 +945,10 @@ func (cc *ClientConn) onIdleTimeout() {
cc.closeIfIdle()
}
func (cc *ClientConn) closeConn() error {
func (cc *ClientConn) closeConn() {
t := time.AfterFunc(250*time.Millisecond, cc.forceCloseConn)
defer t.Stop()
return cc.tconn.Close()
cc.tconn.Close()
}
// A tls.Conn.Close can hang for a long time if the peer is unresponsive.
@@ -990,7 +1014,8 @@ func (cc *ClientConn) Shutdown(ctx context.Context) error {
shutdownEnterWaitStateHook()
select {
case <-done:
return cc.closeConn()
cc.closeConn()
return nil
case <-ctx.Done():
cc.mu.Lock()
// Free the goroutine above
@@ -1027,7 +1052,7 @@ func (cc *ClientConn) sendGoAway() error {
// closes the client connection immediately. In-flight requests are interrupted.
// err is sent to streams.
func (cc *ClientConn) closeForError(err error) error {
func (cc *ClientConn) closeForError(err error) {
cc.mu.Lock()
cc.closed = true
for _, cs := range cc.streams {
@@ -1035,7 +1060,7 @@ func (cc *ClientConn) closeForError(err error) error {
}
cc.cond.Broadcast()
cc.mu.Unlock()
return cc.closeConn()
cc.closeConn()
}
// Close closes the client connection immediately.
@@ -1043,16 +1068,17 @@ func (cc *ClientConn) closeForError(err error) error {
// In-flight requests are interrupted. For a graceful shutdown, use Shutdown instead.
func (cc *ClientConn) Close() error {
err := errors.New("http2: client connection force closed via ClientConn.Close")
return cc.closeForError(err)
cc.closeForError(err)
return nil
}
// closes the client connection immediately. In-flight requests are interrupted.
func (cc *ClientConn) closeForLostPing() error {
func (cc *ClientConn) closeForLostPing() {
err := errors.New("http2: client connection lost")
if f := cc.t.CountError; f != nil {
f("conn_close_lost_ping")
}
return cc.closeForError(err)
cc.closeForError(err)
}
// errRequestCanceled is a copy of net/http's errRequestCanceled because it's not
@@ -1062,7 +1088,7 @@ var errRequestCanceled = errors.New("net/http: request canceled")
func commaSeparatedTrailers(req *http.Request) (string, error) {
keys := make([]string, 0, len(req.Trailer))
for k := range req.Trailer {
k = http.CanonicalHeaderKey(k)
k = canonicalHeader(k)
switch k {
case "Transfer-Encoding", "Trailer", "Content-Length":
return "", fmt.Errorf("invalid Trailer key %q", k)
@@ -1430,11 +1456,19 @@ func (cs *clientStream) cleanupWriteRequest(err error) {
// and in multiple cases: server replies <=299 and >299
// while still writing request body
cc.mu.Lock()
mustCloseBody := false
if cs.reqBody != nil && cs.reqBodyClosed == nil {
mustCloseBody = true
cs.reqBodyClosed = make(chan struct{})
}
bodyClosed := cs.reqBodyClosed
cs.reqBodyClosed = true
cc.mu.Unlock()
if !bodyClosed && cs.reqBody != nil {
if mustCloseBody {
cs.reqBody.Close()
close(bodyClosed)
}
if bodyClosed != nil {
<-bodyClosed
}
if err != nil && cs.sentEndStream {
@@ -1591,7 +1625,7 @@ func (cs *clientStream) writeRequestBody(req *http.Request) (err error) {
var sawEOF bool
for !sawEOF {
n, err := body.Read(buf[:len(buf)])
n, err := body.Read(buf)
if hasContentLen {
remainLen -= int64(n)
if remainLen == 0 && err == nil {
@@ -1614,7 +1648,7 @@ func (cs *clientStream) writeRequestBody(req *http.Request) (err error) {
}
if err != nil {
cc.mu.Lock()
bodyClosed := cs.reqBodyClosed
bodyClosed := cs.reqBodyClosed != nil
cc.mu.Unlock()
switch {
case bodyClosed:
@@ -1709,7 +1743,7 @@ func (cs *clientStream) awaitFlowControl(maxBytes int) (taken int32, err error)
if cc.closed {
return 0, errClientConnClosed
}
if cs.reqBodyClosed {
if cs.reqBodyClosed != nil {
return 0, errStopReqBodyWrite
}
select {
@@ -1894,7 +1928,7 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
// Header list size is ok. Write the headers.
enumerateHeaders(func(name, value string) {
name, ascii := asciiToLower(name)
name, ascii := lowerHeader(name)
if !ascii {
// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
// field names have to be ASCII characters (just as in HTTP/1.x).
@@ -1947,7 +1981,7 @@ func (cc *ClientConn) encodeTrailers(trailer http.Header) ([]byte, error) {
}
for k, vv := range trailer {
lowKey, ascii := asciiToLower(k)
lowKey, ascii := lowerHeader(k)
if !ascii {
// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
// field names have to be ASCII characters (just as in HTTP/1.x).
@@ -2005,7 +2039,7 @@ func (cc *ClientConn) forgetStreamID(id uint32) {
// wake up RoundTrip if there is a pending request.
cc.cond.Broadcast()
closeOnIdle := cc.singleUse || cc.doNotReuse || cc.t.disableKeepAlives()
closeOnIdle := cc.singleUse || cc.doNotReuse || cc.t.disableKeepAlives() || cc.goAway != nil
if closeOnIdle && cc.streamsReserved == 0 && len(cc.streams) == 0 {
if VerboseLogs {
cc.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", cc, cc.singleUse, cc.nextStreamID-2)
@@ -2081,6 +2115,7 @@ func (rl *clientConnReadLoop) cleanup() {
err = io.ErrUnexpectedEOF
}
cc.closed = true
for _, cs := range cc.streams {
select {
case <-cs.peerClosed:
@@ -2279,7 +2314,7 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra
Status: status + " " + http.StatusText(statusCode),
}
for _, hf := range regularFields {
key := http.CanonicalHeaderKey(hf.Name)
key := canonicalHeader(hf.Name)
if key == "Trailer" {
t := res.Trailer
if t == nil {
@@ -2287,7 +2322,7 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra
res.Trailer = t
}
foreachHeaderElement(hf.Value, func(v string) {
t[http.CanonicalHeaderKey(v)] = nil
t[canonicalHeader(v)] = nil
})
} else {
vv := header[key]
@@ -2392,7 +2427,7 @@ func (rl *clientConnReadLoop) processTrailers(cs *clientStream, f *MetaHeadersFr
trailer := make(http.Header)
for _, hf := range f.RegularFields() {
key := http.CanonicalHeaderKey(hf.Name)
key := canonicalHeader(hf.Name)
trailer[key] = append(trailer[key], hf.Value)
}
cs.trailer = trailer
@@ -2674,7 +2709,6 @@ func (rl *clientConnReadLoop) processGoAway(f *GoAwayFrame) error {
if fn := cc.t.CountError; fn != nil {
fn("recv_goaway_" + f.ErrCode.stringToken())
}
}
cc.setGoAway(f)
return nil
@@ -2964,7 +2998,11 @@ func (gz *gzipReader) Read(p []byte) (n int, err error) {
}
func (gz *gzipReader) Close() error {
return gz.body.Close()
if err := gz.body.Close(); err != nil {
return err
}
gz.zerr = fs.ErrClosed
return nil
}
type errorReader struct{ err error }
@@ -3028,7 +3066,7 @@ func traceGotConn(req *http.Request, cc *ClientConn, reused bool) {
cc.mu.Lock()
ci.WasIdle = len(cc.streams) == 0 && reused
if ci.WasIdle && !cc.lastActive.IsZero() {
ci.IdleTime = time.Now().Sub(cc.lastActive)
ci.IdleTime = time.Since(cc.lastActive)
}
cc.mu.Unlock()
+17 -1
View File
@@ -172,7 +172,23 @@ type mmsgTmpsPool struct {
}
func (p *mmsgTmpsPool) Get() *mmsgTmps {
return p.p.Get().(*mmsgTmps)
m := p.p.Get().(*mmsgTmps)
// Clear fields up to the len (not the cap) of the slice,
// assuming that the previous caller only used that many elements.
for i := range m.packer.sockaddrs {
m.packer.sockaddrs[i] = 0
}
m.packer.sockaddrs = m.packer.sockaddrs[:0]
for i := range m.packer.vs {
m.packer.vs[i] = iovec{}
}
m.packer.vs = m.packer.vs[:0]
for i := range m.packer.hs {
m.packer.hs[i].Len = 0
m.packer.hs[i].Hdr = msghdr{}
}
m.packer.hs = m.packer.hs[:0]
return m
}
func (p *mmsgTmpsPool) Put(tmps *mmsgTmps) {
-3
View File
@@ -17,9 +17,6 @@ func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
if sa != nil {
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
h.Namelen = uint32(len(sa))
} else {
h.Name = nil
h.Namelen = 0
}
}
+30
View File
@@ -0,0 +1,30 @@
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_openbsd.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen uint32
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
)
+30
View File
@@ -0,0 +1,30 @@
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_openbsd.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen uint32
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
)
+1 -1
View File
@@ -395,7 +395,7 @@ func New(family, title string) Trace {
}
func (tr *trace) Finish() {
elapsed := time.Now().Sub(tr.Start)
elapsed := time.Since(tr.Start)
tr.mu.Lock()
tr.Elapsed = elapsed
tr.mu.Unlock()
-3
View File
@@ -1,3 +0,0 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.
-3
View File
@@ -1,3 +0,0 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.
+2 -2
View File
@@ -61,8 +61,8 @@ func (g *Group) Wait() error {
// It blocks until the new goroutine can be added without the number of
// active goroutines in the group exceeding the configured limit.
//
// The first call to return a non-nil error cancels the group; its error will be
// returned by Wait.
// The first call to return a non-nil error cancels the group's context, if the
// group was created by calling WithContext. The error will be returned by Wait.
func (g *Group) Go(f func() error) {
if g.sem != nil {
g.sem <- token{}
+4 -1
View File
@@ -6,7 +6,10 @@ package cpu
import "runtime"
const cacheLineSize = 64
// cacheLineSize is used to prevent false sharing of cache lines.
// We choose 128 because Apple Silicon, a.k.a. M1, has 128-byte cache line size.
// It doesn't cost much and is much more future-proof.
const cacheLineSize = 128
func initOptions() {
options = []option{
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !aix && !linux && (ppc64 || ppc64le)
// +build !aix
// +build !linux
// +build ppc64 ppc64le
package cpu
func archInit() {
PPC64.IsPOWER8 = true
Initialized = true
}
+2 -2
View File
@@ -126,7 +126,7 @@ errors=$(
signals=$(
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT' |
sort
)
@@ -136,7 +136,7 @@ echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
sort >_error.grep
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT' |
sort >_signal.grep
echo '// mkerrors.sh' "$@"
+1 -9
View File
@@ -29,8 +29,6 @@ import (
"bytes"
"strings"
"unsafe"
"golang.org/x/sys/internal/unsafeheader"
)
// ByteSliceFromString returns a NUL-terminated slice of bytes
@@ -82,13 +80,7 @@ func BytePtrToString(p *byte) string {
ptr = unsafe.Pointer(uintptr(ptr) + 1)
}
var s []byte
h := (*unsafeheader.Slice)(unsafe.Pointer(&s))
h.Data = unsafe.Pointer(p)
h.Len = n
h.Cap = n
return string(s)
return string(unsafe.Slice(p, n))
}
// Single-word zero for use when we need a valid pointer to 0 bytes.
+31
View File
@@ -0,0 +1,31 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (darwin || freebsd || netbsd || openbsd) && gc
// +build darwin freebsd netbsd openbsd
// +build gc
#include "textflag.h"
//
// System call support for ppc64, BSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
+2 -2
View File
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
package unix
+17 -3
View File
@@ -4,9 +4,7 @@
package unix
import (
"unsafe"
)
import "unsafe"
// IoctlRetInt performs an ioctl operation specified by req on a device
// associated with opened file descriptor fd, and returns a non-negative
@@ -217,3 +215,19 @@ func IoctlKCMAttach(fd int, info KCMAttach) error {
func IoctlKCMUnattach(fd int, info KCMUnattach) error {
return ioctlPtr(fd, SIOCKCMUNATTACH, unsafe.Pointer(&info))
}
// IoctlLoopGetStatus64 gets the status of the loop device associated with the
// file descriptor fd using the LOOP_GET_STATUS64 operation.
func IoctlLoopGetStatus64(fd int) (*LoopInfo64, error) {
var value LoopInfo64
if err := ioctlPtr(fd, LOOP_GET_STATUS64, unsafe.Pointer(&value)); err != nil {
return nil, err
}
return &value, nil
}
// IoctlLoopSetStatus64 sets the status of the loop device associated with the
// file descriptor fd using the LOOP_SET_STATUS64 operation.
func IoctlLoopSetStatus64(fd int, value *LoopInfo64) error {
return ioctlPtr(fd, LOOP_SET_STATUS64, unsafe.Pointer(value))
}

Some files were not shown because too many files have changed in this diff Show More