Nmap中用到的tcp选项解析函数理解

            理解tcp选项的解析时有一些困难,这里记录一下。         

          (u8*) tcp + sizeof(struct tcp_hdr) /*是选项开始位置,因为tcp头部中包含选项,所以th->off这个头部长度是含有option的长度的,但是tcp_hdr结构的定义中不含选择,所以,tcp指针的地址+tcp_hdr结构长度就是选项的开始位置。

            int length = (th->off * 4) - sizeof(struct tcp_hdr); /* 选项的总长度 ,其中th->off 是tcp头部长度*/

            以下是Nmap中,tcp 选项解析的函数定义,这是函数调用  :

            tcppacketoptinfo((u8*) tcp + sizeof(struct tcp_hdr),

           tcp->th_off*4 - sizeof(struct tcp_hdr),  tcpoptinfo, sizeof(tcpoptinfo));//第一个参数,选项首地址,第二个参数,选项长度,第三个和第四个是解析得到的结果的存储位置和内容。

          (开始一直不明白,前两个参数怎么传这个,后来恍然大悟了。很多东西都没有办法问别人,因为每个人都有研究的内容,可能没有办法静下心帮你读一段代码,还是要靠自己领悟。)


以下是Nmap中,tcp 选项解析的函数定义:

/* Get an ASCII information about a tcp option which is pointed by
   optp, with a length of len. The result is stored in the result
   buffer. The result may look like "<mss 1452,sackOK,timestamp
   45848914 0,nop,wscale 7>" */
     
void tcppacketoptinfo(u8 *optp, int len, char *result, int bufsize) {
  assert(optp);
  assert(result);
  char *p, ch;
  u8 *q;
  int opcode;
  u16 tmpshort;
  u32 tmpword1, tmpword2;
  unsigned int i=0;

  p = result;
  *p = '\0';
  q = optp;
  ch = '<';

  while (len > 0 && bufsize > 2) {
    Snprintf(p, bufsize, "%c", ch);
    bufsize--;
    p++;
    opcode = *q++;//opcode = *q++;这样opcode中存入了option的第一个字符,即option中的type。
    if (!opcode) { /* End of List */
//然后开始判断opcode的几种情况0,1,2,3,4,5---具体这五种情况是怎么回事儿,参考关于tcp 选项的介绍即可。                                                    
      Snprintf(p, bufsize, "eol");
      bufsize -= strlen(p);
      p += strlen(p);

      len--;

    } else if (opcode == 1) { /* No Op */
      Snprintf(p, bufsize, "nop");
      bufsize -= strlen(p);
      p += strlen(p);

      len--;
    } else if (opcode == 2) { /* MSS */
      if (len < 4)
        break; /* MSS has 4 bytes */

      q++;
      memcpy(&tmpshort, q, 2);

      Snprintf(p, bufsize, "mss %u", ntohs(tmpshort));
      bufsize -= strlen(p);
      p += strlen(p);

      q += 2;
      len -= 4;
    } else if (opcode == 3) { /* Window Scale */
      if (len < 3)
        break; /* Window Scale option has 3 bytes */

      q++;

      Snprintf(p, bufsize, "wscale %u", *q);
      bufsize -= strlen(p);
      p += strlen(p);

      q++;
      len -= 3;
    } else if (opcode == 4) { /* SACK permitted */
      if (len < 2)
        break; /* SACK permitted option has 2 bytes */

      Snprintf(p, bufsize, "sackOK");
      bufsize -= strlen(p);
      p += strlen(p);

      q++;
      len -= 2;
    } else if (opcode == 5) { /* SACK *//* SACK ,==5时稍微复杂,sockoptlen= N*8+2,以8字节为一块,并且分左4块和右四块,所以程序中(sackoptlen - 2) % 8来处理有多少块,memcpy(&tmpword1, q + i, 4); memcpy(&tmpword2, q + i + 4, 4);
  分别四字节存入*/
      unsigned sackoptlen = *q;
      if ((unsigned) len < sackoptlen)
        break;

      /* This would break parsing, so it's best to just give up */
      if (sackoptlen < 2)
        break;

      q++;

      if ((sackoptlen - 2) == 0 || ((sackoptlen - 2) % 8 != 0)) {
        Snprintf(p, bufsize, "malformed sack");
        bufsize -= strlen(p);
        p += strlen(p);
      } else {
        Snprintf(p, bufsize, "sack %d ", (sackoptlen - 2) / 8);
        bufsize -= strlen(p);
        p += strlen(p);
        for (i = 0; i < sackoptlen - 2; i += 8) {
          memcpy(&tmpword1, q + i, 4);
          memcpy(&tmpword2, q + i + 4, 4);
          Snprintf(p, bufsize, "{%u:%u}", tmpword1, tmpword2);
          bufsize -= strlen(p);
          p += strlen(p);
        }
      }

      q += sackoptlen - 2;
      len -= sackoptlen;
    } else if (opcode == 8) { /* Timestamp */
      if (len < 10)
        break; /* Timestamp option has 10 bytes */

      q++;
      memcpy(&tmpword1, q, 4);
      memcpy(&tmpword2, q + 4, 4);

      Snprintf(p, bufsize, "timestamp %u %u", ntohl(tmpword1),
               ntohl(tmpword2));
      bufsize -= strlen(p);
      p += strlen(p);

      q += 8;
      len -= 10;
    }

    ch = ',';
  }

  if (len > 0) {
    *result = '\0';
    return;
  }

  Snprintf(p, bufsize, ">");
}
 

猜你喜欢

转载自blog.csdn.net/maryfei/article/details/80208433