Release 2017.11.1
This commit is contained in:
parent
82cb539fbe
commit
ff67bd23f2
|
@ -4,7 +4,27 @@ import (
|
|||
"crypto/x509"
|
||||
)
|
||||
|
||||
const cloudflareRootCA = `-----BEGIN CERTIFICATE-----
|
||||
// TODO: remove the Origin CA root certs when migrated to Authenticated Origin Pull certs
|
||||
const cloudflareRootCA = `
|
||||
Issuer: C=US, ST=California, L=San Francisco, O=CloudFlare, Inc., OU=CloudFlare Origin SSL ECC Certificate Authority
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICiDCCAi6gAwIBAgIUXZP3MWb8MKwBE1Qbawsp1sfA/Y4wCgYIKoZIzj0EAwIw
|
||||
gY8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
|
||||
YW4gRnJhbmNpc2NvMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMTgwNgYDVQQL
|
||||
Ey9DbG91ZEZsYXJlIE9yaWdpbiBTU0wgRUNDIENlcnRpZmljYXRlIEF1dGhvcml0
|
||||
eTAeFw0xNjAyMjIxODI0MDBaFw0yMTAyMjIwMDI0MDBaMIGPMQswCQYDVQQGEwJV
|
||||
UzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZ
|
||||
MBcGA1UEChMQQ2xvdWRGbGFyZSwgSW5jLjE4MDYGA1UECxMvQ2xvdWRGbGFyZSBP
|
||||
cmlnaW4gU1NMIEVDQyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwWTATBgcqhkjOPQIB
|
||||
BggqhkjOPQMBBwNCAASR+sGALuaGshnUbcxKry+0LEXZ4NY6JUAtSeA6g87K3jaA
|
||||
xpIg9G50PokpfWkhbarLfpcZu0UAoYy2su0EhN7wo2YwZDAOBgNVHQ8BAf8EBAMC
|
||||
AQYwEgYDVR0TAQH/BAgwBgEB/wIBAjAdBgNVHQ4EFgQUhTBdOypw1O3VkmcH/es5
|
||||
tBoOOKcwHwYDVR0jBBgwFoAUhTBdOypw1O3VkmcH/es5tBoOOKcwCgYIKoZIzj0E
|
||||
AwIDSAAwRQIgEiIEHQr5UKma50D1WRMJBUSgjg24U8n8E2mfw/8UPz0CIQCr5V/e
|
||||
mcifak4CQsr+DH4pn5SJD7JxtCG3YGswW8QZsw==
|
||||
-----END CERTIFICATE-----
|
||||
Issuer: C=US, O=CloudFlare, Inc., OU=CloudFlare Origin SSL Certificate Authority, L=San Francisco, ST=California
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID/DCCAuagAwIBAgIID+rOSdTGfGcwCwYJKoZIhvcNAQELMIGLMQswCQYDVQQG
|
||||
EwJVUzEZMBcGA1UEChMQQ2xvdWRGbGFyZSwgSW5jLjE0MDIGA1UECxMrQ2xvdWRG
|
||||
bGFyZSBPcmlnaW4gU1NMIENlcnRpZmljYXRlIEF1dGhvcml0eTEWMBQGA1UEBxMN
|
||||
|
@ -27,6 +47,42 @@ QGgDl6gRmb8aDwk7Q92BPvek5nMzaWlP82ixavvYI+okoSY8pwdcVKobx6rWzMWz
|
|||
ZEC9M6H3F0dDYE23XcCFIdgNSAmmGyXPBstOe0aAJXwJTxOEPn36VWr0PKIQJy5Y
|
||||
4o1wpMpqCOIwWc8J9REV/REzN6Z1LXImdUgXIXOwrz56gKUJzPejtBQyIGj0mveX
|
||||
Fu6q54beR89jDc+oABmOgg==
|
||||
-----END CERTIFICATE-----
|
||||
Issuer: C=US, O=CloudFlare, Inc., OU=Origin Pull, L=San Francisco, ST=California, CN=origin-pull.cloudflare.net
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGBjCCA/CgAwIBAgIIV5G6lVbCLmEwCwYJKoZIhvcNAQENMIGQMQswCQYDVQQG
|
||||
EwJVUzEZMBcGA1UEChMQQ2xvdWRGbGFyZSwgSW5jLjEUMBIGA1UECxMLT3JpZ2lu
|
||||
IFB1bGwxFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3Ju
|
||||
aWExIzAhBgNVBAMTGm9yaWdpbi1wdWxsLmNsb3VkZmxhcmUubmV0MB4XDTE1MDEx
|
||||
MzAyNDc1M1oXDTIwMDExMjAyNTI1M1owgZAxCzAJBgNVBAYTAlVTMRkwFwYDVQQK
|
||||
ExBDbG91ZEZsYXJlLCBJbmMuMRQwEgYDVQQLEwtPcmlnaW4gUHVsbDEWMBQGA1UE
|
||||
BxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5pYTEjMCEGA1UEAxMa
|
||||
b3JpZ2luLXB1bGwuY2xvdWRmbGFyZS5uZXQwggIiMA0GCSqGSIb3DQEBAQUAA4IC
|
||||
DwAwggIKAoICAQDdsts6I2H5dGyn4adACQRXlfo0KmwsN7B5rxD8C5qgy6spyONr
|
||||
WV0ecvdeGQfWa8Gy/yuTuOnsXfy7oyZ1dm93c3Mea7YkM7KNMc5Y6m520E9tHooc
|
||||
f1qxeDpGSsnWc7HWibFgD7qZQx+T+yfNqt63vPI0HYBOYao6hWd3JQhu5caAcIS2
|
||||
ms5tzSSZVH83ZPe6Lkb5xRgLl3eXEFcfI2DjnlOtLFqpjHuEB3Tr6agfdWyaGEEi
|
||||
lRY1IB3k6TfLTaSiX2/SyJ96bp92wvTSjR7USjDV9ypf7AD6u6vwJZ3bwNisNw5L
|
||||
ptph0FBnc1R6nDoHmvQRoyytoe0rl/d801i9Nru/fXa+l5K2nf1koR3IX440Z2i9
|
||||
+Z4iVA69NmCbT4MVjm7K3zlOtwfI7i1KYVv+ATo4ycgBuZfY9f/2lBhIv7BHuZal
|
||||
b9D+/EK8aMUfjDF4icEGm+RQfExv2nOpkR4BfQppF/dLmkYfjgtO1403X0ihkT6T
|
||||
PYQdmYS6Jf53/KpqC3aA+R7zg2birtvprinlR14MNvwOsDOzsK4p8WYsgZOR4Qr2
|
||||
gAx+z2aVOs/87+TVOR0r14irQsxbg7uP2X4t+EXx13glHxwG+CnzUVycDLMVGvuG
|
||||
aUgF9hukZxlOZnrl6VOf1fg0Caf3uvV8smOkVw6DMsGhBZSJVwao0UQNqQIDAQAB
|
||||
o2YwZDAOBgNVHQ8BAf8EBAMCAAYwEgYDVR0TAQH/BAgwBgEB/wIBAjAdBgNVHQ4E
|
||||
FgQUQ1lLK2mLgOERM2pXzVc42p59xeswHwYDVR0jBBgwFoAUQ1lLK2mLgOERM2pX
|
||||
zVc42p59xeswCwYJKoZIhvcNAQENA4ICAQDKDQM1qPRVP/4Gltz0D6OU6xezFBKr
|
||||
LWtDoA1qW2F7pkiYawCP9MrDPDJsHy7dx+xw3bBZxOsK5PA/T7p1dqpEl6i8F692
|
||||
g//EuYOifLYw3ySPe3LRNhvPl/1f6Sn862VhPvLa8aQAAwR9e/CZvlY3fj+6G5ik
|
||||
3it7fikmKUsVnugNOkjmwI3hZqXfJNc7AtHDFw0mEOV0dSeAPTo95N9cxBbm9PKv
|
||||
qAEmTEXp2trQ/RjJ/AomJyfA1BQjsD0j++DI3a9/BbDwWmr1lJciKxiNKaa0BRLB
|
||||
dKMrYQD+PkPNCgEuojT+paLKRrMyFUzHSG1doYm46NE9/WARTh3sFUp1B7HZSBqA
|
||||
kHleoB/vQ/mDuW9C3/8Jk2uRUdZxR+LoNZItuOjU8oTy6zpN1+GgSj7bHjiy9rfA
|
||||
F+ehdrz+IOh80WIiqs763PGoaYUyzxLvVowLWNoxVVoc9G+PqFKqD988XlipHVB6
|
||||
Bz+1CD4D/bWrs3cC9+kk/jFmrrAymZlkFX8tDb5aXASSLJjUjcptci9SKqtI2h0J
|
||||
wUGkD7+bQAr+7vr8/R+CBmNMe7csE8NeEX6lVMF7Dh0a1YKQa6hUN18bBuYgTMuT
|
||||
QzMmZpRpIBB321ZBlcnlxiTJvWxvbCPHKHj20VwwAz7LONF59s84ZsOqfoBv8gKM
|
||||
s0s5dsq5zpLeaw==
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
func GetCloudflareRootCA() *x509.CertPool {
|
||||
|
|
|
@ -4,23 +4,21 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/cloudflare/cloudflare-warp/origin"
|
||||
tunnelpogs "github.com/cloudflare/cloudflare-warp/tunnelrpc/pogs"
|
||||
cli "gopkg.in/urfave/cli.v2"
|
||||
)
|
||||
|
||||
type templateData struct {
|
||||
ServerName string
|
||||
Request *http.Request
|
||||
Tags []tunnelpogs.Tag
|
||||
Body string
|
||||
}
|
||||
|
||||
const defaultServerName = "the Cloudflare Warp test server"
|
||||
|
@ -42,7 +40,7 @@ const indexTemplate = `
|
|||
</style>
|
||||
</head>
|
||||
<body class="sans-serif black">
|
||||
<div class="bt bw2 b--orange bg-white pb6">
|
||||
<div class="bt bw2 b--orange bg-white pb6">
|
||||
<div class="mw7 center ph4 pt3">
|
||||
<svg id="Layer_2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 109 40.5" class="mw4">
|
||||
<path class="st0" d="M98.6 14.2L93 12.9l-1-.4-25.7.2v12.4l32.3.1z"/>
|
||||
|
@ -56,21 +54,30 @@ const indexTemplate = `
|
|||
running an encrypted, virtual tunnel from your laptop or server to
|
||||
Cloudflare's edge network.
|
||||
</p>
|
||||
<p class="b f5 mt5 fw6">Ready for the next step?</p>
|
||||
<a
|
||||
class="fw6 link white bg-blue ph4 pv2 br1 dib f5 link-hover"
|
||||
<p class="b f5 mt5 fw6">Ready for the next step?</p>
|
||||
<a
|
||||
class="fw6 link white bg-blue ph4 pv2 br1 dib f5 link-hover"
|
||||
style="border-bottom: 1px solid #1f679e"
|
||||
href="https://warp.cloudflare.com">
|
||||
Get started here
|
||||
</a>
|
||||
{{if .Tags}} <section>
|
||||
<h4 class="f6 fw4 pt5 mb2">Connection</h4>
|
||||
<section>
|
||||
<h4 class="f6 fw4 pt5 mb2">Request</h4>
|
||||
<dl class="bl bw2 b--orange ph3 pt3 pb2 bg-light-gray f7 code overflow-x-auto mw-100">
|
||||
{{range .Tags}} <dt class="ttu mb1">{{.Name}}</dt>
|
||||
<dd class="ml0 mb3 f5">{{.Value}}</dd>
|
||||
{{end}} </dl>
|
||||
<dd class="ml0 mb3 f5">Method: {{.Request.Method}}</dd>
|
||||
<dd class="ml0 mb3 f5">Protocol: {{.Request.Proto}}</dd>
|
||||
<dd class="ml0 mb3 f5">Request URL: {{.Request.URL}}</dd>
|
||||
<dd class="ml0 mb3 f5">Transfer encoding: {{.Request.TransferEncoding}}</dd>
|
||||
<dd class="ml0 mb3 f5">Host: {{.Request.Host}}</dd>
|
||||
<dd class="ml0 mb3 f5">Remote address: {{.Request.RemoteAddr}}</dd>
|
||||
<dd class="ml0 mb3 f5">Request URI: {{.Request.RequestURI}}</dd>
|
||||
{{range $key, $value := .Request.Header}}
|
||||
<dd class="ml0 mb3 f5">Header: {{$key}}, Value: {{$value}}</dd>
|
||||
{{end}}
|
||||
<dd class="ml0 mb3 f5">Body: {{.Body}}</dd>
|
||||
</dl>
|
||||
</section>
|
||||
{{end}} </div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -127,10 +134,17 @@ func (s *HelloWorldServer) ListenAndServe(address string) error {
|
|||
func (s *HelloWorldServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
log.WithField("client", r.RemoteAddr).Infof("%s %s %s", r.Method, r.URL, r.Proto)
|
||||
var buffer bytes.Buffer
|
||||
err := s.responseTemplate.Execute(&buffer, &templateData{
|
||||
var body string
|
||||
rawBody, err := ioutil.ReadAll(r.Body)
|
||||
if err == nil {
|
||||
body = string(rawBody)
|
||||
} else {
|
||||
body = ""
|
||||
}
|
||||
err = s.responseTemplate.Execute(&buffer, &templateData{
|
||||
ServerName: s.serverName,
|
||||
Request: r,
|
||||
Tags: tagsFromHeaders(r.Header),
|
||||
Body: body,
|
||||
})
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
@ -139,17 +153,3 @@ func (s *HelloWorldServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
buffer.WriteTo(w)
|
||||
}
|
||||
}
|
||||
|
||||
func tagsFromHeaders(header http.Header) []tunnelpogs.Tag {
|
||||
var tags []tunnelpogs.Tag
|
||||
for headerName, headerValues := range header {
|
||||
trimmed := strings.TrimPrefix(headerName, origin.TagHeaderNamePrefix)
|
||||
if trimmed == headerName {
|
||||
continue
|
||||
}
|
||||
for _, value := range headerValues {
|
||||
tags = append(tags, tunnelpogs.Tag{Name: trimmed, Value: value})
|
||||
}
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
|
|
@ -29,6 +29,8 @@ func runApp(app *cli.App) {
|
|||
app.Run(os.Args)
|
||||
}
|
||||
|
||||
const serviceConfigDir = "/etc/cloudflare-warp"
|
||||
|
||||
var systemdTemplates = []ServiceTemplate{
|
||||
{
|
||||
Path: "/etc/systemd/system/cloudflare-warp.service",
|
||||
|
@ -39,8 +41,7 @@ After=network.target
|
|||
[Service]
|
||||
TimeoutStartSec=0
|
||||
Type=notify
|
||||
ExecStart={{ .Path }} --config /etc/cloudflare-warp.yml --autoupdate 0s
|
||||
User=nobody
|
||||
ExecStart={{ .Path }} --config /etc/cloudflare-warp/config.yml --origincert /etc/cloudflare-warp/cert.pem --autoupdate 0s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
@ -86,7 +87,7 @@ var sysvTemplate = ServiceTemplate{
|
|||
# Short-Description: Cloudflare Warp
|
||||
# Description: Cloudflare Warp agent
|
||||
### END INIT INFO
|
||||
cmd="{{.Path}} --config /etc/cloudflare-warp.yml --pidfile /var/run/$name.pid"
|
||||
cmd="{{.Path}} --config /etc/cloudflare-warp/config.yml --origincert /etc/cloudflare-warp/cert.pem --pidfile /var/run/$name.pid"
|
||||
name=$(basename $(readlink -f $0))
|
||||
pid_file="/var/run/$name.pid"
|
||||
stdout_log="/var/log/$name.log"
|
||||
|
@ -177,6 +178,12 @@ func installLinuxService(c *cli.Context) error {
|
|||
}
|
||||
templateArgs := ServiceTemplateArgs{Path: etPath}
|
||||
|
||||
if err = copyCredentials(serviceConfigDir); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to copy user configuration: %v\n", err)
|
||||
fmt.Fprintf(os.Stderr, "Before running the service, ensure that %s contains two files, %s and %s",
|
||||
serviceConfigDir, credentialFile, configFile)
|
||||
}
|
||||
|
||||
switch {
|
||||
case isSystemd():
|
||||
return installSystemd(&templateArgs)
|
||||
|
|
|
@ -1,31 +1,195 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base32"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
homedir "github.com/mitchellh/go-homedir"
|
||||
cli "gopkg.in/urfave/cli.v2"
|
||||
)
|
||||
|
||||
const baseLoginURL = "https://www.cloudflare.com/a/warp"
|
||||
const baseCertStoreURL = "https://login.cloudflarewarp.com"
|
||||
const clientTimeout = time.Minute * 20
|
||||
|
||||
func login(c *cli.Context) error {
|
||||
path, err := homedir.Expand(defaultConfigPath)
|
||||
configPath, err := homedir.Expand(defaultConfigDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ok, err := fileExists(configPath)
|
||||
if !ok && err == nil {
|
||||
// create config directory if doesn't already exist
|
||||
err = os.Mkdir(configPath, 0700)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path := filepath.Join(configPath, credentialFile)
|
||||
fileInfo, err := os.Stat(path)
|
||||
if err == nil && fileInfo.Size() > 0 {
|
||||
fmt.Fprintf(os.Stderr, `You have an existing config file at %s which login would overwrite.
|
||||
fmt.Fprintf(os.Stderr, `You have an existing certificate at %s which login would overwrite.
|
||||
If this is intentional, please move or delete that file then run this command again.
|
||||
`, defaultConfigPath)
|
||||
`, path)
|
||||
return nil
|
||||
}
|
||||
if err != nil && err.(*os.PathError).Err != syscall.ENOENT {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stderr, "Please visit https://www.cloudflare.com/a/warp to obtain a certificate.")
|
||||
// for local debugging
|
||||
baseURL := baseCertStoreURL
|
||||
if c.IsSet("url") {
|
||||
baseURL = c.String("url")
|
||||
}
|
||||
// Generate a random post URL
|
||||
certURL := baseURL + generateRandomPath()
|
||||
loginURL, err := url.Parse(baseLoginURL)
|
||||
if err != nil {
|
||||
// shouldn't happen, URL is hardcoded
|
||||
return err
|
||||
}
|
||||
loginURL.RawQuery = "callback=" + url.QueryEscape(certURL)
|
||||
|
||||
err = open(loginURL.String())
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, `Please open the following URL and log in with your Cloudflare account:
|
||||
|
||||
%s
|
||||
|
||||
Leave cloudflare-warp running to install the certificate automatically.
|
||||
`, loginURL.String())
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, `A browser window should have opened at the following URL:
|
||||
|
||||
%s
|
||||
|
||||
If the browser failed to open, open it yourself and visit the URL above.
|
||||
|
||||
`, loginURL.String())
|
||||
}
|
||||
|
||||
if download(certURL, path) {
|
||||
fmt.Fprintf(os.Stderr, `You have successfully logged in.
|
||||
If you wish to copy your credentials to a server, they have been saved to:
|
||||
%s
|
||||
`, path)
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, `Failed to write the certificate due to the following error:
|
||||
%v
|
||||
|
||||
Your browser will download the certificate instead. You will have to manually
|
||||
copy it to the following path:
|
||||
|
||||
%s
|
||||
|
||||
`, err, path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateRandomPath generates a random URL to associate with the certificate.
|
||||
func generateRandomPath() string {
|
||||
randomBytes := make([]byte, 40)
|
||||
_, err := rand.Read(randomBytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return "/" + base32.StdEncoding.EncodeToString(randomBytes)
|
||||
}
|
||||
|
||||
// open opens the specified URL in the default browser of the user.
|
||||
func open(url string) error {
|
||||
var cmd string
|
||||
var args []string
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
cmd = "cmd"
|
||||
args = []string{"/c", "start"}
|
||||
case "darwin":
|
||||
cmd = "open"
|
||||
default: // "linux", "freebsd", "openbsd", "netbsd"
|
||||
cmd = "xdg-open"
|
||||
}
|
||||
args = append(args, url)
|
||||
return exec.Command(cmd, args...).Start()
|
||||
}
|
||||
|
||||
func download(certURL, filePath string) bool {
|
||||
client := &http.Client{Timeout: clientTimeout}
|
||||
// attempt a (long-running) certificate get
|
||||
for i := 0; i < 20; i++ {
|
||||
ok, err := tryDownload(client, certURL, filePath)
|
||||
if ok {
|
||||
putSuccess(client, certURL)
|
||||
return true
|
||||
}
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error fetching certificate")
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func tryDownload(client *http.Client, certURL, filePath string) (ok bool, err error) {
|
||||
resp, err := client.Get(certURL)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode == 404 {
|
||||
return false, nil
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return false, fmt.Errorf("Unexpected HTTP error code %d", resp.StatusCode)
|
||||
}
|
||||
if resp.Header.Get("Content-Type") != "application/x-pem-file" {
|
||||
return false, fmt.Errorf("Unexpected content type %s", resp.Header.Get("Content-Type"))
|
||||
}
|
||||
// write response
|
||||
file, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer file.Close()
|
||||
written, err := io.Copy(file, resp.Body)
|
||||
switch {
|
||||
case err != nil:
|
||||
return false, err
|
||||
case resp.ContentLength != written && resp.ContentLength != -1:
|
||||
return false, fmt.Errorf("Short read (%d bytes) from server while writing certificate", written)
|
||||
default:
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
func putSuccess(client *http.Client, certURL string) {
|
||||
// indicate success to the relay server
|
||||
req, err := http.NewRequest("PUT", certURL+"/ok", nil)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("HTTP request error")
|
||||
return
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("HTTP error")
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
log.Errorf("Unexpected HTTP error code %d", resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,12 @@ import (
|
|||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
@ -31,7 +33,9 @@ import (
|
|||
)
|
||||
|
||||
const sentryDSN = "https://56a9c9fa5c364ab28f34b14f35ea0f1b:3e8827f6f9f740738eb11138f7bebb68@sentry.io/189878"
|
||||
const defaultConfigPath = "~/.cloudflare-warp.yml"
|
||||
const defaultConfigDir = "~/.cloudflare-warp"
|
||||
const credentialFile = "cert.pem"
|
||||
const configFile = "config.yml"
|
||||
|
||||
var listeners = gracenet.Net{}
|
||||
var Version = "DEV"
|
||||
|
@ -71,10 +75,15 @@ WARNING:
|
|||
Usage: "Specifies a config file in YAML format.",
|
||||
},
|
||||
altsrc.NewDurationFlag(&cli.DurationFlag{
|
||||
Name: "autoupdate",
|
||||
Usage: "Periodically check for updates, restarting the server with the new version.",
|
||||
Name: "autoupdate-freq",
|
||||
Usage: "Autoupdate frequency. Default is 24h.",
|
||||
Value: time.Hour * 24,
|
||||
}),
|
||||
altsrc.NewBoolFlag(&cli.BoolFlag{
|
||||
Name: "no-autoupdate",
|
||||
Usage: "Disable periodic check for updates, restarting the server with the new version.",
|
||||
Value: false,
|
||||
}),
|
||||
altsrc.NewStringFlag(&cli.StringFlag{
|
||||
Name: "edge",
|
||||
Value: "cftunnel.com:7844",
|
||||
|
@ -88,6 +97,12 @@ WARNING:
|
|||
EnvVars: []string{"TUNNEL_CACERT"},
|
||||
Hidden: true,
|
||||
}),
|
||||
altsrc.NewStringFlag(&cli.StringFlag{
|
||||
Name: "origincert",
|
||||
Usage: "Path to the certificate generated for your origin when you run cloudflare-warp login.",
|
||||
EnvVars: []string{"ORIGIN_CERT"},
|
||||
Value: filepath.Join(defaultConfigDir, credentialFile),
|
||||
}),
|
||||
altsrc.NewStringFlag(&cli.StringFlag{
|
||||
Name: "url",
|
||||
Value: "http://localhost:8080",
|
||||
|
@ -112,18 +127,21 @@ WARNING:
|
|||
}),
|
||||
altsrc.NewStringFlag(&cli.StringFlag{
|
||||
Name: "api-key",
|
||||
Usage: "A Cloudflare API key. Required(can be in the config file) unless you are only running the hello command or login command.",
|
||||
Usage: "This parameter has been deprecated since version 2017.10.1.",
|
||||
EnvVars: []string{"TUNNEL_API_KEY"},
|
||||
Hidden: true,
|
||||
}),
|
||||
altsrc.NewStringFlag(&cli.StringFlag{
|
||||
Name: "api-email",
|
||||
Usage: "The Cloudflare user's email address associated with the API key. Required(can be in the config file) unless you are only running the hello command or login command.",
|
||||
Usage: "This parameter has been deprecated since version 2017.10.1.",
|
||||
EnvVars: []string{"TUNNEL_API_EMAIL"},
|
||||
Hidden: true,
|
||||
}),
|
||||
altsrc.NewStringFlag(&cli.StringFlag{
|
||||
Name: "api-ca-key",
|
||||
Usage: "The Origin CA service key associated with the user. Required(can be in the config file) unless you are only running the hello command or login command.",
|
||||
Usage: "This parameter has been deprecated since version 2017.10.1.",
|
||||
EnvVars: []string{"TUNNEL_API_CA_KEY"},
|
||||
Hidden: true,
|
||||
}),
|
||||
altsrc.NewStringFlag(&cli.StringFlag{
|
||||
Name: "metrics",
|
||||
|
@ -160,12 +178,6 @@ WARNING:
|
|||
Usage: "Maximum number of retries for connection/protocol errors.",
|
||||
EnvVars: []string{"TUNNEL_RETRIES"},
|
||||
}),
|
||||
altsrc.NewBoolFlag(&cli.BoolFlag{
|
||||
Name: "debug",
|
||||
Value: false,
|
||||
Usage: "Enable HTTP requests to the autogenerated cftunnel.com domain.",
|
||||
EnvVars: []string{"TUNNEL_DEBUG"},
|
||||
}),
|
||||
altsrc.NewBoolFlag(&cli.BoolFlag{
|
||||
Name: "hello-world",
|
||||
Usage: "Run Hello World Server",
|
||||
|
@ -207,6 +219,12 @@ WARNING:
|
|||
Action: login,
|
||||
Usage: "Generate a configuration file with your login details",
|
||||
ArgsUsage: " ",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "url",
|
||||
Hidden: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
&cli.Command{
|
||||
Name: "hello",
|
||||
|
@ -239,6 +257,7 @@ func startServer(c *cli.Context) {
|
|||
if err != nil {
|
||||
log.WithError(err).Fatal("Unknown logging level specified")
|
||||
}
|
||||
|
||||
log.SetLevel(logLevel)
|
||||
hostname, err := validation.ValidateHostname(c.String("hostname"))
|
||||
if err != nil {
|
||||
|
@ -260,7 +279,6 @@ func startServer(c *cli.Context) {
|
|||
if c.IsSet("hello-world") {
|
||||
wg.Add(1)
|
||||
listener, err := findAvailablePort()
|
||||
|
||||
if err != nil {
|
||||
listener.Close()
|
||||
log.WithError(err).Fatal("Cannot start Hello World Server")
|
||||
|
@ -268,32 +286,50 @@ func startServer(c *cli.Context) {
|
|||
go func() {
|
||||
startHelloWorldServer(listener, shutdownC)
|
||||
wg.Done()
|
||||
listener.Close()
|
||||
}()
|
||||
c.Set("url", "http://"+listener.Addr().String())
|
||||
log.Infof("Starting Hello World Server at %s", c.String("url"))
|
||||
}
|
||||
|
||||
url, err := validateUrl(c)
|
||||
if err != nil {
|
||||
log.WithError(err).Fatal("Error validating url")
|
||||
}
|
||||
// User must have api-key, api-email and api-ca-key
|
||||
if !c.IsSet("api-key") {
|
||||
log.Fatal("You need to give us your api-key either via the --api-key option or put it in the configuration file. You will also need to give us your api-email and api-ca-key.")
|
||||
}
|
||||
if !c.IsSet("api-email") {
|
||||
log.Fatal("You need to give us your api-email either via the --api-email option or put it in the configuration file. You will also need to give us your api-ca-key.")
|
||||
}
|
||||
if !c.IsSet("api-ca-key") {
|
||||
log.Fatal("You need to give us your api-ca-key either via the --api-ca-key option or put it in the configuration file.")
|
||||
}
|
||||
log.Infof("Proxying tunnel requests to %s", url)
|
||||
|
||||
// Fail if the user provided an old authentication method
|
||||
if c.IsSet("api-key") || c.IsSet("api-email") || c.IsSet("api-ca-key") {
|
||||
log.Fatal("You don't need to give us your api-key anymore. Please use the new log in method. Just run cloudflare-warp login")
|
||||
}
|
||||
|
||||
// Check that the user has acquired a certificate using the log in command
|
||||
originCertPath, err := homedir.Expand(c.String("origincert"))
|
||||
if err != nil {
|
||||
log.WithError(err).Fatalf("Cannot resolve path %s", c.String("origincert"))
|
||||
}
|
||||
ok, err := fileExists(originCertPath)
|
||||
if !ok {
|
||||
log.Fatalf(`Cannot find a valid certificate for your origin at the path:
|
||||
|
||||
%s
|
||||
|
||||
If the path above is wrong, specify the path with the -origincert option.
|
||||
If you don't have a certificate signed by Cloudflare, run the command:
|
||||
|
||||
%s login
|
||||
`, originCertPath, os.Args[0])
|
||||
}
|
||||
// Easier to send the certificate as []byte via RPC than decoding it at this point
|
||||
originCert, err := ioutil.ReadFile(originCertPath)
|
||||
if err != nil {
|
||||
log.WithError(err).Fatalf("Cannot read %s to load origin certificate", originCertPath)
|
||||
}
|
||||
tunnelConfig := &origin.TunnelConfig{
|
||||
EdgeAddr: c.String("edge"),
|
||||
OriginUrl: url,
|
||||
Hostname: hostname,
|
||||
APIKey: c.String("api-key"),
|
||||
APIEmail: c.String("api-email"),
|
||||
APICAKey: c.String("api-ca-key"),
|
||||
OriginCert: originCert,
|
||||
TlsConfig: &tls.Config{},
|
||||
Retries: c.Uint("retries"),
|
||||
HeartbeatInterval: c.Duration("heartbeat-interval"),
|
||||
|
@ -302,7 +338,6 @@ func startServer(c *cli.Context) {
|
|||
ReportedVersion: Version,
|
||||
LBPool: c.String("lb-pool"),
|
||||
Tags: tags,
|
||||
AccessInternalIP: c.Bool("debug"),
|
||||
ConnectedSignal: h2mux.NewSignal(),
|
||||
}
|
||||
|
||||
|
@ -329,7 +364,10 @@ func startServer(c *cli.Context) {
|
|||
wg.Done()
|
||||
}()
|
||||
|
||||
go autoupdate(c.Duration("autoupdate"), shutdownC)
|
||||
if !c.Bool("no-autoupdate") {
|
||||
log.Infof("Autoupdate frequency is set to %v", c.Duration("autoupdate-freq"))
|
||||
go autoupdate(c.Duration("autoupdate-period"), shutdownC)
|
||||
}
|
||||
|
||||
err = WaitForSignal(errC, shutdownC)
|
||||
if err != nil {
|
||||
|
@ -413,21 +451,14 @@ func findInputSourceContext(context *cli.Context) (altsrc.InputSourceContext, er
|
|||
if context.IsSet("config") {
|
||||
return altsrc.NewYamlSourceFromFile(context.String("config"))
|
||||
}
|
||||
for _, tryPath := range []string{
|
||||
defaultConfigPath,
|
||||
"~/.cloudflare-warp.yaml",
|
||||
"~/cloudflare-warp.yaml",
|
||||
"~/cloudflare-warp.yml",
|
||||
"~/.et.yaml",
|
||||
"~/et.yml",
|
||||
"~/et.yaml",
|
||||
"~/.cftunnel.yaml", // for existing users
|
||||
"~/cftunnel.yaml",
|
||||
dirPath, err := homedir.Expand(defaultConfigDir)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
for _, path := range []string{
|
||||
filepath.Join(dirPath, "/config.yml"),
|
||||
filepath.Join(dirPath, "/config.yaml"),
|
||||
} {
|
||||
path, err := homedir.Expand(tryPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
ok, err := fileExists(path)
|
||||
if ok {
|
||||
return altsrc.NewYamlSourceFromFile(path)
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"text/template"
|
||||
|
||||
homedir "github.com/mitchellh/go-homedir"
|
||||
|
@ -78,7 +81,7 @@ func runCommand(command string, args ...string) error {
|
|||
}
|
||||
commandErr, _ := ioutil.ReadAll(stderr)
|
||||
if len(commandErr) > 0 {
|
||||
return fmt.Errorf("%s error: %s", command, commandErr)
|
||||
fmt.Fprintf(os.Stderr, "%s: %s", command, commandErr)
|
||||
}
|
||||
err = cmd.Wait()
|
||||
if err != nil {
|
||||
|
@ -86,3 +89,100 @@ func runCommand(command string, args ...string) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ensureConfigDirExists(configDir string) error {
|
||||
ok, err := fileExists(configDir)
|
||||
if !ok && err == nil {
|
||||
err = os.Mkdir(configDir, 0700)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// openFile opens the file at path. If create is set and the file exists, returns nil, true, nil
|
||||
func openFile(path string, create bool) (file *os.File, exists bool, err error) {
|
||||
expandedPath, err := homedir.Expand(path)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
if create {
|
||||
fileInfo, err := os.Stat(expandedPath)
|
||||
if err == nil && fileInfo.Size() > 0 {
|
||||
return nil, true, nil
|
||||
}
|
||||
file, err = os.OpenFile(expandedPath, os.O_RDWR|os.O_CREATE, 0600)
|
||||
} else {
|
||||
file, err = os.Open(expandedPath)
|
||||
}
|
||||
return file, false, err
|
||||
}
|
||||
|
||||
func copyCertificate(configDir string) error {
|
||||
// Copy certificate
|
||||
destCredentialPath := filepath.Join(configDir, credentialFile)
|
||||
destFile, exists, err := openFile(destCredentialPath, true)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if exists {
|
||||
// credentials already exist, do nothing
|
||||
return nil
|
||||
}
|
||||
defer destFile.Close()
|
||||
|
||||
srcCredentialPath := filepath.Join(defaultConfigDir, credentialFile)
|
||||
srcFile, _, err := openFile(srcCredentialPath, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
_, err = io.Copy(destFile, srcFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to copy %s to %s: %v", srcCredentialPath, destCredentialPath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyCredentials(configDir string) error {
|
||||
if err := ensureConfigDirExists(configDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := copyCertificate(configDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Copy or create config
|
||||
destConfigPath := filepath.Join(configDir, configFile)
|
||||
destFile, exists, err := openFile(destConfigPath, true)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if exists {
|
||||
// config already exists, do nothing
|
||||
return nil
|
||||
}
|
||||
defer destFile.Close()
|
||||
|
||||
srcConfigPath := filepath.Join(defaultConfigDir, configFile)
|
||||
srcFile, _, err := openFile(srcConfigPath, false)
|
||||
if err != nil {
|
||||
fmt.Println("Your service needs a config file that at least specifies the hostname option.")
|
||||
fmt.Println("Type in a hostname now, or leave it blank and create the config file later.")
|
||||
fmt.Print("Hostname: ")
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
input, _ := reader.ReadString('\n')
|
||||
if input == "" {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(destFile, "hostname: %s\n", input)
|
||||
} else {
|
||||
defer srcFile.Close()
|
||||
_, err = io.Copy(destFile, srcFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to copy %s to %s: %v", srcConfigPath, destConfigPath, err)
|
||||
}
|
||||
fmt.Printf("Copied %s to %s", srcConfigPath, destConfigPath)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -34,9 +34,7 @@ type TunnelConfig struct {
|
|||
EdgeAddr string
|
||||
OriginUrl string
|
||||
Hostname string
|
||||
APIKey string
|
||||
APIEmail string
|
||||
APICAKey string
|
||||
OriginCert []byte
|
||||
TlsConfig *tls.Config
|
||||
Retries uint
|
||||
HeartbeatInterval time.Duration
|
||||
|
@ -45,7 +43,6 @@ type TunnelConfig struct {
|
|||
ReportedVersion string
|
||||
LBPool string
|
||||
Tags []tunnelpogs.Tag
|
||||
AccessInternalIP bool
|
||||
ConnectedSignal h2mux.Signal
|
||||
}
|
||||
|
||||
|
@ -78,7 +75,6 @@ func (c *TunnelConfig) RegistrationOptions() *tunnelpogs.RegistrationOptions {
|
|||
ExistingTunnelPolicy: policy,
|
||||
PoolID: c.LBPool,
|
||||
Tags: c.Tags,
|
||||
ExposeInternalHostname: c.AccessInternalIP,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,15 +142,16 @@ func ServeTunnel(
|
|||
return err, true
|
||||
}
|
||||
if registerErr != nil {
|
||||
raven.CaptureError(registerErr, nil)
|
||||
// Don't retry on errors like entitlement failure or version too old
|
||||
if e, ok := registerErr.(printableRegisterTunnelError); ok {
|
||||
log.WithError(e).Error("Cannot register")
|
||||
log.Error(e)
|
||||
if e.permanent {
|
||||
return nil, false
|
||||
}
|
||||
return e.cause, true
|
||||
}
|
||||
// Only log errors to Sentry that may have been caused by the client side, to reduce dupes
|
||||
raven.CaptureError(registerErr, nil)
|
||||
log.Error("Cannot register")
|
||||
return err, true
|
||||
}
|
||||
|
@ -202,7 +199,7 @@ func RegisterTunnel(ctx context.Context, muxer *h2mux.Muxer, config *TunnelConfi
|
|||
})
|
||||
registration, err := ts.RegisterTunnel(
|
||||
ctx,
|
||||
&tunnelpogs.Authentication{Key: config.APIKey, Email: config.APIEmail, OriginCAKey: config.APICAKey},
|
||||
config.OriginCert,
|
||||
config.Hostname,
|
||||
config.RegistrationOptions(),
|
||||
)
|
||||
|
@ -220,9 +217,9 @@ func RegisterTunnel(ctx context.Context, muxer *h2mux.Muxer, config *TunnelConfi
|
|||
permanent: registration.PermanentFailure,
|
||||
}
|
||||
}
|
||||
for _, url := range registration.Urls {
|
||||
log.Infof("Registered at %s", url)
|
||||
}
|
||||
|
||||
log.Infof("Registered at %s", registration.Url)
|
||||
|
||||
for _, logLine := range registration.LogLines {
|
||||
log.Infof(logLine)
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ func UnmarshalAuthentication(s tunnelrpc.Authentication) (*Authentication, error
|
|||
|
||||
type TunnelRegistration struct {
|
||||
Err string
|
||||
Urls []string
|
||||
Url string
|
||||
LogLines []string
|
||||
PermanentFailure bool
|
||||
}
|
||||
|
@ -48,7 +48,6 @@ type RegistrationOptions struct {
|
|||
OS string `capnp:"os"`
|
||||
ExistingTunnelPolicy tunnelrpc.ExistingTunnelPolicy
|
||||
PoolID string `capnp:"poolId"`
|
||||
ExposeInternalHostname bool
|
||||
Tags []Tag
|
||||
}
|
||||
|
||||
|
@ -82,7 +81,7 @@ func UnmarshalServerInfo(s tunnelrpc.ServerInfo) (*ServerInfo, error) {
|
|||
}
|
||||
|
||||
type TunnelServer interface {
|
||||
RegisterTunnel(ctx context.Context, auth *Authentication, hostname string, options *RegistrationOptions) (*TunnelRegistration, error)
|
||||
RegisterTunnel(ctx context.Context, originCert []byte, hostname string, options *RegistrationOptions) (*TunnelRegistration, error)
|
||||
GetServerInfo(ctx context.Context) (*ServerInfo, error)
|
||||
}
|
||||
|
||||
|
@ -95,11 +94,7 @@ type TunnelServer_PogsImpl struct {
|
|||
}
|
||||
|
||||
func (i TunnelServer_PogsImpl) RegisterTunnel(p tunnelrpc.TunnelServer_registerTunnel) error {
|
||||
authentication, err := p.Params.Auth()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pogsAuthentication, err := UnmarshalAuthentication(authentication)
|
||||
originCert, err := p.Params.OriginCert()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -116,7 +111,7 @@ func (i TunnelServer_PogsImpl) RegisterTunnel(p tunnelrpc.TunnelServer_registerT
|
|||
return err
|
||||
}
|
||||
server.Ack(p.Options)
|
||||
registration, err := i.impl.RegisterTunnel(p.Ctx, pogsAuthentication, hostname, pogsOptions)
|
||||
registration, err := i.impl.RegisterTunnel(p.Ctx, originCert, hostname, pogsOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -149,14 +144,10 @@ func (c TunnelServer_PogsClient) Close() error {
|
|||
return c.Conn.Close()
|
||||
}
|
||||
|
||||
func (c TunnelServer_PogsClient) RegisterTunnel(ctx context.Context, auth *Authentication, hostname string, options *RegistrationOptions) (*TunnelRegistration, error) {
|
||||
func (c TunnelServer_PogsClient) RegisterTunnel(ctx context.Context, originCert []byte, hostname string, options *RegistrationOptions) (*TunnelRegistration, error) {
|
||||
client := tunnelrpc.TunnelServer{Client: c.Client}
|
||||
promise := client.RegisterTunnel(ctx, func(p tunnelrpc.TunnelServer_registerTunnel_Params) error {
|
||||
authentication, err := p.NewAuth()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = MarshalAuthentication(authentication, auth)
|
||||
err := p.SetOriginCert(originCert)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ struct Authentication {
|
|||
|
||||
struct TunnelRegistration {
|
||||
err @0 :Text;
|
||||
# A list of URLs that the tunnel is accessible from.
|
||||
urls @1 :List(Text);
|
||||
# the url to access the tunnel
|
||||
url @1 :Text;
|
||||
# Used to inform the client of actions taken.
|
||||
logLines @2 :List(Text);
|
||||
# In case of error, whether the client should attempt to reconnect.
|
||||
|
@ -29,10 +29,8 @@ struct RegistrationOptions {
|
|||
existingTunnelPolicy @3 :ExistingTunnelPolicy;
|
||||
# If using the balancing policy, identifies the LB pool to use.
|
||||
poolId @4 :Text;
|
||||
# Prevents the tunnel from being accessed at <subdomain>.cftunnel.com
|
||||
exposeInternalHostname @5 :Bool;
|
||||
# Client-defined tags to associate with the tunnel
|
||||
tags @6 :List(Tag);
|
||||
tags @5 :List(Tag);
|
||||
}
|
||||
|
||||
struct Tag {
|
||||
|
@ -51,6 +49,6 @@ struct ServerInfo {
|
|||
}
|
||||
|
||||
interface TunnelServer {
|
||||
registerTunnel @0 (auth :Authentication, hostname :Text, options :RegistrationOptions) -> (result :TunnelRegistration);
|
||||
registerTunnel @0 (originCert :Data, hostname :Text, options :RegistrationOptions) -> (result :TunnelRegistration);
|
||||
getServerInfo @1 () -> (result :ServerInfo);
|
||||
}
|
||||
|
|
|
@ -157,29 +157,23 @@ func (s TunnelRegistration) SetErr(v string) error {
|
|||
return s.Struct.SetText(0, v)
|
||||
}
|
||||
|
||||
func (s TunnelRegistration) Urls() (capnp.TextList, error) {
|
||||
func (s TunnelRegistration) Url() (string, error) {
|
||||
p, err := s.Struct.Ptr(1)
|
||||
return capnp.TextList{List: p.List()}, err
|
||||
return p.Text(), err
|
||||
}
|
||||
|
||||
func (s TunnelRegistration) HasUrls() bool {
|
||||
func (s TunnelRegistration) HasUrl() bool {
|
||||
p, err := s.Struct.Ptr(1)
|
||||
return p.IsValid() || err != nil
|
||||
}
|
||||
|
||||
func (s TunnelRegistration) SetUrls(v capnp.TextList) error {
|
||||
return s.Struct.SetPtr(1, v.List.ToPtr())
|
||||
func (s TunnelRegistration) UrlBytes() ([]byte, error) {
|
||||
p, err := s.Struct.Ptr(1)
|
||||
return p.TextBytes(), err
|
||||
}
|
||||
|
||||
// NewUrls sets the urls field to a newly
|
||||
// allocated capnp.TextList, preferring placement in s's segment.
|
||||
func (s TunnelRegistration) NewUrls(n int32) (capnp.TextList, error) {
|
||||
l, err := capnp.NewTextList(s.Struct.Segment(), n)
|
||||
if err != nil {
|
||||
return capnp.TextList{}, err
|
||||
}
|
||||
err = s.Struct.SetPtr(1, l.List.ToPtr())
|
||||
return l, err
|
||||
func (s TunnelRegistration) SetUrl(v string) error {
|
||||
return s.Struct.SetText(1, v)
|
||||
}
|
||||
|
||||
func (s TunnelRegistration) LogLines() (capnp.TextList, error) {
|
||||
|
@ -349,14 +343,6 @@ func (s RegistrationOptions) SetPoolId(v string) error {
|
|||
return s.Struct.SetText(3, v)
|
||||
}
|
||||
|
||||
func (s RegistrationOptions) ExposeInternalHostname() bool {
|
||||
return s.Struct.Bit(16)
|
||||
}
|
||||
|
||||
func (s RegistrationOptions) SetExposeInternalHostname(v bool) {
|
||||
s.Struct.SetBit(16, v)
|
||||
}
|
||||
|
||||
func (s RegistrationOptions) Tags() (Tag_List, error) {
|
||||
p, err := s.Struct.Ptr(4)
|
||||
return Tag_List{List: p.List()}, err
|
||||
|
@ -750,29 +736,18 @@ func (s TunnelServer_registerTunnel_Params) String() string {
|
|||
return str
|
||||
}
|
||||
|
||||
func (s TunnelServer_registerTunnel_Params) Auth() (Authentication, error) {
|
||||
func (s TunnelServer_registerTunnel_Params) OriginCert() ([]byte, error) {
|
||||
p, err := s.Struct.Ptr(0)
|
||||
return Authentication{Struct: p.Struct()}, err
|
||||
return []byte(p.Data()), err
|
||||
}
|
||||
|
||||
func (s TunnelServer_registerTunnel_Params) HasAuth() bool {
|
||||
func (s TunnelServer_registerTunnel_Params) HasOriginCert() bool {
|
||||
p, err := s.Struct.Ptr(0)
|
||||
return p.IsValid() || err != nil
|
||||
}
|
||||
|
||||
func (s TunnelServer_registerTunnel_Params) SetAuth(v Authentication) error {
|
||||
return s.Struct.SetPtr(0, v.Struct.ToPtr())
|
||||
}
|
||||
|
||||
// NewAuth sets the auth field to a newly
|
||||
// allocated Authentication struct, preferring placement in s's segment.
|
||||
func (s TunnelServer_registerTunnel_Params) NewAuth() (Authentication, error) {
|
||||
ss, err := NewAuthentication(s.Struct.Segment())
|
||||
if err != nil {
|
||||
return Authentication{}, err
|
||||
}
|
||||
err = s.Struct.SetPtr(0, ss.Struct.ToPtr())
|
||||
return ss, err
|
||||
func (s TunnelServer_registerTunnel_Params) SetOriginCert(v []byte) error {
|
||||
return s.Struct.SetData(0, v)
|
||||
}
|
||||
|
||||
func (s TunnelServer_registerTunnel_Params) Hostname() (string, error) {
|
||||
|
@ -844,10 +819,6 @@ func (p TunnelServer_registerTunnel_Params_Promise) Struct() (TunnelServer_regis
|
|||
return TunnelServer_registerTunnel_Params{s}, err
|
||||
}
|
||||
|
||||
func (p TunnelServer_registerTunnel_Params_Promise) Auth() Authentication_Promise {
|
||||
return Authentication_Promise{Pipeline: p.Pipeline.GetPipeline(0)}
|
||||
}
|
||||
|
||||
func (p TunnelServer_registerTunnel_Params_Promise) Options() RegistrationOptions_Promise {
|
||||
return RegistrationOptions_Promise{Pipeline: p.Pipeline.GetPipeline(2)}
|
||||
}
|
||||
|
@ -1060,74 +1031,73 @@ func (p TunnelServer_getServerInfo_Results_Promise) Result() ServerInfo_Promise
|
|||
return ServerInfo_Promise{Pipeline: p.Pipeline.GetPipeline(0)}
|
||||
}
|
||||
|
||||
const schema_db8274f9144abc7e = "x\xda\x94To\x88\x14e\x18\x7f~\xef\xbb3\xabp" +
|
||||
"\xb6;\xcc\x0aut\x08b\x90\x82\xe6e\x86\x99\xb4\xe7" +
|
||||
"\xa5\xe6^\xa7\xb7\xaf]a\xe9\x07\xc7\xbd\xf7\xf6\xc6f" +
|
||||
"g\xb6\x99\xd9\xcb\x8b\xd4\x92 \x0c2R\xfb\xd2\x87\xc8" +
|
||||
"\xfbf`%\x14E\x18\x9c\xd0\x1f\xc1\"\x02\x0b\xad\xeb" +
|
||||
"C\x98\x04RH\xd2\x87\x0cb\xe2\x9d\xbd\xd9\x99\xee\x94" +
|
||||
"\xf0\xdb\xfb\xe7y\x7f\xef\xef\xf9=\xcf\xf3[9\xc1\xfa" +
|
||||
"X\xafv\x8fF$\xd6iz\xb4\xae\xf1\xcd\xe4\xfdo" +
|
||||
"\x9c{\x89\x8c\"\x8b\xf6\x9f\x1e(]\x0f\x0f\xfeH\x84" +
|
||||
"U\xfb\xd82\x98\xaf\xb2<\x91y\x88\x0d\x11\xa2\x85\x15" +
|
||||
"LO\xf5\xe6>\"\xa3\x07D\x1a\xcf\x13\xad:\xce\xde" +
|
||||
"\x04\xc1<\xc5\xde#D=\xbf\xf7/p\xaf\x1e\x9c\"" +
|
||||
"\xa3\x88\x14*\x0e4\xb7\xf0\xbf\xcd'\xe3\xd5\xe3\\\xc5" +
|
||||
"\x0e\xec8zD\xbb|\xf4K\x12Ed\x835\x85\xfa" +
|
||||
"\x07_\x0c\x139\xb5\xfc\x87\xbf\x06B\xd4\xfd\xfe\x83\xef" +
|
||||
"\xf6\x8f\\<7\x0b:fwB\x9b4O\xa9w\xe6" +
|
||||
"I\xedYB\xc4.[w\xbc\xf0\xfdC\xd3m\x9e1" +
|
||||
"\xca|\xfd\x08(\x17m}b\xc7\x9e\xf9\xfb.]\x9a" +
|
||||
"\xc9\x00\xea\xea\xba\x16g0_/\x13\xa2\xd5\xbb\xd6\xcb" +
|
||||
"\x9dk\xb6_!\xa3\xc8\xb3b\x98K\xf5+\xe6j]" +
|
||||
"\xfd\xd1\xab\xbfl\x1eR\xab\xe8\xf0\xfe\x0dC\x0f,>" +
|
||||
"s-\x8b\xf6\x8c>\xa9\xd0^\x8c\xd1F\xd7\xfc\xf6\xc8" +
|
||||
"]\x87\xbf\xb86\x8b\xb4\x0a4\x8f\xeb?\x98'c\xc0" +
|
||||
"\x13*\xf6\xea\xa6\xb7\xcew\x17\xba\xff\x9c\xa5F\xac\xf1" +
|
||||
"\xd7z7\xcc\x9f\xe2\xd8\x8b\xfa\xaf\xb4<\x0a[\xae+" +
|
||||
"\x1d\xbf\xc9k+jV\xd3m\xae\xdd\xb8\xd7\x0eB\xdb" +
|
||||
"\xad\x0f\xc7\x17U\xaf\xe0\xd8\xb5\x89* \xba\xc0\x88\x8c" +
|
||||
"\x9e\xb5D\x80\xb1\xf0)\"0\xc3\xe8'*\xdbu\xd7" +
|
||||
"\xf3e4b\x075\xcfu%\xf1Zx`\xb7\xe5X" +
|
||||
"nMv\xe0\xb5\x04\xbe\x0d\xfb\x98\xf4\xc7\xa5\xbf\xc2\x97" +
|
||||
"u;\x08\xa5\xdf>\\R\xb5|\x8b7\x02\xd1\xc5s" +
|
||||
"D9\x10\x19\x1b\x97\x11\x89>\x0e1\xc8`\x00%\xa8" +
|
||||
"\xc3\xca\x00\x91\xd8\xcc!\x86\x19\x0c\xc6J1/\xd1O" +
|
||||
"$\x069\xc4v\x86\x82\xd5\x0a\xc7PL{\x88\x80\"" +
|
||||
"!\x1a\xf3\x82\xd0\xb5\x1a\x92\x88\xd0E\x0c]\x84\x03^" +
|
||||
"3\xb4=7@1\xed\xa2\x99\xe8\x84:K\xa8\xafo" +
|
||||
"\x85c\xd2\x0d\xedr\xcdRobMR\xa6\x8bo\xc4" +
|
||||
"\xf4^\"\xb1\x81CT3L\xb7\xecN\x99\xe6\x9f\x96" +
|
||||
"\x13\x09\x95E\xb2a\xd9N\xb2\x8b<\xdf\xae\xdb\xee\xc3" +
|
||||
"\xeb)\xffh\x1a3\xb7\\\xdbb\x09\xfd\x98\xd1P3" +
|
||||
"\xb4\xf3\x9e\x1b(fwv\x98}\xa8\xe4\xfa\x80CL" +
|
||||
"e\x98}\xaa\xe4\xfa\x98C|\x96av\xa6\x9bH\x9c" +
|
||||
"\xe6\x10g\x19\xc0K\xe0D\xc6\xe7\xef\x10\x89\xb3\x1c\xe2" +
|
||||
"<\x83\x91\xe3%\xe4\x88\x8co\xd7\x12\x89\xaf8\xc4\x05" +
|
||||
"\x06C+\x96\xa0\x11\x19\xdf}B$.p\x88_\x18" +
|
||||
"\x0c=W\x82Nd\xfc\xac\x0a8\xcd!\xfeb\x88j" +
|
||||
"\x8e-\xdd\xb02\x92\xd5\x7f\\\xfa\x81\xed\xb9\xc9\x9e{" +
|
||||
"A'W9\xd3\x89\xf8O+\xa2\x90\xda\x0c\x01\x05B" +
|
||||
"\xb9\xe9yNe$\xf3\xae\xe9\x05\xb2\xe2\"\x94\xbek" +
|
||||
"9\x9b\xbdr\xbb\xec\x001\x80P\x08\xadz\x80\xdb\x08" +
|
||||
"U\x0e\x14S; \xa8\xc3\x8e\xc4H$\xce\x0f[u" +
|
||||
"%\xe9\xbc\x8e\xa4KUVK8\xc4\xca\x8c\xa4\xcbU" +
|
||||
"\xb1\xef\xe6\x10\xf71\x14\xe2\xff\x92\xc2\x8e[NK\xce" +
|
||||
")\xe1\x8dG\xa2.\xc3\xf6\xaa\xe2\x8ez\xf1D4\x10" +
|
||||
"\xdc\xd2\x9bm2h9<\x0cD\xae\xc3w\x81\xaa\xd7" +
|
||||
"<\x0eQb(\xfb\xea>D1\xb5\x94\x9b5|\xf2" +
|
||||
"IAa\xb7\x15\xd0\x88:\xde\x8d\xc4\xb4\x8c\xde\xe7\x88" +
|
||||
"\x19K\xf3H\xfd\x12\x89=\x1a=>1ca>J" +
|
||||
"f\x9d\xcam\xd8>D\x09oZ\x143\xefC\x15\xb8" +
|
||||
"5\xc7P\xb9\xe6\x9d\xff\xcf5\xb1\xc4\x9be\x9a\xc8\xc7" +
|
||||
"G=\x95g\x06m\x0f\x91\xe8\xe2\x10\xb73D\x8e\xd7" +
|
||||
"\x9e|*l\xcd\x94w\xeeL\xb6\xc9\xa5\x93\xc9\xdbf" +
|
||||
"Q\xec\xa0Z\xca,vr\x88\xb1L\xffH\xd5T\xbb" +
|
||||
"8\xc4\xf3\x99\x91\x9cP\xc3\xbb\x97C\x1cKG\xf2\xf5" +
|
||||
"W\x88\xc41\x0e\xf16C^\xfa~B\xa4\xd0\xf2\x9d" +
|
||||
"N_\xab3\xd5\xcd\x8eW\x1f\xb4]\x19\xa8\x99\x9bu" +
|
||||
"\xd5\x94~\xc3r\xa5\x8bp\x93e;-_\xaaFh" +
|
||||
"\x8f\xc8\xbf\x01\x00\x00\xff\xff\x80\xf4\x060"
|
||||
const schema_db8274f9144abc7e = "x\xda\x9cT_h\x1c\xd5\x1b\xfd\xce\xbd3\xbb-$" +
|
||||
"\xbf\xcd0\x1bh\x17B\xa0\xe4\x87\xb6\xd0?\xb1*5" +
|
||||
"\x167\x89m%1m\xf6\xc6Vk\x9b\x87N7\xb7" +
|
||||
"\x9b\x89\xb33\xeb\xccl\xb4\x85\xb4Z\"R\xc1\xa2\x96" +
|
||||
"\x82\x05\x11\x15\x0b*E\xfb\xa0h\xa0\x0f\xf5E\x91\"" +
|
||||
"\xfa\xa0\x82\xd8\x17-E,J!\xf8\xe2\xd3\xc8\x9d\xcd" +
|
||||
"\xec\x8c)\xa6\xd2\xb7;w\xbe?\xe7\x9c\xfb}g\xcb" +
|
||||
"\xd3l\x90\xf5\xeb\x9bu\"\xb1]\xcfE\xdb\xeb\xdf\xbc" +
|
||||
"s\xff\xd9+\xf3d\x94Xt\xfc\xd2h\xf1\xaf\xf0\xe4" +
|
||||
"OD\xd8:\xc7\x8e\xc1|\x95\xe5\x89\xcc\x97\xd98!" +
|
||||
"\xea\x1e\xc1\xd5\xcb\xfd\xda\xa7d\xdc\x05\"\x9d\xe7\x89\xb6" +
|
||||
"\x9eg7@0\x17\xd8G\x84\xa8\xe7\x8f\xe1N\xf7\xe6" +
|
||||
"\xc9\xcbd\x94\x90\x96j\x05>\xc9Ga\xd6\xd5\xd1\xb4" +
|
||||
"\xb9\x0a\x1e=x\xe65\xfd\xfa\x99/I\x94\x90\x8d\xd6" +
|
||||
"U\xb4\xae\xf90\xd7j\xea\xd8\xad=\x01BT\xba\xf8" +
|
||||
"\xe0\x87\xc3S?^YV;\x867\xa7/\x9a\xa7T" +
|
||||
"\x9e\xf9\x82\xfe\x0c!b\xd7\xad\xb5\xcf\xfd\xf0\xd0\xd5\x16" +
|
||||
"\xd0\xb8\xca\xcf\xfa/ -\xda\xf3\xf8\xc1\x99\xd5s\xd7" +
|
||||
"\xae-Q\x80\xfa\xf5\xbd\x1eS\xf8M/\x13\xa2\xfb\x0e" +
|
||||
"\x0d\xc9\xc9m\xfbo\x90Q\xe2\xffPcun\x00\xe6" +
|
||||
"\xda\x9cj\xd2\x9d{\xd1\xac\xabSt\xfa\xf8\x8e\xf1\x07" +
|
||||
"\xd6}\xbe\x98-\xb7/\xb7\xa8\xca\xd99U\xee\xc8\xb6" +
|
||||
"\xdf\x1f\xf9\xff\xe9/\x16\x97\xa1\x8e\x03O\xe56\xc0<" +
|
||||
"\x17W<\xab\x82o\xeez\xf3\xbbR\xa1\xf4\xe72=" +
|
||||
"b\xf5\x16r30\xbf\x8ec\xbf\xca\xfdJ\x1b\xa3\xb0" +
|
||||
"\xe9\xba\xd2\xf1\x1bZusr\xacn\xaaZ\x0d\xb71" +
|
||||
"\xb0\xf3Y;\x08m\xb7\xb67\xbe/W<\xc7\xae\x1e" +
|
||||
"\xad\x00\xa2\x03\x8c\xc8\xe8\x19 \x02\x8c\xee\x03D`\x86" +
|
||||
"1LT\xb6k\xae\xe7\xcbh\xca\x0e\xaa\x9e\xebJ\xe2" +
|
||||
"\xd5\xf0\xc4a\xcb\xb1\xdc\xaal7\xca\xdd\xda\xa8\xd5\xe0" +
|
||||
"1\xe9\xcfJ\x7f\x93/kv\x10J\xbfu\xd9W\xb1" +
|
||||
"\x0a\xbeU\x0fD\x07\xd7\x884\x10\x19;\x0f\x10\x89\x1d" +
|
||||
"\x1c\xa2\xc2`\x00E\xa8\xcb\xdd\xa3Db\x8cC\xecg" +
|
||||
"0\x18+\xc6\x08\xf7\x0d\x13\x89\x0a\x87\x98d\x88<\xdf" +
|
||||
"\xae\xd9\xee\xc3\x92\xb8\x1f\xa2\x93\x18:\x09\xd1\xb4\x17\x84" +
|
||||
"\xaeU\x97D\x84\x0eb\xe8 \x9c\xf0\x1a\xa1\xed\xb9\x01" +
|
||||
"\xba\xd2\xc9\"\xa0\x8b\xb0\x92VC\xcdpZ\xba\xa1]" +
|
||||
"\xb5T2Q,S\x0ay\x1d\x91\x18\xe4\x10c\x19\xc8" +
|
||||
"#\xf7dx$\x90w\x1fNy\xe4\x9f\x92G\x13T" +
|
||||
"\xbd\xb2n\xd9N\xf2\x95\x90\x19\xa2\xfc\xa3i\xccJ\xf8" +
|
||||
"&bU\xfd\x18\xddx\xa37f\xa80\xaeic<" +
|
||||
"\xa7\x14|\x9dC\xbc\x9b\xc1\xf8\xb6R\xf0\x0d\x0e\xf1^" +
|
||||
"\x06\xe3\xf9\x12\x91x\x8bC\\`\x00/\x82\x13\x19\xef" +
|
||||
"\x7f@$.p\x88\xcf\x18\x0c\x8d\x17\xa1\x11\x19\x9f\x0c" +
|
||||
"\x10\x89\x8b\x1c\xe2\x12\x83\xa1kE\xe8D\xc6\xc2\x06\"" +
|
||||
"\xf11\x87\xf8\x96!\xaa:\xb6t\xc3\x91\xa9\xac\xfe\xb3" +
|
||||
"\xd2\x0fl\xcfM\xbe\xb9\x17\xb4\x09\xca\xa5\x89Dk8" +
|
||||
"*^A\x8d$\x0a\xa9\xf7\x10P \x94\x1b\x9e\xe7\x8c" +
|
||||
"L%y\x85\xd0\xaa\x05\xf8\x1f\xa1\xc2\x81\xae\xd4\x01\x08" +
|
||||
"\xea\xb2-\x1b[.[oc`\xafUS2\xadj" +
|
||||
"\xcb\xb4^\xc1\xef\xe3\x10[22mTOy7\x87" +
|
||||
"\xb8\x97\xa1\xa0\xe6\xa9\xfdl\xb3\x96\xd3\x94\xb7<\xd0\xed" +
|
||||
"v\xa0&\xc3\xd6i\xc4=\xe2\xf5U,?o\xd5\x83" +
|
||||
";\xcc\x9e\x90A\xa1\xe9\x84\x81\xd0\xda\x1c:\xd5\xbb\xac" +
|
||||
"\xe2\x10E\x86\xb2/\x83\xa6\x13\xa2+\xb5\x98e\xd3\xce" +
|
||||
"\xff\xad]\xb9\xd5\xa5\xa5\x8fN\xd4\xf6u$vf\xf4" +
|
||||
"\x1f#f\xac\xcf#\xb5R$\xcei\xf4\xf8\xc4\x8c\xee" +
|
||||
"|\x94,<\x95[e\x07\x11%\x0c\xa87\xe60\x88" +
|
||||
"\x0ap\xa7\x062!{\x83\xff\xc2?q\xcd\xdb\xb3o" +
|
||||
"\xf5)(d\x8a{\xa6\xee\x0c\x91\xe8\xe0\x10k\x18\"" +
|
||||
"\xc7[\xf2\x82\xc2\x9e\xcc@\xac\xb4\xa3-\xc0\xc9\xa6\x16" +
|
||||
"T\xb2\xaa\xdf\xd5\xaeo)\x1b\x99\xe4\x10\xd3\x99\xd9\x93" +
|
||||
"\xea\xf2\x10\x87p2+j\xabe\x9e\xe6\x10\xf3\xe9\x8a" +
|
||||
">\xff\x12\x91\x98\xe7\x10\xaf0\xe4\xa5\xef'\x90\xf2M" +
|
||||
"?5\x16\xc7\xab\x8d\xd9\xae\x0c\xd4B.-\x8c\xfa\xa5" +
|
||||
"\xd6\xa4!\xfd\xba\xe5J\x17\xe1.\xcbv\x9a\xbeT\x83" +
|
||||
"B\x0c \xfc\x1d\x00\x00\xff\xff\xfa.\x1fg"
|
||||
|
||||
func init() {
|
||||
schemas.Register(schema_db8274f9144abc7e,
|
||||
|
|
Loading…
Reference in New Issue