Merge branch 'nghttpx-forwarded'
This commit is contained in:
commit
deacc202ff
|
@ -17,6 +17,7 @@ HEADERS = [
|
||||||
"http2-settings",
|
"http2-settings",
|
||||||
"server",
|
"server",
|
||||||
"via",
|
"via",
|
||||||
|
"forwarded",
|
||||||
"x-forwarded-for",
|
"x-forwarded-for",
|
||||||
"x-forwarded-proto",
|
"x-forwarded-proto",
|
||||||
"alt-svc",
|
"alt-svc",
|
||||||
|
|
|
@ -103,7 +103,11 @@ OPTIONS = [
|
||||||
"conf",
|
"conf",
|
||||||
"fastopen",
|
"fastopen",
|
||||||
"tls-dyn-rec-warmup-threshold",
|
"tls-dyn-rec-warmup-threshold",
|
||||||
"tls-dyn-rec-idle-timeout"
|
"tls-dyn-rec-idle-timeout",
|
||||||
|
"add-forwarded",
|
||||||
|
"strip-incoming-forwarded",
|
||||||
|
"forwarded-by",
|
||||||
|
"forwarded-for"
|
||||||
]
|
]
|
||||||
|
|
||||||
LOGVARS = [
|
LOGVARS = [
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -123,6 +124,147 @@ func TestH2H1StripAddXff(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestH2H1AddForwardedObfuscated tests that server generates
|
||||||
|
// Forwarded header field with obfuscated "by" and "for" parameters.
|
||||||
|
func TestH2H1AddForwardedObfuscated(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--add-forwarded=by,for,host,proto"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
pattern := fmt.Sprintf(`by="_[^"]+";for="_[^"]+";host="127.0.0.1:%v";proto="http"`, serverPort)
|
||||||
|
validFwd := regexp.MustCompile(pattern)
|
||||||
|
got := r.Header.Get("Forwarded")
|
||||||
|
|
||||||
|
if !validFwd.MatchString(got) {
|
||||||
|
t.Errorf("Forwarded = %v; want pattern %v", got, pattern)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1AddForwardedObfuscated",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H1AddForwardedByIP tests that server generates Forwarded header
|
||||||
|
// field with IP address in "by" parameter.
|
||||||
|
func TestH2H1AddForwardedByIP(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--add-forwarded=by,for,host,proto", "--forwarded-by=ip", "--forwarded-for=_bravo"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
want := fmt.Sprintf(`by="127.0.0.1:%v";for="_bravo";host="127.0.0.1:%v";proto="http"`, serverPort, serverPort)
|
||||||
|
if got := r.Header.Get("Forwarded"); got != want {
|
||||||
|
t.Errorf("Forwarded = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1AddForwardedByIP",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H1AddForwardedForIP tests that server generates Forwarded header
|
||||||
|
// field with IP address in "for" parameters.
|
||||||
|
func TestH2H1AddForwardedForIP(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--add-forwarded=by,for,host,proto", "--forwarded-by=_alpha", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
want := fmt.Sprintf(`by="_alpha";for="127.0.0.1";host="127.0.0.1:%v";proto="http"`, serverPort)
|
||||||
|
if got := r.Header.Get("Forwarded"); got != want {
|
||||||
|
t.Errorf("Forwarded = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1AddForwardedForIP",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H1AddForwardedMerge tests that server generates Forwarded
|
||||||
|
// header field with IP address in "by" and "for" parameters. The
|
||||||
|
// generated values must be appended to the existing value.
|
||||||
|
func TestH2H1AddForwardedMerge(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--add-forwarded=proto"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if got, want := r.Header.Get("Forwarded"), `host=foo, proto="http"`; got != want {
|
||||||
|
t.Errorf("Forwarded = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1AddForwardedMerge",
|
||||||
|
header: []hpack.HeaderField{
|
||||||
|
pair("forwarded", "host=foo"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H1AddForwardedStrip tests that server generates Forwarded
|
||||||
|
// header field with IP address in "by" and "for" parameters. The
|
||||||
|
// generated values must not include the existing value.
|
||||||
|
func TestH2H1AddForwardedStrip(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--strip-incoming-forwarded", "--add-forwarded=proto"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if got, want := r.Header.Get("Forwarded"), `proto="http"`; got != want {
|
||||||
|
t.Errorf("Forwarded = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1AddForwardedStrip",
|
||||||
|
header: []hpack.HeaderField{
|
||||||
|
pair("forwarded", "host=foo"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H1AddForwardedStatic tests that server generates Forwarded
|
||||||
|
// header field with the given static obfuscated strings for "by" and
|
||||||
|
// "for" parameters.
|
||||||
|
func TestH2H1AddForwardedStatic(t *testing.T) {
|
||||||
|
st := newServerTester([]string{"--add-forwarded=by,for", "--forwarded-by=_alpha", "--forwarded-for=_bravo"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if got, want := r.Header.Get("Forwarded"), `by="_alpha";for="_bravo"`; got != want {
|
||||||
|
t.Errorf("Forwarded = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1AddForwardedStatic",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestH2H1GenerateVia tests that server generates Via header field to and
|
// TestH2H1GenerateVia tests that server generates Via header field to and
|
||||||
// from backend server.
|
// from backend server.
|
||||||
func TestH2H1GenerateVia(t *testing.T) {
|
func TestH2H1GenerateVia(t *testing.T) {
|
||||||
|
@ -1348,6 +1490,60 @@ func TestH2H2TLSXfp(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestH2H2AddForwarded tests that server generates Forwarded header
|
||||||
|
// field using static obfuscated "by" and "for" parameter, and
|
||||||
|
// existing Forwarded header field.
|
||||||
|
func TestH2H2AddForwarded(t *testing.T) {
|
||||||
|
st := newServerTesterTLS([]string{"--http2-bridge", "--add-forwarded=by,for,host,proto", "--forwarded-by=_alpha", "--forwarded-for=_bravo"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
want := fmt.Sprintf(`host=foo, by="_alpha";for="_bravo";host="127.0.0.1:%v";proto="https"`, serverPort)
|
||||||
|
if got := r.Header.Get("Forwarded"); got != want {
|
||||||
|
t.Errorf("Forwarded = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H2AddForwarded",
|
||||||
|
scheme: "https",
|
||||||
|
header: []hpack.HeaderField{
|
||||||
|
pair("forwarded", "host=foo"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestH2H2AddForwardedStrip tests that server generates Forwarded
|
||||||
|
// header field using static obfuscated "by" and "for" parameter, and
|
||||||
|
// existing Forwarded header field stripped.
|
||||||
|
func TestH2H2AddForwardedStrip(t *testing.T) {
|
||||||
|
st := newServerTesterTLS([]string{"--http2-bridge", "--strip-incoming-forwarded", "--add-forwarded=by,for,host,proto", "--forwarded-by=_alpha", "--forwarded-for=_bravo"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
want := fmt.Sprintf(`by="_alpha";for="_bravo";host="127.0.0.1:%v";proto="https"`, serverPort)
|
||||||
|
if got := r.Header.Get("Forwarded"); got != want {
|
||||||
|
t.Errorf("Forwarded = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H2AddForwardedStrip",
|
||||||
|
scheme: "https",
|
||||||
|
header: []hpack.HeaderField{
|
||||||
|
pair("forwarded", "host=foo"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestH2H2ReqPhaseReturn tests mruby request phase hook returns
|
// TestH2H2ReqPhaseReturn tests mruby request phase hook returns
|
||||||
// custom response.
|
// custom response.
|
||||||
func TestH2H2ReqPhaseReturn(t *testing.T) {
|
func TestH2H2ReqPhaseReturn(t *testing.T) {
|
||||||
|
|
11
src/http2.cc
11
src/http2.cc
|
@ -348,6 +348,7 @@ void copy_headers_to_nva_internal(std::vector<nghttp2_nv> &nva,
|
||||||
switch (kv.token) {
|
switch (kv.token) {
|
||||||
case HD_COOKIE:
|
case HD_COOKIE:
|
||||||
case HD_CONNECTION:
|
case HD_CONNECTION:
|
||||||
|
case HD_FORWARDED:
|
||||||
case HD_HOST:
|
case HD_HOST:
|
||||||
case HD_HTTP2_SETTINGS:
|
case HD_HTTP2_SETTINGS:
|
||||||
case HD_KEEP_ALIVE:
|
case HD_KEEP_ALIVE:
|
||||||
|
@ -385,6 +386,7 @@ void build_http1_headers_from_headers(DefaultMemchunks *buf,
|
||||||
switch (kv.token) {
|
switch (kv.token) {
|
||||||
case HD_CONNECTION:
|
case HD_CONNECTION:
|
||||||
case HD_COOKIE:
|
case HD_COOKIE:
|
||||||
|
case HD_FORWARDED:
|
||||||
case HD_HOST:
|
case HD_HOST:
|
||||||
case HD_HTTP2_SETTINGS:
|
case HD_HTTP2_SETTINGS:
|
||||||
case HD_KEEP_ALIVE:
|
case HD_KEEP_ALIVE:
|
||||||
|
@ -638,6 +640,15 @@ int lookup_token(const uint8_t *name, size_t namelen) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 9:
|
||||||
|
switch (name[8]) {
|
||||||
|
case 'd':
|
||||||
|
if (util::streq_l("forwarde", name, 8)) {
|
||||||
|
return HD_FORWARDED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 10:
|
case 10:
|
||||||
switch (name[9]) {
|
switch (name[9]) {
|
||||||
case 'e':
|
case 'e':
|
||||||
|
|
|
@ -218,6 +218,8 @@ int parse_http_status_code(const std::string &src);
|
||||||
|
|
||||||
// Header fields to be indexed, except HD_MAXIDX which is convenient
|
// Header fields to be indexed, except HD_MAXIDX which is convenient
|
||||||
// member to get maximum value.
|
// member to get maximum value.
|
||||||
|
//
|
||||||
|
// generated by genheaderfunc.py
|
||||||
enum {
|
enum {
|
||||||
HD__AUTHORITY,
|
HD__AUTHORITY,
|
||||||
HD__HOST,
|
HD__HOST,
|
||||||
|
@ -234,6 +236,7 @@ enum {
|
||||||
HD_COOKIE,
|
HD_COOKIE,
|
||||||
HD_DATE,
|
HD_DATE,
|
||||||
HD_EXPECT,
|
HD_EXPECT,
|
||||||
|
HD_FORWARDED,
|
||||||
HD_HOST,
|
HD_HOST,
|
||||||
HD_HTTP2_SETTINGS,
|
HD_HTTP2_SETTINGS,
|
||||||
HD_IF_MODIFIED_SINCE,
|
HD_IF_MODIFIED_SINCE,
|
||||||
|
|
64
src/shrpx.cc
64
src/shrpx.cc
|
@ -64,6 +64,7 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
@ -1576,6 +1577,40 @@ HTTP:
|
||||||
--strip-incoming-x-forwarded-for
|
--strip-incoming-x-forwarded-for
|
||||||
Strip X-Forwarded-For header field from inbound client
|
Strip X-Forwarded-For header field from inbound client
|
||||||
requests.
|
requests.
|
||||||
|
--add-forwarded=<LIST>
|
||||||
|
Append RFC 7239 Forwarded header field with parameters
|
||||||
|
specified in comma delimited list <LIST>. The supported
|
||||||
|
parameters are "by", "for", "host", and "proto". By
|
||||||
|
default, the value of "by" and "for" parameters are
|
||||||
|
obfuscated string. See --forwarded-by and
|
||||||
|
--forwarded-for options respectively. Note that nghttpx
|
||||||
|
does not translate non-standard X-Forwarded-* header
|
||||||
|
fields into Forwarded header field, and vice versa.
|
||||||
|
--strip-incoming-forwarded
|
||||||
|
Strip Forwarded header field from inbound client
|
||||||
|
requests.
|
||||||
|
--forwarded-by=(obfuscated|ip|<VALUE>)
|
||||||
|
Specify the parameter value sent out with "by" parameter
|
||||||
|
of Forwarded header field. If "obfuscated" is given,
|
||||||
|
the string is randomly generated at startup. If "ip" is
|
||||||
|
given, the interface address of the connection,
|
||||||
|
including port number, is sent with "by" parameter.
|
||||||
|
User can also specify the static obfuscated string. The
|
||||||
|
limitation is that it must starts with "_", and only
|
||||||
|
consists of character set [A-Za-z0-9._-], as described
|
||||||
|
in RFC 7239.
|
||||||
|
Default: obfuscated
|
||||||
|
--forwarded-for=(obfuscated|ip|<VALUE>)
|
||||||
|
Specify the parameter value sent out with "for"
|
||||||
|
parameter of Forwarded header field. If "obfuscated" is
|
||||||
|
given, the string is randomly generated for each client
|
||||||
|
connection. If "ip" is given, the remote client address
|
||||||
|
of the connection, without port number, is sent with
|
||||||
|
"for" parameter. User can also specify the static
|
||||||
|
obfuscated string. The limitation is that it must
|
||||||
|
starts with "_", and only consists of character set
|
||||||
|
[A-Za-z0-9._-], as described in RFC 7239.
|
||||||
|
Default: obfuscated
|
||||||
--no-via Don't append to Via header field. If Via header field
|
--no-via Don't append to Via header field. If Via header field
|
||||||
is received, it is left unaltered.
|
is received, it is left unaltered.
|
||||||
--no-location-rewrite
|
--no-location-rewrite
|
||||||
|
@ -1832,6 +1867,10 @@ int main(int argc, char **argv) {
|
||||||
{SHRPX_OPT_FASTOPEN, required_argument, &flag, 94},
|
{SHRPX_OPT_FASTOPEN, required_argument, &flag, 94},
|
||||||
{SHRPX_OPT_TLS_DYN_REC_WARMUP_THRESHOLD, required_argument, &flag, 95},
|
{SHRPX_OPT_TLS_DYN_REC_WARMUP_THRESHOLD, required_argument, &flag, 95},
|
||||||
{SHRPX_OPT_TLS_DYN_REC_IDLE_TIMEOUT, required_argument, &flag, 96},
|
{SHRPX_OPT_TLS_DYN_REC_IDLE_TIMEOUT, required_argument, &flag, 96},
|
||||||
|
{SHRPX_OPT_ADD_FORWARDED, required_argument, &flag, 97},
|
||||||
|
{SHRPX_OPT_STRIP_INCOMING_FORWARDED, no_argument, &flag, 98},
|
||||||
|
{SHRPX_OPT_FORWARDED_BY, required_argument, &flag, 99},
|
||||||
|
{SHRPX_OPT_FORWARDED_FOR, required_argument, &flag, 100},
|
||||||
{nullptr, 0, nullptr, 0}};
|
{nullptr, 0, nullptr, 0}};
|
||||||
|
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
@ -2245,6 +2284,22 @@ int main(int argc, char **argv) {
|
||||||
// --tls-dyn-rec-idle-timeout
|
// --tls-dyn-rec-idle-timeout
|
||||||
cmdcfgs.emplace_back(SHRPX_OPT_TLS_DYN_REC_IDLE_TIMEOUT, optarg);
|
cmdcfgs.emplace_back(SHRPX_OPT_TLS_DYN_REC_IDLE_TIMEOUT, optarg);
|
||||||
break;
|
break;
|
||||||
|
case 97:
|
||||||
|
// --add-forwarded
|
||||||
|
cmdcfgs.emplace_back(SHRPX_OPT_ADD_FORWARDED, optarg);
|
||||||
|
break;
|
||||||
|
case 98:
|
||||||
|
// --strip-incoming-forwarded
|
||||||
|
cmdcfgs.emplace_back(SHRPX_OPT_STRIP_INCOMING_FORWARDED, "yes");
|
||||||
|
break;
|
||||||
|
case 99:
|
||||||
|
// --forwarded-by
|
||||||
|
cmdcfgs.emplace_back(SHRPX_OPT_FORWARDED_BY, optarg);
|
||||||
|
break;
|
||||||
|
case 100:
|
||||||
|
// --forwarded-for
|
||||||
|
cmdcfgs.emplace_back(SHRPX_OPT_FORWARDED_FOR, optarg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2555,6 +2610,15 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (get_config()->forwarded_by_node_type == FORWARDED_NODE_OBFUSCATED &&
|
||||||
|
get_config()->forwarded_by_obfuscated.empty()) {
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 gen(rd());
|
||||||
|
auto &dst = mod_config()->forwarded_by_obfuscated;
|
||||||
|
dst = "_";
|
||||||
|
dst += util::random_alpha_digit(gen, SHRPX_OBFUSCATED_NODE_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
if (get_config()->upstream_frame_debug) {
|
if (get_config()->upstream_frame_debug) {
|
||||||
// To make it sync to logging
|
// To make it sync to logging
|
||||||
set_output(stderr);
|
set_output(stderr);
|
||||||
|
|
|
@ -27,6 +27,13 @@
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif // HAVE_UNISTD_H
|
#endif // HAVE_UNISTD_H
|
||||||
|
#ifdef HAVE_SYS_SOCKET_H
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#endif // HAVE_SYS_SOCKET_H
|
||||||
|
#ifdef HAVE_NETDB_H
|
||||||
|
#include <netdb.h>
|
||||||
|
#endif // HAVE_NETDB_H
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
|
|
||||||
#include "shrpx_upstream.h"
|
#include "shrpx_upstream.h"
|
||||||
|
@ -396,6 +403,17 @@ ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
|
||||||
} else {
|
} else {
|
||||||
setup_upstream_io_callback();
|
setup_upstream_io_callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((get_config()->forwarded_params & FORWARDED_FOR) &&
|
||||||
|
get_config()->forwarded_for_node_type == FORWARDED_NODE_OBFUSCATED) {
|
||||||
|
if (get_config()->forwarded_for_obfuscated.empty()) {
|
||||||
|
forwarded_for_obfuscated_ = "_";
|
||||||
|
forwarded_for_obfuscated_ += util::random_alpha_digit(
|
||||||
|
worker_->get_randgen(), SHRPX_OBFUSCATED_NODE_LENGTH);
|
||||||
|
} else {
|
||||||
|
forwarded_for_obfuscated_ = get_config()->forwarded_for_obfuscated;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientHandler::setup_upstream_io_callback() {
|
void ClientHandler::setup_upstream_io_callback() {
|
||||||
|
@ -1099,4 +1117,50 @@ int ClientHandler::proxy_protocol_read() {
|
||||||
return on_proxy_protocol_finish();
|
return on_proxy_protocol_finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string &ClientHandler::get_forwarded_by() {
|
||||||
|
if (get_config()->forwarded_by_node_type == FORWARDED_NODE_OBFUSCATED) {
|
||||||
|
return get_config()->forwarded_by_obfuscated;
|
||||||
|
}
|
||||||
|
if (!local_hostport_.empty()) {
|
||||||
|
return local_hostport_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rv;
|
||||||
|
sockaddr_union su;
|
||||||
|
socklen_t addrlen = sizeof(su);
|
||||||
|
|
||||||
|
rv = getsockname(conn_.fd, &su.sa, &addrlen);
|
||||||
|
if (rv != 0) {
|
||||||
|
return local_hostport_;
|
||||||
|
}
|
||||||
|
|
||||||
|
char host[NI_MAXHOST];
|
||||||
|
rv = getnameinfo(&su.sa, addrlen, host, sizeof(host), nullptr, 0,
|
||||||
|
NI_NUMERICHOST);
|
||||||
|
if (rv != 0) {
|
||||||
|
return local_hostport_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (su.storage.ss_family == AF_INET6) {
|
||||||
|
local_hostport_ = "[";
|
||||||
|
local_hostport_ += host;
|
||||||
|
local_hostport_ += "]:";
|
||||||
|
} else {
|
||||||
|
local_hostport_ = host;
|
||||||
|
local_hostport_ += ':';
|
||||||
|
}
|
||||||
|
|
||||||
|
local_hostport_ += util::utos(get_config()->port);
|
||||||
|
|
||||||
|
return local_hostport_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &ClientHandler::get_forwarded_for() const {
|
||||||
|
if (get_config()->forwarded_for_node_type == FORWARDED_NODE_OBFUSCATED) {
|
||||||
|
return forwarded_for_obfuscated_;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ipaddr_;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -134,6 +134,13 @@ public:
|
||||||
|
|
||||||
void setup_upstream_io_callback();
|
void setup_upstream_io_callback();
|
||||||
|
|
||||||
|
// Returns string suitable for use in "by" parameter of Forwarded
|
||||||
|
// header field.
|
||||||
|
const std::string &get_forwarded_by();
|
||||||
|
// Returns string suitable for use in "for" parameter of Forwarded
|
||||||
|
// header field.
|
||||||
|
const std::string &get_forwarded_for() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Connection conn_;
|
Connection conn_;
|
||||||
ev_timer reneg_shutdown_timer_;
|
ev_timer reneg_shutdown_timer_;
|
||||||
|
@ -143,6 +150,11 @@ private:
|
||||||
std::string port_;
|
std::string port_;
|
||||||
// The ALPN identifier negotiated for this connection.
|
// The ALPN identifier negotiated for this connection.
|
||||||
std::string alpn_;
|
std::string alpn_;
|
||||||
|
// Host and port of this socket (e.g., "[::1]:8443")
|
||||||
|
std::string local_hostport_;
|
||||||
|
// The obfuscated version of client address used in "for" parameter
|
||||||
|
// of Forwarded header field.
|
||||||
|
std::string forwarded_for_obfuscated_;
|
||||||
std::function<int(ClientHandler &)> read_, write_;
|
std::function<int(ClientHandler &)> read_, write_;
|
||||||
std::function<int(ClientHandler &)> on_read_, on_write_;
|
std::function<int(ClientHandler &)> on_read_, on_write_;
|
||||||
Worker *worker_;
|
Worker *worker_;
|
||||||
|
|
|
@ -628,12 +628,38 @@ void parse_mapping(const DownstreamAddr &addr, const char *src) {
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int parse_forwarded_node_type(const std::string &optarg) {
|
||||||
|
if (util::strieq(optarg, "obfuscated")) {
|
||||||
|
return FORWARDED_NODE_OBFUSCATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (util::strieq(optarg, "ip")) {
|
||||||
|
return FORWARDED_NODE_IP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optarg.size() < 2 || optarg[0] != '_') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::find_if_not(std::begin(optarg), std::end(optarg), [](char c) {
|
||||||
|
return util::is_alpha(c) || util::is_digit(c) || c == '.' || c == '_' ||
|
||||||
|
c == '-';
|
||||||
|
}) != std::end(optarg)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FORWARDED_NODE_OBFUSCATED;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
// generated by gennghttpxfun.py
|
// generated by gennghttpxfun.py
|
||||||
enum {
|
enum {
|
||||||
SHRPX_OPTID_ACCEPT_PROXY_PROTOCOL,
|
SHRPX_OPTID_ACCEPT_PROXY_PROTOCOL,
|
||||||
SHRPX_OPTID_ACCESSLOG_FILE,
|
SHRPX_OPTID_ACCESSLOG_FILE,
|
||||||
SHRPX_OPTID_ACCESSLOG_FORMAT,
|
SHRPX_OPTID_ACCESSLOG_FORMAT,
|
||||||
SHRPX_OPTID_ACCESSLOG_SYSLOG,
|
SHRPX_OPTID_ACCESSLOG_SYSLOG,
|
||||||
|
SHRPX_OPTID_ADD_FORWARDED,
|
||||||
SHRPX_OPTID_ADD_REQUEST_HEADER,
|
SHRPX_OPTID_ADD_REQUEST_HEADER,
|
||||||
SHRPX_OPTID_ADD_RESPONSE_HEADER,
|
SHRPX_OPTID_ADD_RESPONSE_HEADER,
|
||||||
SHRPX_OPTID_ADD_X_FORWARDED_FOR,
|
SHRPX_OPTID_ADD_X_FORWARDED_FOR,
|
||||||
|
@ -669,6 +695,8 @@ enum {
|
||||||
SHRPX_OPTID_ERRORLOG_SYSLOG,
|
SHRPX_OPTID_ERRORLOG_SYSLOG,
|
||||||
SHRPX_OPTID_FASTOPEN,
|
SHRPX_OPTID_FASTOPEN,
|
||||||
SHRPX_OPTID_FETCH_OCSP_RESPONSE_FILE,
|
SHRPX_OPTID_FETCH_OCSP_RESPONSE_FILE,
|
||||||
|
SHRPX_OPTID_FORWARDED_BY,
|
||||||
|
SHRPX_OPTID_FORWARDED_FOR,
|
||||||
SHRPX_OPTID_FRONTEND,
|
SHRPX_OPTID_FRONTEND,
|
||||||
SHRPX_OPTID_FRONTEND_FRAME_DEBUG,
|
SHRPX_OPTID_FRONTEND_FRAME_DEBUG,
|
||||||
SHRPX_OPTID_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS,
|
SHRPX_OPTID_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS,
|
||||||
|
@ -707,6 +735,7 @@ enum {
|
||||||
SHRPX_OPTID_RLIMIT_NOFILE,
|
SHRPX_OPTID_RLIMIT_NOFILE,
|
||||||
SHRPX_OPTID_STREAM_READ_TIMEOUT,
|
SHRPX_OPTID_STREAM_READ_TIMEOUT,
|
||||||
SHRPX_OPTID_STREAM_WRITE_TIMEOUT,
|
SHRPX_OPTID_STREAM_WRITE_TIMEOUT,
|
||||||
|
SHRPX_OPTID_STRIP_INCOMING_FORWARDED,
|
||||||
SHRPX_OPTID_STRIP_INCOMING_X_FORWARDED_FOR,
|
SHRPX_OPTID_STRIP_INCOMING_X_FORWARDED_FOR,
|
||||||
SHRPX_OPTID_SUBCERT,
|
SHRPX_OPTID_SUBCERT,
|
||||||
SHRPX_OPTID_SYSLOG_FACILITY,
|
SHRPX_OPTID_SYSLOG_FACILITY,
|
||||||
|
@ -915,11 +944,19 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||||
if (util::strieq_l("client-prox", name, 11)) {
|
if (util::strieq_l("client-prox", name, 11)) {
|
||||||
return SHRPX_OPTID_CLIENT_PROXY;
|
return SHRPX_OPTID_CLIENT_PROXY;
|
||||||
}
|
}
|
||||||
|
if (util::strieq_l("forwarded-b", name, 11)) {
|
||||||
|
return SHRPX_OPTID_FORWARDED_BY;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 13:
|
case 13:
|
||||||
switch (name[12]) {
|
switch (name[12]) {
|
||||||
|
case 'd':
|
||||||
|
if (util::strieq_l("add-forwarde", name, 12)) {
|
||||||
|
return SHRPX_OPTID_ADD_FORWARDED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
if (util::strieq_l("dh-param-fil", name, 12)) {
|
if (util::strieq_l("dh-param-fil", name, 12)) {
|
||||||
return SHRPX_OPTID_DH_PARAM_FILE;
|
return SHRPX_OPTID_DH_PARAM_FILE;
|
||||||
|
@ -931,6 +968,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||||
return SHRPX_OPTID_RLIMIT_NOFILE;
|
return SHRPX_OPTID_RLIMIT_NOFILE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'r':
|
||||||
|
if (util::strieq_l("forwarded-fo", name, 12)) {
|
||||||
|
return SHRPX_OPTID_FORWARDED_FOR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
if (util::strieq_l("verify-clien", name, 12)) {
|
if (util::strieq_l("verify-clien", name, 12)) {
|
||||||
return SHRPX_OPTID_VERIFY_CLIENT;
|
return SHRPX_OPTID_VERIFY_CLIENT;
|
||||||
|
@ -1166,6 +1208,9 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||||
case 24:
|
case 24:
|
||||||
switch (name[23]) {
|
switch (name[23]) {
|
||||||
case 'd':
|
case 'd':
|
||||||
|
if (util::strieq_l("strip-incoming-forwarde", name, 23)) {
|
||||||
|
return SHRPX_OPTID_STRIP_INCOMING_FORWARDED;
|
||||||
|
}
|
||||||
if (util::strieq_l("tls-ticket-key-memcache", name, 23)) {
|
if (util::strieq_l("tls-ticket-key-memcache", name, 23)) {
|
||||||
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED;
|
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED;
|
||||||
}
|
}
|
||||||
|
@ -2015,6 +2060,69 @@ int parse_config(const char *opt, const char *optarg,
|
||||||
mod_config()->accept_proxy_protocol = util::strieq(optarg, "yes");
|
mod_config()->accept_proxy_protocol = util::strieq(optarg, "yes");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
case SHRPX_OPTID_ADD_FORWARDED:
|
||||||
|
mod_config()->forwarded_params = FORWARDED_NONE;
|
||||||
|
for (const auto ¶m : util::parse_config_str_list(optarg)) {
|
||||||
|
if (util::strieq(param, "by")) {
|
||||||
|
mod_config()->forwarded_params |= FORWARDED_BY;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (util::strieq(param, "for")) {
|
||||||
|
mod_config()->forwarded_params |= FORWARDED_FOR;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (util::strieq(param, "host")) {
|
||||||
|
mod_config()->forwarded_params |= FORWARDED_HOST;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (util::strieq(param, "proto")) {
|
||||||
|
mod_config()->forwarded_params |= FORWARDED_PROTO;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(ERROR) << opt << ": unknown parameter " << optarg;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_STRIP_INCOMING_FORWARDED:
|
||||||
|
mod_config()->strip_incoming_forwarded = util::strieq(optarg, "yes");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_FORWARDED_BY:
|
||||||
|
case SHRPX_OPTID_FORWARDED_FOR: {
|
||||||
|
auto type = parse_forwarded_node_type(optarg);
|
||||||
|
|
||||||
|
if (type == -1) {
|
||||||
|
LOG(ERROR) << opt << ": unknown node type or illegal obfuscated string "
|
||||||
|
<< optarg;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (optid) {
|
||||||
|
case SHRPX_OPTID_FORWARDED_BY:
|
||||||
|
mod_config()->forwarded_by_node_type =
|
||||||
|
static_cast<shrpx_forwarded_node_type>(type);
|
||||||
|
if (optarg[0] == '_') {
|
||||||
|
mod_config()->forwarded_by_obfuscated = optarg;
|
||||||
|
} else {
|
||||||
|
mod_config()->forwarded_by_obfuscated = "";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SHRPX_OPTID_FORWARDED_FOR:
|
||||||
|
mod_config()->forwarded_for_node_type =
|
||||||
|
static_cast<shrpx_forwarded_node_type>(type);
|
||||||
|
if (optarg[0] == '_') {
|
||||||
|
mod_config()->forwarded_for_obfuscated = optarg;
|
||||||
|
} else {
|
||||||
|
mod_config()->forwarded_for_obfuscated = "";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
case SHRPX_OPTID_CONF:
|
case SHRPX_OPTID_CONF:
|
||||||
LOG(WARN) << "conf: ignored";
|
LOG(WARN) << "conf: ignored";
|
||||||
|
|
||||||
|
|
|
@ -191,6 +191,13 @@ constexpr char SHRPX_OPT_TLS_DYN_REC_WARMUP_THRESHOLD[] =
|
||||||
"tls-dyn-rec-warmup-threshold";
|
"tls-dyn-rec-warmup-threshold";
|
||||||
constexpr char SHRPX_OPT_TLS_DYN_REC_IDLE_TIMEOUT[] =
|
constexpr char SHRPX_OPT_TLS_DYN_REC_IDLE_TIMEOUT[] =
|
||||||
"tls-dyn-rec-idle-timeout";
|
"tls-dyn-rec-idle-timeout";
|
||||||
|
constexpr char SHRPX_OPT_ADD_FORWARDED[] = "add-forwarded";
|
||||||
|
constexpr char SHRPX_OPT_STRIP_INCOMING_FORWARDED[] =
|
||||||
|
"strip-incoming-forwarded";
|
||||||
|
constexpr static char SHRPX_OPT_FORWARDED_BY[] = "forwarded-by";
|
||||||
|
constexpr char SHRPX_OPT_FORWARDED_FOR[] = "forwarded-for";
|
||||||
|
|
||||||
|
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
|
||||||
|
|
||||||
union sockaddr_union {
|
union sockaddr_union {
|
||||||
sockaddr_storage storage;
|
sockaddr_storage storage;
|
||||||
|
@ -207,6 +214,19 @@ struct Address {
|
||||||
|
|
||||||
enum shrpx_proto { PROTO_HTTP2, PROTO_HTTP };
|
enum shrpx_proto { PROTO_HTTP2, PROTO_HTTP };
|
||||||
|
|
||||||
|
enum shrpx_forwarded_param {
|
||||||
|
FORWARDED_NONE = 0,
|
||||||
|
FORWARDED_BY = 0x1,
|
||||||
|
FORWARDED_FOR = 0x2,
|
||||||
|
FORWARDED_HOST = 0x4,
|
||||||
|
FORWARDED_PROTO = 0x8,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum shrpx_forwarded_node_type {
|
||||||
|
FORWARDED_NODE_OBFUSCATED,
|
||||||
|
FORWARDED_NODE_IP,
|
||||||
|
};
|
||||||
|
|
||||||
struct AltSvc {
|
struct AltSvc {
|
||||||
AltSvc() : port(0) {}
|
AltSvc() : port(0) {}
|
||||||
|
|
||||||
|
@ -283,6 +303,13 @@ struct Config {
|
||||||
Address session_cache_memcached_addr;
|
Address session_cache_memcached_addr;
|
||||||
Address tls_ticket_key_memcached_addr;
|
Address tls_ticket_key_memcached_addr;
|
||||||
Router router;
|
Router router;
|
||||||
|
// obfuscated value used in "by" parameter of Forwarded header
|
||||||
|
// field.
|
||||||
|
std::string forwarded_by_obfuscated;
|
||||||
|
// obfuscated value used in "for" parameter of Forwarded header
|
||||||
|
// field. This is only used when user defined static obfuscated
|
||||||
|
// string is provided.
|
||||||
|
std::string forwarded_for_obfuscated;
|
||||||
std::chrono::seconds tls_session_timeout;
|
std::chrono::seconds tls_session_timeout;
|
||||||
ev_tstamp http2_upstream_read_timeout;
|
ev_tstamp http2_upstream_read_timeout;
|
||||||
ev_tstamp upstream_read_timeout;
|
ev_tstamp upstream_read_timeout;
|
||||||
|
@ -377,6 +404,14 @@ struct Config {
|
||||||
long int tls_proto_mask;
|
long int tls_proto_mask;
|
||||||
// downstream protocol; this will be determined by given options.
|
// downstream protocol; this will be determined by given options.
|
||||||
shrpx_proto downstream_proto;
|
shrpx_proto downstream_proto;
|
||||||
|
// bitwise-OR of one or more of shrpx_forwarded_param values.
|
||||||
|
uint32_t forwarded_params;
|
||||||
|
// type of value recorded in "by" parameter of Forwarded header
|
||||||
|
// field.
|
||||||
|
shrpx_forwarded_node_type forwarded_by_node_type;
|
||||||
|
// type of value recorded in "for" parameter of Forwarded header
|
||||||
|
// field.
|
||||||
|
shrpx_forwarded_node_type forwarded_for_node_type;
|
||||||
int syslog_facility;
|
int syslog_facility;
|
||||||
int backlog;
|
int backlog;
|
||||||
int argc;
|
int argc;
|
||||||
|
@ -399,6 +434,7 @@ struct Config {
|
||||||
bool client_proxy;
|
bool client_proxy;
|
||||||
bool add_x_forwarded_for;
|
bool add_x_forwarded_for;
|
||||||
bool strip_incoming_x_forwarded_for;
|
bool strip_incoming_x_forwarded_for;
|
||||||
|
bool strip_incoming_forwarded;
|
||||||
bool no_via;
|
bool no_via;
|
||||||
bool upstream_no_tls;
|
bool upstream_no_tls;
|
||||||
bool downstream_no_tls;
|
bool downstream_no_tls;
|
||||||
|
|
|
@ -62,6 +62,41 @@ std::string create_via_header_value(int major, int minor) {
|
||||||
return hdrs;
|
return hdrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string create_forwarded(int params, const std::string &node_by,
|
||||||
|
const std::string &node_for,
|
||||||
|
const std::string &host,
|
||||||
|
const std::string &proto) {
|
||||||
|
std::string res;
|
||||||
|
if ((params & FORWARDED_BY) && !node_by.empty()) {
|
||||||
|
res += "by=\"";
|
||||||
|
res += node_by;
|
||||||
|
res += "\";";
|
||||||
|
}
|
||||||
|
if ((params & FORWARDED_FOR) && !node_for.empty()) {
|
||||||
|
res += "for=\"";
|
||||||
|
res += node_for;
|
||||||
|
res += "\";";
|
||||||
|
}
|
||||||
|
if ((params & FORWARDED_HOST) && !host.empty()) {
|
||||||
|
res += "host=\"";
|
||||||
|
res += host;
|
||||||
|
res += "\";";
|
||||||
|
}
|
||||||
|
if ((params & FORWARDED_PROTO) && !proto.empty()) {
|
||||||
|
res += "proto=\"";
|
||||||
|
res += proto;
|
||||||
|
res += "\";";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.empty()) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.erase(res.size() - 1);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
std::string colorizeHeaders(const char *hdrs) {
|
std::string colorizeHeaders(const char *hdrs) {
|
||||||
std::string nhdrs;
|
std::string nhdrs;
|
||||||
const char *p = strchr(hdrs, '\n');
|
const char *p = strchr(hdrs, '\n');
|
||||||
|
|
|
@ -39,6 +39,13 @@ std::string create_error_html(unsigned int status_code);
|
||||||
|
|
||||||
std::string create_via_header_value(int major, int minor);
|
std::string create_via_header_value(int major, int minor);
|
||||||
|
|
||||||
|
// Returns generated RFC 7239 Forwarded header field value. The
|
||||||
|
// |params| is bitwise-OR of zero or more of shrpx_forwarded_param
|
||||||
|
// defined in shrpx_config.h.
|
||||||
|
std::string create_forwarded(int params, const std::string &node_by,
|
||||||
|
const std::string &node_for,
|
||||||
|
const std::string &host, const std::string &proto);
|
||||||
|
|
||||||
// Adds ANSI color codes to HTTP headers |hdrs|.
|
// Adds ANSI color codes to HTTP headers |hdrs|.
|
||||||
std::string colorizeHeaders(const char *hdrs);
|
std::string colorizeHeaders(const char *hdrs);
|
||||||
|
|
||||||
|
|
|
@ -283,7 +283,7 @@ int Http2DownstreamConnection::push_request_headers() {
|
||||||
num_cookies = downstream_->count_crumble_request_cookie();
|
num_cookies = downstream_->count_crumble_request_cookie();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8 means:
|
// 9 means:
|
||||||
// 1. :method
|
// 1. :method
|
||||||
// 2. :scheme
|
// 2. :scheme
|
||||||
// 3. :path
|
// 3. :path
|
||||||
|
@ -292,8 +292,9 @@ int Http2DownstreamConnection::push_request_headers() {
|
||||||
// 6. x-forwarded-for (optional)
|
// 6. x-forwarded-for (optional)
|
||||||
// 7. x-forwarded-proto (optional)
|
// 7. x-forwarded-proto (optional)
|
||||||
// 8. te (optional)
|
// 8. te (optional)
|
||||||
|
// 9. forwarded (optional)
|
||||||
auto nva = std::vector<nghttp2_nv>();
|
auto nva = std::vector<nghttp2_nv>();
|
||||||
nva.reserve(req.fs.headers().size() + 8 + num_cookies +
|
nva.reserve(req.fs.headers().size() + 9 + num_cookies +
|
||||||
get_config()->add_request_headers.size());
|
get_config()->add_request_headers.size());
|
||||||
|
|
||||||
nva.push_back(
|
nva.push_back(
|
||||||
|
@ -326,6 +327,44 @@ int Http2DownstreamConnection::push_request_headers() {
|
||||||
downstream_->crumble_request_cookie(nva);
|
downstream_->crumble_request_cookie(nva);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto upstream = downstream_->get_upstream();
|
||||||
|
auto handler = upstream->get_client_handler();
|
||||||
|
|
||||||
|
std::string forwarded_value;
|
||||||
|
|
||||||
|
auto fwd = get_config()->strip_incoming_forwarded
|
||||||
|
? nullptr
|
||||||
|
: req.fs.header(http2::HD_FORWARDED);
|
||||||
|
|
||||||
|
if (get_config()->forwarded_params) {
|
||||||
|
auto params = get_config()->forwarded_params;
|
||||||
|
|
||||||
|
if (get_config()->http2_proxy || get_config()->client_proxy ||
|
||||||
|
req.method == HTTP_CONNECT) {
|
||||||
|
params &= ~FORWARDED_PROTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto value = http::create_forwarded(params, handler->get_forwarded_by(),
|
||||||
|
handler->get_forwarded_for(),
|
||||||
|
req.authority, req.scheme);
|
||||||
|
if (fwd || !value.empty()) {
|
||||||
|
if (fwd) {
|
||||||
|
forwarded_value = fwd->value;
|
||||||
|
|
||||||
|
if (!value.empty()) {
|
||||||
|
forwarded_value += ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
forwarded_value += value;
|
||||||
|
|
||||||
|
nva.push_back(http2::make_nv_ls("forwarded", forwarded_value));
|
||||||
|
}
|
||||||
|
} else if (fwd) {
|
||||||
|
nva.push_back(http2::make_nv_ls_nocopy("forwarded", fwd->value));
|
||||||
|
forwarded_value = fwd->value;
|
||||||
|
}
|
||||||
|
|
||||||
std::string xff_value;
|
std::string xff_value;
|
||||||
auto xff = req.fs.header(http2::HD_X_FORWARDED_FOR);
|
auto xff = req.fs.header(http2::HD_X_FORWARDED_FOR);
|
||||||
if (get_config()->add_x_forwarded_for) {
|
if (get_config()->add_x_forwarded_for) {
|
||||||
|
@ -333,8 +372,7 @@ int Http2DownstreamConnection::push_request_headers() {
|
||||||
xff_value = (*xff).value;
|
xff_value = (*xff).value;
|
||||||
xff_value += ", ";
|
xff_value += ", ";
|
||||||
}
|
}
|
||||||
xff_value +=
|
xff_value += upstream->get_client_handler()->get_ipaddr();
|
||||||
downstream_->get_upstream()->get_client_handler()->get_ipaddr();
|
|
||||||
nva.push_back(http2::make_nv_ls("x-forwarded-for", xff_value));
|
nva.push_back(http2::make_nv_ls("x-forwarded-for", xff_value));
|
||||||
} else if (xff && !get_config()->strip_incoming_x_forwarded_for) {
|
} else if (xff && !get_config()->strip_incoming_x_forwarded_for) {
|
||||||
nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-for", (*xff).value));
|
nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-for", (*xff).value));
|
||||||
|
|
|
@ -296,6 +296,41 @@ int HttpDownstreamConnection::push_request_headers() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto upstream = downstream_->get_upstream();
|
||||||
|
auto handler = upstream->get_client_handler();
|
||||||
|
|
||||||
|
auto fwd = get_config()->strip_incoming_forwarded
|
||||||
|
? nullptr
|
||||||
|
: req.fs.header(http2::HD_FORWARDED);
|
||||||
|
if (get_config()->forwarded_params) {
|
||||||
|
auto params = get_config()->forwarded_params;
|
||||||
|
|
||||||
|
if (get_config()->http2_proxy || get_config()->client_proxy ||
|
||||||
|
connect_method) {
|
||||||
|
params &= ~FORWARDED_PROTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto value = http::create_forwarded(params, handler->get_forwarded_by(),
|
||||||
|
handler->get_forwarded_for(),
|
||||||
|
req.authority, req.scheme);
|
||||||
|
if (fwd || !value.empty()) {
|
||||||
|
buf->append("Forwarded: ");
|
||||||
|
if (fwd) {
|
||||||
|
buf->append(fwd->value);
|
||||||
|
|
||||||
|
if (!value.empty()) {
|
||||||
|
buf->append(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf->append(value);
|
||||||
|
buf->append("\r\n");
|
||||||
|
}
|
||||||
|
} else if (fwd) {
|
||||||
|
buf->append("Forwarded: ");
|
||||||
|
buf->append(fwd->value);
|
||||||
|
buf->append("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
auto xff = req.fs.header(http2::HD_X_FORWARDED_FOR);
|
auto xff = req.fs.header(http2::HD_X_FORWARDED_FOR);
|
||||||
if (get_config()->add_x_forwarded_for) {
|
if (get_config()->add_x_forwarded_for) {
|
||||||
buf->append("X-Forwarded-For: ");
|
buf->append("X-Forwarded-For: ");
|
||||||
|
|
|
@ -62,10 +62,14 @@ void mcpool_clear_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
std::random_device rd;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
Worker::Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx,
|
Worker::Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx,
|
||||||
ssl::CertLookupTree *cert_tree,
|
ssl::CertLookupTree *cert_tree,
|
||||||
const std::shared_ptr<TicketKeys> &ticket_keys)
|
const std::shared_ptr<TicketKeys> &ticket_keys)
|
||||||
: dconn_pool_(get_config()->downstream_addr_groups.size()),
|
: randgen_(rd()), dconn_pool_(get_config()->downstream_addr_groups.size()),
|
||||||
worker_stat_(get_config()->downstream_addr_groups.size()),
|
worker_stat_(get_config()->downstream_addr_groups.size()),
|
||||||
dgrps_(get_config()->downstream_addr_groups.size()), loop_(loop),
|
dgrps_(get_config()->downstream_addr_groups.size()), loop_(loop),
|
||||||
sv_ssl_ctx_(sv_ssl_ctx), cl_ssl_ctx_(cl_ssl_ctx), cert_tree_(cert_tree),
|
sv_ssl_ctx_(sv_ssl_ctx), cl_ssl_ctx_(cl_ssl_ctx), cert_tree_(cert_tree),
|
||||||
|
@ -268,6 +272,8 @@ MemcachedDispatcher *Worker::get_session_cache_memcached_dispatcher() {
|
||||||
return session_cache_memcached_dispatcher_.get();
|
return session_cache_memcached_dispatcher_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::mt19937 &Worker::get_randgen() { return randgen_; }
|
||||||
|
|
||||||
#ifdef HAVE_MRUBY
|
#ifdef HAVE_MRUBY
|
||||||
int Worker::create_mruby_context() {
|
int Worker::create_mruby_context() {
|
||||||
auto mruby_file = get_config()->mruby_file.get();
|
auto mruby_file = get_config()->mruby_file.get();
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <random>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#ifndef NOTHREADS
|
#ifndef NOTHREADS
|
||||||
#include <future>
|
#include <future>
|
||||||
|
@ -132,6 +133,8 @@ public:
|
||||||
|
|
||||||
MemcachedDispatcher *get_session_cache_memcached_dispatcher();
|
MemcachedDispatcher *get_session_cache_memcached_dispatcher();
|
||||||
|
|
||||||
|
std::mt19937 &get_randgen();
|
||||||
|
|
||||||
#ifdef HAVE_MRUBY
|
#ifdef HAVE_MRUBY
|
||||||
int create_mruby_context();
|
int create_mruby_context();
|
||||||
|
|
||||||
|
@ -144,6 +147,7 @@ private:
|
||||||
#endif // NOTHREADS
|
#endif // NOTHREADS
|
||||||
std::mutex m_;
|
std::mutex m_;
|
||||||
std::vector<WorkerEvent> q_;
|
std::vector<WorkerEvent> q_;
|
||||||
|
std::mt19937 randgen_;
|
||||||
ev_async w_;
|
ev_async w_;
|
||||||
ev_timer mcpool_clear_timer_;
|
ev_timer mcpool_clear_timer_;
|
||||||
MemchunkPool mcpool_;
|
MemchunkPool mcpool_;
|
||||||
|
|
13
src/util.h
13
src/util.h
|
@ -45,6 +45,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
#include "http-parser/http_parser.h"
|
#include "http-parser/http_parser.h"
|
||||||
|
|
||||||
|
@ -622,6 +623,18 @@ uint64_t get_uint64(const uint8_t *data);
|
||||||
int read_mime_types(std::map<std::string, std::string> &res,
|
int read_mime_types(std::map<std::string, std::string> &res,
|
||||||
const char *filename);
|
const char *filename);
|
||||||
|
|
||||||
|
template <typename Generator>
|
||||||
|
std::string random_alpha_digit(Generator &gen, size_t len) {
|
||||||
|
std::string res;
|
||||||
|
res.reserve(len);
|
||||||
|
std::uniform_int_distribution<> dis(0, 26 * 2 + 10 - 1);
|
||||||
|
for (; len > 0; --len) {
|
||||||
|
res += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"[dis(
|
||||||
|
gen)];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace util
|
} // namespace util
|
||||||
|
|
||||||
} // namespace nghttp2
|
} // namespace nghttp2
|
||||||
|
|
Loading…
Reference in New Issue