Annotation of embedaddon/mtr/packet/probe_unix.c, revision 1.1.1.3

1.1       misho       1: /*
                      2:     mtr  --  a network diagnostic tool
                      3:     Copyright (C) 2016  Matt Kimball
                      4: 
                      5:     This program is free software; you can redistribute it and/or modify
                      6:     it under the terms of the GNU General Public License version 2 as
                      7:     published by the Free Software Foundation.
                      8: 
                      9:     This program is distributed in the hope that it will be useful,
                     10:     but WITHOUT ANY WARRANTY; without even the implied warranty of
                     11:     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     12:     GNU General Public License for more details.
                     13: 
1.1.1.2   misho      14:     You should have received a copy of the GNU General Public License along
                     15:     with this program; if not, write to the Free Software Foundation, Inc.,
                     16:     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1.1       misho      17: */
                     18: 
                     19: #include "probe.h"
                     20: 
                     21: #include <assert.h>
                     22: #include <errno.h>
                     23: #include <fcntl.h>
1.1.1.2   misho      24: #ifdef HAVE_ERROR_H
                     25: #include <error.h>
                     26: #else
                     27: #include "portability/error.h"
                     28: #endif
                     29: #ifdef HAVE_LINUX_ERRQUEUE_H
                     30: #include <linux/errqueue.h>
                     31: #endif
1.1       misho      32: #include <stdio.h>
                     33: #include <stdlib.h>
                     34: #include <string.h>
                     35: #include <sys/socket.h>
                     36: #include <unistd.h>
                     37: 
                     38: #include "platform.h"
                     39: #include "protocols.h"
1.1.1.2   misho      40: #include "sockaddr.h"
1.1       misho      41: #include "construct_unix.h"
                     42: #include "deconstruct_unix.h"
                     43: #include "timeval.h"
                     44: 
                     45: /*  A wrapper around sendto for mixed IPv4 and IPv6 sending  */
                     46: static
                     47: int send_packet(
                     48:     const struct net_state_t *net_state,
                     49:     const struct probe_param_t *param,
1.1.1.2   misho      50:     int sequence,
1.1       misho      51:     const char *packet,
                     52:     int packet_size,
                     53:     const struct sockaddr_storage *sockaddr)
                     54: {
1.1.1.2   misho      55:     struct sockaddr_storage dst;
1.1       misho      56:     int send_socket = 0;
                     57:     int sockaddr_length;
                     58: 
1.1.1.2   misho      59:     memcpy(&dst, sockaddr, sizeof(struct sockaddr_storage));
                     60: 
1.1       misho      61:     if (sockaddr->ss_family == AF_INET6) {
                     62:         sockaddr_length = sizeof(struct sockaddr_in6);
                     63: 
                     64:         if (param->protocol == IPPROTO_ICMP) {
1.1.1.2   misho      65:             if (net_state->platform.ip6_socket_raw) {
                     66:                 send_socket = net_state->platform.icmp6_send_socket;
                     67:             } else {
                     68:                 send_socket = net_state->platform.ip6_txrx_icmp_socket;
                     69:             }
1.1       misho      70:         } else if (param->protocol == IPPROTO_UDP) {
1.1.1.2   misho      71:             if (net_state->platform.ip6_socket_raw) {
                     72:                 send_socket = net_state->platform.udp6_send_socket;
                     73:                 /* we got a ipv6 udp raw socket
                     74:                  * the remote port is in the payload
                     75:                  * we do not set in the sockaddr
                     76:                  */
                     77:                 *sockaddr_port_offset(&dst) = 0;
                     78:             } else {
                     79:                 send_socket = net_state->platform.ip6_txrx_udp_socket;
                     80:                 if (param->dest_port) {
                     81:                     *sockaddr_port_offset(&dst) = htons(param->dest_port);
                     82:                 } else {
                     83:                     *sockaddr_port_offset(&dst) = sequence;
                     84:                 }
                     85:             }
1.1       misho      86:         }
                     87:     } else if (sockaddr->ss_family == AF_INET) {
                     88:         sockaddr_length = sizeof(struct sockaddr_in);
                     89: 
1.1.1.2   misho      90:         if (net_state->platform.ip4_socket_raw) {
                     91:             send_socket = net_state->platform.ip4_send_socket;
                     92:         } else {
                     93:             if (param->protocol == IPPROTO_ICMP) {
                     94:                 if (param->is_probing_byte_order) {
                     95:                     send_socket = net_state->platform.ip4_tmp_icmp_socket;;
                     96:                 } else {
                     97:                     send_socket = net_state->platform.ip4_txrx_icmp_socket;
                     98:                 }
                     99:             } else if (param->protocol == IPPROTO_UDP) {
                    100:                 send_socket = net_state->platform.ip4_txrx_udp_socket;
                    101:                 if (param->dest_port) {
                    102:                     *sockaddr_port_offset(&dst) = htons(param->dest_port);
                    103:                 } else {
                    104:                     *sockaddr_port_offset(&dst) = sequence;
                    105:                 }
                    106:             }
                    107:         }
1.1       misho     108:     }
                    109: 
                    110:     if (send_socket == 0) {
                    111:         errno = EINVAL;
                    112:         return -1;
                    113:     }
                    114: 
                    115:     return sendto(send_socket, packet, packet_size, 0,
1.1.1.2   misho     116:                   (struct sockaddr *) &dst, sockaddr_length);
1.1       misho     117: }
                    118: 
                    119: /*
                    120:     Nearly all fields in the IP header should be encoded in network byte
                    121:     order prior to passing to send().  However, the required byte order of
                    122:     the length field of the IP header is inconsistent between operating
                    123:     systems and operating system versions.  FreeBSD 11 requires the length
                    124:     field in network byte order, but some older versions of FreeBSD
                    125:     require host byte order.  OS X requires the length field in host
                    126:     byte order.  Linux will accept either byte order.
                    127: 
                    128:     Test for a byte order which works by sending a ping to localhost.
                    129: */
                    130: static
                    131: void check_length_order(
                    132:     struct net_state_t *net_state)
                    133: {
                    134:     char packet[PACKET_BUFFER_SIZE];
                    135:     struct probe_param_t param;
1.1.1.2   misho     136:     struct probe_t p0 = {.sequence = MIN_PORT };
1.1       misho     137:     ssize_t bytes_sent;
                    138:     int packet_size;
                    139: 
1.1.1.2   misho     140: #ifdef __linux__
                    141:     /*  Linux will accept either byte order and check below fails to work
                    142:      *  in some cases due to sendto() returning EPERM. */
                    143:     return;
                    144: #endif
                    145: 
1.1       misho     146:     memset(&param, 0, sizeof(struct probe_param_t));
                    147:     param.ip_version = 4;
                    148:     param.protocol = IPPROTO_ICMP;
                    149:     param.ttl = 255;
                    150:     param.remote_address = "127.0.0.1";
1.1.1.2   misho     151:     param.is_probing_byte_order = true;
1.1       misho     152: 
1.1.1.2   misho     153: 
                    154:     if (resolve_probe_addresses(net_state, &param, &p0.remote_addr,
                    155:                 &p0.local_addr)) {
1.1.1.3 ! misho     156:         fprintf(stderr, "Error decoding localhost address (%s/%s)\n",
1.1.1.2   misho     157:                 probe_err, strerror (errno));
1.1       misho     158:         exit(EXIT_FAILURE);
                    159:     }
                    160: 
                    161:     /*  First attempt to ping the localhost with network byte order  */
                    162:     net_state->platform.ip_length_host_order = false;
                    163: 
1.1.1.2   misho     164:     packet_size = construct_packet(net_state, NULL, &p0,
1.1       misho     165:                                    packet, PACKET_BUFFER_SIZE,
1.1.1.2   misho     166:                                    &param);
1.1       misho     167:     if (packet_size < 0) {
1.1.1.2   misho     168:       error(EXIT_FAILURE, errno, "Unable to send to localhost");
1.1       misho     169:     }
                    170: 
                    171:     bytes_sent =
1.1.1.2   misho     172:         send_packet(net_state, &param, MIN_PORT, packet, packet_size,
                    173:                     &p0.remote_addr);
1.1       misho     174:     if (bytes_sent > 0) {
                    175:         return;
                    176:     }
                    177: 
                    178:     /*  Since network byte order failed, try host byte order  */
                    179:     net_state->platform.ip_length_host_order = true;
                    180: 
1.1.1.2   misho     181:     packet_size = construct_packet(net_state, NULL, &p0,
1.1       misho     182:                                    packet, PACKET_BUFFER_SIZE,
1.1.1.2   misho     183:                                    &param);
1.1       misho     184:     if (packet_size < 0) {
1.1.1.2   misho     185:         error(EXIT_FAILURE, errno, "Unable to send to localhost");
1.1       misho     186:     }
                    187: 
                    188:     bytes_sent =
1.1.1.2   misho     189:         send_packet(net_state, &param, MIN_PORT, packet, packet_size,
                    190:                     &p0.remote_addr);
1.1       misho     191:     if (bytes_sent < 0) {
1.1.1.2   misho     192:         error(EXIT_FAILURE, errno, "Unable to send with swapped length");
1.1       misho     193:     }
                    194: }
                    195: 
                    196: /*
                    197:     Check to see if SCTP is support.  We can't just rely on checking
                    198:     if IPPROTO_SCTP is defined, because while that is necessary,
                    199:     MacOS as of "Sierra" defines IPPROTO_SCTP, but creating an SCTP
                    200:     socket results in an error.
                    201: */
                    202: static
                    203: void check_sctp_support(
                    204:     struct net_state_t *net_state)
                    205: {
                    206: #ifdef IPPROTO_SCTP
                    207:     int sctp_socket;
                    208: 
                    209:     sctp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
                    210:     if (sctp_socket != -1) {
                    211:         close(sctp_socket);
                    212: 
                    213:         net_state->platform.sctp_support = true;
                    214:     }
                    215: #endif
                    216: }
                    217: 
                    218: /*  Set a socket to non-blocking mode  */
                    219: void set_socket_nonblocking(
                    220:     int socket)
                    221: {
                    222:     int flags;
                    223: 
                    224:     flags = fcntl(socket, F_GETFL, 0);
                    225:     if (flags == -1) {
1.1.1.2   misho     226:         error(EXIT_FAILURE, errno, "Unexpected socket F_GETFL error");
1.1       misho     227:     }
                    228: 
                    229:     if (fcntl(socket, F_SETFL, flags | O_NONBLOCK)) {
1.1.1.2   misho     230:         error(EXIT_FAILURE, errno, "Unexpected socket F_SETFL O_NONBLOCK error");
1.1       misho     231:     }
                    232: }
                    233: 
                    234: /*  Open the raw sockets for sending/receiving IPv4 packets  */
                    235: static
1.1.1.2   misho     236: int open_ip4_sockets_raw(
1.1       misho     237:     struct net_state_t *net_state)
                    238: {
                    239:     int send_socket;
                    240:     int recv_socket;
                    241:     int trueopt = 1;
                    242: 
                    243:     send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
                    244:     if (send_socket == -1) {
1.1.1.2   misho     245:         send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
                    246:         if (send_socket == -1) {
                    247:             return -1;
                    248:         }
1.1       misho     249:     }
                    250: 
                    251:     /*
                    252:        We will be including the IP header in transmitted packets.
                    253:        Linux doesn't require this, but BSD derived network stacks do.
                    254:      */
                    255:     if (setsockopt
                    256:         (send_socket, IPPROTO_IP, IP_HDRINCL, &trueopt, sizeof(int))) {
                    257: 
                    258:         close(send_socket);
                    259:         return -1;
                    260:     }
                    261: 
                    262:     /*
                    263:        Open a second socket with IPPROTO_ICMP because we are only
                    264:        interested in receiving ICMP packets, not all packets.
                    265:      */
                    266:     recv_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
                    267:     if (recv_socket == -1) {
                    268:         close(send_socket);
                    269:         return -1;
                    270:     }
                    271: 
                    272:     net_state->platform.ip4_present = true;
1.1.1.2   misho     273:     net_state->platform.ip4_socket_raw = true;
1.1       misho     274:     net_state->platform.ip4_send_socket = send_socket;
                    275:     net_state->platform.ip4_recv_socket = recv_socket;
                    276: 
                    277:     return 0;
                    278: }
                    279: 
1.1.1.2   misho     280: #ifdef HAVE_LINUX_ERRQUEUE_H
                    281: /*  Open DGRAM sockets for sending/receiving IPv4 packets  */
                    282: static
                    283: int open_ip4_sockets_dgram(
                    284:     struct net_state_t *net_state)
                    285: {
                    286:     int udp_socket;
                    287:     int icmp_socket, icmp_tmp_socket;
                    288: #ifdef HAVE_LINUX_ERRQUEUE_H
                    289:     int val = 1;
                    290: #endif
                    291: 
                    292:     icmp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
                    293:     if (icmp_socket == -1) {
                    294:         return -1;
                    295:     }
                    296: #ifdef HAVE_LINUX_ERRQUEUE_H
                    297:     if (setsockopt(icmp_socket, SOL_IP, IP_RECVERR, &val, sizeof(val)) < 0) {
                    298:         return -1;
                    299:     }
                    300: #endif
                    301: 
                    302:     udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
                    303:     if (udp_socket == -1) {
                    304:         close(icmp_socket);
                    305:         return -1;
                    306:     }
                    307: #ifdef HAVE_LINUX_ERRQUEUE_H
                    308:     if (setsockopt(udp_socket, SOL_IP, IP_RECVERR, &val, sizeof(val)) < 0) {
                    309:         close(icmp_socket);
                    310:         close(udp_socket);
                    311:         return -1;
                    312:     }
                    313: #endif
                    314: 
                    315:     icmp_tmp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
                    316:     if (icmp_tmp_socket == -1) {
                    317:         close(icmp_socket);
                    318:         close(udp_socket);
                    319:         return -1;
                    320:     }
                    321: 
                    322:     net_state->platform.ip4_present = true;
                    323:     net_state->platform.ip4_socket_raw = false;
                    324:     net_state->platform.ip4_txrx_icmp_socket = icmp_socket;
                    325:     net_state->platform.ip4_tmp_icmp_socket = icmp_tmp_socket;
                    326:     net_state->platform.ip4_txrx_udp_socket = udp_socket;
                    327: 
                    328:     return 0;
                    329: }
                    330: #endif
                    331: 
1.1       misho     332: /*  Open the raw sockets for sending/receiving IPv6 packets  */
                    333: static
1.1.1.2   misho     334: int open_ip6_sockets_raw(
1.1       misho     335:     struct net_state_t *net_state)
                    336: {
                    337:     int send_socket_icmp;
                    338:     int send_socket_udp;
                    339:     int recv_socket;
                    340: 
                    341:     send_socket_icmp = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
                    342:     if (send_socket_icmp == -1) {
                    343:         return -1;
                    344:     }
                    345: 
                    346:     send_socket_udp = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
                    347:     if (send_socket_udp == -1) {
                    348:         close(send_socket_icmp);
                    349: 
                    350:         return -1;
                    351:     }
                    352: 
                    353:     recv_socket = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
                    354:     if (recv_socket == -1) {
                    355:         close(send_socket_icmp);
                    356:         close(send_socket_udp);
                    357: 
                    358:         return -1;
                    359:     }
                    360: 
                    361:     net_state->platform.ip6_present = true;
1.1.1.2   misho     362:     net_state->platform.ip6_socket_raw = true;
1.1       misho     363:     net_state->platform.icmp6_send_socket = send_socket_icmp;
                    364:     net_state->platform.udp6_send_socket = send_socket_udp;
                    365:     net_state->platform.ip6_recv_socket = recv_socket;
                    366: 
                    367:     return 0;
                    368: }
                    369: 
1.1.1.2   misho     370: #ifdef HAVE_LINUX_ERRQUEUE_H
                    371: /*  Open DGRAM sockets for sending/receiving IPv6 packets  */
                    372: static
                    373: int open_ip6_sockets_dgram(
                    374:     struct net_state_t *net_state)
                    375: {
                    376:     int icmp_socket;
                    377:     int udp_socket;
                    378: #ifdef HAVE_LINUX_ERRQUEUE_H
                    379:     int val = 1;
                    380: #endif
                    381: 
                    382:     icmp_socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
                    383:     if (icmp_socket == -1) {
                    384:         return -1;
                    385:     }
                    386: #ifdef HAVE_LINUX_ERRQUEUE_H
                    387:     if (setsockopt(icmp_socket, SOL_IPV6, IPV6_RECVERR, &val, sizeof(val)) < 0) {
                    388:         return -1;
                    389:     }
                    390: #endif
                    391: 
                    392:     udp_socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
                    393:     if (udp_socket == -1) {
                    394:         close(icmp_socket);
                    395:         return -1;
                    396:     }
                    397: #ifdef HAVE_LINUX_ERRQUEUE_H
                    398:     if (setsockopt(udp_socket, SOL_IPV6, IPV6_RECVERR, &val, sizeof(val)) < 0) {
                    399:         close(icmp_socket);
                    400:         close(udp_socket);
                    401:         return -1;
                    402:     }
                    403: #endif
                    404: 
                    405:     net_state->platform.ip6_present = true;
                    406:     net_state->platform.ip6_socket_raw = false;
                    407:     net_state->platform.ip6_txrx_icmp_socket = icmp_socket;
                    408:     net_state->platform.ip6_txrx_udp_socket = udp_socket;
                    409: 
                    410:     return 0;
                    411: }
                    412: #endif
                    413: 
1.1       misho     414: /*
                    415:     The first half of the net state initialization.  Since this
                    416:     happens with elevated privileges, this is kept as minimal
                    417:     as possible to minimize security risk.
                    418: */
                    419: void init_net_state_privileged(
                    420:     struct net_state_t *net_state)
                    421: {
                    422:     int ip4_err = 0;
                    423:     int ip6_err = 0;
                    424: 
                    425:     memset(net_state, 0, sizeof(struct net_state_t));
                    426: 
                    427:     net_state->platform.next_sequence = MIN_PORT;
                    428: 
1.1.1.2   misho     429:     if (open_ip4_sockets_raw(net_state)) {
                    430: #ifdef HAVE_LINUX_ERRQUEUE_H
                    431:         /* fall back to using unprivileged sockets */
                    432:         if (open_ip4_sockets_dgram(net_state)) {
                    433:             ip4_err = errno;
                    434:         }
                    435: #endif
1.1       misho     436:     }
1.1.1.2   misho     437:     if (open_ip6_sockets_raw(net_state)) {
                    438: #ifdef HAVE_LINUX_ERRQUEUE_H
                    439:         /* fall back to using unprivileged sockets */
                    440:         if (open_ip6_sockets_dgram(net_state)) {
                    441:             ip6_err = errno;
                    442:         }
                    443: #endif
1.1       misho     444:     }
                    445: 
                    446:     /*
                    447:        If we couldn't open either IPv4 or IPv6 sockets, we can't do
                    448:        much, so print errors and exit.
                    449:      */
                    450:     if (!net_state->platform.ip4_present
                    451:         && !net_state->platform.ip6_present) {
1.1.1.2   misho     452:         error(0, ip4_err, "Failure to open IPv4 sockets");
                    453:         error(0, ip6_err, "Failure to open IPv6 sockets");
1.1       misho     454:         exit(EXIT_FAILURE);
                    455:     }
                    456: }
                    457: 
                    458: /*
                    459:     The second half of net state initialization, which is run
                    460:     at normal privilege levels.
                    461: */
                    462: void init_net_state(
                    463:     struct net_state_t *net_state)
                    464: {
1.1.1.2   misho     465:     if (net_state->platform.ip4_socket_raw) {
                    466:         set_socket_nonblocking(net_state->platform.ip4_recv_socket);
                    467:     } else {
                    468:         set_socket_nonblocking(net_state->platform.ip4_txrx_icmp_socket);
                    469:         set_socket_nonblocking(net_state->platform.ip4_txrx_udp_socket);
                    470:     }
                    471:     if (net_state->platform.ip6_socket_raw) {
                    472:         set_socket_nonblocking(net_state->platform.ip6_recv_socket);
                    473:     } else {
                    474:         set_socket_nonblocking(net_state->platform.ip6_txrx_icmp_socket);
                    475:         set_socket_nonblocking(net_state->platform.ip6_txrx_udp_socket);
                    476:     }
1.1       misho     477: 
                    478:     if (net_state->platform.ip4_present) {
                    479:         check_length_order(net_state);
                    480:     }
                    481: 
                    482:     check_sctp_support(net_state);
                    483: }
                    484: 
                    485: /*
                    486:     Returns true if we were able to open sockets for a particular
                    487:     IP protocol version.
                    488: */
                    489: bool is_ip_version_supported(
                    490:     struct net_state_t *net_state,
                    491:     int ip_version)
                    492: {
                    493:     if (ip_version == 4) {
                    494:         return net_state->platform.ip4_present;
                    495:     } else if (ip_version == 6) {
                    496:         return net_state->platform.ip6_present;
                    497:     } else {
                    498:         return false;
                    499:     }
                    500: }
                    501: 
                    502: /*  Returns true if we can transmit probes using the specified protocol  */
                    503: bool is_protocol_supported(
                    504:     struct net_state_t * net_state,
                    505:     int protocol)
                    506: {
                    507:     if (protocol == IPPROTO_ICMP) {
                    508:         return true;
                    509:     }
                    510: 
                    511:     if (protocol == IPPROTO_UDP) {
                    512:         return true;
                    513:     }
                    514: 
                    515:     if (protocol == IPPROTO_TCP) {
                    516:         return true;
                    517:     }
                    518: #ifdef IPPROTO_SCTP
                    519:     if (protocol == IPPROTO_SCTP) {
                    520:         return net_state->platform.sctp_support;
                    521:     }
                    522: #endif
                    523: 
                    524:     return false;
                    525: }
                    526: 
                    527: /*  Report an error during send_probe based on the errno value  */
                    528: static
                    529: void report_packet_error(
                    530:     int command_token)
                    531: {
                    532:     if (errno == EINVAL) {
                    533:         printf("%d invalid-argument\n", command_token);
                    534:     } else if (errno == ENETDOWN) {
                    535:         printf("%d network-down\n", command_token);
                    536:     } else if (errno == ENETUNREACH) {
                    537:         printf("%d no-route\n", command_token);
                    538:     } else if (errno == EHOSTUNREACH) {
                    539:         printf("%d no-route\n", command_token);
                    540:     } else if (errno == EPERM) {
                    541:         printf("%d permission-denied\n", command_token);
                    542:     } else if (errno == EADDRINUSE) {
                    543:         printf("%d address-in-use\n", command_token);
                    544:     } else if (errno == EADDRNOTAVAIL) {
                    545:         printf("%d address-not-available\n", command_token);
                    546:     } else {
                    547:         printf("%d unexpected-error errno %d\n", command_token, errno);
                    548:     }
                    549: }
                    550: 
                    551: /*  Craft a custom ICMP packet for a network probe.  */
                    552: void send_probe(
                    553:     struct net_state_t *net_state,
                    554:     const struct probe_param_t *param)
                    555: {
                    556:     char packet[PACKET_BUFFER_SIZE];
                    557:     struct probe_t *probe;
1.1.1.2   misho     558:     int trytimes;
1.1       misho     559:     int packet_size;
                    560: 
                    561:     probe = alloc_probe(net_state, param->command_token);
                    562:     if (probe == NULL) {
                    563:         printf("%d probes-exhausted\n", param->command_token);
                    564:         return;
                    565:     }
                    566: 
1.1.1.2   misho     567:     if (resolve_probe_addresses(net_state, param, &probe->remote_addr,
                    568:                 &probe->local_addr)) {
1.1       misho     569:         printf("%d invalid-argument\n", param->command_token);
                    570:         free_probe(net_state, probe);
                    571:         return;
                    572:     }
                    573: 
                    574:     if (gettimeofday(&probe->platform.departure_time, NULL)) {
1.1.1.2   misho     575:         error(EXIT_FAILURE, errno, "gettimeofday failure");
1.1       misho     576:     }
                    577: 
1.1.1.3 ! misho     578:     // there might be an off-by-one in the number of tries here.
1.1.1.2   misho     579:     // this is intentional.  It is no use exhausting the very last
1.1.1.3 ! misho     580:     // open port. Max 10 retries would've been acceptable too I think.
1.1.1.2   misho     581:     for (trytimes=MIN_PORT; trytimes < MAX_PORT; trytimes++) {
1.1.1.3 ! misho     582: 
1.1.1.2   misho     583:         packet_size = construct_packet(net_state, &probe->platform.socket,
                    584:                          probe, packet, PACKET_BUFFER_SIZE,
                    585:                          param);
                    586: 
                    587:         if (packet_size > 0) break; // no retry if we succeed.
                    588: 
1.1.1.3 ! misho     589:         if ((param->protocol != IPPROTO_TCP) &&
1.1.1.2   misho     590:             (param->protocol != IPPROTO_SCTP)) break; // no retry if not TCP/SCTP
                    591: 
                    592:         if ((errno != EADDRINUSE) && (errno != EADDRNOTAVAIL)) {
                    593:             break; // no retry
                    594:         }
                    595: 
                    596:        probe->sequence = net_state->platform.next_sequence++;
1.1.1.3 ! misho     597: 
1.1.1.2   misho     598:                if (net_state->platform.next_sequence > MAX_PORT) {
                    599:             net_state->platform.next_sequence = MIN_PORT;
                    600:         }
                    601:     }
1.1       misho     602: 
                    603:     if (packet_size < 0) {
                    604:         /*
                    605:            When using a stream protocol, FreeBSD will return ECONNREFUSED
                    606:            when connecting to localhost if the port doesn't exist,
                    607:            even if the socket is non-blocking, so we should be
                    608:            prepared for that.
                    609:          */
                    610:         if (errno == ECONNREFUSED) {
                    611:             receive_probe(net_state, probe, ICMP_ECHOREPLY,
                    612:                           &probe->remote_addr, NULL, 0, NULL);
                    613:         } else {
                    614:             report_packet_error(param->command_token);
                    615:             free_probe(net_state, probe);
                    616:         }
                    617: 
                    618:         return;
                    619:     }
                    620: 
                    621:     if (packet_size > 0) {
1.1.1.2   misho     622:         if (send_packet(net_state, param, probe->sequence,
1.1       misho     623:                         packet, packet_size, &probe->remote_addr) == -1) {
                    624: 
                    625:             report_packet_error(param->command_token);
                    626:             free_probe(net_state, probe);
                    627:             return;
                    628:         }
                    629:     }
                    630: 
                    631:     probe->platform.timeout_time = probe->platform.departure_time;
                    632:     probe->platform.timeout_time.tv_sec += param->timeout;
                    633: }
                    634: 
                    635: /*  When allocating a probe, assign it a unique port number  */
                    636: void platform_alloc_probe(
                    637:     struct net_state_t *net_state,
                    638:     struct probe_t *probe)
                    639: {
                    640:     probe->sequence = net_state->platform.next_sequence++;
                    641: 
                    642:     if (net_state->platform.next_sequence > MAX_PORT) {
                    643:         net_state->platform.next_sequence = MIN_PORT;
                    644:     }
                    645: }
                    646: 
                    647: /*
                    648:     When freeing the probe, close the socket for the probe,
                    649:     if one has been opened
                    650: */
                    651: void platform_free_probe(
                    652:     struct probe_t *probe)
                    653: {
                    654:     if (probe->platform.socket) {
                    655:         close(probe->platform.socket);
                    656:         probe->platform.socket = 0;
                    657:     }
                    658: }
                    659: 
                    660: /*
                    661:     Compute the round trip time of a just-received probe and pass it
                    662:     to the platform agnostic response handling.
                    663: */
                    664: void receive_probe(
                    665:     struct net_state_t *net_state,
                    666:     struct probe_t *probe,
                    667:     int icmp_type,
                    668:     const struct sockaddr_storage *remote_addr,
                    669:     struct timeval *timestamp,
                    670:     int mpls_count,
                    671:     struct mpls_label_t *mpls)
                    672: {
                    673:     unsigned int round_trip_us;
                    674:     struct timeval *departure_time = &probe->platform.departure_time;
                    675:     struct timeval now;
                    676: 
                    677:     if (timestamp == NULL) {
                    678:         if (gettimeofday(&now, NULL)) {
1.1.1.2   misho     679:             error(EXIT_FAILURE, errno, "gettimeofday failure");
1.1       misho     680:         }
                    681: 
                    682:         timestamp = &now;
                    683:     }
                    684: 
                    685:     round_trip_us =
                    686:         (timestamp->tv_sec - departure_time->tv_sec) * 1000000 +
                    687:         timestamp->tv_usec - departure_time->tv_usec;
                    688: 
                    689:     respond_to_probe(net_state, probe, icmp_type,
                    690:                      remote_addr, round_trip_us, mpls_count, mpls);
                    691: }
                    692: 
                    693: /*
                    694:     Read all available packets through our receiving raw socket, and
1.1.1.2   misho     695:     handle any responses to probes we have previously sent.
1.1       misho     696: */
                    697: static
1.1.1.2   misho     698: void receive_replies_from_recv_socket(
1.1       misho     699:     struct net_state_t *net_state,
                    700:     int socket,
                    701:     received_packet_func_t handle_received_packet)
                    702: {
                    703:     char packet[PACKET_BUFFER_SIZE];
                    704:     int packet_length;
                    705:     struct sockaddr_storage remote_addr;
                    706:     struct timeval timestamp;
1.1.1.2   misho     707:     int flag = 0;
                    708: #ifdef HAVE_LINUX_ERRQUEUE_H
                    709:     struct cmsghdr *cm;
                    710:     struct sock_extended_err *ee = NULL;
                    711:     bool icmp_connrefused_received = false;
                    712:     bool icmp_hostunreach_received = false;
                    713: #endif
1.1       misho     714: 
                    715:     /*  Read until no more packets are available  */
                    716:     while (true) {
1.1.1.2   misho     717:         struct iovec iov;
                    718:         struct msghdr msg;
                    719:         char control[1024];
                    720: 
                    721:         memset(&msg, 0, sizeof(msg));
                    722:         memset(&iov, 0, sizeof(iov));
                    723:         iov.iov_base = packet;
                    724:         iov.iov_len = sizeof(packet);
                    725:         msg.msg_iov = &iov;
                    726:         msg.msg_iovlen = 1;
                    727:         msg.msg_name = (struct sockaddr*) &remote_addr;
                    728:         msg.msg_namelen = sizeof(remote_addr);
                    729:         msg.msg_control = control;
                    730:         msg.msg_controllen = sizeof(control);
                    731:         packet_length = recvmsg(socket, &msg, flag);
1.1       misho     732: 
                    733:         /*
                    734:            Get the time immediately after reading the packet to
                    735:            keep the timing as precise as we can.
                    736:          */
                    737:         if (gettimeofday(&timestamp, NULL)) {
1.1.1.2   misho     738:             error(EXIT_FAILURE, errno, "gettimeofday failure");
1.1       misho     739:         }
                    740: 
                    741:         if (packet_length == -1) {
                    742:             /*
                    743:                EAGAIN will be returned if there is no current packet
                    744:                available.
                    745:              */
                    746:             if (errno == EAGAIN) {
                    747:                 return;
                    748:             }
                    749: 
                    750:             /*
                    751:                EINTER will be returned if we received a signal during
                    752:                receive.
                    753:              */
                    754:             if (errno == EINTR) {
1.1.1.2   misho     755:                 /* clear error */
                    756:                 int so_err;
                    757:                 socklen_t so_err_size = sizeof(so_err);
                    758:                 int err;
                    759: 
                    760:                 do {
                    761:                   err = getsockopt(socket, SOL_SOCKET, SO_ERROR, &so_err, &so_err_size);
                    762:                 } while (err < 0 && errno == EINTR);
1.1       misho     763:                 continue;
                    764:             }
                    765: 
1.1.1.2   misho     766:             /* handle error received in error queue */
                    767:             if (errno == EHOSTUNREACH) {
                    768:                 /* potential error caused by ttl, read inner icmp hdr from err queue */
                    769: #ifdef HAVE_LINUX_ERRQUEUE_H
                    770:                 icmp_hostunreach_received = true;
                    771:                 flag |= MSG_ERRQUEUE;
                    772: #endif
                    773:                 continue;
                    774:             }
                    775: 
                    776:             if (errno == ECONNREFUSED) {
                    777:                 /* udp packet reached dst, read inner udp hdr from err queue */
                    778: #ifdef HAVE_LINUX_ERRQUEUE_H
                    779:                 icmp_connrefused_received = true;
                    780:                 flag |= MSG_ERRQUEUE;
                    781: #endif
                    782:                 continue;
                    783:             }
                    784: 
                    785:             error(EXIT_FAILURE, errno, "Failure receiving replies");
1.1       misho     786:         }
                    787: 
1.1.1.2   misho     788: #ifdef HAVE_LINUX_ERRQUEUE_H
                    789:         /* get src ip for packets read from err queue */
                    790:         if (flag & MSG_ERRQUEUE) {
                    791:             for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) {
                    792:                 if (cm->cmsg_level == SOL_IP) {
                    793:                     if (cm->cmsg_type == IP_RECVERR) {
                    794:                         ee = (struct sock_extended_err *) CMSG_DATA(cm);
                    795:                     }
                    796:                 }
                    797:                 else if (cm->cmsg_level == SOL_IPV6) {
                    798:                     if (cm->cmsg_type == IPV6_RECVERR) {
                    799:                         ee = (struct sock_extended_err *) CMSG_DATA(cm);
                    800:                     }
                    801:                 }
                    802:             }
                    803:             if (ee) {
                    804:                 memcpy(&remote_addr, SO_EE_OFFENDER(ee), sizeof(remote_addr));
                    805:             }
                    806:         }
                    807: 
                    808: #ifdef SO_PROTOCOL
                    809:         if (icmp_connrefused_received) {
                    810:             /* using ICMP type ICMP_ECHOREPLY is not a bug, it is an
                    811:                indication of successfully reaching dst host.
                    812:              */
                    813:             handle_error_queue_packet(net_state, &remote_addr, ICMP_ECHOREPLY, IPPROTO_UDP,
                    814:                     packet, packet_length, &timestamp);
                    815:         } else if (icmp_hostunreach_received) {
                    816:             /* handle packet based on send socket protocol */
                    817:             int proto, length = sizeof(int);
                    818: 
                    819:             if (getsockopt(socket, SOL_SOCKET, SO_PROTOCOL, &proto, &length) < 0) {
                    820:                 error(EXIT_FAILURE, errno, "getsockopt SO_PROTOCOL error");
                    821:             }
                    822:             handle_error_queue_packet(net_state, &remote_addr, ICMP_TIME_EXCEEDED, proto,
                    823:                     packet, packet_length, &timestamp);
                    824:         } else {
                    825: #endif
                    826: #endif
                    827:             /* ICMP packets received from raw socket */
                    828:             handle_received_packet(net_state, &remote_addr, packet,
                    829:                                    packet_length, &timestamp);
                    830: #ifdef HAVE_LINUX_ERRQUEUE_H
                    831: #ifdef SO_PROTOCOL
                    832:         }
                    833: #endif
                    834: #endif
1.1       misho     835:     }
                    836: }
                    837: 
                    838: /*
                    839:     Attempt to send using the probe's socket, in order to check whether
                    840:     the connection has completed, for stream oriented protocols such as
                    841:     TCP.
                    842: */
                    843: static
                    844: void receive_replies_from_probe_socket(
                    845:     struct net_state_t *net_state,
                    846:     struct probe_t *probe)
                    847: {
                    848:     int probe_socket;
                    849:     struct timeval zero_time;
                    850:     int err;
                    851:     int err_length = sizeof(int);
                    852:     fd_set write_set;
                    853: 
                    854:     probe_socket = probe->platform.socket;
                    855:     if (!probe_socket) {
                    856:         return;
                    857:     }
                    858: 
                    859:     FD_ZERO(&write_set);
                    860:     FD_SET(probe_socket, &write_set);
                    861: 
                    862:     zero_time.tv_sec = 0;
                    863:     zero_time.tv_usec = 0;
                    864: 
                    865:     if (select(probe_socket + 1, NULL, &write_set, NULL, &zero_time) == -1) {
                    866:         if (errno == EAGAIN) {
                    867:             return;
                    868:         } else {
1.1.1.2   misho     869:             error(EXIT_FAILURE, errno, "probe socket select error");
1.1       misho     870:         }
                    871:     }
                    872: 
                    873:     /*
                    874:        If the socket is writable, the connection attempt has completed.
                    875:      */
                    876:     if (!FD_ISSET(probe_socket, &write_set)) {
                    877:         return;
                    878:     }
                    879: 
                    880:     if (getsockopt(probe_socket, SOL_SOCKET, SO_ERROR, &err, &err_length)) {
1.1.1.2   misho     881:         error(EXIT_FAILURE, errno, "probe socket SO_ERROR");
1.1       misho     882:     }
                    883: 
                    884:     /*
                    885:        If the connection complete successfully, or was refused, we can
                    886:        assume our probe arrived at the destination.
                    887:      */
                    888:     if (!err || err == ECONNREFUSED) {
                    889:         receive_probe(net_state, probe, ICMP_ECHOREPLY,
                    890:                       &probe->remote_addr, NULL, 0, NULL);
                    891:     } else {
                    892:         errno = err;
                    893:         report_packet_error(probe->token);
                    894:         free_probe(net_state, probe);
                    895:     }
                    896: }
                    897: 
                    898: /*  Check both the IPv4 and IPv6 sockets for incoming packets  */
                    899: void receive_replies(
                    900:     struct net_state_t *net_state)
                    901: {
                    902:     struct probe_t *probe;
                    903:     struct probe_t *probe_safe_iter;
                    904: 
                    905:     if (net_state->platform.ip4_present) {
1.1.1.2   misho     906:         if (net_state->platform.ip4_socket_raw) {
                    907:             receive_replies_from_recv_socket(net_state,
                    908:                                              net_state->platform.
                    909:                                              ip4_recv_socket,
                    910:                                              handle_received_ip4_packet);
                    911:         } else {
                    912:             receive_replies_from_recv_socket(net_state,
                    913:                                              net_state->platform.
                    914:                                              ip4_txrx_icmp_socket,
                    915:                                              handle_received_ip4_packet);
                    916:             receive_replies_from_recv_socket(net_state,
                    917:                                              net_state->platform.
                    918:                                              ip4_txrx_udp_socket,
                    919:                                              handle_received_ip4_packet);
                    920:         }
1.1       misho     921:     }
                    922: 
                    923:     if (net_state->platform.ip6_present) {
1.1.1.2   misho     924:         if (net_state->platform.ip6_socket_raw) {
                    925:             receive_replies_from_recv_socket(net_state,
                    926:                                              net_state->platform.
                    927:                                              ip6_recv_socket,
                    928:                                              handle_received_ip6_packet);
                    929:         } else {
                    930:             receive_replies_from_recv_socket(net_state,
                    931:                                              net_state->platform.
                    932:                                              ip6_txrx_icmp_socket,
                    933:                                              handle_received_ip6_packet);
                    934:             receive_replies_from_recv_socket(net_state,
                    935:                                              net_state->platform.
                    936:                                              ip6_txrx_udp_socket,
                    937:                                              handle_received_ip6_packet);
                    938:         }
1.1       misho     939:     }
                    940: 
                    941:     LIST_FOREACH_SAFE(probe, &net_state->outstanding_probes,
                    942:                       probe_list_entry, probe_safe_iter) {
                    943: 
                    944:         receive_replies_from_probe_socket(net_state, probe);
                    945:     }
                    946: }
                    947: 
                    948: /*
                    949:     Put all of our probe sockets in the read set used for an upcoming
                    950:     select so we can wake when any of them become readable.
                    951: */
                    952: int gather_probe_sockets(
                    953:     const struct net_state_t *net_state,
                    954:     fd_set * write_set)
                    955: {
                    956:     int probe_socket;
                    957:     int nfds;
                    958:     const struct probe_t *probe;
                    959: 
                    960:     nfds = 0;
                    961: 
                    962:     LIST_FOREACH(probe, &net_state->outstanding_probes, probe_list_entry) {
                    963:         probe_socket = probe->platform.socket;
                    964: 
                    965:         if (probe_socket) {
                    966:             FD_SET(probe_socket, write_set);
                    967:             if (probe_socket >= nfds) {
                    968:                 nfds = probe_socket + 1;
                    969:             }
                    970:         }
                    971:     }
                    972: 
                    973:     return nfds;
                    974: }
                    975: 
                    976: /*
                    977:     Check for any probes for which we have not received a response
                    978:     for some time, and report a time-out, assuming that we won't
                    979:     receive a future reply.
                    980: */
                    981: void check_probe_timeouts(
                    982:     struct net_state_t *net_state)
                    983: {
                    984:     struct timeval now;
                    985:     struct probe_t *probe;
                    986:     struct probe_t *probe_safe_iter;
                    987: 
                    988:     if (gettimeofday(&now, NULL)) {
1.1.1.2   misho     989:         error(EXIT_FAILURE, errno, "gettimeofday failure");
1.1       misho     990:     }
                    991: 
                    992:     LIST_FOREACH_SAFE(probe, &net_state->outstanding_probes,
                    993:                       probe_list_entry, probe_safe_iter) {
                    994: 
                    995:         if (compare_timeval(probe->platform.timeout_time, now) < 0) {
                    996:             /*  Report timeout to the command stream  */
                    997:             printf("%d no-reply\n", probe->token);
                    998: 
                    999:             free_probe(net_state, probe);
                   1000:         }
                   1001:     }
                   1002: }
                   1003: 
                   1004: /*
                   1005:     Find the remaining time until the next probe times out.
                   1006:     This may be a negative value if the next probe timeout has
                   1007:     already elapsed.
                   1008: 
                   1009:     Returns false if no probes are currently outstanding, and true
                   1010:     if a timeout value for the next probe exists.
                   1011: */
                   1012: bool get_next_probe_timeout(
                   1013:     const struct net_state_t *net_state,
                   1014:     struct timeval *timeout)
                   1015: {
                   1016:     bool have_timeout;
                   1017:     const struct probe_t *probe;
                   1018:     struct timeval now;
                   1019:     struct timeval probe_timeout;
                   1020: 
                   1021:     if (gettimeofday(&now, NULL)) {
1.1.1.2   misho    1022:         error(EXIT_FAILURE, errno, "gettimeofday failure");
1.1       misho    1023:     }
                   1024: 
                   1025:     have_timeout = false;
                   1026:     LIST_FOREACH(probe, &net_state->outstanding_probes, probe_list_entry) {
                   1027:         probe_timeout.tv_sec =
                   1028:             probe->platform.timeout_time.tv_sec - now.tv_sec;
                   1029:         probe_timeout.tv_usec =
                   1030:             probe->platform.timeout_time.tv_usec - now.tv_usec;
                   1031: 
                   1032:         normalize_timeval(&probe_timeout);
                   1033:         if (have_timeout) {
                   1034:             if (compare_timeval(probe_timeout, *timeout) < 0) {
                   1035:                 /*  If this probe has a sooner timeout, store it instead  */
                   1036:                 *timeout = probe_timeout;
                   1037:             }
                   1038:         } else {
                   1039:             *timeout = probe_timeout;
                   1040:             have_timeout = true;
                   1041:         }
                   1042:     }
                   1043: 
                   1044:     return have_timeout;
                   1045: }

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