?? tcp_scan.c
字號:
/* * tcp_scan.c -- A large scale TCP ports scanner. * Created: Xie Han, net lab of Peking University. <e@pku.edu.cn> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* I like BSD style better. */#define _BSD_SOURCE#include <errno.h>#include <sys/types.h>#include <sys/time.h>#include <sys/select.h>#include <sys/socket.h>#include <netinet/in.h>#include <netinet/ip.h>#include <netinet/ip_icmp.h>#ifdef IPV6# include <netinet/ip6.h># include <netinet/icmp6.h>#endif#include <netinet/tcp.h>#include <arpa/inet.h>#include <time.h>#include <unistd.h>#include <fcntl.h>#include <stdlib.h>#include <string.h>#include <rbtree.h>#include <unp.h>#include "tcp_scan.h"#define TCP_SCANNER_PORT 12200#define TCP_SCAN_REPEATS 4#define MAX_SEG_LIFETIME 30#define SET_FD_NONBLOCK(fd) \({ \ int __flags = fcntl(fd, F_GETFL, 0); \ if (__flags >= 0) \ __flags = fcntl(fd, F_SETFL, __flags | O_NONBLOCK); \ __flags; \})#ifdef IPV6# define IN6_ADDR_NEXT(addr) \do { \ int i; \ for (i = 15; i >= 0; i--) \ { \ if (++(addr)->s6_addr[i] != 0) \ break; \ } \} while (0)#endif/* "sockaddr" structs arranged in a Red-Black tree. */struct __sockaddr_rb{ struct rb_node rb; socklen_t addrlen; struct sockaddr sockaddr;};/* Union of sockaddr. */union __sa_union{ struct sockaddr sockaddr; struct sockaddr_in sin;#ifdef IPV6 struct sockaddr_in6 sin6;#endif};/* IP pseudoheader of TCP or UDP. */struct __ip_pheader{ struct in_addr src; struct in_addr dst; unsigned char zero; unsigned char protocol; unsigned short len;};#ifdef IPV6struct __ip6_pheader{ struct in6_addr src; struct in6_addr dst; unsigned int len; unsigned short zero1; unsigned char zero2; unsigned char next;};#endif/* TCP header combined with IP pseudoheader. */struct __tcp_pheader{#ifdef IPV6 union { struct __ip6_pheader phdr6; struct { char __null__[sizeof (struct __ip6_pheader) - sizeof (struct __ip_pheader)]; struct __ip_pheader phdr; }; };#else struct __ip_pheader phdr;#endif struct tcphdr tcphdr;};unsigned short __tcp_scanner_port = TCP_SCANNER_PORT;int __tcp_scan_repeats = TCP_SCAN_REPEATS;int __max_seg_lifetime = MAX_SEG_LIFETIME;/* For the sake of simplicity. */static unsigned int __tcp_header_seq;static scan_info_t __info;static void *__arg;inline static void __make_tcp_ip_pheader(const struct in_addr *saddr, const struct in_addr *daddr, struct __ip_pheader *phdr){ phdr->src = *saddr; phdr->dst = *daddr; phdr->zero = 0; phdr->protocol = IPPROTO_TCP; phdr->len = htons(sizeof (struct tcphdr));}#ifdef IPV6inline static void __make_tcp_ip6_pheader(const struct in6_addr *saddr, const struct in6_addr *daddr, struct __ip6_pheader *phdr){ phdr->src = *saddr; phdr->dst = *daddr; phdr->len = htonl(sizeof (struct tcphdr)); phdr->zero1 = 0; phdr->zero2 = 0; phdr->next = IPPROTO_TCP;}#endif/* Send a TCP packet. (Without TCP options or TCP data.) */static int __tcp_send(int sockfd, struct __tcp_pheader *tcpphdr, const void *saddr, const struct sockaddr *daddr, socklen_t addrlen){ unsigned short *pfrom; int len; switch (daddr->sa_family) { case AF_INET: __make_tcp_ip_pheader((const struct in_addr *)saddr, &((const struct sockaddr_in *)daddr)-> sin_addr, &tcpphdr->phdr); pfrom = (unsigned short *)&tcpphdr->phdr; len = sizeof (struct __ip_pheader) + sizeof (struct tcphdr); break;#ifdef IPV6 case AF_INET6: __make_tcp_ip6_pheader((const struct in6_addr *)saddr, &((const struct sockaddr_in6 *)daddr)-> sin6_addr, &tcpphdr->phdr6); pfrom = (unsigned short *)&tcpphdr->phdr6; len = sizeof (struct __ip6_pheader) + sizeof (struct tcphdr); break;#endif default: errno = EAFNOSUPPORT; return -1; } tcpphdr->tcphdr.th_sum = 0; tcpphdr->tcphdr.th_sum = in_cksum(pfrom, len); return sendto(sockfd, &tcpphdr->tcphdr, sizeof (struct tcphdr), 0, daddr, addrlen);}/* Send a SYN packet to the remote server. */static int __tcp_syn(int sockfd, unsigned short sport, unsigned short dport, const void *saddr, const struct sockaddr *daddr, socklen_t addrlen){ struct __tcp_pheader tcpphdr = { tcphdr : { th_sport : htons(sport), th_dport : htons(dport), th_seq : htonl(__tcp_header_seq), th_ack : htonl(0), th_x2 : 0, th_off : sizeof (struct tcphdr) >> 2, th_flags : TH_SYN, th_win : htons(8192), th_urp : htons(0) } }; return __tcp_send(sockfd, &tcpphdr, saddr, daddr, addrlen);}/* Tell the remote server that connection is aborted. */static int __tcp_rst(int sockfd, unsigned short sport, unsigned short dport, const void *saddr, const struct sockaddr *daddr, socklen_t addrlen){ struct __tcp_pheader tcpphdr = { tcphdr : { th_sport : htons(sport), th_dport : htons(dport), th_seq : htonl(0), th_ack : htonl(0), th_x2 : 0, th_off : sizeof (struct tcphdr) >> 2, th_flags : TH_RST, th_win : htons(0), th_urp : htons(0) } }; return __tcp_send(sockfd, &tcpphdr, saddr, daddr, addrlen);}/* Search a sockaddr in a Red-Black tree. */static struct __sockaddr_rb *__rb_search_sockaddr(const struct sockaddr *sockaddr, socklen_t addrlen, const struct rb_root *root){ const struct rb_node *p = root->node; struct __sockaddr_rb *entry; int n; while (p) { entry = rb_entry(p, struct __sockaddr_rb, rb); if (addrlen < entry->addrlen) n = -1; else if (addrlen > entry->addrlen) n = 1; else if ((n = memcmp(sockaddr, &entry->sockaddr, addrlen)) == 0) return entry; p = n < 0 ? p->left : p->right; } return NULL;}/* Insert a sockaddr into a Red-Black tree. */static struct __sockaddr_rb *__rb_insert_sockaddr(const struct sockaddr *sockaddr, socklen_t addrlen, struct rb_root *root){ struct rb_node **p = &root->node; struct rb_node *parent = NULL; struct __sockaddr_rb *entry; int n; while (*p) { parent = *p; entry = rb_entry(parent, struct __sockaddr_rb, rb); if (addrlen < entry->addrlen) n = -1; else if (addrlen > entry->addrlen) n = 1; else if ((n = memcmp(sockaddr, &entry->sockaddr, addrlen)) == 0) return entry; p = n < 0 ? &parent->left : &parent->right; } #define __SOCKADDR_RB_LEN \ (sizeof (struct __sockaddr_rb) - sizeof (struct sockaddr) + addrlen) if (entry = (struct __sockaddr_rb *)malloc(__SOCKADDR_RB_LEN)) { entry->addrlen = addrlen; memcpy(&entry->sockaddr, sockaddr, addrlen); rb_link_node(&entry->rb, parent, p); rb_insert_color(&entry->rb, root); return NULL; } #undef __SOCKADDR_RB_LEN return (struct __sockaddr_rb *)-1;}static void __rb_destroy_sockaddr(struct rb_root *root){ struct __sockaddr_rb *entry; while (root->node) { entry = rb_entry(root->node, struct __sockaddr_rb, rb); rb_erase(root->node, root); free(entry); }}static int __proc_tcp_packet(int sockfd, const struct tcphdr *tcphdr, const void *daddr, const struct sockaddr *saddr, socklen_t addrlen, struct rb_root *root){ struct __sockaddr_rb *entry; int state; if (ntohs(tcphdr->th_dport) == __tcp_scanner_port) { if (tcphdr->th_flags & (TH_SYN | TH_RST) && tcphdr->th_flags & TH_ACK && ntohl(tcphdr->th_ack) == __tcp_header_seq + 1) { if (tcphdr->th_flags & TH_SYN) { /* The connection is accepted. Abort it. */ __tcp_rst(sockfd, __tcp_scanner_port, ntohs(tcphdr->th_sport), daddr, saddr, addrlen); } if (!(entry = __rb_insert_sockaddr(saddr, addrlen, root))) { state = tcphdr->th_flags & TH_SYN ? TS_ACCEPTED : TS_REFUSED; if (__info(saddr, addrlen, state, __arg) < 0) return -1; } else if (entry == (struct __sockaddr_rb *)-1) return -1; } } return 0;}static int __recv_tcp_packet(int sockfd, struct rb_root *root){ /* We do not care the TCP options or TCP data, so the buffer size is the biggest IPv4 header size, which is bigger than IPv6 header size, plus TCP header size. */ #define __BUFSIZE ((0xf << 2) + sizeof (struct tcphdr)) char buf[__BUFSIZE]; struct ip *iphdr = (struct ip *)buf;#ifdef IPV6 struct ip6_hdr *ip6hdr = (struct ip6_hdr *)buf;#endif struct tcphdr *tcphdr; union __sa_union un; socklen_t addrlen; ssize_t n; while (addrlen = sizeof (union __sa_union), (n = recvfrom(sockfd, buf, __BUFSIZE, 0, &un.sockaddr, &addrlen)) >= 0) { if (un.sockaddr.sa_family == AF_INET) { /* Make sure that it is a valid TCP packet. */ if (n >= sizeof (struct ip) && iphdr->ip_p == IPPROTO_TCP && n >= (iphdr->ip_hl << 2) + sizeof (struct tcphdr)) { tcphdr = (struct tcphdr *)(buf + (iphdr->ip_hl << 2)); un.sin.sin_port = tcphdr->th_sport; if (__proc_tcp_packet(sockfd, tcphdr, &iphdr->ip_dst, &un.sockaddr, addrlen, root) < 0) break; } }#ifdef IPV6 else if (un.sockaddr.sa_family == AF_INET6) { if (n >= sizeof (struct ip6_hdr) + sizeof (struct tcphdr) && ip6hdr->ip6_nxt == IPPROTO_TCP) { tcphdr = (struct tcphdr *)(ip6hdr + 1); un.sin6.sin6_port = tcphdr->th_sport; if (__proc_tcp_packet(sockfd, tcphdr, &ip6hdr->ip6_dst, &un.sockaddr, addrlen, root) < 0) break; } }#endif } #undef __BUFSIZE return n < 0 && errno == EAGAIN ? 0 : -1;}static int __proc_icmp_packet(const struct icmp *icmp, size_t icmplen, struct sockaddr *saddr, socklen_t addrlen, struct rb_root *root){ struct __sockaddr_rb *entry; const struct ip *iphdr; const struct tcphdr *tcphdr; /* We care only ICMP unreach packet. */ #define __offset(type, member) ((size_t)&((type *)0)->member) if (icmp->icmp_type == ICMP_UNREACH) { /* if (icmplen >= sizeof (struct icmp) + sizeof (struct ip)) */ if (icmplen >= __offset(struct icmp, icmp_data) + sizeof (struct ip)) { iphdr = (const struct ip *)icmp->icmp_data; if (icmplen >= __offset(struct icmp, icmp_data) + (iphdr->ip_hl << 2) + 8) { tcphdr = (const struct tcphdr *)((const char *)iphdr + (iphdr->ip_hl << 2)); if (ntohs(tcphdr->th_sport) == __tcp_scanner_port && ntohl(tcphdr->th_seq) == __tcp_header_seq) { ((struct sockaddr_in *)saddr)->sin_port = tcphdr->th_dport; if (!(entry = __rb_insert_sockaddr(saddr, addrlen, root))) { if (__info(saddr, addrlen, TS_UNREACH, __arg) < 0) return -1; }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -