File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mtr / packet / deconstruct_unix.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:18:58 2023 UTC (9 months, 1 week ago) by misho
Branches: mtr, MAIN
CVS tags: v0_95, HEAD
Version 0.95

    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: 
   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.
   17: */
   18: 
   19: #include "deconstruct_unix.h"
   20: 
   21: #include <stdio.h>
   22: #include <stdlib.h>
   23: #include <string.h>
   24: 
   25: #include "protocols.h"
   26: #include "sockaddr.h"
   27: 
   28: #define MAX_MPLS_LABELS 8
   29: 
   30: /*
   31:     Given an ICMP id + ICMP sequence, find the match probe we've
   32:     transmitted and if found, respond to the command which sent it
   33: */
   34: static
   35: void find_and_receive_probe(
   36:     struct net_state_t *net_state,
   37:     const struct sockaddr_storage *remote_addr,
   38:     struct timeval *timestamp,
   39:     int icmp_type,
   40:     int protocol,
   41:     int icmp_id,
   42:     int icmp_sequence,
   43:     int mpls_count,
   44:     struct mpls_label_t *mpls)
   45: {
   46:     struct probe_t *probe;
   47: 
   48:     probe = find_probe(net_state, protocol, icmp_id, icmp_sequence);
   49:     if (probe == NULL) {
   50:         return;
   51:     }
   52: 
   53:     receive_probe(net_state, probe, icmp_type,
   54:                   remote_addr, timestamp, mpls_count, mpls);
   55: }
   56: 
   57: /*
   58:     Handle a UDP packet received embedded in an ICMP reply.
   59:     The sequence number identifying the probe might be in
   60:     the source port number, the destination port number, or
   61:     the checksum.  We'll check all three.
   62: */
   63: static
   64: void handle_inner_udp_packet(
   65:     struct net_state_t *net_state,
   66:     const struct sockaddr_storage *remote_addr,
   67:     int icmp_result,
   68:     int af,
   69:     const void *ip,
   70:     const struct UDPHeader *udp,
   71:     int udp_length,
   72:     struct timeval *timestamp,
   73:     int mpls_count,
   74:     struct mpls_label_t *mpls)
   75: {
   76:     struct probe_t *probe;
   77: 
   78:     probe = find_probe(net_state, IPPROTO_UDP, 0, udp->dstport);
   79:     if (probe == NULL) {
   80:         probe = find_probe(net_state, IPPROTO_UDP, 0, udp->srcport);
   81:     }
   82:     if (probe == NULL) {
   83:         probe = find_probe(net_state, IPPROTO_UDP, 0, udp->checksum);
   84:     }
   85:     if (probe == NULL)
   86:         return;
   87: 
   88:     if (probe->remote_addr.ss_family != remote_addr->ss_family)
   89:         return;
   90: 
   91:     if (udp->dstport != *sockaddr_port_offset(&probe->remote_addr) )
   92:         return;
   93: 
   94:     if (udp->srcport != *sockaddr_port_offset(&probe->local_addr) )
   95:         return;
   96: 
   97:     void *saddr, *daddr;
   98:     if (af == AF_INET)
   99:     {
  100:         saddr = &((struct IPHeader *)ip)->saddr;
  101:         daddr = &((struct IPHeader *)ip)->daddr;
  102:     } else
  103:     if (af == AF_INET6)
  104:     {
  105:         daddr = &((struct IP6Header *)ip)->daddr;
  106:         saddr = &((struct IP6Header *)ip)->saddr;
  107:     } else
  108:     {
  109:         return;
  110:     }
  111: 
  112:     if ( memcmp(sockaddr_addr_offset(&probe->remote_addr),
  113:                daddr,
  114:                sockaddr_addr_size(&probe->remote_addr)) != 0 )
  115:             return;
  116: 
  117:     if ( memcmp(sockaddr_addr_offset(&probe->local_addr),
  118:            saddr,
  119:            sockaddr_addr_size(&probe->local_addr)) != 0)
  120:         return;
  121: 
  122:     /* probe is not null */
  123:     receive_probe(net_state, probe, icmp_result,
  124:                       remote_addr, timestamp, mpls_count, mpls);
  125: }
  126: 
  127: void handle_error_queue_packet(
  128:     struct net_state_t *net_state,
  129:     const struct sockaddr_storage *remote_addr,
  130:     int icmp_result,
  131:     int proto,
  132:     char *packet,
  133:     int packet_length,
  134:     struct timeval *timestamp)
  135: {
  136:     if (proto == IPPROTO_UDP) {
  137:         handle_inner_udp_packet(net_state, remote_addr, ICMP_TIME_EXCEEDED, 0, NULL,
  138:                 (struct UDPHeader *)packet, packet_length, timestamp, 0, NULL);
  139:     } else if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) {
  140:         const struct ICMPHeader *icmp = (struct ICMPHeader *)packet;
  141:         find_and_receive_probe(net_state, remote_addr, timestamp,
  142:                                ICMP_TIME_EXCEEDED, IPPROTO_ICMP, icmp->id,
  143:                                icmp->sequence, 0, NULL);
  144:     }
  145: 
  146: }
  147: 
  148: /*
  149:     We've received an ICMP message with an embedded IP packet.
  150:     We will try to determine which of our outgoing probes
  151:     corresponds to the embedded IP packet and record the response.
  152: */
  153: static
  154: void handle_inner_ip4_packet(
  155:     struct net_state_t *net_state,
  156:     const struct sockaddr_storage *remote_addr,
  157:     int icmp_result,
  158:     const struct IPHeader *ip,
  159:     int packet_length,
  160:     struct timeval *timestamp,
  161:     int mpls_count,
  162:     struct mpls_label_t *mpls)
  163: {
  164:     const int ip_icmp_size =
  165:         sizeof(struct IPHeader) + sizeof(struct ICMPHeader);
  166:     const int ip_udp_size =
  167:         sizeof(struct IPHeader) + sizeof(struct UDPHeader);
  168:     const int ip_tcp_size =
  169:         sizeof(struct IPHeader) + sizeof(struct TCPHeader);
  170:     const struct ICMPHeader *icmp;
  171:     const struct UDPHeader *udp;
  172:     const struct TCPHeader *tcp;
  173:     int udp_length;
  174: #ifdef IPPROTO_SCTP
  175:     const int ip_sctp_size =
  176:         sizeof(struct IPHeader) + sizeof(struct SCTPHeader);
  177:     const struct SCTPHeader *sctp;
  178: #endif
  179: 
  180:     if (ip->protocol == IPPROTO_ICMP) {
  181:         if (packet_length < ip_icmp_size) {
  182:             return;
  183:         }
  184: 
  185:         icmp = (struct ICMPHeader *) (ip + 1);
  186: 
  187:         find_and_receive_probe(net_state, remote_addr, timestamp,
  188:                                icmp_result, IPPROTO_ICMP, icmp->id,
  189:                                icmp->sequence, mpls_count, mpls);
  190:     } else if (ip->protocol == IPPROTO_UDP) {
  191:         if (packet_length < ip_udp_size) {
  192:             return;
  193:         }
  194: 
  195:         udp = (struct UDPHeader *) (ip + 1);
  196:         udp_length = packet_length - sizeof(struct IPHeader);
  197: 
  198:         handle_inner_udp_packet(net_state, remote_addr, icmp_result, AF_INET, ip, udp,
  199:                                 udp_length, timestamp, mpls_count, mpls);
  200:     } else if (ip->protocol == IPPROTO_TCP) {
  201:         if (packet_length < ip_tcp_size) {
  202:             return;
  203:         }
  204: 
  205:         tcp = (struct TCPHeader *) (ip + 1);
  206: 
  207:         find_and_receive_probe(net_state, remote_addr, timestamp,
  208:                                icmp_result, IPPROTO_TCP, 0, tcp->srcport,
  209:                                mpls_count, mpls);
  210: #ifdef IPPROTO_SCTP
  211:     } else if (ip->protocol == IPPROTO_SCTP) {
  212:         if (packet_length < ip_sctp_size) {
  213:             return;
  214:         }
  215: 
  216:         sctp = (struct SCTPHeader *) (ip + 1);
  217: 
  218:         find_and_receive_probe(net_state, remote_addr, timestamp,
  219:                                icmp_result, IPPROTO_SCTP, 0, sctp->srcport,
  220:                                mpls_count, mpls);
  221: #endif
  222:     }
  223: }
  224: 
  225: /*
  226:     Examine the IPv6 header embedded in a returned ICMPv6 packet
  227:     in order to match it with a probe which we previously sent.
  228: */
  229: static
  230: void handle_inner_ip6_packet(
  231:     struct net_state_t *net_state,
  232:     const struct sockaddr_storage *remote_addr,
  233:     int icmp_result,
  234:     const struct IP6Header *ip,
  235:     int packet_length,
  236:     struct timeval *timestamp,
  237:     int mpls_count,
  238:     struct mpls_label_t *mpls)
  239: {
  240:     const int ip_icmp_size =
  241:         sizeof(struct IP6Header) + sizeof(struct ICMPHeader);
  242:     const int ip_udp_size =
  243:         sizeof(struct IP6Header) + sizeof(struct UDPHeader);
  244:     const int ip_tcp_size =
  245:         sizeof(struct IP6Header) + sizeof(struct TCPHeader);
  246:     const struct ICMPHeader *icmp;
  247:     const struct UDPHeader *udp;
  248:     const struct TCPHeader *tcp;
  249:     int udp_length;
  250: #ifdef IPPROTO_SCTP
  251:     const int ip_sctp_size =
  252:         sizeof(struct IPHeader) + sizeof(struct SCTPHeader);
  253:     const struct SCTPHeader *sctp;
  254: #endif
  255: 
  256:     if (ip->protocol == IPPROTO_ICMPV6) {
  257:         if (packet_length < ip_icmp_size) {
  258:             return;
  259:         }
  260: 
  261:         icmp = (struct ICMPHeader *) (ip + 1);
  262: 
  263:         find_and_receive_probe(net_state, remote_addr, timestamp,
  264:                                icmp_result, IPPROTO_ICMP, icmp->id,
  265:                                icmp->sequence, mpls_count, mpls);
  266:     } else if (ip->protocol == IPPROTO_UDP) {
  267:         if (packet_length < ip_udp_size) {
  268:             return;
  269:         }
  270: 
  271:         udp = (struct UDPHeader *) (ip + 1);
  272:         udp_length = packet_length - sizeof(struct IP6Header);
  273: 
  274:         handle_inner_udp_packet(net_state, remote_addr, icmp_result, AF_INET6, ip, udp,
  275:                                 udp_length, timestamp, mpls_count, mpls);
  276:     } else if (ip->protocol == IPPROTO_TCP) {
  277:         if (packet_length < ip_tcp_size) {
  278:             return;
  279:         }
  280: 
  281:         tcp = (struct TCPHeader *) (ip + 1);
  282:         find_and_receive_probe(net_state, remote_addr, timestamp,
  283:                                icmp_result, IPPROTO_TCP, 0, tcp->srcport,
  284:                                mpls_count, mpls);
  285: #ifdef IPPROTO_SCTP
  286:     } else if (ip->protocol == IPPROTO_SCTP) {
  287:         if (packet_length < ip_sctp_size) {
  288:             return;
  289:         }
  290: 
  291:         sctp = (struct SCTPHeader *) (ip + 1);
  292: 
  293:         find_and_receive_probe(net_state, remote_addr, timestamp,
  294:                                icmp_result, IPPROTO_SCTP, 0, sctp->srcport,
  295:                                mpls_count, mpls);
  296: #endif
  297:     }
  298: }
  299: 
  300: /*  Convert an ICMP MPLS extension object into an mpls_label_t structure  */
  301: static
  302: int decode_mpls_object(
  303:     struct ICMPExtensionObject *icmp_obj,
  304:     int obj_len,
  305:     struct mpls_label_t *mpls,
  306:     int mpls_count)
  307: {
  308:     int label_bytes;
  309:     int labels_present;
  310:     int i;
  311:     struct ICMPExtMPLSLabel *ext_mpls;
  312:     struct ICMPExtMPLSLabel *ext_label;
  313:     struct mpls_label_t *label;
  314: 
  315:     label_bytes = obj_len - sizeof(struct ICMPExtensionObject);
  316:     labels_present = label_bytes / sizeof(struct ICMPExtMPLSLabel);
  317: 
  318:     ext_mpls = (struct ICMPExtMPLSLabel *) (icmp_obj + 1);
  319:     for (i = 0; i < mpls_count && i < labels_present; i++) {
  320:         ext_label = &ext_mpls[i];
  321:         label = &mpls[i];
  322: 
  323:         memset(label, 0, sizeof(struct mpls_label_t));
  324: 
  325:         label->label =
  326:             ext_label->label[0] << 12 |
  327:             ext_label->label[1] << 4 | ext_label->label[2] >> 4;
  328:         label->traffic_class = (ext_label->label[2] & 0x0E) >> 1;
  329:         label->bottom_of_stack = ext_label->label[2] & 0x01;
  330:         label->ttl = ext_label->ttl;
  331:     }
  332: 
  333:     return i;
  334: }
  335: 
  336: /*  Extract MPLS labels from the ICMP extension header, if present  */
  337: static
  338: int decode_mpls_labels(
  339:     const struct ICMPHeader *icmp,
  340:     int packet_length,
  341:     struct mpls_label_t *mpls,
  342:     int mpls_count)
  343: {
  344:     const int icmp_orig_icmp_ext_size =
  345:         sizeof(struct ICMPHeader) + ICMP_ORIGINAL_DATAGRAM_MIN_SIZE +
  346:         sizeof(struct ICMPExtensionHeader);
  347:     char *inner_packet;
  348:     char *icmp_object_bytes;
  349:     struct ICMPExtensionHeader *icmp_ext;
  350:     struct ICMPExtensionObject *icmp_obj;
  351:     int remaining_size;
  352:     int obj_len;
  353: 
  354:     if (packet_length < icmp_orig_icmp_ext_size) {
  355:         return 0;
  356:     }
  357: 
  358:     inner_packet = (char *) (icmp + 1);
  359:     icmp_ext = (struct ICMPExtensionHeader *)
  360:         (inner_packet + ICMP_ORIGINAL_DATAGRAM_MIN_SIZE);
  361: 
  362:     if ((icmp_ext->version & 0xF0) != 0x20) {
  363:         return 0;
  364:     }
  365: 
  366:     remaining_size = packet_length - icmp_orig_icmp_ext_size;
  367:     icmp_object_bytes = (char *) (icmp_ext + 1);
  368: 
  369:     /*
  370:        Iterate through the chain of extension objects, looking for
  371:        an MPLS label extension.
  372:      */
  373:     while (remaining_size >= sizeof(struct ICMPExtensionObject)) {
  374:         icmp_obj = (struct ICMPExtensionObject *) icmp_object_bytes;
  375:         obj_len = ntohs(icmp_obj->len);
  376: 
  377:         if (obj_len > remaining_size) {
  378:             return 0;
  379:         }
  380:         if (obj_len < sizeof(struct ICMPExtensionObject)) {
  381:             return 0;
  382:         }
  383: 
  384:         if (icmp_obj->classnum == ICMP_EXT_MPLS_CLASSNUM &&
  385:             icmp_obj->ctype == ICMP_EXT_MPLS_CTYPE) {
  386: 
  387:             return decode_mpls_object(icmp_obj, obj_len, mpls, mpls_count);
  388:         }
  389: 
  390:         remaining_size -= obj_len;
  391:         icmp_object_bytes += obj_len;
  392:     }
  393: 
  394:     return 0;
  395: }
  396: 
  397: /*
  398:     Decode the ICMP header received and try to find a probe which it
  399:     is in response to.
  400: */
  401: static
  402: void handle_received_icmp4_packet(
  403:     struct net_state_t *net_state,
  404:     const struct sockaddr_storage *remote_addr,
  405:     const struct ICMPHeader *icmp,
  406:     int packet_length,
  407:     struct timeval *timestamp)
  408: {
  409:     int icmp_ip_size = 0;
  410:     const struct IPHeader *inner_ip;
  411:     int inner_size = packet_length - sizeof(struct ICMPHeader);
  412:     int mpls_count;
  413:     struct mpls_label_t mpls[MAX_MPLS_LABELS];
  414: 
  415:     if (net_state->platform.ip4_socket_raw) {
  416:         icmp_ip_size += sizeof(struct IPHeader);
  417:     }
  418:     icmp_ip_size += sizeof(struct ICMPHeader);
  419:     mpls_count =
  420:         decode_mpls_labels(icmp, packet_length, mpls, MAX_MPLS_LABELS);
  421: 
  422:     /*  If we get an echo reply, our probe reached the destination host  */
  423:     if (icmp->type == ICMP_ECHOREPLY) {
  424:         find_and_receive_probe(net_state, remote_addr, timestamp,
  425:                                ICMP_ECHOREPLY, IPPROTO_ICMP, icmp->id,
  426:                                icmp->sequence, mpls_count, mpls);
  427:     }
  428: 
  429:     if (packet_length < icmp_ip_size) {
  430:         return;
  431:     }
  432:     inner_ip = (struct IPHeader *) (icmp + 1);
  433: 
  434:     /*
  435:        If we get a time exceeded, we got a response from an intermediate
  436:        host along the path to our destination.
  437:      */
  438:     if (icmp->type == ICMP_TIME_EXCEEDED) {
  439:         /*
  440:            The IP packet inside the ICMP response contains our original
  441:            IP header.  That's where we can get our original ID and
  442:            sequence number.
  443:          */
  444:         handle_inner_ip4_packet(net_state, remote_addr,
  445:                                 ICMP_TIME_EXCEEDED, inner_ip, inner_size,
  446:                                 timestamp, mpls_count, mpls);
  447:     }
  448: 
  449:     if (icmp->type == ICMP_DEST_UNREACH) {
  450:         /*
  451:            We'll get a ICMP_PORT_UNREACH when a non-ICMP probe
  452:            reaches its final destination.  (Assuming that port isn't
  453:            open on the destination host.)
  454:          */
  455:         if (icmp->code == ICMP_PORT_UNREACH) {
  456:             handle_inner_ip4_packet(net_state, remote_addr,
  457:                                     ICMP_ECHOREPLY, inner_ip, inner_size,
  458:                                     timestamp, mpls_count, mpls);
  459:         } else {
  460:             /*
  461:                 ICMP_DEST_UNREACH subtypes other than port unreachable
  462:                 indicate an exceptional condition, and will be reported
  463:                 as a "no route to host" probe response.
  464:             */
  465:             handle_inner_ip4_packet(net_state, remote_addr,
  466:                                     ICMP_DEST_UNREACH, inner_ip, inner_size,
  467:                                     timestamp, mpls_count, mpls);
  468:         }
  469:     }
  470: }
  471: 
  472: /*
  473:     Decode the ICMPv6 header.  The code duplication with ICMPv4 is
  474:     unfortunate, but small details in structure size and ICMP
  475:     constants differ.
  476: */
  477: static
  478: void handle_received_icmp6_packet(
  479:     struct net_state_t *net_state,
  480:     const struct sockaddr_storage *remote_addr,
  481:     const struct ICMPHeader *icmp,
  482:     int packet_length,
  483:     struct timeval *timestamp)
  484: {
  485:     const int icmp_ip_size =
  486:         sizeof(struct ICMPHeader) + sizeof(struct IP6Header);
  487:     const struct IP6Header *inner_ip;
  488:     int inner_size = packet_length - sizeof(struct ICMPHeader);
  489:     int mpls_count;
  490:     struct mpls_label_t mpls[MAX_MPLS_LABELS];
  491: 
  492:     mpls_count =
  493:         decode_mpls_labels(icmp, packet_length, mpls, MAX_MPLS_LABELS);
  494: 
  495:     if (icmp->type == ICMP6_ECHOREPLY) {
  496:         find_and_receive_probe(net_state, remote_addr, timestamp,
  497:                                ICMP_ECHOREPLY, IPPROTO_ICMP, icmp->id,
  498:                                icmp->sequence, mpls_count, mpls);
  499:     }
  500: 
  501:     if (packet_length < icmp_ip_size) {
  502:         return;
  503:     }
  504:     inner_ip = (struct IP6Header *) (icmp + 1);
  505: 
  506:     if (icmp->type == ICMP6_TIME_EXCEEDED) {
  507:         handle_inner_ip6_packet(net_state, remote_addr,
  508:                                 ICMP_TIME_EXCEEDED, inner_ip, inner_size,
  509:                                 timestamp, mpls_count, mpls);
  510:     }
  511: 
  512:     if (icmp->type == ICMP6_DEST_UNREACH) {
  513:         if (icmp->code == ICMP6_PORT_UNREACH) {
  514:             handle_inner_ip6_packet(net_state, remote_addr,
  515:                                     ICMP_ECHOREPLY, inner_ip, inner_size,
  516:                                     timestamp, mpls_count, mpls);
  517:         } else {
  518:             handle_inner_ip6_packet(net_state, remote_addr,
  519:                                     ICMP_DEST_UNREACH, inner_ip, inner_size,
  520:                                     timestamp, mpls_count, mpls);
  521:         }
  522:     }
  523: }
  524: 
  525: /*
  526:     We've received a new IPv4 ICMP packet.
  527:     We'll check to see that it is a response to one of our probes, and
  528:     if so, report the result of the probe to our command stream.
  529: */
  530: void handle_received_ip4_packet(
  531:     struct net_state_t *net_state,
  532:     const struct sockaddr_storage *remote_addr,
  533:     const void *packet,
  534:     int packet_length,
  535:     struct timeval *timestamp)
  536: {
  537:     int ip_icmp_size = 0;
  538:     const struct IPHeader *ip;
  539:     const struct ICMPHeader *icmp;
  540:     int icmp_length;
  541: 
  542:     if (net_state->platform.ip4_socket_raw) {
  543:         ip_icmp_size += sizeof(struct IPHeader);
  544:     }
  545:     ip_icmp_size += sizeof(struct ICMPHeader);
  546: 
  547:     /*  Ensure that we don't access memory beyond the bounds of the packet  */
  548:     if (packet_length < ip_icmp_size) {
  549:         return;
  550:     }
  551: 
  552:     if (net_state->platform.ip4_socket_raw) {
  553:         ip = (struct IPHeader *) packet;
  554:         if (ip->protocol != IPPROTO_ICMP) {
  555:             return;
  556:         }
  557: 
  558:         icmp = (struct ICMPHeader *) (ip + 1);
  559:         icmp_length = packet_length - sizeof(struct IPHeader);
  560:     } else {
  561:         icmp = (struct ICMPHeader *) packet;
  562:         icmp_length = packet_length;
  563:     }
  564: 
  565:     handle_received_icmp4_packet(net_state, remote_addr, icmp, icmp_length,
  566:                                  timestamp);
  567: }
  568: 
  569: /*
  570:     Unlike ICMPv6 raw sockets, unlike ICMPv4, don't include the IP header
  571:     in received packets, so we can assume the packet we got starts
  572:     with the ICMP packet.
  573: */
  574: void handle_received_ip6_packet(
  575:     struct net_state_t *net_state,
  576:     const struct sockaddr_storage *remote_addr,
  577:     const void *packet,
  578:     int packet_length,
  579:     struct timeval *timestamp)
  580: {
  581:     const struct ICMPHeader *icmp;
  582: 
  583:     icmp = (struct ICMPHeader *) packet;
  584: 
  585:     handle_received_icmp6_packet(net_state, remote_addr, icmp,
  586:                                  packet_length, timestamp);
  587: }

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