int trace_read (trace_t * t) { int len; unsigned char data[56]; /* For a TIME_EXCEEDED datagram. */ struct ip *ip; icmphdr_t *ic; socklen_t siz; assert (t); siz = sizeof (t->from); len = recvfrom (t->icmpfd, (char *) data, 56, 0, (struct sockaddr *) &t->from, &siz); if (len < 0) error (EXIT_FAILURE, errno, "recvfrom"); icmp_generic_decode (data, 56, &ip, &ic); switch (t->type) { case TRACE_UDP: { unsigned short *port; if ((ic->icmp_type != ICMP_TIME_EXCEEDED && ic->icmp_type != ICMP_DEST_UNREACH) || (ic->icmp_type == ICMP_DEST_UNREACH && ic->icmp_code != ICMP_PORT_UNREACH)) return -1; /* check whether it's for us */ port = (unsigned short *) &ic->icmp_ip + 11; if (*port != t->to.sin_port) return -1; if (ic->icmp_code == ICMP_PORT_UNREACH) /* FIXME: Ugly hack. */ stop = 1; } break; case TRACE_ICMP: if (ic->icmp_type != ICMP_TIME_EXCEEDED && ic->icmp_type != ICMP_ECHOREPLY) return -1; if (ic->icmp_type == ICMP_ECHOREPLY && (ic->icmp_seq != pid || ic->icmp_id != pid)) return -1; else if (ic->icmp_type == ICMP_TIME_EXCEEDED) { unsigned short *seq = (unsigned short *) &ic->icmp_ip + 12; unsigned short *ident = (unsigned short *) &ic->icmp_ip + 13; if (*seq != pid || *ident != pid) return -1; } if (ip->ip_src.s_addr == dest.sin_addr.s_addr) /* FIXME: Ugly hack. */ stop = 1; break; /* FIXME: Type according to RFC 1393. */ default: break; } return 0; }
int ping_recv (PING * p) { socklen_t fromlen = sizeof (p->ping_from.ping_sockaddr); int n, rc; icmphdr_t *icmp; struct ip *ip; int dupflag; n = recvfrom (p->ping_fd, (char *) p->ping_buffer, _PING_BUFLEN (p, USE_IPV6), 0, (struct sockaddr *) &p->ping_from.ping_sockaddr, &fromlen); if (n < 0) return -1; rc = icmp_generic_decode (p->ping_buffer, n, &ip, &icmp); if (rc < 0) { /*FIXME: conditional */ fprintf (stderr, "packet too short (%d bytes) from %s\n", n, inet_ntoa (p->ping_from.ping_sockaddr.sin_addr)); return -1; } switch (icmp->icmp_type) { case ICMP_ECHOREPLY: case ICMP_TIMESTAMPREPLY: case ICMP_ADDRESSREPLY: /* case ICMP_ROUTERADV: */ if (icmp->icmp_id != p->ping_ident) return -1; if (rc) fprintf (stderr, "checksum mismatch from %s\n", inet_ntoa (p->ping_from.ping_sockaddr.sin_addr)); p->ping_num_recv++; if (_PING_TST (p, icmp->icmp_seq)) { p->ping_num_rept++; p->ping_num_recv--; dupflag = 1; } else { _PING_SET (p, icmp->icmp_seq); dupflag = 0; } if (p->ping_event.handler) (*p->ping_event.handler) (dupflag ? PEV_DUPLICATE : PEV_RESPONSE, p->ping_closure, &p->ping_dest.ping_sockaddr, &p->ping_from.ping_sockaddr, ip, icmp, n); break; case ICMP_ECHO: case ICMP_TIMESTAMP: case ICMP_ADDRESS: return -1; default: if (!my_echo_reply (p, icmp)) return -1; if (p->ping_event.handler) (*p->ping_event.handler) (PEV_NOECHO, p->ping_closure, &p->ping_dest.ping_sockaddr, &p->ping_from.ping_sockaddr, ip, icmp, n); } return 0; }
int icmp_echo_decode (unsigned char * buffer, size_t bufsize, struct ip **ipp, icmphdr_t ** icmpp) { return icmp_generic_decode (buffer, bufsize, ipp, icmpp); }