java-topology/defects/traefik/unit/TraefikTest.java

119 lines
4.5 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import java.util.*;
/**
* CWE-407 unit tests for Traefik defects.
*
* traefik-0001: pkg/ip/checker.go ContainsIP()
* authorizedIPs is []*net.IP — linear scan with Equal() per request.
* O(T) where T = trusted IP count. Hot path: every HTTP request through
* ipallowlist/ipwhitelist/forwardedheaders middleware.
* Fix: map[[16]byte]struct{} for O(1) exact-IP lookup.
*
* traefik-0002: pkg/middlewares/headers/header.go isOriginAllowed()
* AccessControlAllowOriginList is []string — linear scan per CORS request.
* O(O) where O = allowed origin count. Hot path: every CORS response.
* Fix: map[string]struct{} built at init time for O(1) lookup.
*/
public class TraefikTest {
// --- traefik-0001 ---
static boolean containsIP_slice(List<String> authorizedIPs, String addr) {
for (String ip : authorizedIPs) { // O(T) — defect
if (ip.equals(addr)) return true;
}
return false;
}
static boolean containsIP_map(Set<String> authorizedMap, String addr) {
return authorizedMap.contains(addr); // O(1) — fix
}
static void testTraefik0001() throws Exception {
int T = 500; // trusted IPs (Cloudflare + enterprise egress IPs)
List<String> ipSlice = new ArrayList<>(T);
Set<String> ipMap = new HashSet<>(T);
for (int i = 0; i < T; i++) {
String ip = "10." + (i / 256) + "." + (i % 256) + ".1";
ipSlice.add(ip);
ipMap.add(ip);
}
// target near end (worst case for linear scan)
String target = "10." + ((T - 1) / 256) + "." + ((T - 1) % 256) + ".1";
String unknown = "1.2.3.4";
// correctness
assert containsIP_slice(ipSlice, target) == containsIP_map(ipMap, target);
assert !containsIP_slice(ipSlice, unknown) && !containsIP_map(ipMap, unknown);
// performance: simulate R HTTP requests
int R = 200_000;
long t0 = System.nanoTime();
for (int r = 0; r < R; r++) containsIP_slice(ipSlice, target);
long tSlice = System.nanoTime() - t0;
t0 = System.nanoTime();
for (int r = 0; r < R; r++) containsIP_map(ipMap, target);
long tMap = System.nanoTime() - t0;
double ratio = (double) tSlice / tMap;
System.out.printf("traefik-0001: slice=%.3fs map=%.3fs ratio=%.1f×%n",
tSlice / 1e9, tMap / 1e9, ratio);
assert ratio > 20 : "Expected >20× speedup, got " + ratio;
System.out.println("PASS traefik-0001");
}
// --- traefik-0002 ---
static boolean isOriginAllowed_list(List<String> allowList, String origin) {
for (String item : allowList) { // O(O) — defect
if (item.equals("*") || item.equals(origin)) return true;
}
return false;
}
static boolean isOriginAllowed_map(Set<String> allowSet, String origin) {
return allowSet.contains("*") || allowSet.contains(origin); // O(1) — fix
}
static void testTraefik0002() throws Exception {
int O = 200; // allowed origins (multi-tenant SaaS: many partner domains)
List<String> allowList = new ArrayList<>(O);
Set<String> allowSet = new HashSet<>(O);
for (int i = 0; i < O; i++) {
String origin = "https://partner-" + i + ".example.com";
allowList.add(origin);
allowSet.add(origin);
}
// target near end (worst case)
String target = "https://partner-" + (O - 1) + ".example.com";
String blocked = "https://evil.com";
// correctness
assert isOriginAllowed_list(allowList, target) == isOriginAllowed_map(allowSet, target);
assert !isOriginAllowed_list(allowList, blocked) && !isOriginAllowed_map(allowSet, blocked);
int R = 200_000;
long t0 = System.nanoTime();
for (int r = 0; r < R; r++) isOriginAllowed_list(allowList, target);
long tList = System.nanoTime() - t0;
t0 = System.nanoTime();
for (int r = 0; r < R; r++) isOriginAllowed_map(allowSet, target);
long tMap = System.nanoTime() - t0;
double ratio = (double) tList / tMap;
System.out.printf("traefik-0002: list=%.3fs map=%.3fs ratio=%.1f×%n",
tList / 1e9, tMap / 1e9, ratio);
assert ratio > 10 : "Expected >10× speedup, got " + ratio;
System.out.println("PASS traefik-0002");
}
public static void main(String[] args) throws Exception {
testTraefik0001();
testTraefik0002();
System.out.println("ALL PASS");
}
}