弄了两天,终于搞定了!把最简单的icmp报文发送实现了。本程序在Linux环境编写,使用原始套接字。
实现步骤:
1、得到protocol实体(protoent,声明于<netdb.h>);
2、初始化地址结构(sockaddr_in,声明于<netinet/in.h>);
3、创建套接字(socket(),声明于<sys/socket.h>,参数声明于<sys/types.h>);
4、更改socket选项,更改发送缓冲区大小(setsockopt(),声明于<sys/socket.h><sys/types.h>);
5、发送报文(sendto(),声明于<sys/types.h><sys/socket.h>);
6、关闭socket描述符(close(),声明于<unistd.h>);
代码:
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
typedef unsigned char byte;
typedef unsigned long ulong;
typedef unsigned short ushort;
const char* proto_name
="icmp";
const char* ip_str
="10.14.4.167";
# define SEND_BUFF1024
# define CK_NULL(___ent,___str) ({ \
if(___ent==NULL)printf(___str); \
})
# define PRT_ADDR_TEST(___addr) ({ \
printf("direction ip is:%d.%d.%d.%d\r\n", \
(___addr&0x000000ff), \
(___addr&0x0000ff00)>>8, \
(___addr&0x00ff0000)>>16, \
(___addr&0xff000000)>>24 \
); \
})
byte
send_buffer[SEND_BUFF];
// declare function
ushort
icmp_cal_cksum(byte*,int);
void
icmp_create(){
struct icmp* icmph=
(struct icmp*)send_buffer;
int pid,
i,
data_len;
pid=getuid();
data_len=SEND_BUFF-8; // send_length sub icmp header_length
icmph->icmp_type=ICMP_ECHO;
icmph->icmp_code=0;
icmph->icmp_cksum=0;
icmph->icmp_seq=0;
icmph->icmp_id=pid;
for(i=0;i<data_len;i++)
icmph->icmp_data[i]=i;
icmph->icmp_cksum=icmp_cal_cksum((byte*)icmph,data_len);
}
ushort
icmp_cal_cksum(byte* _data,int _data_len){
int sum=0;
int odd=_data_len&0x01;
ushort* value=(ushort*)_data;
while(_data_len & 0xfffe){
sum+=*(ushort*)_data;
_data+=2;
_data_len-=2;
}
if(odd){
ushort tmp=((*_data)<<8)&0xff00;
sum+=tmp;
}
sum=(sum>>16)+(sum&0xffff);
sum+=(sum>>16);
return ~sum;
}
int
main(int argc,char** argv){
// socket fd
int sockfd;
// return err code
int err_code;
// send data length
int snd_len;
// long addr
ulong addr_l;
// protocol entity
struct protoent* protocol;
// socket send buffer length
int send_buff=SEND_BUFF;
// protocol socket address
struct sockaddr_in dest_addr;
// get protocol entity
protocol=getprotobyname(proto_name);
CK_NULL(protocol,"error! cannot get protocol entity!!!\r\n");
// convert ip str to u_long
addr_l=inet_addr(ip_str);
if(addr_l==INADDR_NONE){
printf("error! cannot convert ip str to long addr!!!\r\n");
return -1;
}
addr_l=htonl(addr_l);
PRT_ADDR_TEST(addr_l);
// set memory 0
bzero((char*)&dest_addr,sizeof(dest_addr));
// full sockaddr_in struct
memcpy((char*)&dest_addr.sin_addr,&addr_l,sizeof(addr_l));
sockfd=socket(AF_INET,SOCK_RAW,protocol->p_proto);
if(sockfd<0){
printf("error!cannot create sockfd!\r\n");
return -1;
}
err_code=setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&send_buff,sizeof(send_buff));
icmp_create();
snd_len=sendto(sockfd,send_buffer,send_buff,0,(struct sockaddr*)&dest_addr,sizeof(dest_addr));
if(snd_len<send_buff){
printf("error!send data length is not enougth!\r\n");
return -1;
}
printf("data has sended length=%d\r\n",snd_len);
close(sockfd);
return 0;
}
注:创建原始套接字时应使用管理员权限,否则会创建失败!好像也有代码中获取权限的方法,但我没有去查相关资料。