arp,udp,icmp编码实现理解

简介: arp,udp,icmp编码实现理解

一直关注tcp/ip的底层协议栈,终于有了大概的了解,通过ntytcp了解tcp相关的底层实现,发现除了tcp协议栈相关的东西,还有udp,arp,icmp(ping命令相关),以及通过netmap对网卡数据进行接收的相关基础知识点,幸好,听过king老师相关的课程,这里就简单的做一些整理。

1:概念介绍:

1:arp:地址解析协议(ip层/数据链路层)

维护了计算机ip和mac地址(物理地址)的对应关系。 (因为网络通信时实际传输的是“帧”,帧里面是有目标主机的MAC地址的)

==》在TCP/IP模型中,ARP协议属于IP层;在OSI模型中,ARP协议属于链路层。

    ==》局域网内维护ip和mac地址的对应关系

    ==》如果是外网,路由器网关作为中转,网关直连的网卡上请求对方网关的MAC地址,然后网关通过IP层查询目标主机,获取mac地址发送。


2:icmp:网络控制消息协议(网络层)

为了辅助IP 协议,交换各种各样的控制信息而被制造出来的。 属于网络层协议(IP,icmp)

主要功能:差错通知和信息查询

例如:ping命令,traceroute命令

3:udp:用户数据报协议(传输层)

UDP是基于IP的简单协议,不可靠的协议。

udp传输速度快,可以用在下载,游戏方向。

用户可以自己实现可靠的数据传输,通过增加确认和重传机制,实现udp的可靠传输。

2:协议数据结构

1:根据协议栈分析数据的结构:

根据图形理解:

发送数据时,其实就是应用层我们的数据外层以此包上各个协议栈的数据。

而接受数据时,其实就是从链路层开始一层层解析最外层的数据,获得最后特定协议特定数据模块

2:以太帧的结构

以太帧起始部分由前同步码和帧开始定界符组成,后面紧跟着一个以太网报头,以 MAC 地址说明目的地址和源地址。以太帧的中部是该帧负载的包含其他协议报头的数据包,如 IP 协议。

以太帧由一个 32 位冗余校验码结尾,用于检验数据传输是否出现损坏。以太帧结构如图所示。

注意:其中的数据块长度最小为 46 字节,最大为 1500 字节。

3:arp协议的分析

arp属于网络层,就是给arp数据块加上网络层的arp头信息,再加上数据链路层头信息。

arp报文格式:

相关代码结构定义如下:

#define ETH_ALEN  6
//以太网协议头的定义
struct ethhdr {
  unsigned char h_dest[ETH_ALEN];
  unsigned char h_source[ETH_ALEN];
  unsigned short h_proto;     //arp 为0x0806   ip数据包为 0x0800
};
//arp协议头的定义
struct arphdr {
  unsigned short h_type;    //目标网卡的硬件类型 1为以太网地址
  unsigned short h_proto;   //协议类型 0x0800表示ip协议
  unsigned char h_addrlen;  //硬件地址长度 如以太网地址长度为6,对应硬件类型
  unsigned char protolen;   //协议地址长度 如arp,ip协议,值是4
  unsigned short oper;      // arp请求:1 arp应答:2 rarp请求:3 rarp应答4
  unsigned char smac[ETH_ALEN];  //源mac地址
  unsigned int sip;        //源ip地址
  unsigned char dmac[ETH_ALEN];  //目标mac地址
  unsigned int dip;        //目标ip地址
};
//arp的整体包,
struct arppkt {
  struct ethhdr eh;
  struct arphdr arp;
};

如果用wireshark抓包分析,参考网络上的图:

4:ICMP协议:控制报文协议

ICMP 协议用于在 IP 主机和路由器之间传递控制消息,描述网络是否通畅、主机是否可达、路由器是否可用等网络状态。

icmp协议位于传输层:

struct ethhdr {
  unsigned char h_dest[ETH_ALEN];   //目的mac地址
  unsigned char h_source[ETH_ALEN]; //源mac地址
  unsigned short h_proto;       //上一层协议类型,如0x0800代表上一层是IP协议,0x0806为arp
};
struct iphdr {
  unsigned char version;  //4 位IP版本号+4位首部长度
  unsigned char tos;    //8位服务类型TOS
  unsigned short tot_len; //16位IP包总长度(字节)
  unsigned short id;      //16位标识, 用于辅助IP包的拆装
  unsigned short flag_off;    //3位标志位+13位偏移位, 也是用于IP包的拆装
  unsigned char ttl;      //8位IP包生存时间 TTL
  unsigned char protocol;   //8位协议 (TCP, UDP 或其他)
  unsigned short check;   //16位IP首部校验和,最初置零,等所有包头都填写正确后,计算并替换.
  unsigned int saddr;     //32位源IP地址
  unsigned int daddr;     //32位目的IP地址
};
struct icmphdr {
  unsigned char type;   //标识ICMP报文的类型,分为两种查询报文和差错报文
  unsigned char code;   //标识对应ICMP报文的代码,于type共同表示报文类型
  unsigned short check;   //ICMP报文数据部分在内的整个ICMP数据报的校验和 从TYPE开始,直到最后一位用户数据,如果为字节数为奇数则补充一位
  unsigned short identifier;  //识别号(一般用进程号作为识别号), 用于匹配ECHO和ECHO REPLY包
  unsigned short seq;     //报文序列号, 用于标记ECHO报文顺序
  unsigned char data[32];   //时间戳
};
//icmp协议包的定义
struct icmppkt {
  struct ethhdr eh;
  struct iphdr ip;
  struct icmphdr icmp;
};

5:UDP协议:用户数据报协议

#define ETH_ALEN  6
struct ethhdr {
  unsigned char h_dest[ETH_ALEN];
  unsigned char h_source[ETH_ALEN];
  unsigned short h_proto;
};
struct iphdr {
  unsigned char version;
  unsigned char tos;
  unsigned short tot_len;
  unsigned short id;
  unsigned short flag_off;
  unsigned char ttl;
  unsigned char protocol;
  unsigned short check;
  unsigned int saddr;
  unsigned int daddr;
};
//共8个字节
struct udphdr {
  unsigned short source;  // 源端口号16bit
  unsigned short dest;  // 目的端口号16bit
  unsigned short len;   // 数据包长度16bit
  unsigned short check; // 校验和16bit
};
//udp数据包
struct udppkt {
  struct ethhdr eh;
  struct iphdr ip;
  struct udphdr udp;
  unsigned char body[128];
};

3:测试抓包

1:arp抓包测试:

2:icmp抓包测试:

3:udp抓包测试:

4:tcp/ip抓包测试:

4:编码实现

用netmap和相关的自定义协议包实现对arp,udp,icmp报文的接受。

void echo_arp_pkt(struct arppkt *arp, struct arppkt *arp_rt, char *hmac) {
  memcpy(arp_rt, arp, sizeof(struct arppkt));
  memcpy(arp_rt->eh.h_dest, arp->eh.h_source, ETH_ALEN);
  str2mac(arp_rt->eh.h_source, hmac);
  arp_rt->eh.h_proto = arp->eh.h_proto;
  arp_rt->arp.h_addrlen = 6;
  arp_rt->arp.protolen = 4;
  arp_rt->arp.oper = htons(2);
  str2mac(arp_rt->arp.smac, hmac);
  arp_rt->arp.sip = arp->arp.dip;
  memcpy(arp_rt->arp.dmac, arp->arp.smac, ETH_ALEN);
  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_dest, udp->eh.h_source, ETH_ALEN);
  memcpy(udp_rt->eh.h_source, udp->eh.h_dest, ETH_ALEN);
  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_dest, icmp->eh.h_source, ETH_ALEN);
  memcpy(icmp_rt->eh.h_source, icmp->eh.h_dest, ETH_ALEN);
  icmp_rt->icmp.check = in_cksum((unsigned short*)&icmp_rt->icmp, sizeof(struct icmphdr));
}
#define PROTO_IP  0x0800
#define PROTO_ARP 0x0806
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;
                //ip头中检验udp协议和icmp协议
        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.tot_len));
          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.2.217")) {
          echo_arp_pkt(arp, &arp_rt, "00:50:56:33:1c:ca");
          nm_inject(nmr, &arp_rt, sizeof(struct arppkt));
        }
      }
    } 
  }
}
目录
相关文章
|
21天前
|
缓存 网络协议 Ubuntu
dpdk课程学习之练习笔记一(接收,发送,arp,icmp功能测试)
dpdk课程学习之练习笔记一(接收,发送,arp,icmp功能测试)
71 0
|
21天前
|
存储 缓存 网络协议
dpdk课程学习之练习笔记二(arp, udp协议api测试)
dpdk课程学习之练习笔记二(arp, udp协议api测试)
80 0
|
缓存 网络协议 Linux
计算机网络——Wireshark软件使用与协议分析(ARP协议、IP与ICMP分析)
Wireshark软件使用与协议分析 ARP协议分析 使用 Wireshark 抓取局域网的数据包并进行分析: 1. 学习 Wireshark 基本操作:重点掌握捕获过滤器和显示过滤器。 2. 观察 MAC 地址:了解 MAC 地址的组成,辨识 MAC 地址类型。 3. 分析以太网帧结构:观察以太网帧的首部和尾部,了解数据封装成帧的原理。 4. 分析 ARP 协议:抓取 ARP 请求和应答报文,分析其工作过程。 IP与ICMP分析 启动 Wireshark,捕捉网络命令执行过程中本机接受和发送的数据报。
1876 0
计算机网络——Wireshark软件使用与协议分析(ARP协议、IP与ICMP分析)
|
21天前
|
网络协议 数据格式
|
21天前
|
网络协议 API 网络安全
用户态协议栈设计实现udp,arp与icmp协议
用户态协议栈设计实现udp,arp与icmp协议
69 1
|
8月前
|
缓存 网络协议 Shell
网络协议格式 | 以太网帧、ARP数据报、IP数据报、UDP数据报、TCP数据报
网络协议格式 | 以太网帧、ARP数据报、IP数据报、UDP数据报、TCP数据报
73 0
|
11月前
|
运维 网络协议 应用服务中间件
C/S UDP通信实践踩坑记录与对于ICMP的进一步认识
C/S UDP通信实践踩坑记录与对于ICMP的进一步认识
|
缓存 网络协议 网络架构
三十二、ARP协议、DHCP协议、ICMP协议
三十二、ARP协议、DHCP协议、ICMP协议
三十二、ARP协议、DHCP协议、ICMP协议
|
网络协议 C语言
arp、ethernet、icmp、udp、ip协议的C语言实现(计算机网络协议栈实验)
arp、ethernet、icmp、udp、ip协议的C语言实现(计算机网络协议栈实验)
415 0
arp、ethernet、icmp、udp、ip协议的C语言实现(计算机网络协议栈实验)
|
5天前
|
网络协议 Java
Java的Socket编程:TCP/IP与UDP深入探索
Java的Socket编程:TCP/IP与UDP深入探索
12 0