Annotation of embedaddon/mtr/packet/deconstruct_unix.c, revision 1.1.1.1

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

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