java-topology/defects/nmap/unit/NmapMergePortListsTest.java
russell@unturf.com ba818693db nmap-0002 + haproxy-0004 + nginx-0004 + weechat-0003 + zeek-0002 + curl-0004: 6 new CWE-407 defects in network tools; count 693→699
nmap-0002:     nmap.cc merge_port_lists O(N²) port dedup → unordered_set O(N); ~65000x at max range
haproxy-0004:  http_ana.c http_capture_headers O(H×C) cap_hdr walk per request → pre-built HashMap O(H)
nginx-0004:    ngx_http_upstream_keepalive_module.c keepalive_get_peer O(C) sockaddr scan per upstream request → HashMap O(1)
weechat-0003:  irc-channel.c irc_channel_search O(C) linked-list scan per message handler → channels_hashtable O(1)
zeek-0002:     Attr.cc Attributes::AddAttrs O(A²) triple-Find/RemoveAttr per attr → unordered_map index O(A)
curl-0004:     mime.c search_header O(P×H) 3x per part per mime_add_headers → pre-indexed header name set O(P)
2026-03-29 22:22:11 -04:00

90 lines
3.4 KiB
Java

package unit;
import java.util.*;
/**
* nmap-0002 — CWE-407: O(N²) port deduplication in merge_port_lists
*
* Models nmap.cc insert_port_into_merge_list():
* Slow: for each port to insert, linear scan of already-merged list (O(N))
* called N times → O(N²) total
* Fast: unordered_set<uint16_t>: O(1) insert + dedup → O(N) total
*
* Trigger: nmap -PS<range> -PA<range> with large overlapping port lists.
* Default lists are tiny (1-2 ports), but user can pass 1-65535 for both.
*/
public class NmapMergePortListsTest {
// --- SLOW: linear scan dedup (defect) ---
static long mergePortListsSlow(int[] list1, int[] list2) {
long ops = 0;
List<Integer> merged = new ArrayList<>(list1.length + list2.length);
for (int p : list1) {
boolean found = false;
for (int m : merged) { ops++; if (m == p) { found = true; break; } }
if (!found) merged.add(p);
}
for (int p : list2) {
boolean found = false;
for (int m : merged) { ops++; if (m == p) { found = true; break; } }
if (!found) merged.add(p);
}
return ops;
}
// --- FAST: hash set dedup (fix) ---
static long mergePortListsFast(int[] list1, int[] list2) {
long ops = 0;
Set<Integer> seen = new HashSet<>((list1.length + list2.length) * 2);
for (int p : list1) { ops++; seen.add(p); }
for (int p : list2) { ops++; seen.add(p); }
return ops;
}
public static void main(String[] args) {
System.out.println("nmap-0002 CWE-407: merge_port_lists O(N²) vs O(N)");
System.out.println("===================================================");
// Small test: two overlapping port lists
int N = 500;
int[] list1 = new int[N];
int[] list2 = new int[N];
for (int i = 0; i < N; i++) {
list1[i] = i + 1; // ports 1..500
list2[i] = i + 250; // ports 250..750 (overlap with list1)
}
long slowOps = mergePortListsSlow(list1, list2);
long fastOps = mergePortListsFast(list1, list2);
System.out.printf(" N=%d ports per list (250 overlap)%n", N);
System.out.printf(" Slow (linear scan): %,d ops%n", slowOps);
System.out.printf(" Fast (hash set): %,d ops%n", fastOps);
System.out.printf(" Op ratio: %.0fx%n", (double) slowOps / fastOps);
// Larger test
int N2 = 2000;
int[] big1 = new int[N2];
int[] big2 = new int[N2];
for (int i = 0; i < N2; i++) {
big1[i] = i + 1;
big2[i] = i + 1000; // 1000 overlap
}
long slowOps2 = mergePortListsSlow(big1, big2);
long fastOps2 = mergePortListsFast(big1, big2);
System.out.printf("%n N=%d ports per list (1000 overlap)%n", N2);
System.out.printf(" Slow (linear scan): %,d ops%n", slowOps2);
System.out.printf(" Fast (hash set): %,d ops%n", fastOps2);
System.out.printf(" Op ratio: %.0fx%n", (double) slowOps2 / fastOps2);
// Assert O(N²) vs O(N)
assert slowOps > fastOps * (N / 2) :
"Expected slow > fast*" + (N/2) + " but slow=" + slowOps + " fast=" + fastOps;
assert slowOps2 > fastOps2 * (N2 / 4) :
"Expected slow2 > fast2*" + (N2/4) + " but slow2=" + slowOps2 + " fast2=" + fastOps2;
System.out.println("\nPASS");
}
}