Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
caddy
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
caddy
Commits
8db80c4a
Commit
8db80c4a
authored
Feb 16, 2018
by
Matthew Holt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
tls: Fix HTTP->HTTPS redirects and HTTP challenge when using custom port
parent
4704a56a
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
38 additions
and
46 deletions
+38
-46
caddyhttp/httpserver/https.go
caddyhttp/httpserver/https.go
+17
-13
caddyhttp/httpserver/server.go
caddyhttp/httpserver/server.go
+2
-20
caddytls/config.go
caddytls/config.go
+7
-6
caddytls/httphandler.go
caddytls/httphandler.go
+10
-5
caddytls/httphandler_test.go
caddytls/httphandler_test.go
+2
-2
No files found.
caddyhttp/httpserver/https.go
View file @
8db80c4a
...
@@ -159,25 +159,29 @@ func hostHasOtherPort(allConfigs []*SiteConfig, thisConfigIdx int, otherPort str
...
@@ -159,25 +159,29 @@ func hostHasOtherPort(allConfigs []*SiteConfig, thisConfigIdx int, otherPort str
// be the HTTPS configuration. The returned configuration is set
// be the HTTPS configuration. The returned configuration is set
// to listen on HTTPPort. The TLS field of cfg must not be nil.
// to listen on HTTPPort. The TLS field of cfg must not be nil.
func
redirPlaintextHost
(
cfg
*
SiteConfig
)
*
SiteConfig
{
func
redirPlaintextHost
(
cfg
*
SiteConfig
)
*
SiteConfig
{
redirPort
:=
cfg
.
Addr
.
Port
if
redirPort
==
DefaultHTTPSPort
{
redirPort
=
""
// default port is redundant
}
redirMiddleware
:=
func
(
next
Handler
)
Handler
{
redirMiddleware
:=
func
(
next
Handler
)
Handler
{
return
HandlerFunc
(
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
(
int
,
error
)
{
return
HandlerFunc
(
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
(
int
,
error
)
{
// Construct the URL to which to redirect. Note that the Host in a
request might
// Construct the URL to which to redirect. Note that the Host in a
//
contain a port, but we just need the hostname; we'll set the port if needed
.
//
request might contain a port, but we just need the hostname
.
toURL
:=
"https://"
toURL
:=
"https://"
requestHost
,
_
,
err
:=
net
.
SplitHostPort
(
r
.
Host
)
requestHost
,
_
,
err
:=
net
.
SplitHostPort
(
r
.
Host
)
if
err
!=
nil
{
if
err
!=
nil
{
requestHost
=
r
.
Host
// Host did not contain a port; great
requestHost
=
r
.
Host
// host did not contain a port; okay
}
if
redirPort
==
""
{
toURL
+=
requestHost
}
else
{
toURL
+=
net
.
JoinHostPort
(
requestHost
,
redirPort
)
}
}
// The rest of the URL will consist of the hostname and the URI.
// We do not append a port because if the HTTPSPort is changed
// from the default value, it is probably because there is port
// forwarding going on; and we do not need to specify the default
// HTTPS port in the redirect. Serving HTTPS on a port other than
// 443 is unusual, and is considered an advanced use case. If port
// forwarding IS happening, then redirecting the external client to
// this internal port will cause the connection to fail; and it
// definitely causes ACME HTTP-01 challenges to fail, because it
// only allows redirecting to port 80 or 443 (as of Feb 2018).
// If a user wants to redirect HTTP to HTTPS on an external port
// other than 443, they can easily configure that themselves.
toURL
+=
requestHost
toURL
+=
r
.
URL
.
RequestURI
()
toURL
+=
r
.
URL
.
RequestURI
()
w
.
Header
()
.
Set
(
"Connection"
,
"close"
)
w
.
Header
()
.
Set
(
"Connection"
,
"close"
)
...
...
caddyhttp/httpserver/server.go
View file @
8db80c4a
...
@@ -389,7 +389,7 @@ func (s *Server) serveHTTP(w http.ResponseWriter, r *http.Request) (int, error)
...
@@ -389,7 +389,7 @@ func (s *Server) serveHTTP(w http.ResponseWriter, r *http.Request) (int, error)
if
vhost
==
nil
{
if
vhost
==
nil
{
// check for ACME challenge even if vhost is nil;
// check for ACME challenge even if vhost is nil;
// could be a new host coming online soon
// could be a new host coming online soon
if
caddytls
.
HTTPChallengeHandler
(
w
,
r
,
"localhost"
,
caddytls
.
DefaultHTTPAlternatePort
)
{
if
caddytls
.
HTTPChallengeHandler
(
w
,
r
,
"localhost"
)
{
return
0
,
nil
return
0
,
nil
}
}
// otherwise, log the error and write a message to the client
// otherwise, log the error and write a message to the client
...
@@ -405,7 +405,7 @@ func (s *Server) serveHTTP(w http.ResponseWriter, r *http.Request) (int, error)
...
@@ -405,7 +405,7 @@ func (s *Server) serveHTTP(w http.ResponseWriter, r *http.Request) (int, error)
// we still check for ACME challenge if the vhost exists,
// we still check for ACME challenge if the vhost exists,
// because we must apply its HTTP challenge config settings
// because we must apply its HTTP challenge config settings
if
s
.
proxyHTTPChallenge
(
vhost
,
w
,
r
)
{
if
caddytls
.
HTTPChallengeHandler
(
w
,
r
,
vhost
.
ListenHost
)
{
return
0
,
nil
return
0
,
nil
}
}
...
@@ -422,24 +422,6 @@ func (s *Server) serveHTTP(w http.ResponseWriter, r *http.Request) (int, error)
...
@@ -422,24 +422,6 @@ func (s *Server) serveHTTP(w http.ResponseWriter, r *http.Request) (int, error)
return
vhost
.
middlewareChain
.
ServeHTTP
(
w
,
r
)
return
vhost
.
middlewareChain
.
ServeHTTP
(
w
,
r
)
}
}
// proxyHTTPChallenge solves the ACME HTTP challenge if r is the HTTP
// request for the challenge. If it is, and if the request has been
// fulfilled (response written), true is returned; false otherwise.
// If you don't have a vhost, just call the challenge handler directly.
func
(
s
*
Server
)
proxyHTTPChallenge
(
vhost
*
SiteConfig
,
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
bool
{
if
vhost
.
Addr
.
Port
!=
caddytls
.
HTTPChallengePort
{
return
false
}
if
vhost
.
TLS
!=
nil
&&
vhost
.
TLS
.
Manual
{
return
false
}
altPort
:=
caddytls
.
DefaultHTTPAlternatePort
if
vhost
.
TLS
!=
nil
&&
vhost
.
TLS
.
AltHTTPPort
!=
""
{
altPort
=
vhost
.
TLS
.
AltHTTPPort
}
return
caddytls
.
HTTPChallengeHandler
(
w
,
r
,
vhost
.
ListenHost
,
altPort
)
}
// Address returns the address s was assigned to listen on.
// Address returns the address s was assigned to listen on.
func
(
s
*
Server
)
Address
()
string
{
func
(
s
*
Server
)
Address
()
string
{
return
s
.
Server
.
Addr
return
s
.
Server
.
Addr
...
...
caddytls/config.go
View file @
8db80c4a
...
@@ -93,16 +93,17 @@ type Config struct {
...
@@ -93,16 +93,17 @@ type Config struct {
// an ACME challenge
// an ACME challenge
ListenHost
string
ListenHost
string
// The alternate port (ONLY port, not host)
// The alternate port (ONLY port, not host) to
// to use for the ACME HTTP challenge; this
// use for the ACME HTTP challenge; if non-empty,
// port will be used if we proxy challenges
// this port will be used instead of
// coming in on port 80 to this alternate port
// HTTPChallengePort to spin up a listener for
// the HTTP challenge
AltHTTPPort
string
AltHTTPPort
string
// The alternate port (ONLY port, not host)
// The alternate port (ONLY port, not host)
// to use for the ACME TLS-SNI challenge.
// to use for the ACME TLS-SNI challenge.
// The system must forward
the standard p
ort
// The system must forward
TLSSNIChallengeP
ort
//
for the TLS-SNI challenge to this port.
//
to this port for challenge to succeed
AltTLSSNIPort
string
AltTLSSNIPort
string
// The string identifier of the DNS provider
// The string identifier of the DNS provider
...
...
caddytls/httphandler.go
View file @
8db80c4a
...
@@ -27,10 +27,11 @@ import (
...
@@ -27,10 +27,11 @@ import (
const
challengeBasePath
=
"/.well-known/acme-challenge"
const
challengeBasePath
=
"/.well-known/acme-challenge"
// HTTPChallengeHandler proxies challenge requests to ACME client if the
// HTTPChallengeHandler proxies challenge requests to ACME client if the
// request path starts with challengeBasePath. It returns true if it
// request path starts with challengeBasePath, if the HTTP challenge is not
// handled the request and no more needs to be done; it returns false
// disabled, and if we are known to be obtaining a certificate for the name.
// if this call was a no-op and the request still needs handling.
// It returns true if it handled the request and no more needs to be done;
func
HTTPChallengeHandler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
listenHost
,
altPort
string
)
bool
{
// it returns false if this call was a no-op and the request still needs handling.
func
HTTPChallengeHandler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
listenHost
string
)
bool
{
if
!
strings
.
HasPrefix
(
r
.
URL
.
Path
,
challengeBasePath
)
{
if
!
strings
.
HasPrefix
(
r
.
URL
.
Path
,
challengeBasePath
)
{
return
false
return
false
}
}
...
@@ -50,7 +51,11 @@ func HTTPChallengeHandler(w http.ResponseWriter, r *http.Request, listenHost, al
...
@@ -50,7 +51,11 @@ func HTTPChallengeHandler(w http.ResponseWriter, r *http.Request, listenHost, al
listenHost
=
"localhost"
listenHost
=
"localhost"
}
}
upstream
,
err
:=
url
.
Parse
(
fmt
.
Sprintf
(
"%s://%s:%s"
,
scheme
,
listenHost
,
altPort
))
// always proxy to the DefaultHTTPAlternatePort because obviously the
// ACME challenge request already got into one of our HTTP handlers, so
// it means we must have started a HTTP listener on the alternate
// port instead; which is only accessible via listenHost
upstream
,
err
:=
url
.
Parse
(
fmt
.
Sprintf
(
"%s://%s:%s"
,
scheme
,
listenHost
,
DefaultHTTPAlternatePort
))
if
err
!=
nil
{
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
log
.
Printf
(
"[ERROR] ACME proxy handler: %v"
,
err
)
log
.
Printf
(
"[ERROR] ACME proxy handler: %v"
,
err
)
...
...
caddytls/httphandler_test.go
View file @
8db80c4a
...
@@ -39,7 +39,7 @@ func TestHTTPChallengeHandlerNoOp(t *testing.T) {
...
@@ -39,7 +39,7 @@ func TestHTTPChallengeHandlerNoOp(t *testing.T) {
t
.
Fatalf
(
"Could not craft request, got error: %v"
,
err
)
t
.
Fatalf
(
"Could not craft request, got error: %v"
,
err
)
}
}
rw
:=
httptest
.
NewRecorder
()
rw
:=
httptest
.
NewRecorder
()
if
HTTPChallengeHandler
(
rw
,
req
,
""
,
DefaultHTTPAlternatePort
)
{
if
HTTPChallengeHandler
(
rw
,
req
,
""
)
{
t
.
Errorf
(
"Got true with this URL, but shouldn't have: %s"
,
url
)
t
.
Errorf
(
"Got true with this URL, but shouldn't have: %s"
,
url
)
}
}
}
}
...
@@ -76,7 +76,7 @@ func TestHTTPChallengeHandlerSuccess(t *testing.T) {
...
@@ -76,7 +76,7 @@ func TestHTTPChallengeHandlerSuccess(t *testing.T) {
}
}
rw
:=
httptest
.
NewRecorder
()
rw
:=
httptest
.
NewRecorder
()
HTTPChallengeHandler
(
rw
,
req
,
""
,
DefaultHTTPAlternatePort
)
HTTPChallengeHandler
(
rw
,
req
,
""
)
if
!
proxySuccess
{
if
!
proxySuccess
{
t
.
Fatal
(
"Expected request to be proxied, but it wasn't"
)
t
.
Fatal
(
"Expected request to be proxied, but it wasn't"
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment