|
| 1 | +/* |
| 2 | + * Regression: ossec-execd treats two IPv6 spellings as two blocks |
| 3 | + * |
| 4 | + * ANT-2026-PTTDW7PW / CWE-178 |
| 5 | + * |
| 6 | + * ExecdStart() compares the srcip text with strcmp(). 2001:DB8::7 and |
| 7 | + * 2001:db8::7 are one address to pf, so the first timeout deletes the |
| 8 | + * table entry while execd still counts the other spelling as blocked. |
| 9 | + * A literal address must have one spelling before it is compared, |
| 10 | + * stored, or handed to the script. Host names, "-", CIDR, and a |
| 11 | + * leading "!" stay as written. |
| 12 | + * |
| 13 | + * Build (from src/): |
| 14 | + * make -f tests/regressions/Makefile issue_pttdw7pw_ipv6_case |
| 15 | + * |
| 16 | + * Run: |
| 17 | + * ./issue_pttdw7pw_ipv6_case |
| 18 | + */ |
| 19 | + |
| 20 | +#include <stdio.h> |
| 21 | +#include <string.h> |
| 22 | + |
| 23 | +#include "shared.h" |
| 24 | +#include "os_execd/execd.h" |
| 25 | + |
| 26 | +static int failures = 0; |
| 27 | + |
| 28 | +static void expect(int cond, const char *msg) |
| 29 | +{ |
| 30 | + if (cond) { |
| 31 | + printf(" ok: %s\n", msg); |
| 32 | + } else { |
| 33 | + printf(" FAIL: %s\n", msg); |
| 34 | + failures++; |
| 35 | + } |
| 36 | +} |
| 37 | + |
| 38 | +static void same_spelling(const char *a, const char *b, const char *want, const char *msg) |
| 39 | +{ |
| 40 | + char ca[64]; |
| 41 | + char cb[64]; |
| 42 | + int ra; |
| 43 | + int rb; |
| 44 | + |
| 45 | + ca[0] = '\0'; |
| 46 | + cb[0] = '\0'; |
| 47 | + ra = CanonicalIP(a, ca, sizeof(ca)); |
| 48 | + rb = CanonicalIP(b, cb, sizeof(cb)); |
| 49 | + expect(ra == 1 && rb == 1 && strcmp(ca, cb) == 0 && strcmp(ca, want) == 0, msg); |
| 50 | +} |
| 51 | + |
| 52 | +int main(void) |
| 53 | +{ |
| 54 | + char dst[64]; |
| 55 | + |
| 56 | + printf("execd IPv6 address spelling\n"); |
| 57 | + |
| 58 | + same_spelling("2001:DB8::7", "2001:db8::7", "2001:db8::7", |
| 59 | + "IPv6 letter case is one spelling"); |
| 60 | + same_spelling("::ffff:192.0.2.1", "192.0.2.1", "192.0.2.1", |
| 61 | + "an IPv4-mapped address is the IPv4 address"); |
| 62 | + same_spelling("192.0.2.1", "192.0.2.1", "192.0.2.1", |
| 63 | + "an IPv4 address stays dotted decimal"); |
| 64 | + |
| 65 | + expect(CanonicalIP("mail.example", dst, sizeof(dst)) == 0, |
| 66 | + "a host name is left unchanged"); |
| 67 | + expect(CanonicalIP("-", dst, sizeof(dst)) == 0, |
| 68 | + "a dash user placeholder is left unchanged"); |
| 69 | + expect(CanonicalIP("2001:db8::/64", dst, sizeof(dst)) == 0, |
| 70 | + "a CIDR prefix is left unchanged"); |
| 71 | + expect(CanonicalIP("!192.0.2.1", dst, sizeof(dst)) == 0, |
| 72 | + "a negated address is left unchanged"); |
| 73 | + |
| 74 | + if (failures) { |
| 75 | + printf("FAIL: %d IPv6 spelling check(s)\n", failures); |
| 76 | + return 1; |
| 77 | + } |
| 78 | + printf("ok\n"); |
| 79 | + return 0; |
| 80 | +} |
0 commit comments