Skip to content

Commit a7f965f

Browse files
committed
fix: resolve duplicate response headers and support CIDR notation in IP blacklist
Remove header duplication in copyResponse where recorder.Header() and w.Header() share the same map, causing every header to be doubled. The recorder delegates Header() and WriteHeader() to the underlying writer, so only the body needs copying. Support CIDR notation entries in IP blacklist files by detecting existing prefix notation before appending a default mask. Also fix IPv6 single-host default from /64 to /128. Bump version to v0.3.0. Fixes #91 Closes #92
1 parent 10639ca commit a7f965f

File tree

3 files changed

+16
-14
lines changed

3 files changed

+16
-14
lines changed

caddywaf.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ var (
4949
)
5050

5151
// Add or update the version constant as needed
52-
const wafVersion = "v0.2.0" // update this value to the new release version when tagging
52+
const wafVersion = "v0.3.0" // update this value to the new release version when tagging
5353

5454
// ==================== Initialization and Setup ====================
5555

@@ -498,7 +498,15 @@ func (m *Middleware) loadIPBlacklist(path string, blacklistMap iptrie.Trie) erro
498498

499499
// Convert the map to CIDRTrie
500500
for ip := range blacklist {
501-
prefix, err := netip.ParsePrefix(appendCIDR(ip))
501+
var prefix netip.Prefix
502+
var err error
503+
504+
if strings.Contains(ip, "/") {
505+
prefix, err = netip.ParsePrefix(ip)
506+
} else {
507+
prefix, err = netip.ParsePrefix(appendCIDR(ip))
508+
}
509+
502510
if err != nil {
503511
m.logger.Warn("Skipping invalid IP in blacklist", zap.String("ip", ip), zap.Error(err))
504512
continue

handler.go

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -231,21 +231,15 @@ func (m *Middleware) logRequestCompletion(logID string, state *WAFState) {
231231
)
232232
}
233233

234-
// copyResponse copies the captured response from the recorder to the original writer
234+
// copyResponse copies the captured response body from the recorder to the original writer.
235+
// Headers and status code are already on w because the recorder delegates Header() and
236+
// WriteHeader() directly to the underlying ResponseWriter, so only the body needs copying.
235237
func (m *Middleware) copyResponse(w http.ResponseWriter, recorder *responseRecorder, r *http.Request) {
236-
header := w.Header()
237-
for key, values := range recorder.Header() {
238-
for _, value := range values {
239-
header.Add(key, value)
240-
}
241-
}
242-
w.WriteHeader(recorder.StatusCode())
243-
244238
logID := getLogID(r.Context())
245239
if logID == "unknown" {
246-
m.logger.Error("Log ID not found in context during response copy") // added error log for clarity
240+
m.logger.Error("Log ID not found in context during response copy")
247241
}
248-
_, err := w.Write(recorder.body.Bytes()) // Copy body from recorder to original writer
242+
_, err := w.Write(recorder.body.Bytes())
249243
if err != nil {
250244
m.logger.Error("Failed to write recorded response body to client", zap.Error(err), zap.String("log_id", logID))
251245
}

helpers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func appendCIDR(ip string) string {
3333
ip += "/32"
3434
// IPv6
3535
} else {
36-
ip += "/64"
36+
ip += "/128"
3737
}
3838
return ip
3939
}

0 commit comments

Comments
 (0)