环境:ubuntu 8.04
需要用到的工具:libnet,libpcap,tcpdump
安装这些工具:sudo apt-get install libnet-dev libpcap-dev tcpdump
本程序在freebsd下测试没有通过。libnet发送包,libpcap接收包,很方便(特别是libpcap的过滤规则)。
先创建接收线程,再发送syn扫描数据包。如果采用单线程,先发送再接收,则收不到任何数据。
在用libnet和libpcap设置网络设备时,一定要是有“真实”ip的设备,即:用此ip能够与目标主机通信,在我的机器上是ppp0(我用的ADSL),用eth0则不行。
源代码
//编译: gcc synscan.c -o synscan -lnet -lpcap -lpthread
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LOCALPORT 55555
#define ETHERNET_LEN 14
#define SLEEP_TIME 1
#define TH_SYN 0x02
#define TH_ACK 0x10
//在我的机子上,网络设备必须设置为ppp0;如果为NULL,则libnet和libpcap会自动查找合适的网络设备
#ifdef __GUZHOU
# define DEVICE "ppp0"
#else
# define DEVICE NULL
#endif
#define RECV_IPPACKET_SIZE 40
static unsigned char recvbuf[RECV_IPPACKET_SIZE]; //接收缓存
#define TH_FLAG 33 //TCP标志位在recvbuf中的位置
struct syn_scanner
{
uint32_t dst_ip;
uint16_t dst_port;
};
static struct syn_scanner scanner;
static uint32_t gethostip(const char *name)
{
struct hostent *hostinfo = NULL;
uint32_t *addr = NULL;
hostinfo = gethostbyname(name);
if (!hostinfo)
return -1;
if (AF_INET != hostinfo->h_addrtype)
return -1;
addr = (uint32_t *) (hostinfo->h_addr_list[0]);
return *addr;
}
static uint32_t flag; //用于判断recvbuf是否为收到的分组
static void *recv_packet(void *arg)
{
flag = 0;
char *dev, errbuf[PCAP_ERRBUF_SIZE];
pcap_t *handle;
struct bpf_program fp;
bpf_u_int32 mask, net;
struct pcap_pkthdr header;
const unsigned char *packet;
char filter_exp[100] = "src host ";
char tmp[100] = " and src port ", t[10];
const struct syn_scanner *ss;
struct in_addr addr;
ss = (const struct syn_scanner *)arg;
if (NULL == ss)
{
fprintf(stderr, "arg is NULL/n");
return NULL;
}
dev = DEVICE;
if (NULL == dev)
{
dev = pcap_lookupdev(errbuf);
if (NULL == dev)
{
fprintf(stderr, "pcap_lookupdev() error/n");
return NULL;
}
}
printf("pcap Network interface: %s/n", dev);
if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1)
{
fprintf(stderr, "pcap_lookupnet() error/n");
return NULL;
}
handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
if (NULL == handle)
{
fprintf(stderr, "pcap_open_live() error/n");
return NULL;
}
addr.s_addr = ss->dst_ip;
strcat(filter_exp, inet_ntoa(addr));
sprintf(t, "%u", ss->dst_port);
strcat(tmp, t);
strcat(filter_exp, tmp);
printf("filter: %s/n", filter_exp); //打印过滤规则
if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1)
{
fprintf(stderr, "pcap_compiler() error/n");
return NULL;
}
if (pcap_setfilter(handle, &fp) == -1)
{
fprintf(stderr, "pcap_setfilter() error");
return NULL;
}
packet = pcap_next(handle, &header); //若没有分组传过来,则会阻塞
printf("Jacked a packet with length of [%d]/n", header.len);
//把收到的分组从ip头开始的ETHERNET_LEN存到recvbuf中
int i;
packet += ETHERNET_LEN;
for (i = 0; i < RECV_IPPACKET_SIZE; i++)
recvbuf[i] = packet[i];
flag = 1;
return NULL;
}
static int send_syn(const struct syn_scanner *ss)
{
uint32_t src_ip, dst_ip;
uint16_t dst_port;
libnet_t *l;
char errbuf[LIBNET_ERRBUF_SIZE];
pthread_t recv;
dst_ip = ss->dst_ip;
dst_port = ss->dst_port;
l = libnet_init(LIBNET_RAW4, DEVICE, errbuf);
if (NULL == l)
{
fprintf(stderr, "libnet_init() error/n");
return -1;
}
src_ip = libnet_get_ipaddr4(l);
if (-1 == src_ip || 0 == src_ip)
{
fprintf(stderr, "libent_get_ipaddr4() error/n");
return -1;
}
printf("dst ip: %s, port: %u/n", inet_ntoa(*(struct in_addr *)&dst_ip), dst_port);
printf("src ip: %s/n", inet_ntoa(*(struct in_addr *)&src_ip));
if (libnet_build_tcp(LOCALPORT, dst_port, 0, 0, TH_SYN, 0, 0, 0, LIBNET_TCP_H, NULL, 0, l, 0) == -1)
{
fprintf(stderr, "libnet_build_tcp() error/n");
return -1;
}
if (libnet_build_ipv4
(LIBNET_IPV4_H + LIBNET_TCP_H, 0, 242, 0, 64, IPPROTO_TCP, 0, src_ip, dst_ip, NULL, 0, l, 0) == -1)
{
fprintf(stderr, "libnet_build_ipv4() error/n");
return -1;
}
if (libnet_write(l) == -1)
{
fprintf(stderr, "libnet_write() error/n");
return -1;
}
libnet_destroy(l);
return 1;
}
//解析分组,这里我简单地打印分组的内容
static void parse_packet(const unsigned char *buf, const unsigned int len)
{
int i;
printf("The buffer is:/n");
for (i = 0; i < len; i++)
printf("%u ", buf[i]);
putchar('/n');
}
int main(int argc, char **argv)
{
pthread_t recv;
void *retval;
if (3 != argc)
{
fprintf(stderr, "Usage: %s dst_ip dst_port/n", argv[0]);
return -1;
}
scanner.dst_ip = gethostip(argv[1]);
sscanf(argv[2], "%u", &(scanner.dst_port));
if (scanner.dst_ip == -1)
{
fprintf(stderr, "gethostip() error/n");
return -1;
}
printf("Scanning.../n");
//创建接收线程
if (pthread_create(&recv, NULL, recv_packet, &scanner))
{
fprintf(stderr, "pthread_create() error/n");
return -1;
}
if (send_syn(&scanner) == -1)
{
fprintf(stderr, "send_syn() error/n");
return -1;
}
pthread_join(recv,&retval);
if ((recvbuf[TH_FLAG] & TH_SYN) && (recvbuf[TH_FLAG] & TH_ACK))
printf("%s: %s is opend/n", argv[1], argv[2]);
else
printf("%s: %s is closed/n", argv[1], argv[2]);
if (flag)
parse_packet(recvbuf, RECV_IPPACKET_SIZE);
return 0;
}