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: O(1) insert + dedup → O(N) total * * Trigger: nmap -PS -PA 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 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 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"); } }