"Fossies" - the Fresh Open Source Software Archive

Member "tcpdump-4.99.1/./print-ip.c" (7 Jun 2021, 12578 Bytes) of package /linux/misc/tcpdump-4.99.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
    3  *  The Regents of the University of California.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that: (1) source code distributions
    7  * retain the above copyright notice and this paragraph in its entirety, (2)
    8  * distributions including binary code include the above copyright notice and
    9  * this paragraph in its entirety in the documentation or other materials
   10  * provided with the distribution, and (3) all advertising materials mentioning
   11  * features or use of this software display the following acknowledgement:
   12  * ``This product includes software developed by the University of California,
   13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
   14  * the University nor the names of its contributors may be used to endorse
   15  * or promote products derived from this software without specific prior
   16  * written permission.
   17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
   18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
   19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   20  */
   21 
   22 /* \summary: IP printer */
   23 
   24 #ifdef HAVE_CONFIG_H
   25 #include <config.h>
   26 #endif
   27 
   28 #include "netdissect-stdinc.h"
   29 
   30 #include "netdissect.h"
   31 #include "addrtoname.h"
   32 #include "extract.h"
   33 
   34 #include "ip.h"
   35 #include "ipproto.h"
   36 
   37 
   38 static const struct tok ip_option_values[] = {
   39     { IPOPT_EOL, "EOL" },
   40     { IPOPT_NOP, "NOP" },
   41     { IPOPT_TS, "timestamp" },
   42     { IPOPT_SECURITY, "security" },
   43     { IPOPT_RR, "RR" },
   44     { IPOPT_SSRR, "SSRR" },
   45     { IPOPT_LSRR, "LSRR" },
   46     { IPOPT_RA, "RA" },
   47     { IPOPT_RFC1393, "traceroute" },
   48     { 0, NULL }
   49 };
   50 
   51 /*
   52  * print the recorded route in an IP RR, LSRR or SSRR option.
   53  */
   54 static int
   55 ip_printroute(netdissect_options *ndo,
   56               const u_char *cp, u_int length)
   57 {
   58     u_int ptr;
   59     u_int len;
   60 
   61     if (length < 3) {
   62         ND_PRINT(" [bad length %u]", length);
   63         return (0);
   64     }
   65     if ((length + 1) & 3)
   66         ND_PRINT(" [bad length %u]", length);
   67     ptr = GET_U_1(cp + 2) - 1;
   68     if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
   69         ND_PRINT(" [bad ptr %u]", GET_U_1(cp + 2));
   70 
   71     for (len = 3; len < length; len += 4) {
   72         ND_TCHECK_4(cp + len);  /* Needed to print the IP addresses */
   73         ND_PRINT(" %s", GET_IPADDR_STRING(cp + len));
   74         if (ptr > len)
   75             ND_PRINT(",");
   76     }
   77     return (0);
   78 
   79 trunc:
   80     return (-1);
   81 }
   82 
   83 /*
   84  * If source-routing is present and valid, return the final destination.
   85  * Otherwise, return IP destination.
   86  *
   87  * This is used for UDP and TCP pseudo-header in the checksum
   88  * calculation.
   89  */
   90 static uint32_t
   91 ip_finddst(netdissect_options *ndo,
   92            const struct ip *ip)
   93 {
   94     u_int length;
   95     u_int len;
   96     const u_char *cp;
   97 
   98     cp = (const u_char *)(ip + 1);
   99     length = IP_HL(ip) * 4;
  100     if (length < sizeof(struct ip))
  101         goto trunc;
  102     length -= sizeof(struct ip);
  103 
  104     for (; length != 0; cp += len, length -= len) {
  105         int tt;
  106 
  107         tt = GET_U_1(cp);
  108         if (tt == IPOPT_EOL)
  109             break;
  110         else if (tt == IPOPT_NOP)
  111             len = 1;
  112         else {
  113             len = GET_U_1(cp + 1);
  114             if (len < 2)
  115                 break;
  116         }
  117         if (length < len)
  118             goto trunc;
  119         ND_TCHECK_LEN(cp, len);
  120         switch (tt) {
  121 
  122         case IPOPT_SSRR:
  123         case IPOPT_LSRR:
  124             if (len < 7)
  125                 break;
  126             return (GET_IPV4_TO_NETWORK_ORDER(cp + len - 4));
  127         }
  128     }
  129 trunc:
  130     return (GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst));
  131 }
  132 
  133 /*
  134  * Compute a V4-style checksum by building a pseudoheader.
  135  */
  136 uint16_t
  137 nextproto4_cksum(netdissect_options *ndo,
  138                  const struct ip *ip, const uint8_t *data,
  139                  u_int len, u_int covlen, uint8_t next_proto)
  140 {
  141     struct phdr {
  142         uint32_t src;
  143         uint32_t dst;
  144         uint8_t mbz;
  145         uint8_t proto;
  146         uint16_t len;
  147     } ph;
  148     struct cksum_vec vec[2];
  149 
  150     /* pseudo-header.. */
  151     ph.len = htons((uint16_t)len);
  152     ph.mbz = 0;
  153     ph.proto = next_proto;
  154     ph.src = GET_IPV4_TO_NETWORK_ORDER(ip->ip_src);
  155     if (IP_HL(ip) == 5)
  156         ph.dst = GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst);
  157     else
  158         ph.dst = ip_finddst(ndo, ip);
  159 
  160     vec[0].ptr = (const uint8_t *)(void *)&ph;
  161     vec[0].len = sizeof(ph);
  162     vec[1].ptr = data;
  163     vec[1].len = covlen;
  164     return (in_cksum(vec, 2));
  165 }
  166 
  167 static int
  168 ip_printts(netdissect_options *ndo,
  169            const u_char *cp, u_int length)
  170 {
  171     u_int ptr;
  172     u_int len;
  173     u_int hoplen;
  174     const char *type;
  175 
  176     if (length < 4) {
  177         ND_PRINT("[bad length %u]", length);
  178         return (0);
  179     }
  180     ND_PRINT(" TS{");
  181     hoplen = ((GET_U_1(cp + 3) & 0xF) != IPOPT_TS_TSONLY) ? 8 : 4;
  182     if ((length - 4) & (hoplen-1))
  183         ND_PRINT("[bad length %u]", length);
  184     ptr = GET_U_1(cp + 2) - 1;
  185     len = 0;
  186     if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)
  187         ND_PRINT("[bad ptr %u]", GET_U_1(cp + 2));
  188     switch (GET_U_1(cp + 3)&0xF) {
  189     case IPOPT_TS_TSONLY:
  190         ND_PRINT("TSONLY");
  191         break;
  192     case IPOPT_TS_TSANDADDR:
  193         ND_PRINT("TS+ADDR");
  194         break;
  195     case IPOPT_TS_PRESPEC:
  196         ND_PRINT("PRESPEC");
  197         break;
  198     default:
  199         ND_PRINT("[bad ts type %u]", GET_U_1(cp + 3)&0xF);
  200         goto done;
  201     }
  202 
  203     type = " ";
  204     for (len = 4; len < length; len += hoplen) {
  205         if (ptr == len)
  206             type = " ^ ";
  207         ND_TCHECK_LEN(cp + len, hoplen);
  208         ND_PRINT("%s%u@%s", type, GET_BE_U_4(cp + len + hoplen - 4),
  209               hoplen!=8 ? "" : GET_IPADDR_STRING(cp + len));
  210         type = " ";
  211     }
  212 
  213 done:
  214     ND_PRINT("%s", ptr == len ? " ^ " : "");
  215 
  216     if (GET_U_1(cp + 3) >> 4)
  217         ND_PRINT(" [%u hops not recorded]} ", GET_U_1(cp + 3)>>4);
  218     else
  219         ND_PRINT("}");
  220     return (0);
  221 
  222 trunc:
  223     return (-1);
  224 }
  225 
  226 /*
  227  * print IP options.
  228    If truncated return -1, else 0.
  229  */
  230 static int
  231 ip_optprint(netdissect_options *ndo,
  232             const u_char *cp, u_int length)
  233 {
  234     u_int option_len;
  235     const char *sep = "";
  236 
  237     for (; length > 0; cp += option_len, length -= option_len) {
  238         u_int option_code;
  239 
  240         ND_PRINT("%s", sep);
  241         sep = ",";
  242 
  243         option_code = GET_U_1(cp);
  244 
  245         ND_PRINT("%s",
  246                   tok2str(ip_option_values,"unknown %u",option_code));
  247 
  248         if (option_code == IPOPT_NOP ||
  249                     option_code == IPOPT_EOL)
  250             option_len = 1;
  251 
  252         else {
  253             option_len = GET_U_1(cp + 1);
  254             if (option_len < 2) {
  255                 ND_PRINT(" [bad length %u]", option_len);
  256                 return 0;
  257             }
  258         }
  259 
  260         if (option_len > length) {
  261             ND_PRINT(" [bad length %u]", option_len);
  262             return 0;
  263         }
  264 
  265         ND_TCHECK_LEN(cp, option_len);
  266 
  267         switch (option_code) {
  268         case IPOPT_EOL:
  269             return 0;
  270 
  271         case IPOPT_TS:
  272             if (ip_printts(ndo, cp, option_len) == -1)
  273                 goto trunc;
  274             break;
  275 
  276         case IPOPT_RR:       /* fall through */
  277         case IPOPT_SSRR:
  278         case IPOPT_LSRR:
  279             if (ip_printroute(ndo, cp, option_len) == -1)
  280                 goto trunc;
  281             break;
  282 
  283         case IPOPT_RA:
  284             if (option_len < 4) {
  285                 ND_PRINT(" [bad length %u]", option_len);
  286                 break;
  287             }
  288             ND_TCHECK_1(cp + 3);
  289             if (GET_BE_U_2(cp + 2) != 0)
  290                 ND_PRINT(" value %u", GET_BE_U_2(cp + 2));
  291             break;
  292 
  293         case IPOPT_NOP:       /* nothing to print - fall through */
  294         case IPOPT_SECURITY:
  295         default:
  296             break;
  297         }
  298     }
  299     return 0;
  300 
  301 trunc:
  302     return -1;
  303 }
  304 
  305 #define IP_RES 0x8000
  306 
  307 static const struct tok ip_frag_values[] = {
  308         { IP_MF,        "+" },
  309         { IP_DF,        "DF" },
  310     { IP_RES,       "rsvd" }, /* The RFC3514 evil ;-) bit */
  311         { 0,            NULL }
  312 };
  313 
  314 
  315 /*
  316  * print an IP datagram.
  317  */
  318 void
  319 ip_print(netdissect_options *ndo,
  320      const u_char *bp,
  321      u_int length)
  322 {
  323     const struct ip *ip;
  324     u_int off;
  325     u_int hlen;
  326     u_int len;
  327     struct cksum_vec vec[1];
  328     uint8_t ip_tos, ip_ttl, ip_proto;
  329     uint16_t sum, ip_sum;
  330     const char *p_name;
  331     int truncated = 0;
  332 
  333     ndo->ndo_protocol = "ip";
  334     ip = (const struct ip *)bp;
  335     if (IP_V(ip) != 4) { /* print version and fail if != 4 */
  336         if (IP_V(ip) == 6)
  337           ND_PRINT("IP6, wrong link-layer encapsulation");
  338         else
  339           ND_PRINT("IP%u", IP_V(ip));
  340         nd_print_invalid(ndo);
  341         return;
  342     }
  343     if (!ndo->ndo_eflag)
  344         ND_PRINT("IP ");
  345 
  346     ND_TCHECK_SIZE(ip);
  347     if (length < sizeof (struct ip)) {
  348         ND_PRINT("truncated-ip %u", length);
  349         return;
  350     }
  351     hlen = IP_HL(ip) * 4;
  352     if (hlen < sizeof (struct ip)) {
  353         ND_PRINT("bad-hlen %u", hlen);
  354         return;
  355     }
  356 
  357     len = GET_BE_U_2(ip->ip_len);
  358     if (length < len)
  359         ND_PRINT("truncated-ip - %u bytes missing! ",
  360             len - length);
  361     if (len < hlen) {
  362 #ifdef GUESS_TSO
  363             if (len) {
  364                 ND_PRINT("bad-len %u", len);
  365                 return;
  366             }
  367             else {
  368                 /* we guess that it is a TSO send */
  369                 len = length;
  370             }
  371 #else
  372             ND_PRINT("bad-len %u", len);
  373             return;
  374 #endif /* GUESS_TSO */
  375     }
  376 
  377     /*
  378      * Cut off the snapshot length to the end of the IP payload.
  379      */
  380     nd_push_snapend(ndo, bp + len);
  381 
  382     len -= hlen;
  383 
  384     off = GET_BE_U_2(ip->ip_off);
  385 
  386         ip_proto = GET_U_1(ip->ip_p);
  387 
  388         if (ndo->ndo_vflag) {
  389             ip_tos = GET_U_1(ip->ip_tos);
  390             ND_PRINT("(tos 0x%x", ip_tos);
  391             /* ECN bits */
  392             switch (ip_tos & 0x03) {
  393 
  394             case 0:
  395                 break;
  396 
  397             case 1:
  398                 ND_PRINT(",ECT(1)");
  399                 break;
  400 
  401             case 2:
  402                 ND_PRINT(",ECT(0)");
  403                 break;
  404 
  405             case 3:
  406                 ND_PRINT(",CE");
  407                 break;
  408             }
  409 
  410             ip_ttl = GET_U_1(ip->ip_ttl);
  411             if (ip_ttl >= 1)
  412                 ND_PRINT(", ttl %u", ip_ttl);
  413 
  414         /*
  415          * for the firewall guys, print id, offset.
  416              * On all but the last stick a "+" in the flags portion.
  417          * For unfragmented datagrams, note the don't fragment flag.
  418          */
  419         ND_PRINT(", id %u, offset %u, flags [%s], proto %s (%u)",
  420                          GET_BE_U_2(ip->ip_id),
  421                          (off & IP_OFFMASK) * 8,
  422                          bittok2str(ip_frag_values, "none", off & (IP_RES|IP_DF|IP_MF)),
  423                          tok2str(ipproto_values, "unknown", ip_proto),
  424                          ip_proto);
  425 
  426             ND_PRINT(", length %u", GET_BE_U_2(ip->ip_len));
  427 
  428             if ((hlen - sizeof(struct ip)) > 0) {
  429                 ND_PRINT(", options (");
  430                 if (ip_optprint(ndo, (const u_char *)(ip + 1),
  431                     hlen - sizeof(struct ip)) == -1) {
  432                         ND_PRINT(" [truncated-option]");
  433             truncated = 1;
  434                 }
  435                 ND_PRINT(")");
  436             }
  437 
  438         if (!ndo->ndo_Kflag && (const u_char *)ip + hlen <= ndo->ndo_snapend) {
  439             vec[0].ptr = (const uint8_t *)(const void *)ip;
  440             vec[0].len = hlen;
  441             sum = in_cksum(vec, 1);
  442         if (sum != 0) {
  443             ip_sum = GET_BE_U_2(ip->ip_sum);
  444             ND_PRINT(", bad cksum %x (->%x)!", ip_sum,
  445                  in_cksum_shouldbe(ip_sum, sum));
  446         }
  447         }
  448 
  449         ND_PRINT(")\n    ");
  450         if (truncated) {
  451         ND_PRINT("%s > %s: ",
  452              GET_IPADDR_STRING(ip->ip_src),
  453              GET_IPADDR_STRING(ip->ip_dst));
  454         nd_print_trunc(ndo);
  455         nd_pop_packet_info(ndo);
  456         return;
  457         }
  458     }
  459 
  460     /*
  461      * If this is fragment zero, hand it to the next higher
  462      * level protocol.  Let them know whether there are more
  463      * fragments.
  464      */
  465     if ((off & IP_OFFMASK) == 0) {
  466         uint8_t nh = GET_U_1(ip->ip_p);
  467 
  468         if (nh != IPPROTO_TCP && nh != IPPROTO_UDP &&
  469             nh != IPPROTO_SCTP && nh != IPPROTO_DCCP) {
  470             ND_PRINT("%s > %s: ",
  471                      GET_IPADDR_STRING(ip->ip_src),
  472                      GET_IPADDR_STRING(ip->ip_dst));
  473         }
  474         /*
  475          * Do a bounds check before calling ip_demux_print().
  476          * At least the header data is required.
  477          */
  478         if (!ND_TTEST_LEN((const u_char *)ip, hlen)) {
  479             ND_PRINT(" [remaining caplen(%u) < header length(%u)]",
  480                  ND_BYTES_AVAILABLE_AFTER((const u_char *)ip),
  481                  hlen);
  482             nd_trunc_longjmp(ndo);
  483         }
  484         ip_demux_print(ndo, (const u_char *)ip + hlen, len, 4,
  485                    off & IP_MF, GET_U_1(ip->ip_ttl), nh, bp);
  486     } else {
  487         /*
  488          * Ultra quiet now means that all this stuff should be
  489          * suppressed.
  490          */
  491         if (ndo->ndo_qflag > 1) {
  492             nd_pop_packet_info(ndo);
  493             return;
  494         }
  495 
  496         /*
  497          * This isn't the first frag, so we're missing the
  498          * next level protocol header.  print the ip addr
  499          * and the protocol.
  500          */
  501         ND_PRINT("%s > %s:", GET_IPADDR_STRING(ip->ip_src),
  502                   GET_IPADDR_STRING(ip->ip_dst));
  503         if (!ndo->ndo_nflag && (p_name = netdb_protoname(ip_proto)) != NULL)
  504             ND_PRINT(" %s", p_name);
  505         else
  506             ND_PRINT(" ip-proto-%u", ip_proto);
  507     }
  508     nd_pop_packet_info(ndo);
  509     return;
  510 
  511 trunc:
  512     nd_print_trunc(ndo);
  513 }
  514 
  515 void
  516 ipN_print(netdissect_options *ndo, const u_char *bp, u_int length)
  517 {
  518     ndo->ndo_protocol = "ipn";
  519     if (length < 1) {
  520         ND_PRINT("truncated-ip %u", length);
  521         return;
  522     }
  523 
  524     switch (GET_U_1(bp) & 0xF0) {
  525     case 0x40:
  526         ip_print(ndo, bp, length);
  527         break;
  528     case 0x60:
  529         ip6_print(ndo, bp, length);
  530         break;
  531     default:
  532         ND_PRINT("unknown ip %u", (GET_U_1(bp) & 0xF0) >> 4);
  533         break;
  534     }
  535 }