零拷贝: 是指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));
}
}
}
}
}