+1
-1
conf/config.example.toml
+1
-1
conf/config.example.toml
+5
-2
src/config.go
+5
-2
src/config.go
···
152
152
NodeID int `toml:"node-id"`
153
153
// Whether audit reports should be stored whenever an audit event occurs.
154
154
Collect bool `toml:"collect"`
155
-
// Whether audit reports should include principal's IP address.
156
-
IncludeIPs bool `toml:"include-ip"`
155
+
// If not empty, includes the principal's IP address in audit reports, with the value specifying
156
+
// the source of the IP address. If the value is "X-Forwarded-For", the last item of the
157
+
// corresponding header field (assumed to be comma-separated) is used. If the value is
158
+
// "RemoteAddr", the connecting host's address is used. Any other value is disallowed.
159
+
IncludeIPs string `toml:"include-ip"`
157
160
// Endpoint to notify with a `GET /<notify-url>?<id>` whenever an audit event occurs.
158
161
NotifyURL *URL `toml:"notify-url"`
159
162
}
+46
src/http.go
+46
src/http.go
···
2
2
3
3
import (
4
4
"cmp"
5
+
"fmt"
6
+
"net"
7
+
"net/http"
5
8
"regexp"
6
9
"slices"
7
10
"strconv"
···
129
132
}
130
133
return preferredAcceptOffer(encs)
131
134
}
135
+
136
+
func chainHTTPMiddleware(middleware ...func(http.Handler) http.Handler) func(http.Handler) http.Handler {
137
+
return func(handler http.Handler) http.Handler {
138
+
for idx := len(middleware) - 1; idx >= 0; idx-- {
139
+
handler = middleware[idx](handler)
140
+
}
141
+
return handler
142
+
}
143
+
}
144
+
145
+
func remoteAddrMiddleware(handler http.Handler) http.Handler {
146
+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
147
+
var readXForwardedFor bool
148
+
switch config.Audit.IncludeIPs {
149
+
case "X-Forwarded-For":
150
+
readXForwardedFor = true
151
+
case "RemoteAddr", "":
152
+
readXForwardedFor = false
153
+
default:
154
+
panic(fmt.Errorf("config.Audit.IncludeIPs is set to an unknown value (%q)",
155
+
config.Audit.IncludeIPs))
156
+
}
157
+
158
+
usingOriginalRemoteAddr := true
159
+
if readXForwardedFor {
160
+
forwardedFor := strings.Split(r.Header.Get("X-Forwarded-For"), ",")
161
+
if len(forwardedFor) > 0 {
162
+
remoteAddr := strings.TrimSpace(forwardedFor[len(forwardedFor)-1])
163
+
if remoteAddr != "" {
164
+
r.RemoteAddr = remoteAddr
165
+
usingOriginalRemoteAddr = false
166
+
}
167
+
}
168
+
}
169
+
if usingOriginalRemoteAddr {
170
+
if ipAddress, _, err := net.SplitHostPort(r.RemoteAddr); err == nil {
171
+
r.RemoteAddr = ipAddress
172
+
}
173
+
}
174
+
175
+
handler.ServeHTTP(w, r)
176
+
})
177
+
}
+7
-4
src/main.go
+7
-4
src/main.go
···
132
132
133
133
func serve(ctx context.Context, listener net.Listener, handler http.Handler) {
134
134
if listener != nil {
135
-
handler = panicHandler(handler)
136
-
137
135
server := http.Server{Handler: handler}
138
136
server.Protocols = new(http.Protocols)
139
137
server.Protocols.SetHTTP1(true)
···
537
535
}
538
536
backend = NewObservedBackend(backend)
539
537
540
-
go serve(ctx, pagesListener, ObserveHTTPHandler(http.HandlerFunc(ServePages)))
541
-
go serve(ctx, caddyListener, ObserveHTTPHandler(http.HandlerFunc(ServeCaddy)))
538
+
middleware := chainHTTPMiddleware(
539
+
panicHandler,
540
+
remoteAddrMiddleware,
541
+
ObserveHTTPHandler,
542
+
)
543
+
go serve(ctx, pagesListener, middleware(http.HandlerFunc(ServePages)))
544
+
go serve(ctx, caddyListener, middleware(http.HandlerFunc(ServeCaddy)))
542
545
go serve(ctx, metricsListener, promhttp.Handler())
543
546
544
547
if config.Insecure {
+2
-5
src/pages.go
+2
-5
src/pages.go
···
9
9
"fmt"
10
10
"io"
11
11
"maps"
12
-
"net"
13
12
"net/http"
14
13
"net/url"
15
14
"os"
···
802
801
803
802
func ServePages(w http.ResponseWriter, r *http.Request) {
804
803
r = r.WithContext(WithPrincipal(r.Context()))
805
-
if config.Audit.IncludeIPs {
806
-
if ipAddress, _, err := net.SplitHostPort(r.RemoteAddr); err == nil {
807
-
GetPrincipal(r.Context()).IpAddress = proto.String(ipAddress)
808
-
}
804
+
if config.Audit.IncludeIPs != "" {
805
+
GetPrincipal(r.Context()).IpAddress = proto.String(r.RemoteAddr)
809
806
}
810
807
// We want upstream health checks to be done as closely to the normal flow as possible;
811
808
// any intentional deviation is an opportunity to miss an issue that will affect our