测试环境:
操作系统: Microsoft Windows 2000 with Service Pack 4
开发环境: Microsoft Visual C++6 with Service Pack 6
其它: Winpcap 3.1 beta 3
代码
//tracer.c
//Copyright (c) 1999 - 2004
//S8S8.net Network Tech. Forum
//written by '13th Floor'
//All rights reserved.
#include <winsock2.h>
#include <ws2tcpip.h>
#include <cstring>
#include <queue>
using namespace std;
#include "pcap.h"
#include "headers.h"
#include "tracer.h"
char* FLT_EXPR = "ip and icmp[icmptype]=icmp-timxceed or tcp[tcpflags]=tcp-rst";
unsigned short checksum(unsigned short *buffer, int size)
{
unsigned long cksum = 0;
while(size > 1) {
cksum += *buffer++;
size -= sizeof(unsigned short);
}
if(size)
cksum += *(unsigned char*)buffer;
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >> 16);
return (unsigned short)(~cksum);
}
int build_packets(
unsigned long local_addr,
unsigned long dst_addr,
char* buf,
unsigned char TTL)
{
static unsigned long SEQ = 0x2344512;
int datasize =0;
IP_HDR ip_header;
TCP_HDR tcp_header;
PSD_HDR psd_header;
ip_header.h_verlen =
(4 << 4 | sizeof(ip_header) / sizeof(unsigned long));
ip_header.total_len = htons(sizeof(IP_HDR) + sizeof(TCP_HDR));
ip_header.ident = 1;
ip_header.frag_and_flags = 0;
ip_header.ttl = TTL;
ip_header.proto = IPPROTO_TCP;
ip_header.checksum = 0;
ip_header.saddr = local_addr;
ip_header.daddr = dst_addr;
tcp_header.th_sport = htons(7000);
tcp_header.th_dport = htons(5000);
tcp_header.th_seq = SEQ++;
tcp_header.th_ack = 0;
tcp_header.th_lenres = (sizeof(TCP_HDR) / 4 << 4 | 0);
tcp_header.th_flag = 16;
tcp_header.th_win = htons(16384);
tcp_header.th_urp = 0;
tcp_header.th_sum = 0;
psd_header.saddr = ip_header.saddr;
psd_header.daddr = ip_header.daddr;
psd_header.mbz = 0;
psd_header.proto = IPPROTO_TCP;
psd_header.tcpl = htons(sizeof(tcp_header));
memcpy(buf, &psd_header, sizeof(psd_header));
memcpy(buf + sizeof(psd_header), &tcp_header, sizeof(tcp_header));
tcp_header.th_sum = checksum((unsigned short *)buf,
sizeof(psd_header) + sizeof(tcp_header));
memcpy(buf, &ip_header, sizeof(ip_header));
memcpy(buf + sizeof(ip_header), &tcp_header, sizeof(tcp_header));
memset(buf + sizeof(ip_header) + sizeof(tcp_header), 0, 4);
datasize = sizeof(ip_header) + sizeof(tcp_header);
ip_header.checksum = checksum((unsigned short*)buf,datasize);
memcpy(buf, &ip_header, sizeof(ip_header));
return 0;
}
int start_trace(
queue<unsigned long>& dst_addr_queue,
unsigned long local_addr,
SOCKET& socket)
{
char snd_buf[128];
int ret;
sockaddr_in dst_addr;
pcap_t* adhandle;
struct pcap_pkthdr *header;
const u_char *pkt_data;
//Setup for winpcap
pcap_if_t *alldevs, *d;
char errbuf[PCAP_ERRBUF_SIZE];
unsigned int netmask;
bpf_program fcode;
if (pcap_findalldevs(&alldevs, errbuf) == -1)
throw ("Error in pcap_findalldevs");
try {
d = alldevs->next;
if ((adhandle= pcap_open_live(
d->name, //adapter
65536,
1,
1000, //time out
errbuf))
== NULL)
throw ("Failed to open adapter!");
if(d->addresses != NULL)
netmask=((struct sockaddr_in *)
(d->addresses->netmask))
->sin_addr.S_un.S_addr;
else
netmask=0xffffff;
if(pcap_compile(adhandle,
&fcode,
FLT_EXPR,
1,
netmask) <0
)
throw ("Failed to compile the filter");
if(pcap_setfilter(adhandle, &fcode)<0) {
throw ("Error setting the filter");
}
}
catch (const char * error) {
pcap_freealldevs(alldevs);
throw (error);
}
pcap_freealldevs(alldevs);
//Setup for Winsock
WSADATA wsaData;
BOOL flag = TRUE;
int time_out = 2000;
socket = INVALID_SOCKET;
if (WSAStartup(MAKEWORD(2, 1), &wsaData) !=0)
throw ("WSAStartup() failed");
try {
socket = WSASocket(AF_INET, SOCK_RAW, IPPROTO_RAW,
NULL,0, WSA_FLAG_OVERLAPPED);
if (socket == INVALID_SOCKET)
throw ("WSASocket() failed");
if (setsockopt(socket, IPPROTO_IP, IP_HDRINCL,
(char*)&flag, sizeof(int)) == SOCKET_ERROR)
throw ("Failed to set IP_HDRINCL");
if (setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO,
(char*)&time_out, sizeof(time_out)) == SOCKET_ERROR)
throw ("Failed to set SO_SNDTIMEO");
}
catch(const char* error) {
if (socket != INVALID_SOCKET)
closesocket(socket);
WSACleanup();
throw error;
}
//Get local address
char name[255];
PHOSTENT hostinfo;
if (gethostname(name, sizeof(name))==0)
if ((hostinfo = gethostbyname(name)) !=NULL)
local_addr = (*(struct in_addr*)
*hostinfo->h_addr_list).s_addr;
//Start Trace
while (dst_addr_queue.empty() == false) {
unsigned long crt_addr = dst_addr_queue.front();
memset(&dst_addr, 0, sizeof(dst_addr));
dst_addr.sin_family = AF_INET;
dst_addr.sin_addr.s_addr = crt_addr;
printf("\n\nTracing: ");
printf("%s\n", inet_ntoa(*(in_addr*)&crt_addr));
for (unsigned char ttl = 1; ttl <= 30; ttl++) {
build_packets(local_addr, crt_addr, snd_buf, ttl);
ret = sendto(socket, snd_buf, sizeof(IP_HDR)+sizeof(TCP_HDR),
0, (sockaddr*)&dst_addr, sizeof(dst_addr));
ret = pcap_next_ex(adhandle, &header, &pkt_data);
if (ret == 0) {
printf("%s\n", "time out");
continue;
}
IP_HDR* iphdr = (IP_HDR*)(pkt_data + 14);
printf("%s\n", inet_ntoa(*(in_addr*)&(iphdr->saddr)));
if (iphdr->proto == IPPROTO_TCP) break;
}
dst_addr_queue.pop();
}
return 0;
}
//headers.h
//Copyright (c) 1999 - 2004
//S8S8.net Network Tech. Forum
//written by '13th Floor'
//All rights reserved.
#ifndef _HEADERS_H
#define _HEADERS_H
//IP Header
typedef struct _iphdr {
unsigned char h_verlen; //IP Version
unsigned char tos; //Type of Service; 8 bits
unsigned short total_len; //total length; 16 bits
unsigned short ident; //Identification; 16 bits
unsigned short frag_and_flags; //Flags
unsigned char ttl; //Time to live; 8 bits
unsigned char proto; //Protocol; 8 bits
unsigned short checksum; //Checksum; 16 bits
unsigned long saddr; //Source IP address; 32 bits
unsigned long daddr; //Destination IP address; 32 bits
} IP_HDR;
//PSD Header
typedef struct _psdhdr {
unsigned long saddr; //Source IP address; 32 bits
unsigned long daddr; //Destination IP address; 32 bits
unsigned char mbz; //padding
unsigned char proto; //Protocol; 8 bits
unsigned short tcpl; //TCP length; 16 bits
} PSD_HDR;
//TCP Header
typedef struct _tcphdr {
unsigned short th_sport; //Source port; 16 bits
unsigned short th_dport; //Destination port; 16 bits
unsigned long th_seq; //Sequence Number; 32 bits
unsigned long th_ack; //Acknowledgment Number; 32 bits
unsigned char th_lenres; //Data Offset / reserved
unsigned char th_flag; //ECN / Control Bits; 6 bits
unsigned short th_win; //Window; 16 bits
unsigned short th_sum; //Checksum; 16 bits
unsigned short th_urp; //Urgent Pointer; 16 bits
} TCP_HDR;
//ICMP Header
typedef struct _icmphdr {
unsigned char i_type; //ICMP Type; 8 bits
unsigned char i_code; //ICMP Code; 8 bits
unsigned short i_cksum; //ICMP header checksum; 16 bits
unsigned short i_id; //Identification; 16 bits
unsigned short i_seq; //Sequence Number; 16 bits
unsigned long timestamp; //Timestamp; 32 bits
} ICMP_HDR;
#endif