DF-5707 / probe.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | /* * probe.c - DF-5707 oracle prover: sends N ICMP echo requests to 127.0.0.1 * through ipfw rule "prob 0.5 deny icmp from any to any icmptypes 8 via lo0" * and classifies each packet: * 'D' sendto returned EACCES (denied at lo0 out-check: 1 draw, d1 < T) * 'T' sent, no reply (denied at lo0 in-check: 2 draws, d1>=T, d2 < T) * 'R' reply received (passed both request checks; reply draws never * deny: total 4 draws, d1>=T, d2>=T) * Prints the obs string plus randseed before/after (read via /dev/mem). * * usage: probe <n> <delay_ms> <RSstatefile-out> */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <time.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/ip_icmp.h> #include <arpa/inet.h> #define KERNBASE 0xFFFFFFFF80000000ULL #define RSPHYS 0x1120c80 /* randseed phys = va - KERNBASE */ static uint64_t read_rs(int fd) { uint64_t v = 0; if (pread(fd, &v, 8, RSPHYS) != 8) { perror("pread rs"); exit(1); } return v; } static unsigned short cksum(unsigned short *p, int n) { unsigned long s = 0; while (n > 1) { s += *p++; n -= 2; } if (n) s += *(unsigned char *)p; s = (s >> 16) + (s & 0xffff); s += (s >> 16); return ~s; } int main(int argc, char **argv) { int n = argc > 1 ? atoi(argv[1]) : 40; int delay_ms = argc > 2 ? atoi(argv[2]) : 20; int mfd = open("/dev/mem", O_RDONLY); if (mfd < 0) { perror("open /dev/mem"); return 1; } int s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (s < 0) { perror("socket"); return 1; } struct sockaddr_in dst; memset(&dst, 0, sizeof(dst)); dst.sin_family = AF_INET; dst.sin_addr.s_addr = inet_addr("127.0.0.1"); char *obs = calloc(n + 1, 1); uint64_t s0 = read_rs(mfd); struct timespec ts = { 0, delay_ms * 1000000 }; for (int i = 0; i < n; i++) { char pkt[64]; memset(pkt, 0, sizeof(pkt)); struct icmp *icp = (struct icmp *)pkt; icp->icmp_type = ICMP_ECHO; icp->icmp_code = 0; icp->icmp_id = htons(0x5707); icp->icmp_seq = htons(i); icp->icmp_cksum = 0; icp->icmp_cksum = cksum((unsigned short *)pkt, 64); if (sendto(s, pkt, 64, 0, (struct sockaddr *)&dst, sizeof(dst)) < 0) { if (errno == EACCES) obs[i] = 'D'; else { fprintf(stderr, "sendto errno %d\n", errno); obs[i] = 'X'; } } else { obs[i] = 'T'; /* upgraded to R if reply arrives */ } nanosleep(&ts, NULL); } /* drain replies: match icmp_id, echo reply type, seq */ struct timeval tv = { 0, 300000 }; if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) perror("setsockopt"); int got = 0; for (;;) { char buf[128]; struct sockaddr_in from; socklen_t flen = sizeof(from); ssize_t r = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *)&from, &flen); if (r < 0) break; /* timeout: no more replies */ struct icmp *icp = (struct icmp *)(buf + 20); /* skip IP hdr (raw recv w/o IPHDRINCL gives ip header) */ if ((size_t)r >= 20 + 8 && icp->icmp_type == ICMP_ECHOREPLY && icp->icmp_id == htons(0x5707)) { int seq = ntohs(icp->icmp_seq); if (seq >= 0 && seq < n && obs[seq] == 'T') { obs[seq] = 'R'; got++; } } } uint64_t s1 = read_rs(mfd); printf("RS0=%llx\n", (unsigned long long)s0); printf("RS1=%llx\n", (unsigned long long)s1); printf("OBS=%s\n", obs); fprintf(stderr, "sent=%d replies=%d D=%zd T=%zd R=%zd\n", n, got, (size_t)strchr(obs,'D') ? 0 : 0, (size_t)0, (size_t)0); int cD=0,cT=0,cR=0; for (char *p = obs; *p; p++) { if(*p=='D')cD++; else if(*p=='T')cT++; else if(*p=='R')cR++; } fprintf(stderr, "counts D=%d T=%d R=%d\n", cD, cT, cR); return 0; } |