LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 5885|回复: 14

TCP端口扫描

[复制链接]
发表于 2005-5-5 23:19:04 | 显示全部楼层 |阅读模式
以前写的一段代码,用于发现internet上的tcp服务,如果大家对端口扫描感兴趣应该是不错的参考。当时参与了一个ftp文件搜索的项目,这是其中的一个模块,感觉写得还不错,用一台PC机只需两个多小时就可以发现全国的ftp服务。有人有兴趣的话我明天再给出代码的详细说明。

tcp_scan.h:

  1. #ifndef _TCP_SCAN_H_
  2. #define _TCP_SCAN_H_

  3. #include <sys/types.h>
  4. #include <sys/socket.h>

  5. #define TS_ACCEPTED         1
  6. #define TS_REFUSED          2
  7. #define TS_UNREACH          3

  8. struct addrseg
  9. {
  10.     int as_family;
  11.     void *as_address;
  12.     unsigned int as_bits;
  13.     struct addrseg *as_next;
  14. };

  15. typedef int (*scan_info_t)(const struct sockaddr *, socklen_t, int, void *);

  16. #ifdef __cplusplus
  17. extern "C"
  18. {
  19. #endif

  20. int tcp_scan(const struct addrseg *addrscope, const unsigned short *ports,
  21.              unsigned int ifindex, const char *ifname, int resetuid,
  22.              scan_info_t info, void *arg);

  23. #ifdef __cplusplus
  24. }
  25. #endif

  26. #endif

复制代码


tcp_scan.c:

  1. /* I like BSD style better. */
  2. #define _BSD_SOURCE
  3. #include <errno.h>
  4. #include <sys/types.h>
  5. #include <sys/time.h>
  6. #include <sys/select.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <netinet/ip.h>
  10. #include <netinet/ip_icmp.h>
  11. #ifdef IPV6
  12. # include <netinet/ip6.h>
  13. # include <netinet/icmp6.h>
  14. #endif
  15. #include <netinet/tcp.h>
  16. #include <arpa/inet.h>
  17. #include <time.h>
  18. #include <unistd.h>
  19. #include <fcntl.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <rbtree.h>
  23. #include <unp.h>
  24. #include "tcp_scan.h"

  25. #define TCP_SCANNER_PORT        12200
  26. #define TCP_SCAN_REPEATS        4
  27. #define MAX_SEG_LIFETIME        30

  28. #ifndef offsetof
  29. # define offsetof(type, member)     ((size_t)&((type *)0)->member)
  30. #endif

  31. #define SET_FD_NONBLOCK(fd) \
  32. ({                                                                      \
  33.     int __flags = fcntl(fd, F_GETFL, 0);                                \
  34.     if (__flags >= 0)                                                   \
  35.         __flags = fcntl(fd, F_SETFL, __flags | O_NONBLOCK);             \
  36.     __flags;                                                            \
  37. })

  38. #ifdef IPV6
  39. # define IN6_ADDR_NEXT(addr) \
  40. do {                                                                    \
  41.     int __i;                                                            \
  42.     for (__i = 15; __i >= 0; __i--)                                     \
  43.     {                                                                   \
  44.         if (++((unsigned char *)(addr))[__i] != 0)                      \
  45.             break;                                                      \
  46.     }                                                                   \
  47. } while (0)
  48. #endif

  49. #ifndef __linux__
  50. # define select(maxfdp1, rset, wset, xset, timeout) \
  51. ({                                                                      \
  52.     struct timeval __tv = *(timeout);                                   \
  53.     long __tps = sysconf(_SC_CLK_TCK);                                  \
  54.     clock_t __clock = times(NULL);                                      \
  55.     int __n = select(maxfdp1, rset, wset, xset, timeout);               \
  56.     __clock = times(NULL) - __clock;                                    \
  57.     *(timeout) = __tv;                                                  \
  58.     if (((timeout)->tv_sec -= __clock / __tps) < 0)                     \
  59.     {                                                                   \
  60.         (timeout)->tv_usec += 1000000 * (timeout)->tv_sec;              \
  61.         (timeout)->tv_sec = 0;                                          \
  62.     }                                                                   \
  63.     if (((timeout)->tv_usec -= __clock % __tps * 1000000 / __tps) < 0)  \
  64.         (timeout)->tv_usec = 0;                                         \
  65.     __n;                                                                \
  66. })
  67. #endif

  68. /* "sockaddr" structs arranged in a Red-Black tree. */
  69. struct __sockaddr_rb
  70. {
  71.     struct rb_node rb;
  72.     socklen_t addrlen;
  73.     struct sockaddr sockaddr;
  74. };

  75. /* Union of sockaddr. */
  76. union __sa_union
  77. {
  78.     struct sockaddr sockaddr;
  79.     struct sockaddr_in sin;
  80. #ifdef IPV6
  81.     struct sockaddr_in6 sin6;
  82. #endif
  83. };

  84. /* IP pseudoheader of TCP or UDP. */
  85. struct __ip_pheader
  86. {
  87.     struct in_addr src;
  88.     struct in_addr dst;
  89.     unsigned char zero;
  90.     unsigned char protocol;
  91.     unsigned short len;
  92. };

  93. #ifdef IPV6

  94. struct __ip6_pheader
  95. {
  96.     struct in6_addr src;
  97.     struct in6_addr dst;
  98.     unsigned int len;
  99.     unsigned short zero1;
  100.     unsigned char zero2;
  101.     unsigned char next;
  102. };

  103. #endif

  104. /* TCP header combined with IP pseudoheader. */
  105. struct __tcp_pheader
  106. {
  107. #ifdef IPV6
  108.     union
  109.     {
  110.         struct __ip6_pheader phdr6;
  111.         struct
  112.         {
  113.             char __pad[sizeof (struct __ip6_pheader) -
  114.                        sizeof (struct __ip_pheader)];
  115.             struct __ip_pheader phdr;
  116.         };
  117.     };
  118. #else
  119.     struct __ip_pheader phdr;
  120. #endif
  121.     struct tcphdr tcphdr;
  122. };

  123. unsigned short __tcp_scanner_port = TCP_SCANNER_PORT;
  124. int __tcp_scan_repeats = TCP_SCAN_REPEATS;
  125. int __max_seg_lifetime = MAX_SEG_LIFETIME;

  126. /* For the sake of simplicity. */
  127. static unsigned int __tcp_header_seq;
  128. static scan_info_t __info;
  129. static void *__arg;

  130. inline static void __make_tcp_ip_pheader(const struct in_addr *saddr,
  131.                                          const struct in_addr *daddr,
  132.                                          struct __ip_pheader *phdr)
  133. {
  134.     phdr->src = *saddr;
  135.     phdr->dst = *daddr;
  136.     phdr->zero = 0;
  137.     phdr->protocol = IPPROTO_TCP;
  138.     phdr->len = htons(sizeof (struct tcphdr));
  139. }

  140. #ifdef IPV6

  141. inline static void __make_tcp_ip6_pheader(const struct in6_addr *saddr,
  142.                                           const struct in6_addr *daddr,
  143.                                           struct __ip6_pheader *phdr)
  144. {
  145.     phdr->src = *saddr;
  146.     phdr->dst = *daddr;
  147.     phdr->len = htonl(sizeof (struct tcphdr));
  148.     phdr->zero1 = 0;
  149.     phdr->zero2 = 0;
  150.     phdr->next = IPPROTO_TCP;
  151. }

  152. #endif

  153. /* Send a TCP packet. (Without TCP options or TCP data.) */
  154. static int __tcp_send(int sockfd, struct __tcp_pheader *tcpphdr,
  155.                       const void *saddr, const struct sockaddr *daddr,
  156.                       socklen_t addrlen)
  157. {
  158.     unsigned short *pfrom;
  159.     int len;

  160.     switch (daddr->sa_family)
  161.     {
  162.     case AF_INET:
  163.         __make_tcp_ip_pheader((const struct in_addr *)saddr,
  164.                               &((const struct sockaddr_in *)daddr)->
  165.                               sin_addr, &tcpphdr->phdr);
  166.         pfrom = (unsigned short *)&tcpphdr->phdr;
  167.         len = sizeof (struct __ip_pheader) + sizeof (struct tcphdr);
  168.         break;
  169. #ifdef IPV6
  170.     case AF_INET6:
  171.         __make_tcp_ip6_pheader((const struct in6_addr *)saddr,
  172.                                &((const struct sockaddr_in6 *)daddr)->
  173.                                sin6_addr, &tcpphdr->phdr6);
  174.         pfrom = (unsigned short *)&tcpphdr->phdr6;
  175.         len = sizeof (struct __ip6_pheader) + sizeof (struct tcphdr);
  176.         break;
  177. #endif
  178.     default:
  179.         errno = EAFNOSUPPORT;
  180.         return -1;
  181.     }

  182.     tcpphdr->tcphdr.th_sum = 0;
  183.     tcpphdr->tcphdr.th_sum = in_cksum(pfrom, len);
  184.     return sendto(sockfd, &tcpphdr->tcphdr, sizeof (struct tcphdr), 0,
  185.                   daddr, addrlen);
  186. }

  187. /* Send a SYN packet to the remote server. */
  188. static int __tcp_syn(int sockfd, unsigned short sport, unsigned short dport,
  189.                      const void *saddr, const struct sockaddr *daddr,
  190.                      socklen_t addrlen)
  191. {
  192.     struct __tcp_pheader tcpphdr = {
  193.         tcphdr  :   {
  194.             th_sport    :   htons(sport),
  195.             th_dport    :   htons(dport),
  196.             th_seq      :   htonl(__tcp_header_seq),
  197.             th_ack      :   htonl(0),
  198.             th_x2       :   0,
  199.             th_off      :   sizeof (struct tcphdr) >> 2,
  200.             th_flags    :   TH_SYN,
  201.             th_win      :   htons(8192),
  202.             th_urp      :   htons(0)
  203.         }
  204.     };

  205.     return __tcp_send(sockfd, &tcpphdr, saddr, daddr, addrlen);
  206. }

  207. /* Tell the remote server that connection is aborted. */
  208. static int __tcp_rst(int sockfd, unsigned short sport, unsigned short dport,
  209.                      const void *saddr, const struct sockaddr *daddr,
  210.                      socklen_t addrlen)
  211. {
  212.     struct __tcp_pheader tcpphdr = {
  213.         tcphdr  :   {
  214.             th_sport    :   htons(sport),
  215.             th_dport    :   htons(dport),
  216.             th_seq      :   htonl(0),
  217.             th_ack      :   htonl(0),
  218.             th_x2       :   0,
  219.             th_off      :   sizeof (struct tcphdr) >> 2,
  220.             th_flags    :   TH_RST,
  221.             th_win      :   htons(0),
  222.             th_urp      :   htons(0)
  223.         }
  224.     };

  225.     return __tcp_send(sockfd, &tcpphdr, saddr, daddr, addrlen);
  226. }

  227. /* Search a sockaddr in a Red-Black tree. */
  228. static struct __sockaddr_rb *
  229. __rb_search_sockaddr(const struct sockaddr *sockaddr, socklen_t addrlen,
  230.                      const struct rb_root *root)
  231. {
  232.     const struct rb_node *p = root->node;
  233.     struct __sockaddr_rb *entry;
  234.     int n;

  235.     while (p)
  236.     {
  237.         entry = rb_entry(p, struct __sockaddr_rb, rb);
  238.         if (addrlen < entry->addrlen)
  239.             n = -1;
  240.         else if (addrlen > entry->addrlen)
  241.             n = 1;
  242.         else if ((n = memcmp(sockaddr, &entry->sockaddr, addrlen)) == 0)
  243.             return entry;

  244.         p = n < 0 ? p->left : p->right;
  245.     }

  246.     return NULL;
  247. }

  248. /* Insert a sockaddr into a Red-Black tree. */
  249. static struct __sockaddr_rb *
  250. __rb_insert_sockaddr(const struct sockaddr *sockaddr, socklen_t addrlen,
  251.                      struct rb_root *root)
  252. {
  253.     struct rb_node **p = &root->node;
  254.     struct rb_node *parent = NULL;
  255.     struct __sockaddr_rb *entry;
  256.     int n;

  257.     while (*p)
  258.     {
  259.         parent = *p;
  260.         entry = rb_entry(parent, struct __sockaddr_rb, rb);
  261.         if (addrlen < entry->addrlen)
  262.             n = -1;
  263.         else if (addrlen > entry->addrlen)
  264.             n = 1;
  265.         else if ((n = memcmp(sockaddr, &entry->sockaddr, addrlen)) == 0)
  266.             return entry;

  267.         p = n < 0 ? &parent->left : &parent->right;
  268.     }

  269.     #define __SOCKADDR_RB_SIZE \
  270.         (offsetof(struct __sockaddr_rb, sockaddr) + addrlen)
  271.     if (entry = (struct __sockaddr_rb *)malloc(__SOCKADDR_RB_SIZE))
  272.     {
  273.         entry->addrlen = addrlen;
  274.         memcpy(&entry->sockaddr, sockaddr, addrlen);
  275.         rb_link_node(&entry->rb, parent, p);
  276.         rb_insert_color(&entry->rb, root);
  277.         return NULL;
  278.     }
  279.     #undef __SOCKADDR_RB_SIZE

  280.     return (struct __sockaddr_rb *)-1;
  281. }

  282. static void __rb_destroy_sockaddr(struct rb_root *root)
  283. {
  284.     struct __sockaddr_rb *entry;

  285.     while (root->node)
  286.     {
  287.         entry = rb_entry(root->node, struct __sockaddr_rb, rb);
  288.         rb_erase(root->node, root);
  289.         free(entry);
  290.     }
  291. }

  292. static int __proc_tcp_packet(int sockfd, const struct tcphdr *tcphdr,
  293.                              const void *daddr, const struct sockaddr *saddr,
  294.                              socklen_t addrlen, struct rb_root *root)
  295. {
  296.     struct __sockaddr_rb *entry;
  297.     int state;

  298.     if (ntohs(tcphdr->th_dport) == __tcp_scanner_port)
  299.     {
  300.         if (tcphdr->th_flags & (TH_SYN | TH_RST) &&
  301.             tcphdr->th_flags & TH_ACK &&
  302.             ntohl(tcphdr->th_ack) == __tcp_header_seq + 1)
  303.         {
  304.             if (tcphdr->th_flags & TH_SYN)
  305.             {
  306.                 /* Be a polite scanner! */
  307.                 __tcp_rst(sockfd, __tcp_scanner_port,
  308.                           ntohs(tcphdr->th_sport),
  309.                           daddr, saddr, addrlen);
  310.             }

  311.             if (!(entry = __rb_insert_sockaddr(saddr, addrlen, root)))
  312.             {
  313.                 state = tcphdr->th_flags & TH_SYN ? TS_ACCEPTED : TS_REFUSED;
  314.                 if (__info(saddr, addrlen, state, __arg) < 0)
  315.                     return -1;
  316.             }
  317.             else if (entry == (struct __sockaddr_rb *)-1)
  318.                 return -1;
  319.         }
  320.     }

  321.     return 0;
  322. }

  323. static int __recv_tcp_packet(int sockfd, struct rb_root *root)
  324. {
  325.     /* We do not care the TCP options or TCP data, so the buffer size is the
  326.        biggest IPv4 header size, which is bigger than IPv6 header size, plus
  327.        TCP header size. */
  328.     #define __BUFSIZE   ((0xf << 2) + sizeof (struct tcphdr))
  329.     char buf[__BUFSIZE];
  330.     struct ip *iphdr = (struct ip *)buf;
  331. #ifdef IPV6
  332.     struct ip6_hdr *ip6hdr = (struct ip6_hdr *)buf;
  333. #endif
  334.     struct tcphdr *tcphdr;
  335.     union __sa_union un;
  336.     socklen_t addrlen;
  337.     ssize_t n;

  338.     while (addrlen = sizeof (union __sa_union), (n = recvfrom(sockfd, buf,
  339.                             __BUFSIZE, 0, &un.sockaddr, &addrlen)) >= 0)
  340.     {
  341.         if (un.sockaddr.sa_family == AF_INET)
  342.         {
  343.             /* Make sure that it is a valid TCP packet. */
  344.             if (n >= sizeof (struct ip) && iphdr->ip_p == IPPROTO_TCP &&
  345.                 n >= (iphdr->ip_hl << 2) + sizeof (struct tcphdr))
  346.             {
  347.                 tcphdr = (struct tcphdr *)(buf + (iphdr->ip_hl << 2));
  348.                 un.sin.sin_port = tcphdr->th_sport;
  349.                 if (__proc_tcp_packet(sockfd, tcphdr, &iphdr->ip_dst,
  350.                                       &un.sockaddr, addrlen, root) < 0)
  351.                     break;
  352.             }
  353.         }
  354. #ifdef IPV6
  355.         else if (un.sockaddr.sa_family == AF_INET6)
  356.         {
  357.             if (n >= sizeof (struct ip6_hdr) + sizeof (struct tcphdr) &&
  358.                 ip6hdr->ip6_nxt == IPPROTO_TCP)
  359.             {
  360.                 tcphdr = (struct tcphdr *)(ip6hdr + 1);
  361.                 un.sin6.sin6_port = tcphdr->th_sport;
  362.                 if (__proc_tcp_packet(sockfd, tcphdr, &ip6hdr->ip6_dst,
  363.                                       &un.sockaddr, addrlen, root) < 0)
  364.                     break;
  365.             }
  366.         }
  367. #endif
  368.     }

  369.     #undef __BUFSIZE
  370.     return n < 0 && errno == EAGAIN ? 0 : -1;
  371. }

  372. static int __proc_icmp_packet(const struct icmp *icmp, size_t icmplen,
  373.                               struct sockaddr *saddr, socklen_t addrlen,
  374.                               struct rb_root *root)
  375. {
  376.     struct __sockaddr_rb *entry;
  377.     const struct ip *iphdr;
  378.     const struct tcphdr *tcphdr;

  379.     /* We care only ICMP unreach packet. */
  380.     if (icmp->icmp_type == ICMP_UNREACH)
  381.     {
  382.     /*  if (icmplen >= sizeof (struct icmp) + sizeof (struct ip))   */
  383.         if (icmplen >= offsetof(struct icmp, icmp_data) + sizeof (struct ip))
  384.         {
  385.             iphdr = (const struct ip *)icmp->icmp_data;
  386.             if (icmplen >= offsetof(struct icmp, icmp_data) +
  387.                            (iphdr->ip_hl << 2) + 8)
  388.             {
  389.                 tcphdr = (const struct tcphdr *)((const char *)iphdr +
  390.                                                  (iphdr->ip_hl << 2));
  391.                 if (ntohs(tcphdr->th_sport) == __tcp_scanner_port &&
  392.                     ntohl(tcphdr->th_seq) == __tcp_header_seq)
  393.                 {
  394.                     ((struct sockaddr_in *)saddr)->sin_port = tcphdr->th_dport;
  395.                     if (!(entry = __rb_insert_sockaddr(saddr, addrlen, root)))
  396.                     {
  397.                         if (__info(saddr, addrlen, TS_UNREACH, __arg) < 0)
  398.                             return -1;
  399.                     }
  400.                     else if (entry == (struct __sockaddr_rb *)-1)
  401.                         return -1;
  402.                 }
  403.             }
  404.         }
  405.     }

  406.     return 0;
  407. }

  408. #ifdef IPV6

  409. static int __proc_icmp6_packet(const struct icmp6_hdr *icmp6, size_t icmplen,
  410.                                struct sockaddr *saddr, socklen_t addrlen,
  411.                                struct rb_root *root)
  412. {
  413.     struct __sockaddr_rb *entry;
  414.     const struct ip6_hdr *ip6hdr;
  415.     const struct tcphdr *tcphdr;

  416.     if (icmp6->icmp6_type == ICMP6_DST_UNREACH)
  417.     {
  418.         if (icmplen >= sizeof (struct icmp6_hdr) + sizeof (struct ip6_hdr) + 8)
  419.         {
  420.             ip6hdr = (const struct ip6_hdr *)(icmp6 + 1);
  421.             tcphdr = (const struct tcphdr *)(ip6hdr + 1);
  422.             if (ntohs(tcphdr->th_sport) == __tcp_scanner_port &&
  423.                 ntohl(tcphdr->th_seq) == __tcp_header_seq)
  424.             {
  425.                 ((struct sockaddr_in6 *)saddr)->sin6_port = tcphdr->th_dport;
  426.                 if (!(entry = __rb_insert_sockaddr(saddr, addrlen, root)))
  427.                 {
  428.                     if (__info(saddr, addrlen, TS_UNREACH, __arg) < 0)
  429.                         return -1;
  430.                 }
  431.                 else if (entry == (struct __sockaddr_rb *)-1)
  432.                     return -1;
  433.             }
  434.         }
  435.     }

  436.     return 0;
  437. }

  438. #endif

  439. static int __recv_icmp_packet(int sockfd, struct rb_root *root)
  440. {
  441.     /* Biggest IPv4 header, ICMP header, the returned IP header with
  442.        8 bytes TCP header. */
  443.     #define __BUFSIZE \
  444.         ((0xf << 2) + offsetof(struct icmp, icmp_data) + (0xf << 2) + 8)
  445.     char buf[__BUFSIZE];
  446.     struct ip *iphdr = (struct ip *)buf;
  447. #ifdef IPV6
  448.     struct ip6_hdr *ip6hdr = (struct ip6_hdr *)buf;
  449. #endif
  450.     union __sa_union un;
  451.     socklen_t addrlen;
  452.     ssize_t n;

  453.     while (addrlen = sizeof (union __sa_union), (n = recvfrom(sockfd, buf,
  454.                             __BUFSIZE, 0, &un.sockaddr, &addrlen)) >= 0)
  455.     {
  456.         if (un.sockaddr.sa_family == AF_INET)
  457.         {
  458.             if (n >= sizeof (struct ip) && iphdr->ip_p == IPPROTO_ICMP &&
  459.                 n >= (iphdr->ip_hl << 2) + offsetof(struct icmp, icmp_data))
  460.             {
  461.                 struct icmp *icmp = (struct icmp *)(buf + (iphdr->ip_hl << 2));
  462.                 if (__proc_icmp_packet(icmp, n - (iphdr->ip_hl << 2),
  463.                                        &un.sockaddr, addrlen, root) < 0)
  464.                     break;
  465.             }
  466.         }
  467. #ifdef IPV6
  468.         else if (un.sockaddr.sa_family == AF_INET6)
  469.         {
  470.             if (n >= sizeof (struct ip6_hdr) + sizeof (struct icmp6_hdr) &&
  471.                 ip6hdr->ip6_nxt == IPPROTO_ICMPV6)
  472.             {
  473.                 struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)(ip6hdr + 1);
  474.                 if (__proc_icmp6_packet(icmp6, n - sizeof (struct ip6_hdr),
  475.                                         &un.sockaddr, addrlen, root) < 0)
  476.                     break;
  477.             }
  478.         }
  479. #endif
  480.     }

  481.     #undef __BUFSIZE
  482.     return n < 0 && errno == EAGAIN ? 0 : -1;
  483. }

  484. inline static int
  485. #ifdef IPV6
  486. __scan_ip_seg(const struct in_addr *address, unsigned int bits,
  487.               unsigned short port, int tcpsock, int icmpsock,
  488.               int tcpsock6, int icmpsock6, const struct in_addr *myaddr,
  489.               struct rb_root *root)
  490. #else
  491. __scan_ip_seg(const struct in_addr *address, unsigned int bits,
  492.               unsigned short port, int tcpsock, int icmpsock,
  493.               const struct in_addr *myaddr, struct rb_root *root)
  494. #endif
  495. {
  496.     unsigned int hostmax = 0;
  497.     unsigned int host;
  498.     struct sockaddr_in sin;
  499.     unsigned int bit = 1;

  500.     bzero(&sin, sizeof (struct sockaddr_in));
  501.     sin.sin_family = AF_INET;
  502.     for (host = 0; host < 32 - bits; host++)
  503.     {
  504.         hostmax |= bit;
  505.         bit <<= 1;
  506.     }

  507.     host = ntohl(address->s_addr) & ~hostmax;
  508.     hostmax |= ntohl(address->s_addr);
  509.     do
  510.     {
  511.         sin.sin_addr.s_addr = htonl(host);
  512.         if (!__rb_search_sockaddr((struct sockaddr *)&sin,
  513.                     sizeof (struct sockaddr_in), root))
  514.         {
  515.             __tcp_syn(tcpsock, __tcp_scanner_port, port,
  516.                       myaddr, (struct sockaddr *)&sin,
  517.                       sizeof (struct sockaddr_in));
  518.         }

  519.         if (__recv_tcp_packet(tcpsock, root) < 0)
  520.             return -1;
  521.         if (__recv_icmp_packet(icmpsock, root) < 0)
  522.             return -1;
  523. #ifdef IPV6
  524.         if (tcpsock6 >= 0)
  525.         {
  526.             if (__recv_tcp_packet(tcpsock6, root) < 0)
  527.                 return -1;
  528.             if (__recv_icmp_packet(icmpsock6, root) < 0)
  529.                 return -1;
  530.         }
  531. #endif
  532.     } while (host++ != hostmax);

  533.     return 0;
  534. }

  535. #ifdef IPV6

  536. inline static int
  537. __scan_ip6_seg(const struct in6_addr *address, unsigned int bits,
  538.                unsigned short port, int tcpsock, int icmpsock,
  539.                int tcpsock6, int icmpsock6, const struct in6_addr *myaddr,
  540.                struct rb_root *root)
  541. {
  542.     struct in6_addr hostmax;
  543.     struct in6_addr host;
  544.     struct sockaddr_in6 sin6;
  545.     unsigned char bit = 1;
  546.     int i, j;

  547.     bzero(&hostmax, sizeof (struct in6_addr));
  548.     for (i = 15; i > bits >> 3; i--)
  549.         hostmax.s6_addr[i] = 0xff;

  550.     for (j = 0; j < (128 - bits) & 7; j++)
  551.     {
  552.         hostmax.s6_addr[i] |= bit;
  553.         bit <<= 1;
  554.     }

  555.     for (i = 0; i < 4; i++)
  556.     {
  557.         host.s6_addr32[i] = address->s6_addr32[i] & ~hostmax.s6_addr32[i];
  558.         hostmax.s6_addr32[i] |= address->s6_addr32[i];
  559.     }

  560.     bzero(&sin6, sizeof (struct sockaddr_in6));
  561.     sin6.sin6_family = AF_INET6;
  562.     while (1)
  563.     {
  564.         sin6.sin6_addr = host;
  565.         if (!__rb_search_sockaddr((struct sockaddr *)&sin6,
  566.                     sizeof (struct sockaddr_in6), root))
  567.         {
  568.             __tcp_syn(tcpsock, __tcp_scanner_port, port,
  569.                       myaddr, (struct sockaddr *)&sin6,
  570.                       sizeof (struct sockaddr_in6));
  571.         }

  572.         if (tcpsock >= 0)
  573.         {
  574.             if (__recv_tcp_packet(tcpsock, root) < 0)
  575.                 return -1;
  576.             if (__recv_icmp_packet(icmpsock, root) < 0)
  577.                 return -1;
  578.         }

  579.         if (__recv_tcp_packet(tcpsock6, root) < 0)
  580.             return -1;
  581.         if (__recv_icmp_packet(icmpsock6, root) < 0)
  582.             return -1;

  583.         if (IN6_ARE_ADDR_EQUAL(&host, &hostmax))
  584.             break;
  585.         IN6_ADDR_NEXT(&host);
  586.     }

  587.     return 0;
  588. }

  589. #endif

  590. #ifdef IPV6
  591. static int __wait_response(int tcpsock, int icmpsock, int tcpsock6,
  592.                            int icmpsock6, struct rb_root *root)
  593. #else
  594. static int __wait_response(int tcpsock, int icmpsock, struct rb_root *root)
  595. #endif
  596. {
  597.     fd_set all, rset;
  598.     struct timeval timeout = {
  599.         tv_sec      :   __max_seg_lifetime << 1,
  600.         tv_usec     :   0
  601.     };
  602.     int maxfd = -1;
  603.     int n;

  604.     #define __max(x, y)     ((x) > (y) ? (x) : (y))
  605.     if (tcpsock >= 0)
  606.     {
  607.         FD_SET(tcpsock, &all);
  608.         FD_SET(icmpsock, &all);
  609.         maxfd = __max(tcpsock, icmpsock);
  610.     }
  611. #ifdef IPV6
  612.     if (tcpsock6 >= 0)
  613.     {
  614.         FD_SET(tcpsock6, &all);
  615.         FD_SET(icmpsock6, &all);
  616.         maxfd = __max(maxfd, __max(tcpsock6, icmpsock6));
  617.     }
  618. #endif
  619.     #undef __max

  620.     /* Wait at least 2*MSL for all IP segments to expire. */
  621.     while (rset = all, (n = select(maxfd + 1, &rset, NULL, NULL,
  622.                                    &timeout)) > 0)
  623.     {
  624.         if (tcpsock >= 0)
  625.         {
  626.             if (FD_ISSET(tcpsock, &rset))
  627.             {
  628.                 if (__recv_tcp_packet(tcpsock, root) < 0)
  629.                     return -1;
  630.             }
  631.             if (FD_ISSET(icmpsock, &rset))
  632.             {
  633.                 if (__recv_icmp_packet(icmpsock, root) < 0)
  634.                     return -1;
  635.             }
  636.         }
  637. #ifdef IPV6
  638.         if (tcpsock6 >= 0)
  639.         {
  640.             if (FD_ISSET(tcpsock6, &rset))
  641.             {
  642.                 if (__recv_tcp_packet(tcpsock6, root) < 0)
  643.                     return -1;
  644.             }
  645.             if (FD_ISSET(icmpsock6, &rset))
  646.             {
  647.                 if (__recv_icmp_packet(icmpsock6, root) < 0)
  648.                     return -1;
  649.             }
  650.         }
  651. #endif
  652.     }

  653.     return n;
  654. }

  655. int tcp_scan(const struct addrseg *scope, const unsigned short *ports,
  656.              unsigned int ifindex, const char *ifname, int resetuid,
  657.              scan_info_t info, void *arg)
  658. {
  659.     const struct addrseg *p;
  660.     const short *port;
  661.     int tcpsock = -1, icmpsock = -1;
  662.     struct in_addr ipaddr;
  663. #ifdef IPV6
  664.     int tcpsock6 = -1, icmpsock6 = -1;
  665.     struct in6_addr ip6addr;
  666. #endif
  667.     union __sa_union un;
  668.     int i, ret = -1;
  669.     struct rb_root root = RB_ROOT;

  670.     for (p = scope; p; p = p->as_next)
  671.     {
  672.         switch (p->as_family)
  673.         {
  674.         case AF_INET:
  675.             tcpsock = -2;
  676.             break;
  677. #ifdef IPV6
  678.         case AF_INET6:
  679.             tcpsock6 = -2;
  680.             break;
  681. #endif
  682.         default:
  683.             errno = EAFNOSUPPORT;
  684.             return -1;
  685.         }
  686.     }

  687.     if (tcpsock == -2)
  688.     {
  689.         if (getifaddr(AF_INET, ifindex, ifname, &ipaddr) < 0)
  690.             goto error;
  691.         if ((tcpsock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0)
  692.             goto error;
  693.         if ((icmpsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
  694.             goto error;
  695.         bzero(&un.sin, sizeof (struct sockaddr_in));
  696.         un.sin.sin_family = AF_INET;
  697.         un.sin.sin_addr = ipaddr;
  698.         if (bind(tcpsock, &un.sockaddr, sizeof (struct sockaddr_in)) < 0)
  699.             goto error;
  700.         if (bind(icmpsock, &un.sockaddr, sizeof (struct sockaddr_in)) < 0)
  701.             goto error;
  702.         if (SET_FD_NONBLOCK(tcpsock) < 0)
  703.             goto error;
  704.         if (SET_FD_NONBLOCK(icmpsock) < 0)
  705.             goto error;
  706.     }

  707. #ifdef IPV6
  708.     if (tcpsock6 == -2)
  709.     {
  710.         if (getifaddr(AF_INET6, ifindex, ifname, &ip6addr) < 0)
  711.             goto error;
  712.         if ((tcpsock6 = socket(AF_INET6, SOCK_RAW, IPPROTO_TCP)) < 0)
  713.             goto error;
  714.         if ((icmpsock6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
  715.             goto error;
  716.         bzero(&un.sin6, sizeof (struct sockaddr_in6));
  717.         un.sin6.sin6_family = AF_INET6;
  718.         un.sin6.sin6_addr = ip6addr;
  719.         if (bind(tcpsock6, &un.sockaddr, sizeof (struct sockaddr_in6)) < 0)
  720.             goto error;
  721.         if (bind(icmpsock6, &un.sockaddr, sizeof (struct sockaddr_in6)) < 0)
  722.             goto error;
  723.         if (SET_FD_NONBLOCK(tcpsock6) < 0)
  724.             goto error;
  725.         if (SET_FD_NONBLOCK(icmpsock6) < 0)
  726.             goto error;
  727.     }
  728. #endif

  729.     /* We no longer need root privilege. */
  730.     if (resetuid)
  731.         setuid(getuid());

  732.     /* Generate a random TCP sequance. */
  733.     srand(time(NULL));
  734.     __tcp_header_seq = rand();

  735.     __info = info;
  736.     __arg = arg;
  737.     for (i = 0; i < __tcp_scan_repeats; i++)
  738.     {
  739.         for (port = ports; *port; port++)
  740.         {
  741.             for (p = scope; p; p = p->as_next)
  742.             {
  743.                 if (p->as_family == AF_INET)
  744.                 {
  745. #ifdef IPV6
  746.                     if (__scan_ip_seg(p->as_address, p->as_bits, *port,
  747.                                       tcpsock, icmpsock, tcpsock6,
  748.                                       icmpsock6, &ipaddr, &root) < 0)
  749.                         goto error;
  750. #else
  751.                     if (__scan_ip_seg(p->as_address, p->as_bits,
  752.                                       *port, tcpsock, icmpsock,
  753.                                       &ipaddr, &root) < 0)
  754.                         goto error;
  755. #endif
  756.                 }
  757. #ifdef IPV6
  758.                 else /* if (p->as_family == AF_INET6) */
  759.                 {
  760.                     if (__scan_ip6_seg(p->as_address, p->as_bits, *port,
  761.                                        tcpsock, icmpsock, tcpsock6,
  762.                                        icmpsock6, &ip6addr, &root) < 0)
  763.                         goto error;
  764.                 }
  765. #endif
  766.             }
  767.         }
  768.     }

  769. #ifdef IPV6
  770.     if (__wait_response(tcpsock, icmpsock, tcpsock6, icmpsock6, &root) >= 0)
  771.         ret = 0;
  772. #else
  773.     if (__wait_response(tcpsock, icmpsock, &root) >= 0)
  774.         ret = 0;
  775. #endif

  776. error:
  777.     __rb_destroy_sockaddr(&root);
  778.     if (tcpsock >= 0)
  779.         close(tcpsock);
  780.     if (icmpsock >= 0)
  781.         close(icmpsock);
  782. #ifdef IPV6
  783.     if (tcpsock6 >= 0)
  784.         close(tcpsock6);
  785.     if (icmpsock6 >= 0)
  786.         close(icmpsock6);
  787. #endif

  788.     return ret;
  789. }

复制代码
发表于 2005-5-6 08:38:17 | 显示全部楼层
继续贴全呀,兄弟,这是很好参考资料。
回复 支持 反对

使用道具 举报

发表于 2005-5-6 09:26:48 | 显示全部楼层
不错,不过兄台的函数命名方法,看的不习惯啊!
回复 支持 反对

使用道具 举报

发表于 2005-5-6 10:16:07 | 显示全部楼层
下划线开头是一般是定义库函数中的符号。他这个程序应该是以库的形式来使用的。
回复 支持 反对

使用道具 举报

发表于 2005-5-6 11:30:22 | 显示全部楼层
关注!!!
回复 支持 反对

使用道具 举报

发表于 2005-5-6 14:18:53 | 显示全部楼层
继续贴啊!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-5-6 17:03:35 | 显示全部楼层
大家这么关注,继续写。要把整个东西解释清楚挺难的,先从接口开始。当时的需求是,给定一个IP地址范围,要以最快的速度发现存在ftp服务的地址。因为ftp服务一般都是使用21端口,所以想到的使用的方法就是检测21端口是否可连接。想了很久,接口的设计如下:
int tcp_scan(const struct addrseg *addrscope, const unsigned short *ports,
             unsigned int ifindex, const char *ifname, int resetuid,
             scan_info_t info, void *arg);
只有一个函数,而且没有使用面向对象的设计方法。解释一下各个参数的意义:

const struct addrseg *addrscope: 要扫描的地址范围,是一个结点类型为struct addrseg的链表,每个结点为一个IP地址段。struct addrseg的定义如下:
struct addrseg
{
    int as_family;
    void *as_address;
    unsigned int as_bits;
    struct addrseg *as_next;
};
其中,as_family表示这个地址段的类型,可以是AF_INET或AF_INET6,分别表示IPv4地址和IPv6地址;as_address指向一个struct in_addr结构(IPv4)或struct in6_addr结构(IPV6)。as_bits指明as_address的有效位数,有效位数越少,则这个地址段越大。例如,地址段162.105.*.*,其地址有效位为16位;如果一个地址段只包含一个地址,如162.105.80.1,则其地址有效位为32位。as_next指向下一个地址段,若as_next == NULL则表示链表结束。

const unsigned short *ports:要扫描的一组端口。也就是一个unsigned short型的数组,以0作为结束。

unsigned int ifindex,const char *ifname:指定一个网络设备作为出口。这两个参数本来不应该存在,但我为了省过内部检查路由表麻烦,让函数调用者指定一个网络设备,以这个设备的地址作为每个包的源地址(这个源地址只用于计算TCP校验和)。这样做的好处是加快了扫描速度,缺点是对于多网卡的机器只能使用其中一块网卡。当ifindex不为0,使用ifindex,ifname参数被乎略。当ifindex为0时,使用ifname。

int resetuid:因为函数要打开一个raw socket,因此运行的时候需要root权限。这个参数表示,是否在打开了raw socket之后把进程的有效权限置为实际用户权限,也就是说,是否调用setuid(getuid())。

scan_info_t info,void *arg:回调函数,用于通知道调用者有响应的IP地址。在tcp_scan.h中有如下定义:
typedef int (*scan_info_t)(const struct sockaddr *, socklen_t, int, void *);
前两上参数const struct sockaddr *和socklen_t指明一个有响应的地址。每三个参数int表示响应的状态,可能为TS_ACCEPTED,TS_REFUSED或TS_UNREACH,分别表示该地址可连接,拒绝连接和不可达。最后一个参数void *为用户自定义参数,直接由tcp_scan的最后一个参数void *arg传到回调函数。

tcp_scan返回非负值表示成功,返回负值表示失败,错误原因保存在errno中。当回调函数返回负值,tcp_scan以失败返回。

下面一个简单例子,用于发现162.105.*.*和166.111.*.*里的所有http服务和ftp服务,并且把地址打印出来:


  1. static int __print_result(const struct sockaddr *sockaddr, socklen_t addrlen,
  2.                           int state, void *arg)
  3. {
  4.     struct sockaddr_in *sin = (struct sockaddr_in *)sockaddr;
  5.     char addrstr[INET_ADDRSTRLEN + 1];
  6.     unsigned short port = ntohs(sin->sin_port);
  7.     const char *state_str;

  8.     inet_ntop(sockaddr->sin_family, sockaddr->sin_addr, addrstr,
  9.               INET_ADDRSTRLEN + 1);
  10.     switch (state)
  11.     {
  12.     case TS_ACCEPTED:
  13.         state_str = "Connection accepted.";
  14.         break;
  15.     case TS_REFUSED:
  16.         state_str = "Connection refused.";
  17.         break;
  18.     case TS_UNREACH:
  19.         state_str = "Destination unreachable.";
  20.         break;
  21.     default:
  22.         state_str = "Unknown state.";
  23.         break;
  24.     }

  25.     printf("%s %u:%s\n", addrstr, port, state_str);
  26.     return 0;
  27. }

  28. int main(void)
  29. {
  30.     struct addrseg addrseg[2];
  31.     struct in_addr in_addr[2];
  32.     unsigned short ports[] = { 80, 21, 0 };

  33.     inet_pton(AF_INET, "162.105.0.0", in_addr);
  34.     inet_pton(AF_INET, "166.111.0.0", in_addr + 1);

  35.     addrseg[0].as_family = AF_INET;
  36.     addrseg[0].as_addr = in_addr;
  37.     addrseg[0].as_bits = 16;
  38.     addrseg[0].as_next = addrseg + 1;

  39.     addrseg[1].as_family = AF_INET;
  40.     addrseg[1].as_addr = in_addr + 1;
  41.     addrseg[1].as_bits = 16;
  42.     addrseg[1].as_next = NULL;

  43.     return tcp_scan(addrseg, ports, 0, "eth0", 1,
  44.                     __print_result, NULL);
  45. }

复制代码


今天先说这些了,以前写过文档现在找不着了,连例子都是现写的。内部实现以后再讲。仔细看懂这个接口的设计,应该对提高编程水平很有帮助。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-5-6 18:02:37 | 显示全部楼层
关于我的代码风格问题,我一般所有的模块内部符号都以双下划线开头。以前编程的时候,只在一处被调用的函数无论多长都定义为inline,让编译器自行决定是否展开,现在想起来好像没有这个必要。
回复 支持 反对

使用道具 举报

发表于 2005-5-7 09:19:32 | 显示全部楼层
只在写driver的时候,这样写到,呵呵,不错,建议看这个的有点tcp/ip的基础啊!
回复 支持 反对

使用道具 举报

发表于 2006-9-18 11:35:51 | 显示全部楼层
楼主大虾!我是新手,但非常感兴趣,可否指导一下!谢谢!qq:254836615   email:zhanghx1977@163.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表