用户态协议栈的简单实现

零拷贝: 是指cpu指令没有参与

数据链路层里面传输的数字信号(0,1)

物理层是指光纤或者双绞线中传输的光信号或者电信号

网卡的作用:把光电信号转成数字信号(上行) 把数字信号转成光电信号(下行)

网络抓包的实现方式

raw_socket

netmap

dpdk

IP层数据包截图

首部长度代表的是IP数据报头部的长度,即图中固定部分的长度。

图中每行是32bits(即4字节),图中标识的固定部分总共有5行,所以IP首部最小是20个字节(5行*4字节每行=20字节)

首部长度是4bit,而2^4是16,所以它的取值范围是0-15(也可理解为4bit即是4个1,转换成十进制就是15),图中每行是4个字节(32bits),所以最大长度就是15*4=60字节。从中也就得知首部长度最小数字是5,即0101(因为IP首部最小是20字节)。

总长度总字是16bits,以字节为单位。所以总长度最大是65535个字节,也即是IP分组的最大长度。

柔性数组:

在 C90 之前, 并不支持0长度的数组, 0长度数组是 GNU C 的一个扩展, 因此早期的编译器中是无法通过编译的,0长度数组其实就是灵活的运用的数组指向的是其后面的连续的内存空间,所以 GNU 就对其进行了0长度数组的扩展. 当使用data[0]的时候, 也就是0长度数组的时候,0长度数组作为数组名, 并不占用存储空间.

在C99之后,也加了类似的扩展,只不过用的是 char payload[]这种形式(所以如果你在编译的时候确实需要用到-pedantic参数,那么你可以将char payload[0]类型改成char payload[], 这样就可以编译通过了,当然你的编译器必须支持C99标准的,如果太古老的编译器,那可能不支持了

对于 GNU C 增加的扩展, GCC 提供了编译选项来明确的标识出他们

1、-pedantic 选项,那么使用了扩展语法的地方将产生相应的警告信息

2、-Wall 使用它能够使GCC产生尽可能多的警告信息

3、-Werror, 它要求GCC将所有的警告当成错误进行处理

位域与大小端:

大端: 按照给出的顺序来写 

netmap:

代码:

#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#include <sys/poll.h>
#include <arpa/inet.h>


#define NETMAP_WITH_LIBS

#include <net/netmap_user.h> 
#pragma pack(1)  
//1zijieduiqi

#define ETH_LENGTH 6
#define PROTO_IP   0x0800
#define PROTO_ARP  0x0806
#define PROTO_UDP  17
#define PROTO_ICMP 1
#define PROTO_IGMP 2

struct ethhdr
{
    unsigned char h_dst[ETH_LENGTH];
    unsigned char h_src[ETH_LENGTH];
    unsigned short h_proto;
};   //sizeof 14

struct iphdr
{
    unsigned char  hdrlen:4,
                   version:4;
    unsigned char  tos;
    unsigned short totlen;
    unsigned short id;
    unsigned short flag_offset;
    unsigned char  ttl;  //time to live
    unsigned char  protocol;
    unsigned short check;
    unsigned int   saddr;
    unsigned int   daddr;
};   //sizeof  20

struct udphdr
{
    unsigned short source;
    unsigned short dest;
    unsigned short len;
    unsigned short check;
}; //sizeof  8

struct udppkt
{
    struct ethhdr eh;
    struct iphdr  ip;
    struct udphdr udp;
    unsigned char body[0]; //柔性数组,占位符.
};

struct arphdr
{
    unsigned short h_type;
    unsigned short h_proto;

    unsigned char h_addrlen;
    unsigned char h_protolen;

    unsigned short oper;
    unsigned char smac[ETH_LENGTH];
    unsigned int sip;
    unsigned char dmac[ETH_LENGTH];
    unsigned int dip;
};

struct arppkt
{
    struct ethhdr eh;
    struct arphdr arp;
};

struct icmphdr {
	unsigned char type;
	unsigned char code;
	unsigned short check;
	unsigned short identifier;
	unsigned short seq;
	unsigned char data[32];
};

struct icmppkt {
	struct ethhdr eh;
	struct iphdr ip;
	struct icmphdr icmp;
};

void print_mac(unsigned char *mac) 
{
	int i = 0;
	for (i = 0;i < ETH_LENGTH-1;i ++) 
    {
		printf("%02x:", mac[i]);
	}
	printf("%02x", mac[i]);
}

void print_ip(unsigned char *ip) 
{
	int i = 0;

	for (i = 0;i < 3;i ++) 
    {
		printf("%d.", ip[i]);
	}
	printf("%d", ip[i]);
}


void print_arp(struct arppkt *arp) 
{
	print_mac(arp->eh.h_dst);
	printf(" ");

	print_mac(arp->eh.h_src);
	printf(" ");

	printf("0x%04x ", ntohs(arp->eh.h_proto));
	printf("  ");
	
}

int str2mac(char *mac, char *str) 
{
	char *p = str;
	unsigned char value = 0x0;
	int i = 0;

	while (*p != '\0') 
    {
		if (*p == ':') 
        {
			mac[i++] = value;
			value = 0x0;
		} 
        else 
        {
			unsigned char temp = *p;
			if (temp <= '9' && temp >= '0') 
            {
				temp -= '0';
			} 
            else if (temp <= 'f' && temp >= 'a') 
            {
				temp -= 'a';
				temp += 10;
			} 
            else if (temp <= 'F' && temp >= 'A') 
            {
				temp -= 'A';
				temp += 10;
			} 
            else 
            {	
				break;
			}
			value <<= 4;
			value |= temp;
		}
		p ++;
	}
	mac[i] = value;
	return 0;
}

void echo_arp_pkt(struct arppkt *arp,struct arppkt *arp_rt, char *mac)
{
    memcpy(arp_rt,arp,sizeof(struct arppkt));
    memcpy(arp_rt->eh.h_dst, arp->eh.h_src, ETH_LENGTH);
    arp_rt->eh.h_proto = arp->eh.h_proto;

	arp_rt->arp.h_addrlen = 6;
	arp_rt->arp.h_protolen = 4;
	arp_rt->arp.oper = htons(2);
	
	str2mac(arp_rt->arp.smac, mac);
	arp_rt->arp.sip = arp->arp.dip;
	
	memcpy(arp_rt->arp.dmac, arp->arp.smac, ETH_LENGTH);
	arp_rt->arp.dip = arp->arp.sip;
}

void echo_udp_pkt(struct udppkt *udp, struct udppkt *udp_rt) 
{
	memcpy(udp_rt, udp, sizeof(struct udppkt));

	memcpy(udp_rt->eh.h_dst, udp->eh.h_src, ETH_LENGTH);
	memcpy(udp_rt->eh.h_src, udp->eh.h_dst, ETH_LENGTH);

	udp_rt->ip.saddr = udp->ip.daddr;
	udp_rt->ip.daddr = udp->ip.saddr;

	udp_rt->udp.source = udp->udp.dest;
	udp_rt->udp.dest = udp->udp.source;
}

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

	while (nleft > 1)  
    {
		sum += *w++;
		nleft -= 2;
	}

	if (nleft == 1) 
    {
		*(u_char *)(&answer) = *(u_char *)w ;
		sum += answer;
	}

	sum = (sum >> 16) + (sum & 0xffff);	
	sum += (sum >> 16);			
	answer = ~sum;
	
	return (answer);
}

void echo_icmp_pkt(struct icmppkt *icmp, struct icmppkt *icmp_rt) 
{
	memcpy(icmp_rt, icmp, sizeof(struct icmppkt));

	icmp_rt->icmp.type = 0x0; //
	icmp_rt->icmp.code = 0x0; //
	icmp_rt->icmp.check = 0x0;

	icmp_rt->ip.saddr = icmp->ip.daddr;
	icmp_rt->ip.daddr = icmp->ip.saddr;

	memcpy(icmp_rt->eh.h_dst, icmp->eh.h_src, ETH_LENGTH);
	memcpy(icmp_rt->eh.h_src, icmp->eh.h_dst, ETH_LENGTH);

	icmp_rt->icmp.check = in_cksum((unsigned short*)&icmp_rt->icmp, sizeof(struct icmphdr));
}

int main() 
{
	
	struct ethhdr *eh;
	struct pollfd pfd = {0};
	struct nm_pkthdr h;
	unsigned char *stream = NULL;

	struct nm_desc *nmr = nm_open("netmap:eth0", NULL, 0, NULL);
	if (nmr == NULL) 
    {
		return -1;
	}

	pfd.fd = nmr->fd;
	pfd.events = POLLIN;

	while (1) 
    {
		int ret = poll(&pfd, 1, -1);
		if (ret < 0) continue;
		
		if (pfd.revents & POLLIN) 
        {
			stream = nm_nextpkt(nmr, &h);
			eh = (struct ethhdr*)stream;

			if (ntohs(eh->h_proto) == PROTO_IP) 
            {
				struct udppkt *udp = (struct udppkt*)stream;
				if (udp->ip.protocol == PROTO_UDP) 
                {
					struct in_addr addr;
					addr.s_addr = udp->ip.saddr;

					int udp_length = ntohs(udp->udp.len);
					printf("%s:%d:length:%d, ip_len:%d --> ", inet_ntoa(addr), udp->udp.source, 
						udp_length, ntohs(udp->ip.totlen));

					udp->body[udp_length-8] = '\0';
					printf("udp --> %s\n", udp->body);
                    #if 1
					struct udppkt udp_rt;
					echo_udp_pkt(udp, &udp_rt);
					nm_inject(nmr, &udp_rt, sizeof(struct udppkt));
                    #endif
				} 
                else if (udp->ip.protocol == PROTO_ICMP) 
                {
					struct icmppkt *icmp = (struct icmppkt*)stream;
					printf("icmp ---------- --> %d, %x\n", icmp->icmp.type, icmp->icmp.check);
					if (icmp->icmp.type == 0x08) 
                    {
						struct icmppkt icmp_rt = {0};
						echo_icmp_pkt(icmp, &icmp_rt);

						//printf("icmp check %x\n", icmp_rt.icmp.check);
						nm_inject(nmr, &icmp_rt, sizeof(struct icmppkt));
					}
					
				} 
                else if (udp->ip.protocol == PROTO_IGMP) 
                {

				} 
                else 
                {
					printf("other ip packet");
				}
			}  
            else if (ntohs(eh->h_proto) == PROTO_ARP) 
            {
				struct arppkt *arp = (struct arppkt *)stream;
				struct arppkt arp_rt;

				if (arp->arp.dip == inet_addr("192.168.61.130")) 
                {
					echo_arp_pkt(arp, &arp_rt, "00:0c:29:30:ec:30");
					nm_inject(nmr, &arp_rt, sizeof(struct arppkt));
				}
			}
		} 
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值