/* * Print ICMP packets that a raw socket receives on MacOS. * * Note: this does NOT work for echo, timestamps, mask requests! * http://stackoverflow.com/questions/6878603/strange-raw-socket-on-mac-os-x * * This will NOT work for any TCP or UDP either. From http://sock-raw.org/papers/sock_raw: FreeBSD takes another approach. It *never* passes TCP or UDP packets to raw sockets. Such packets need to be read directly at the datalink layer by using libraries like libpcap or the bpf API. It also *never* passes any fragmented datagram. Each datagram has to be completeley reassembled before it is passed to a raw socket. FreeBSD passes to a raw socket: a) every IP datagram with a protocol field that is not registered in the kernel b) all IGMP packets after kernel finishes processing them c) all ICMP packets (except echo request, timestamp request and address mask request) after kernel finishes processes them Note that if your computer is *sending* echo requests, then the incoming echo _replies_ will show on the raw socket. Echo requests from other machines would not, as per above, although these machines will see echo replies from yours. */ #include #include #include #include #include #include #include // inet_ntoa int main(){ int sockfd,retval,n; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; char buf[10000]; int i; // 0 serves as a catch-all for any protocol, including ICMP and those // not handled (gets, e.g., protocol 10) // This will allegedly not work on Linux. sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); // 0 for any proto if (sockfd < 0){ perror("sock:"); exit(1); } clilen = sizeof(struct sockaddr_in); while(1){ printf(" before recvfrom\n"); n = recvfrom(sockfd, buf, 10000, 0, (struct sockaddr *)&cliaddr, &clilen); printf(" rec'd %d bytes\n",n); struct ip *ip_hdr = (struct ip *)buf; printf("IP header is %d bytes.\n", ip_hdr->ip_hl*4); for (i = 0; i < n; i++) { printf("%02X%s", (uint8_t)buf[i], (i + 1)%16 ? " " : "\n"); } printf("\n"); struct icmp *icmp_hdr = (struct icmp *)((char *)ip_hdr + (4 * ip_hdr->ip_hl)); printf("ICMP msgtype=%d, code=%d ", icmp_hdr->icmp_type, icmp_hdr->icmp_code); printf("%s -> ", inet_ntoa(ip_hdr->ip_src)); // Doing this print in one go may surprise you: printf("%s\n", inet_ntoa(ip_hdr->ip_dst)); // remember that ntoa's return buffer is reused! } }