Diff for /embedaddon/mtr/packet/probe_unix.c between versions 1.1.1.1 and 1.1.1.2

version 1.1.1.1, 2019/10/21 14:25:31 version 1.1.1.2, 2021/03/17 00:07:30
Line 11 Line 11
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.      GNU General Public License for more details.
   
    You should have received a copy of the GNU General Public License    You should have received a copy of the GNU General Public License along
    along with this program; if not, write to the Free Software    with this program; if not, write to the Free Software Foundation, Inc.,
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */  */
   
 #include "probe.h"  #include "probe.h"
Line 21 Line 21
 #include <assert.h>  #include <assert.h>
 #include <errno.h>  #include <errno.h>
 #include <fcntl.h>  #include <fcntl.h>
   #ifdef HAVE_ERROR_H
   #include <error.h>
   #else
   #include "portability/error.h"
   #endif
   #ifdef HAVE_LINUX_ERRQUEUE_H
   #include <linux/errqueue.h>
   #endif
 #include <stdio.h>  #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
Line 29 Line 37
   
 #include "platform.h"  #include "platform.h"
 #include "protocols.h"  #include "protocols.h"
   #include "sockaddr.h"
 #include "construct_unix.h"  #include "construct_unix.h"
 #include "deconstruct_unix.h"  #include "deconstruct_unix.h"
 #include "timeval.h"  #include "timeval.h"
Line 38  static Line 47  static
 int send_packet(  int send_packet(
     const struct net_state_t *net_state,      const struct net_state_t *net_state,
     const struct probe_param_t *param,      const struct probe_param_t *param,
       int sequence,
     const char *packet,      const char *packet,
     int packet_size,      int packet_size,
     const struct sockaddr_storage *sockaddr)      const struct sockaddr_storage *sockaddr)
 {  {
       struct sockaddr_storage dst;
     int send_socket = 0;      int send_socket = 0;
     int sockaddr_length;      int sockaddr_length;
   
       memcpy(&dst, sockaddr, sizeof(struct sockaddr_storage));
   
     if (sockaddr->ss_family == AF_INET6) {      if (sockaddr->ss_family == AF_INET6) {
         sockaddr_length = sizeof(struct sockaddr_in6);          sockaddr_length = sizeof(struct sockaddr_in6);
   
         if (param->protocol == IPPROTO_ICMP) {          if (param->protocol == IPPROTO_ICMP) {
            send_socket = net_state->platform.icmp6_send_socket;            if (net_state->platform.ip6_socket_raw) {
                 send_socket = net_state->platform.icmp6_send_socket;
             } else {
                 send_socket = net_state->platform.ip6_txrx_icmp_socket;
             }
         } else if (param->protocol == IPPROTO_UDP) {          } else if (param->protocol == IPPROTO_UDP) {
            send_socket = net_state->platform.udp6_send_socket;            if (net_state->platform.ip6_socket_raw) {
                 send_socket = net_state->platform.udp6_send_socket;
                 /* we got a ipv6 udp raw socket
                  * the remote port is in the payload
                  * we do not set in the sockaddr
                  */
                 *sockaddr_port_offset(&dst) = 0;
             } else {
                 send_socket = net_state->platform.ip6_txrx_udp_socket;
                 if (param->dest_port) {
                     *sockaddr_port_offset(&dst) = htons(param->dest_port);
                 } else {
                     *sockaddr_port_offset(&dst) = sequence;
                 }
             }
         }          }
     } else if (sockaddr->ss_family == AF_INET) {      } else if (sockaddr->ss_family == AF_INET) {
         sockaddr_length = sizeof(struct sockaddr_in);          sockaddr_length = sizeof(struct sockaddr_in);
   
        send_socket = net_state->platform.ip4_send_socket;        if (net_state->platform.ip4_socket_raw) {
             send_socket = net_state->platform.ip4_send_socket;
         } else {
             if (param->protocol == IPPROTO_ICMP) {
                 if (param->is_probing_byte_order) {
                     send_socket = net_state->platform.ip4_tmp_icmp_socket;;
                 } else {
                     send_socket = net_state->platform.ip4_txrx_icmp_socket;
                 }
             } else if (param->protocol == IPPROTO_UDP) {
                 send_socket = net_state->platform.ip4_txrx_udp_socket;
                 if (param->dest_port) {
                     *sockaddr_port_offset(&dst) = htons(param->dest_port);
                 } else {
                     *sockaddr_port_offset(&dst) = sequence;
                 }
             }
         }
     }      }
   
     if (send_socket == 0) {      if (send_socket == 0) {
Line 65  int send_packet( Line 113  int send_packet(
     }      }
   
     return sendto(send_socket, packet, packet_size, 0,      return sendto(send_socket, packet, packet_size, 0,
                  (struct sockaddr *) sockaddr, sockaddr_length);                  (struct sockaddr *) &dst, sockaddr_length);
 }  }
   
 /*  /*
Line 85  void check_length_order( Line 133  void check_length_order(
 {  {
     char packet[PACKET_BUFFER_SIZE];      char packet[PACKET_BUFFER_SIZE];
     struct probe_param_t param;      struct probe_param_t param;
    struct sockaddr_storage dest_sockaddr;    struct probe_t p0 = {.sequence = MIN_PORT };
    struct sockaddr_storage src_sockaddr; 
     ssize_t bytes_sent;      ssize_t bytes_sent;
     int packet_size;      int packet_size;
   
   #ifdef __linux__
       /*  Linux will accept either byte order and check below fails to work
        *  in some cases due to sendto() returning EPERM. */
       return;
   #endif
   
     memset(&param, 0, sizeof(struct probe_param_t));      memset(&param, 0, sizeof(struct probe_param_t));
     param.ip_version = 4;      param.ip_version = 4;
     param.protocol = IPPROTO_ICMP;      param.protocol = IPPROTO_ICMP;
     param.ttl = 255;      param.ttl = 255;
     param.remote_address = "127.0.0.1";      param.remote_address = "127.0.0.1";
       param.is_probing_byte_order = true;
   
    if (resolve_probe_addresses(&param, &dest_sockaddr, &src_sockaddr)) {
        fprintf(stderr, "Error decoding localhost address\n");    if (resolve_probe_addresses(net_state, &param, &p0.remote_addr,
                 &p0.local_addr)) {
         fprintf(stderr, "Error decoding localhost address (%s/%s)\n", 
                 probe_err, strerror (errno));
         exit(EXIT_FAILURE);          exit(EXIT_FAILURE);
     }      }
   
     /*  First attempt to ping the localhost with network byte order  */      /*  First attempt to ping the localhost with network byte order  */
     net_state->platform.ip_length_host_order = false;      net_state->platform.ip_length_host_order = false;
   
    packet_size = construct_packet(net_state, NULL, MIN_PORT,    packet_size = construct_packet(net_state, NULL, &p0,
                                    packet, PACKET_BUFFER_SIZE,                                     packet, PACKET_BUFFER_SIZE,
                                   &dest_sockaddr, &src_sockaddr, &param);                                   &param);
     if (packet_size < 0) {      if (packet_size < 0) {
        perror("Unable to send to localhost");      error(EXIT_FAILURE, errno, "Unable to send to localhost");
        exit(EXIT_FAILURE); 
     }      }
   
     bytes_sent =      bytes_sent =
        send_packet(net_state, &param, packet, packet_size,        send_packet(net_state, &param, MIN_PORT, packet, packet_size,
                    &dest_sockaddr);                    &p0.remote_addr);
     if (bytes_sent > 0) {      if (bytes_sent > 0) {
         return;          return;
     }      }
Line 122  void check_length_order( Line 178  void check_length_order(
     /*  Since network byte order failed, try host byte order  */      /*  Since network byte order failed, try host byte order  */
     net_state->platform.ip_length_host_order = true;      net_state->platform.ip_length_host_order = true;
   
    packet_size = construct_packet(net_state, NULL, MIN_PORT,    packet_size = construct_packet(net_state, NULL, &p0,
                                    packet, PACKET_BUFFER_SIZE,                                     packet, PACKET_BUFFER_SIZE,
                                   &dest_sockaddr, &src_sockaddr, &param);                                   &param);
     if (packet_size < 0) {      if (packet_size < 0) {
        perror("Unable to send to localhost");        error(EXIT_FAILURE, errno, "Unable to send to localhost");
        exit(EXIT_FAILURE); 
     }      }
   
     bytes_sent =      bytes_sent =
        send_packet(net_state, &param, packet, packet_size,        send_packet(net_state, &param, MIN_PORT, packet, packet_size,
                    &dest_sockaddr);                    &p0.remote_addr);
     if (bytes_sent < 0) {      if (bytes_sent < 0) {
        perror("Unable to send with swapped length");        error(EXIT_FAILURE, errno, "Unable to send with swapped length");
        exit(EXIT_FAILURE); 
     }      }
 }  }
   
Line 169  void set_socket_nonblocking( Line 223  void set_socket_nonblocking(
   
     flags = fcntl(socket, F_GETFL, 0);      flags = fcntl(socket, F_GETFL, 0);
     if (flags == -1) {      if (flags == -1) {
        perror("Unexpected socket F_GETFL error");        error(EXIT_FAILURE, errno, "Unexpected socket F_GETFL error");
        exit(EXIT_FAILURE); 
     }      }
   
     if (fcntl(socket, F_SETFL, flags | O_NONBLOCK)) {      if (fcntl(socket, F_SETFL, flags | O_NONBLOCK)) {
        perror("Unexpected socket F_SETFL O_NONBLOCK error");        error(EXIT_FAILURE, errno, "Unexpected socket F_SETFL O_NONBLOCK error");
        exit(EXIT_FAILURE); 
     }      }
 }  }
   
 /*  Open the raw sockets for sending/receiving IPv4 packets  */  /*  Open the raw sockets for sending/receiving IPv4 packets  */
 static  static
int open_ip4_sockets(int open_ip4_sockets_raw(
     struct net_state_t *net_state)      struct net_state_t *net_state)
 {  {
     int send_socket;      int send_socket;
Line 190  int open_ip4_sockets( Line 242  int open_ip4_sockets(
   
     send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);      send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
     if (send_socket == -1) {      if (send_socket == -1) {
        return -1;        send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
         if (send_socket == -1) {
             return -1;
         }
     }      }
   
     /*      /*
Line 215  int open_ip4_sockets( Line 270  int open_ip4_sockets(
     }      }
   
     net_state->platform.ip4_present = true;      net_state->platform.ip4_present = true;
       net_state->platform.ip4_socket_raw = true;
     net_state->platform.ip4_send_socket = send_socket;      net_state->platform.ip4_send_socket = send_socket;
     net_state->platform.ip4_recv_socket = recv_socket;      net_state->platform.ip4_recv_socket = recv_socket;
   
     return 0;      return 0;
 }  }
   
   #ifdef HAVE_LINUX_ERRQUEUE_H
   /*  Open DGRAM sockets for sending/receiving IPv4 packets  */
   static
   int open_ip4_sockets_dgram(
       struct net_state_t *net_state)
   {
       int udp_socket;
       int icmp_socket, icmp_tmp_socket;
   #ifdef HAVE_LINUX_ERRQUEUE_H
       int val = 1;
   #endif
   
       icmp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
       if (icmp_socket == -1) {
           return -1;
       }
   #ifdef HAVE_LINUX_ERRQUEUE_H
       if (setsockopt(icmp_socket, SOL_IP, IP_RECVERR, &val, sizeof(val)) < 0) {
           return -1;
       }
   #endif
   
       udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
       if (udp_socket == -1) {
           close(icmp_socket);
           return -1;
       }
   #ifdef HAVE_LINUX_ERRQUEUE_H
       if (setsockopt(udp_socket, SOL_IP, IP_RECVERR, &val, sizeof(val)) < 0) {
           close(icmp_socket);
           close(udp_socket);
           return -1;
       }
   #endif
   
       icmp_tmp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
       if (icmp_tmp_socket == -1) {
           close(icmp_socket);
           close(udp_socket);
           return -1;
       }
   
       net_state->platform.ip4_present = true;
       net_state->platform.ip4_socket_raw = false;
       net_state->platform.ip4_txrx_icmp_socket = icmp_socket;
       net_state->platform.ip4_tmp_icmp_socket = icmp_tmp_socket;
       net_state->platform.ip4_txrx_udp_socket = udp_socket;
   
       return 0;
   }
   #endif
   
 /*  Open the raw sockets for sending/receiving IPv6 packets  */  /*  Open the raw sockets for sending/receiving IPv6 packets  */
 static  static
int open_ip6_sockets(int open_ip6_sockets_raw(
     struct net_state_t *net_state)      struct net_state_t *net_state)
 {  {
     int send_socket_icmp;      int send_socket_icmp;
Line 251  int open_ip6_sockets( Line 359  int open_ip6_sockets(
     }      }
   
     net_state->platform.ip6_present = true;      net_state->platform.ip6_present = true;
       net_state->platform.ip6_socket_raw = true;
     net_state->platform.icmp6_send_socket = send_socket_icmp;      net_state->platform.icmp6_send_socket = send_socket_icmp;
     net_state->platform.udp6_send_socket = send_socket_udp;      net_state->platform.udp6_send_socket = send_socket_udp;
     net_state->platform.ip6_recv_socket = recv_socket;      net_state->platform.ip6_recv_socket = recv_socket;
Line 258  int open_ip6_sockets( Line 367  int open_ip6_sockets(
     return 0;      return 0;
 }  }
   
   #ifdef HAVE_LINUX_ERRQUEUE_H
   /*  Open DGRAM sockets for sending/receiving IPv6 packets  */
   static
   int open_ip6_sockets_dgram(
       struct net_state_t *net_state)
   {
       int icmp_socket;
       int udp_socket;
   #ifdef HAVE_LINUX_ERRQUEUE_H
       int val = 1;
   #endif
   
       icmp_socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
       if (icmp_socket == -1) {
           return -1;
       }
   #ifdef HAVE_LINUX_ERRQUEUE_H
       if (setsockopt(icmp_socket, SOL_IPV6, IPV6_RECVERR, &val, sizeof(val)) < 0) {
           return -1;
       }
   #endif
   
       udp_socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
       if (udp_socket == -1) {
           close(icmp_socket);
           return -1;
       }
   #ifdef HAVE_LINUX_ERRQUEUE_H
       if (setsockopt(udp_socket, SOL_IPV6, IPV6_RECVERR, &val, sizeof(val)) < 0) {
           close(icmp_socket);
           close(udp_socket);
           return -1;
       }
   #endif
   
       net_state->platform.ip6_present = true;
       net_state->platform.ip6_socket_raw = false;
       net_state->platform.ip6_txrx_icmp_socket = icmp_socket;
       net_state->platform.ip6_txrx_udp_socket = udp_socket;
   
       return 0;
   }
   #endif
   
 /*  /*
     The first half of the net state initialization.  Since this      The first half of the net state initialization.  Since this
     happens with elevated privileges, this is kept as minimal      happens with elevated privileges, this is kept as minimal
Line 273  void init_net_state_privileged( Line 426  void init_net_state_privileged(
   
     net_state->platform.next_sequence = MIN_PORT;      net_state->platform.next_sequence = MIN_PORT;
   
    if (open_ip4_sockets(net_state)) {    if (open_ip4_sockets_raw(net_state)) {
        ip4_err = errno;#ifdef HAVE_LINUX_ERRQUEUE_H
         /* fall back to using unprivileged sockets */
         if (open_ip4_sockets_dgram(net_state)) {
             ip4_err = errno;
         }
 #endif
     }      }
    if (open_ip6_sockets(net_state)) {    if (open_ip6_sockets_raw(net_state)) {
        ip6_err = errno;#ifdef HAVE_LINUX_ERRQUEUE_H
         /* fall back to using unprivileged sockets */
         if (open_ip6_sockets_dgram(net_state)) {
             ip6_err = errno;
         }
 #endif
     }      }
   
     /*      /*
Line 286  void init_net_state_privileged( Line 449  void init_net_state_privileged(
      */       */
     if (!net_state->platform.ip4_present      if (!net_state->platform.ip4_present
         && !net_state->platform.ip6_present) {          && !net_state->platform.ip6_present) {
        error(0, ip4_err, "Failure to open IPv4 sockets");
        errno = ip4_err;        error(0, ip6_err, "Failure to open IPv6 sockets");
        perror("Failure to open IPv4 sockets"); 
 
        errno = ip6_err; 
        perror("Failure to open IPv6 sockets"); 
 
         exit(EXIT_FAILURE);          exit(EXIT_FAILURE);
     }      }
 }  }
Line 304  void init_net_state_privileged( Line 462  void init_net_state_privileged(
 void init_net_state(  void init_net_state(
     struct net_state_t *net_state)      struct net_state_t *net_state)
 {  {
    set_socket_nonblocking(net_state->platform.ip4_recv_socket);    if (net_state->platform.ip4_socket_raw) {
    set_socket_nonblocking(net_state->platform.ip6_recv_socket);        set_socket_nonblocking(net_state->platform.ip4_recv_socket);
     } else {
         set_socket_nonblocking(net_state->platform.ip4_txrx_icmp_socket);
         set_socket_nonblocking(net_state->platform.ip4_txrx_udp_socket);
     }
     if (net_state->platform.ip6_socket_raw) {
         set_socket_nonblocking(net_state->platform.ip6_recv_socket);
     } else {
         set_socket_nonblocking(net_state->platform.ip6_txrx_icmp_socket);
         set_socket_nonblocking(net_state->platform.ip6_txrx_udp_socket);
     }
   
     if (net_state->platform.ip4_present) {      if (net_state->platform.ip4_present) {
         check_length_order(net_state);          check_length_order(net_state);
Line 387  void send_probe( Line 555  void send_probe(
 {  {
     char packet[PACKET_BUFFER_SIZE];      char packet[PACKET_BUFFER_SIZE];
     struct probe_t *probe;      struct probe_t *probe;
       int trytimes;
     int packet_size;      int packet_size;
     struct sockaddr_storage src_sockaddr;  
   
     probe = alloc_probe(net_state, param->command_token);      probe = alloc_probe(net_state, param->command_token);
     if (probe == NULL) {      if (probe == NULL) {
Line 396  void send_probe( Line 564  void send_probe(
         return;          return;
     }      }
   
    if (resolve_probe_addresses(param, &probe->remote_addr, &src_sockaddr)) {    if (resolve_probe_addresses(net_state, param, &probe->remote_addr,
                 &probe->local_addr)) {
         printf("%d invalid-argument\n", param->command_token);          printf("%d invalid-argument\n", param->command_token);
         free_probe(net_state, probe);          free_probe(net_state, probe);
         return;          return;
     }      }
   
     if (gettimeofday(&probe->platform.departure_time, NULL)) {      if (gettimeofday(&probe->platform.departure_time, NULL)) {
        perror("gettimeofday failure");        error(EXIT_FAILURE, errno, "gettimeofday failure");
        exit(EXIT_FAILURE); 
     }      }
   
    packet_size =    // there might be an off-by-one in the number of tries here. 
        construct_packet(net_state, &probe->platform.socket,    // this is intentional.  It is no use exhausting the very last
                         probe->sequence, packet, PACKET_BUFFER_SIZE,    // open port. Max 10 retries would've been acceptable too I think. 
                         &probe->remote_addr, &src_sockaddr, param);    for (trytimes=MIN_PORT; trytimes < MAX_PORT; trytimes++) {
                         
         packet_size = construct_packet(net_state, &probe->platform.socket,
                          probe, packet, PACKET_BUFFER_SIZE,
                          param);
   
           if (packet_size > 0) break; // no retry if we succeed.
   
           if ((param->protocol != IPPROTO_TCP) && 
               (param->protocol != IPPROTO_SCTP)) break; // no retry if not TCP/SCTP
   
           if ((errno != EADDRINUSE) && (errno != EADDRNOTAVAIL)) {
               break; // no retry
           }
   
           probe->sequence = net_state->platform.next_sequence++;
                   
           if (net_state->platform.next_sequence > MAX_PORT) {
               net_state->platform.next_sequence = MIN_PORT;
           }
       }
   
     if (packet_size < 0) {      if (packet_size < 0) {
         /*          /*
            When using a stream protocol, FreeBSD will return ECONNREFUSED             When using a stream protocol, FreeBSD will return ECONNREFUSED
Line 431  void send_probe( Line 619  void send_probe(
     }      }
   
     if (packet_size > 0) {      if (packet_size > 0) {
        if (send_packet(net_state, param,        if (send_packet(net_state, param, probe->sequence,
                         packet, packet_size, &probe->remote_addr) == -1) {                          packet, packet_size, &probe->remote_addr) == -1) {
   
             report_packet_error(param->command_token);              report_packet_error(param->command_token);
Line 488  void receive_probe( Line 676  void receive_probe(
   
     if (timestamp == NULL) {      if (timestamp == NULL) {
         if (gettimeofday(&now, NULL)) {          if (gettimeofday(&now, NULL)) {
            perror("gettimeofday failure");            error(EXIT_FAILURE, errno, "gettimeofday failure");
            exit(EXIT_FAILURE); 
         }          }
   
         timestamp = &now;          timestamp = &now;
Line 505  void receive_probe( Line 692  void receive_probe(
   
 /*  /*
     Read all available packets through our receiving raw socket, and      Read all available packets through our receiving raw socket, and
    handle any responses to probes we have preivously sent.    handle any responses to probes we have previously sent.
 */  */
 static  static
void receive_replies_from_icmp_socket(void receive_replies_from_recv_socket(
     struct net_state_t *net_state,      struct net_state_t *net_state,
     int socket,      int socket,
     received_packet_func_t handle_received_packet)      received_packet_func_t handle_received_packet)
Line 516  void receive_replies_from_icmp_socket( Line 703  void receive_replies_from_icmp_socket(
     char packet[PACKET_BUFFER_SIZE];      char packet[PACKET_BUFFER_SIZE];
     int packet_length;      int packet_length;
     struct sockaddr_storage remote_addr;      struct sockaddr_storage remote_addr;
     socklen_t sockaddr_length;  
     struct timeval timestamp;      struct timeval timestamp;
       int flag = 0;
   #ifdef HAVE_LINUX_ERRQUEUE_H
       struct cmsghdr *cm;
       struct sock_extended_err *ee = NULL;
       bool icmp_connrefused_received = false;
       bool icmp_hostunreach_received = false;
   #endif
   
     /*  Read until no more packets are available  */      /*  Read until no more packets are available  */
     while (true) {      while (true) {
        sockaddr_length = sizeof(struct sockaddr_storage);        struct iovec iov;
        packet_length = recvfrom(socket, packet, PACKET_BUFFER_SIZE, 0,        struct msghdr msg;
                                 (struct sockaddr *) &remote_addr,        char control[1024];
                                 &sockaddr_length); 
   
           memset(&msg, 0, sizeof(msg));
           memset(&iov, 0, sizeof(iov));
           iov.iov_base = packet;
           iov.iov_len = sizeof(packet);
           msg.msg_iov = &iov;
           msg.msg_iovlen = 1;
           msg.msg_name = (struct sockaddr*) &remote_addr;
           msg.msg_namelen = sizeof(remote_addr);
           msg.msg_control = control;
           msg.msg_controllen = sizeof(control);
           packet_length = recvmsg(socket, &msg, flag);
   
         /*          /*
            Get the time immediately after reading the packet to             Get the time immediately after reading the packet to
            keep the timing as precise as we can.             keep the timing as precise as we can.
          */           */
         if (gettimeofday(&timestamp, NULL)) {          if (gettimeofday(&timestamp, NULL)) {
            perror("gettimeofday failure");            error(EXIT_FAILURE, errno, "gettimeofday failure");
            exit(EXIT_FAILURE); 
         }          }
   
         if (packet_length == -1) {          if (packet_length == -1) {
Line 549  void receive_replies_from_icmp_socket( Line 752  void receive_replies_from_icmp_socket(
                receive.                 receive.
              */               */
             if (errno == EINTR) {              if (errno == EINTR) {
                   /* clear error */
                   int so_err;
                   socklen_t so_err_size = sizeof(so_err);
                   int err;
   
                   do {
                     err = getsockopt(socket, SOL_SOCKET, SO_ERROR, &so_err, &so_err_size);
                   } while (err < 0 && errno == EINTR);
                 continue;                  continue;
             }              }
   
            perror("Failure receiving replies");            /* handle error received in error queue */
            exit(EXIT_FAILURE);            if (errno == EHOSTUNREACH) {
                 /* potential error caused by ttl, read inner icmp hdr from err queue */
 #ifdef HAVE_LINUX_ERRQUEUE_H
                 icmp_hostunreach_received = true;
                 flag |= MSG_ERRQUEUE;
 #endif
                 continue;
             }
 
             if (errno == ECONNREFUSED) {
                 /* udp packet reached dst, read inner udp hdr from err queue */
 #ifdef HAVE_LINUX_ERRQUEUE_H
                 icmp_connrefused_received = true;
                 flag |= MSG_ERRQUEUE;
 #endif
                 continue;
             }
 
             error(EXIT_FAILURE, errno, "Failure receiving replies");
         }          }
   
        handle_received_packet(net_state, &remote_addr, packet,#ifdef HAVE_LINUX_ERRQUEUE_H
                               packet_length, &timestamp);        /* get src ip for packets read from err queue */
         if (flag & MSG_ERRQUEUE) {
             for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) {
                 if (cm->cmsg_level == SOL_IP) {
                     if (cm->cmsg_type == IP_RECVERR) {
                         ee = (struct sock_extended_err *) CMSG_DATA(cm);
                     }
                 }
                 else if (cm->cmsg_level == SOL_IPV6) {
                     if (cm->cmsg_type == IPV6_RECVERR) {
                         ee = (struct sock_extended_err *) CMSG_DATA(cm);
                     }
                 }
             }
             if (ee) {
                 memcpy(&remote_addr, SO_EE_OFFENDER(ee), sizeof(remote_addr));
             }
         }
 
 #ifdef SO_PROTOCOL
         if (icmp_connrefused_received) {
             /* using ICMP type ICMP_ECHOREPLY is not a bug, it is an
                indication of successfully reaching dst host.
              */
             handle_error_queue_packet(net_state, &remote_addr, ICMP_ECHOREPLY, IPPROTO_UDP,
                     packet, packet_length, &timestamp);
         } else if (icmp_hostunreach_received) {
             /* handle packet based on send socket protocol */
             int proto, length = sizeof(int);
 
             if (getsockopt(socket, SOL_SOCKET, SO_PROTOCOL, &proto, &length) < 0) {
                 error(EXIT_FAILURE, errno, "getsockopt SO_PROTOCOL error");
             }
             handle_error_queue_packet(net_state, &remote_addr, ICMP_TIME_EXCEEDED, proto,
                     packet, packet_length, &timestamp);
         } else {
 #endif
 #endif
             /* ICMP packets received from raw socket */
             handle_received_packet(net_state, &remote_addr, packet,
                                    packet_length, &timestamp);
 #ifdef HAVE_LINUX_ERRQUEUE_H
 #ifdef SO_PROTOCOL
         }
 #endif
 #endif
     }      }
 }  }
   
Line 592  void receive_replies_from_probe_socket( Line 866  void receive_replies_from_probe_socket(
         if (errno == EAGAIN) {          if (errno == EAGAIN) {
             return;              return;
         } else {          } else {
            perror("probe socket select error");            error(EXIT_FAILURE, errno, "probe socket select error");
            exit(EXIT_FAILURE); 
         }          }
     }      }
   
Line 605  void receive_replies_from_probe_socket( Line 878  void receive_replies_from_probe_socket(
     }      }
   
     if (getsockopt(probe_socket, SOL_SOCKET, SO_ERROR, &err, &err_length)) {      if (getsockopt(probe_socket, SOL_SOCKET, SO_ERROR, &err, &err_length)) {
        perror("probe socket SO_ERROR");        error(EXIT_FAILURE, errno, "probe socket SO_ERROR");
        exit(EXIT_FAILURE); 
     }      }
   
     /*      /*
Line 631  void receive_replies( Line 903  void receive_replies(
     struct probe_t *probe_safe_iter;      struct probe_t *probe_safe_iter;
   
     if (net_state->platform.ip4_present) {      if (net_state->platform.ip4_present) {
        receive_replies_from_icmp_socket(net_state,        if (net_state->platform.ip4_socket_raw) {
                                         net_state->platform.            receive_replies_from_recv_socket(net_state,
                                         ip4_recv_socket,                                             net_state->platform.
                                         handle_received_ip4_packet);                                             ip4_recv_socket,
                                              handle_received_ip4_packet);
         } else {
             receive_replies_from_recv_socket(net_state,
                                              net_state->platform.
                                              ip4_txrx_icmp_socket,
                                              handle_received_ip4_packet);
             receive_replies_from_recv_socket(net_state,
                                              net_state->platform.
                                              ip4_txrx_udp_socket,
                                              handle_received_ip4_packet);
         }
     }      }
   
     if (net_state->platform.ip6_present) {      if (net_state->platform.ip6_present) {
        receive_replies_from_icmp_socket(net_state,        if (net_state->platform.ip6_socket_raw) {
                                         net_state->platform.            receive_replies_from_recv_socket(net_state,
                                         ip6_recv_socket,                                             net_state->platform.
                                         handle_received_ip6_packet);                                             ip6_recv_socket,
                                              handle_received_ip6_packet);
         } else {
             receive_replies_from_recv_socket(net_state,
                                              net_state->platform.
                                              ip6_txrx_icmp_socket,
                                              handle_received_ip6_packet);
             receive_replies_from_recv_socket(net_state,
                                              net_state->platform.
                                              ip6_txrx_udp_socket,
                                              handle_received_ip6_packet);
         }
     }      }
   
     LIST_FOREACH_SAFE(probe, &net_state->outstanding_probes,      LIST_FOREACH_SAFE(probe, &net_state->outstanding_probes,
Line 692  void check_probe_timeouts( Line 986  void check_probe_timeouts(
     struct probe_t *probe_safe_iter;      struct probe_t *probe_safe_iter;
   
     if (gettimeofday(&now, NULL)) {      if (gettimeofday(&now, NULL)) {
        perror("gettimeofday failure");        error(EXIT_FAILURE, errno, "gettimeofday failure");
        exit(EXIT_FAILURE); 
     }      }
   
     LIST_FOREACH_SAFE(probe, &net_state->outstanding_probes,      LIST_FOREACH_SAFE(probe, &net_state->outstanding_probes,
Line 726  bool get_next_probe_timeout( Line 1019  bool get_next_probe_timeout(
     struct timeval probe_timeout;      struct timeval probe_timeout;
   
     if (gettimeofday(&now, NULL)) {      if (gettimeofday(&now, NULL)) {
        perror("gettimeofday failure");        error(EXIT_FAILURE, errno, "gettimeofday failure");
        exit(EXIT_FAILURE); 
     }      }
   
     have_timeout = false;      have_timeout = false;

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>