Linux开发——原始套接字

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_25490573/article/details/102568759

基于原始套接字的协议

SOFP    ICMP    STCP MPLS    op-vpn     GRE  rip   ARR  DHCP   PPPOE   EIGRP   VPN

原始套接字内核实现

socket 

          sys_socketcall

                            call   SYS_SOCKET

原始套接字目标

1,直接操作各层数据

2,IP/ICMP/IGMP........协议的实现

3,网络诊断,测试程序(Poc漏洞利用工具)

原始套接字流程

创建

socket(AF_INER,SOCK_STREAM,IPPROTO_XXX);

socket(AF_INER,SOCK_RAW,IPPROTO_XXXX);

IPPROTO_XXXX:需要创建的协议类型

开启修改选项          开启可修改头选项,选择是否设置IP_HDRINCL

实现协议

套接字选项

获得系统管理员权限办法:sudo 运行程序 

setuid(getpid());

端口查看方法: netstat -aptn|grep 8080

setsockopt 设置选项值

int setsockopt(SOCKET s,int level,int optname,const char FAR * optval,int optlen);

getsockopt获取选项值

int getsockopt(SOCKET s,int levcl,int optname,char FAR*optval,int FAR *optlen);

协议组成

SYN洪水攻击程序

ICMP协议编程

静态协议:ip首部:20字节  + ICMP报文

ICMP 例子

#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "signal.h"
#include "arpa/inet.h"
#include "sys/types.h"
#include "sys/socket.h"
#include "unistd.h"
#include "netinet/in.h"
#include "netinet/ip.h"
#include "netinet/ip_icmp.h"
#include "netdb.h"
#include "setjmp.h"
#include "errno.h"
#include <sys/time.h>


#define PACKET_SIZE			4096
#define MAX_WAIT_TIME		5
#define MAX_NO_PACKETS		4
#define DATA_LEN			56

char sendpacket[PACKET_SIZE];
char recvpacket[PACKET_SIZE];

int nsend =0,nreceived = 0;
struct timeval tvrecv;

struct sockaddr_in from;

void statistics(int signo);
unsigned short cal_chksum(unsigned short *addr,int len);
int pack (int pack_no,int pid);
void send_packet(int sockfd,int pid,struct sockaddr_in dest_addr);
void recv_packet(int sockfd,int pid);
int unpack(char * buf,int len,int pid);
void tv_sub(struct timeval * out,struct timeval *in);

void statistics(int signo)
{
	printf("\n-----------------------------PING statistics--------------------------\n");
	printf("%d packets transmitted,%d received,%d lost\n",nsend,nreceived,(nsend-nreceived));

	exit(1);
}

unsigned short cal_chksum(unsigned short * addr,int len)
{
	int nleft = len;
	int sum = 0;
	unsigned short * w = addr;
	unsigned short answer = 0;

	while(nleft > 1)
	{
		sum+=*w++;
		nleft-=2;
	}
	if(nleft == 1)
	{
		*(unsigned char *)(&answer)= *(unsigned char *)w;
		sum+=answer;
	}
	sum = (sum>>16)+(sum&0xffff);
	sum+=(sum>>16);
	answer = ~sum;

	return answer;
}

int pack(int pack_no,int pid)
{
	int i,packsize;
	struct icmp * icmp;
	struct timeval * tval;

	icmp=(struct icmp *)sendpacket;
	icmp->icmp_type = ICMP_ECHO; //类型
	icmp->icmp_code = 0;         //代码
	icmp->icmp_cksum = 0;        //校验和
	icmp->icmp_seq = pack_no;    //序号,第几个包
	icmp->icmp_id = pid;         //进程号,因为icmp不绑定端口 所以需要制定进程
	packsize = 8+DATA_LEN;       //56指icmp头的大小  8指的数据区大小
	tval = (struct timeval *)icmp->icmp_data;

	gettimeofday(tval,NULL);

	icmp->icmp_cksum = cal_chksum((unsigned short *)icmp,packsize);//计算校验和
	return packsize;
}

void send_packet(int sockfd,int pid,struct sockaddr_in dest_addr)
{
	int packetsize;

	while(nsend<MAX_NO_PACKETS)
	{
		nsend++;
		packetsize = pack(nsend,pid);
		if(sendto(sockfd,sendpacket,packetsize,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr))==-1)
		{
			perror("sendto error");
			continue;
		}
		sleep(1);
	}
}

void recv_packet(int sockfd,int pid)
{
	int n,fromlen;
	extern int errno;
	signal(SIGALRM,statistics);
	fromlen = sizeof(from);
	while(nreceived<nsend)
	{
		alarm(MAX_WAIT_TIME);
		if((n = recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(struct sockaddr *)&from,&fromlen))==-1)
		{
			if(errno==EINTR)continue;
			perror("recvfrom error");
			continue;
		}
		gettimeofday(&tvrecv,NULL);
		if(unpack(recvpacket,n,pid)==-1)
			continue;
		nreceived++;
	}

}

int unpack(char * buf,int len,int pid)
{
	int i,iphdrlen;
	struct ip *ip;
	struct icmp *icmp;
	struct timeval * tvsend;
	double rtt;

	ip = (struct ip *)buf;
	iphdrlen = ip->ip_hl<<2;

	icmp = (struct icmp *)(buf + iphdrlen);
	len -= iphdrlen;
	if(len<8)
	{
		printf("ICMP  packets `s h_length is less than 8\n");
		return -1;
	}
	if((icmp->icmp_type==ICMP_ECHOREPLY)&&(icmp->icmp_id == pid))
	{
		tvsend = (struct timeval *)icmp->icmp_data;
		tv_sub(&tvrecv,tvsend);
		rtt = tvrecv.tv_sec*1000+tvrecv.tv_usec/1000;
		printf("%d byte from %s: icmp_seq=%d ttl=%d rtt=%.3f ms\n",len,inet_ntoa(from.sin_addr),nreceived,(len-sizeof(icmp->icmp_data)),rtt);	
	}
	else
		return -1;
}
void tv_sub(struct timeval*out ,struct timeval *in)
{
	if((out->tv_usec-=in->tv_usec)<0)
	{
		--out->tv_sec;
		out->tv_usec+=1000000;
	}
	out->tv_sec-=in->tv_sec;
}
int main(int argc, char const *argv[])
{
	int sockfd;
	struct sockaddr_in dest_addr;
	pid_t pid;
	struct hostent * host;
	struct protoent * protocol;
	unsigned long inaddr = 0l;
	int waittime = MAX_WAIT_TIME;
	int size = 50*1024;

	if(argc<2)
	{
		printf("usage:%s hostname/IP address\n",argv[0]);
		exit(1);
	}
	//获取icmp协议名字
	if((protocol = getprotobyname("icmp"))==NULL)
	{
		perror("getprotobyname");
		exit(1);
	}
	if((sockfd=socket(AF_INET,SOCK_RAW,protocol->p_proto))<0)
	{
		perror("socket error");
		exit(1);
	}

	setuid(getuid());
    //改变接受buf
    setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size));

    bzero(&dest_addr,sizeof(dest_addr));
    dest_addr.sin_family = AF_INET;

    //用gethostbyname 获得主机ip
    if (inaddr=inet_addr(argv[1])==INADDR_NONE)
    {
    	if((host=gethostbyname(argv[1]))==NULL)
    	{
    		perror("gethostbyname");
    		exit(1);
    	}
    	memcpy((char *)&(dest_addr.sin_addr),host->h_addr,host->h_length);
    }
    else
    	memcpy((char *)&(dest_addr.sin_addr),(char *)&inaddr,sizeof(inaddr));

    printf("PING %s(%s): %d bytes data in ICMP packets.\n",argv[1],inet_ntoa(dest_addr.sin_addr),MAX_NO_PACKETS);

    pid = getpid();

    send_packet(sockfd,pid,dest_addr);

    recv_packet(sockfd,pid);

    statistics(SIGALRM);

    close(sockfd);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_25490573/article/details/102568759