Annotation of embedaddon/mtr/test/packet_listen.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 <netinet/in.h>
                     20: #include <stdbool.h>
                     21: #include <stdio.h>
                     22: #include <stdlib.h>
                     23: #include <sys/socket.h>
                     24: #include <unistd.h>
                     25: 
                     26: #include "packet/protocols.h"
                     27: 
                     28: #define MAX_PACKET_SIZE 9000
                     29: 
                     30: /*
                     31:     The first probe sent by mtr-packet will have this sequence number,
                     32:     so wait for an ICMP packet with this sequence ID.
                     33: */
                     34: #define SEQUENCE_NUM 33000
                     35: 
                     36: /*
                     37:     Check to see if the packet we've recieved is intended for this test
                     38:     process.  We expected the ICMP sequence number to be equal to our
                     39:     process ID.
                     40: */
                     41: bool is_packet_for_us4(
                     42:     char *packet,
                     43:     int packet_size)
                     44: {
                     45:     int ip_icmp_size = sizeof(struct IPHeader) + sizeof(struct ICMPHeader);
                     46:     int expected_sequence;
                     47:     struct IPHeader *ip;
                     48:     struct ICMPHeader *icmp;
                     49: 
                     50:     if (packet_size < ip_icmp_size) {
                     51:         return false;
                     52:     }
                     53: 
                     54:     ip = (struct IPHeader *)packet;
                     55:     icmp = (struct ICMPHeader *)(ip + 1);
                     56: 
                     57:     expected_sequence = htons(SEQUENCE_NUM);
                     58:     if (icmp->sequence == expected_sequence) {
                     59:         return true;
                     60:     }
                     61: 
                     62:     return false;
                     63: }
                     64: 
                     65: /*
                     66:     Check to see if the ICMPv6 packet is for us.
                     67:     Unlike ICMPv4 packets, ICMPv6 packets don't include the IP header.
                     68: */
                     69: bool is_packet_for_us6(
                     70:     char *packet,
                     71:     int packet_size)
                     72: {
                     73:     int expected_sequence;
                     74:     struct ICMPHeader *icmp;
                     75: 
                     76:     if (packet_size < sizeof(struct ICMPHeader)) {
                     77:         return false;
                     78:     }
                     79: 
                     80:     icmp = (struct ICMPHeader *)packet;
                     81: 
                     82:     expected_sequence = htons(SEQUENCE_NUM);
                     83:     if (icmp->sequence == expected_sequence) {
                     84:         return true;
                     85:     }
                     86: 
                     87:     return false;
                     88: }
                     89: 
                     90: /*
                     91:     Check that all the bytes in the body of the packet have the same value.
                     92:     If so, return that value.  If not, return -1.
                     93: */
                     94: int get_packet_pattern(
                     95:     unsigned char *packet,
                     96:     int packet_size)
                     97: {
                     98:     int fill_value;
                     99:     int i;
                    100: 
                    101:     if (packet_size <= 0) {
                    102:         return -1;
                    103:     }
                    104: 
                    105:     fill_value = packet[0];
                    106:     for (i = 1; i < packet_size; i++) {
                    107:         if (packet[i] != fill_value) {
                    108:             return -1;
                    109:         }
                    110:     }
                    111: 
                    112:     return fill_value;
                    113: }
                    114: 
                    115: /*  Print information about the ICMPv4 packet we received  */
                    116: void dump_packet_info4(
                    117:     char *packet,
                    118:     int packet_size)
                    119: {
                    120:     int ip_icmp_size = sizeof(struct IPHeader) + sizeof(struct ICMPHeader);
                    121:     int pattern;
                    122:     struct IPHeader *ip;
                    123:     struct ICMPHeader *icmp;
                    124:     unsigned char *body;
                    125:     int body_size;
                    126: 
                    127:     ip = (struct IPHeader *)packet;
                    128:     icmp = (struct ICMPHeader *)(ip + 1);
                    129:     body = (unsigned char *)(icmp + 1);
                    130:     body_size = packet_size - ip_icmp_size;
                    131: 
                    132:     printf("size %d\n", packet_size);
                    133:     printf("tos %d\n", ip->tos);
                    134: 
                    135:     pattern = get_packet_pattern(body, body_size);
                    136:     if (pattern < 0) {
                    137:         printf("bitpattern none\n");
                    138:     } else {
                    139:         printf("bitpattern %d\n", pattern);
                    140:     }
                    141: }
                    142: 
                    143: /*  Print information about an ICMPv6 packet  */
                    144: void dump_packet_info6(
                    145:     char *packet,
                    146:     int packet_size)
                    147: {
                    148:     int pattern;
                    149:     struct ICMPHeader *icmp;
                    150:     unsigned char *body;
                    151:     int body_size;
                    152:     int total_size;
                    153: 
                    154:     icmp = (struct ICMPHeader *)packet;
                    155:     body = (unsigned char *)(icmp + 1);
                    156:     body_size = packet_size - sizeof(struct ICMPHeader);
                    157: 
                    158:     total_size = packet_size + sizeof(struct IP6Header);
                    159:     printf("size %d\n", total_size);
                    160: 
                    161:     pattern = get_packet_pattern(body, body_size);
                    162:     if (pattern < 0) {
                    163:         printf("bitpattern none\n");
                    164:     } else {
                    165:         printf("bitpattern %d\n", pattern);
                    166:     }
                    167: }
                    168: 
                    169: /*  Receive ICMP packets until we get one intended for this test process  */
                    170: void loop_on_receive(
                    171:     int icmp_socket,
                    172:     int ip_version)
                    173: {
                    174:     int packet_size;
                    175:     char packet[MAX_PACKET_SIZE];
                    176: 
                    177:     while (true) {
                    178:         packet_size = recv(icmp_socket, packet, MAX_PACKET_SIZE, 0);
                    179:         if (packet_size < -1) {
                    180:             perror("Failure during receive");
                    181:             exit(EXIT_FAILURE);
                    182:         }
                    183: 
                    184:         if (ip_version == 6) {
                    185:             if (is_packet_for_us6(packet, packet_size)) {
                    186:                 dump_packet_info6(packet, packet_size);
                    187:                 return;
                    188:             }
                    189:         } else {
                    190:             if (is_packet_for_us4(packet, packet_size)) {
                    191:                 dump_packet_info4(packet, packet_size);
                    192:                 return;
                    193:             }
                    194:         }
                    195:     }
                    196: }
                    197: 
                    198: /*  Parse the commandline arguments  */
                    199: void parse_cmdline(
                    200:     int argc,
                    201:     char **argv,
                    202:     int *ip_version)
                    203: {
                    204:     int opt;
                    205: 
                    206:     *ip_version = 4;
                    207: 
                    208:     while ((opt = getopt(argc, argv, "46")) != -1) {
                    209:         if (opt == '4') {
                    210:             *ip_version = 4;
                    211:         }
                    212: 
                    213:         if (opt == '6') {
                    214:             *ip_version = 6;
                    215:         }
                    216:     }
                    217: }
                    218: 
                    219: /*
                    220:     A helper for mtr-packet testing which waits for an ICMP packet
                    221:     intended for this test process, and then prints information about
                    222:     it.
                    223: */
                    224: int main(
                    225:     int argc,
                    226:     char **argv)
                    227: {
                    228:     int icmp_socket;
                    229:     int ip_version;
                    230: 
                    231:     parse_cmdline(argc, argv, &ip_version);
                    232: 
                    233:     if (ip_version == 6) {
                    234:         icmp_socket = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
                    235:     } else {
                    236:         icmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
                    237:     }
                    238:     if (icmp_socket < 0) {
                    239:         perror("Failure opening listening socket");
                    240:         exit(EXIT_FAILURE);
                    241:     }
                    242: 
                    243:     printf("status listening\n");
                    244:     fflush(stdout);
                    245: 
                    246:     loop_on_receive(icmp_socket, ip_version);
                    247: 
                    248:     return EXIT_SUCCESS;
                    249: }

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