2.Ether协议分析与实践

2. Ether 协议分析与实践

1. 概述

1.1 简介

  • 以太网是当前应用最普遍的局域网技术,取代了其他局域网标准如令牌环、FDDI和ARCNET
  • 以太网提供基于数据报、全双工、不可靠的通讯协议

1.2 常见以太网类型

速度常用名称IEEE标准名称线缆类型最大传输距离
10Mbps以太网802.3双绞线100m
100Mbps快速以太网802.3u双绞线100m
1Gbps吉比特以太网802.3z光纤5000m
1Gbps吉比特以太网802.3ab双绞线100m
10Gbps10吉比特以太网802.3an双绞线100m

1.3 以太帧数据格式

  • 以太网中 MTU 为 1500 字节, 而 Internet 中默认 MTU 为 576 字节
  • 双方都可以给对方发信息(全双工),所以必须有双方的地址(目的 MAC 地址和源 MAC 地址)
  • 为了提高信道的利用率,还需要通过一个字段来区分不同的通信(多路复用),如 0x0800(IP)、0x0806(ARP) 、0x80dd(IPv6)等。比如说,打电话时,信道基本上都是空闲的,绝大部分时间都是在等待人说话,人说话的速度,相对于传输速度来说,太慢了,非常浪费资源!所以我们完全可以在同一时间,收邮件、看新闻等,类型字段就是为了区分不同的通信
# 开启网卡混杂模式, 网卡默认会丢弃目的地址与自己不符的数据帧
shell> sudo ip link set eth0 promisc on     # off 表示关闭
shell> ip link show eth0                    # 查看开启结果, 是否包含 promisc
2: eth0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 00:0c:0c:0c:0c:0c brd ff:ff:ff:ff:ff:ff

# 查看和修改 MTU
cat /sys/class/net/eth0/mtu
echo 1460 | sudo tee /sys/class/net/eth0/mtu

# 路径 MTU
ping -s 1461 -M do baidu.com
ping: local error: Message too long, mtu=1460

2. 以太网编程

2.1 eth.h

shell> cat eth.h
#ifndef __eth_h___
#define __eth_h___

#define ETH_ALEN     6                   /* Octets in one ethernet addr   */
#define ETH_TLEN     2                   /* Octets in ethernet type field */
#define ETH_DATA_LEN 1500                /* Max. octets in payload    */
#define ETH_MIN_MTU  68                  /* Min IPv4 MTU per RFC791  */
#define ETH_MAX_MTU  0xFFFFU             /* 65535, same as IP_MAX_MTU    */

#define ETH_PROTO_ARP 0x0806             /* ARP 协议 */
#define ETH_PROTO_IP  0x0800             /* IP 协议 */

struct eth_frame {
    unsigned char  dest_addr[ETH_ALEN];  /* destination eth addr */
    unsigned char  src_addr[ETH_ALEN];   /* source ether addr */
    unsigned short proto;                /* packet type ID field */
    unsigned char  payload[0];           /* data */
	// unsigned char  crc[4];            /* checksum */
} __attribute__((packed));


struct eth_frame* eth_alloc_frame(const char *dest_mac, const char *src_mac,
		unsigned short proto, const void *data, const size_t lenght);

void eth_free_packet(struct eth_frame **frame);


int eth_socket(const char *iface);

ssize_t eth_send(int sockfd, struct eth_frame *frame, size_t size, int flags);

ssize_t eth_recv(int sockfd, void *buffer, size_t size, int flags);

void eth_close(int sockfd); 

#endif /* __eth_h___ */

2.2 eth.c

shell> cat eth.c 
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <net/if.h>          // for if_nametoindex
#include <arpa/inet.h>       // for htons
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ether.h>   // for ether_aton
#include <linux/if_packet.h>

#include "eth.h"
#include "common.h"

struct eth_frame* eth_alloc_frame(const char *dest_mac, const char *src_mac, 
		unsigned short proto, const void *data, const size_t size)
{
	struct ether_addr *addr;
	struct eth_frame *frame;
	frame = (struct eth_frame*)calloc(1, sizeof(struct eth_frame) + size);	

	addr = ether_aton(dest_mac);            // 将 mac 地址转换为网络字节序
	memcpy(frame->dest_addr, addr->ether_addr_octet, sizeof(addr->ether_addr_octet));

	addr = ether_aton(src_mac);             // 将 mac 地址转换为网络字节序
	memcpy(frame->src_addr, addr->ether_addr_octet, sizeof(addr->ether_addr_octet));

	frame->proto = htons(proto);            // 转换为网络字节序
	
	memcpy(frame->payload, data, size);
	return frame;
}

void eth_free_packet(struct eth_frame **frame) 
{
	if (NULL != frame && NULL != *frame) {
		free(*frame);
		*frame = NULL;
	}
}


int eth_socket(const char *iface) 
{
	int sockfd;
	struct sockaddr_ll sll;

	// create raw socket
	if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) 
		handle_error("socket");

	// config socket	
	memset(&sll, 0, sizeof(struct sockaddr_ll));
	sll.sll_family  = AF_PACKET;
	sll.sll_ifindex = if_nametoindex(iface);	  // 绑定哪块网卡

	// bind interface
	if (bind(sockfd, (struct sockaddr *)&sll, sizeof(sll)) == -1) 
		handle_error("bind");
	
	return sockfd;
}

ssize_t eth_send(int sockfd, struct eth_frame *frame, size_t size, int flags) 
{
	ssize_t count;
	if ((count = send(sockfd, frame, size, flags)) == -1)
		handle_error("send");
	return count;
}

ssize_t eth_recv(int sockfd, void *buffer, size_t size, int flags)
{
	ssize_t count;
	if ((count = recv(sockfd, frame, size, flags)) == -1)
		handle_error("recv");
	return count;
}

void eth_close(int sockfd) 
{
	if (close(sockfd) == -1)
		handle_error("close");
}

2.3 main.c

shell> cat main.c
#include <stdio.h>
#include <string.h>
#include "eth.h"

#define ARP_PROTO  0x0806
#define SRC_IP     "192.168.2.100"      /* 本机 IP */
#define SRC_MAC    "00:0C:0C:0C:0C:0C"  /* 本机 MAC */
#define DEST_MAC   "FF:FF:FF:FF:FF:FF"  /* 广播地址 */

static void test_eth(const char *dest_mac, const char *src_mac, 
		unsigned short proto, const void *data, size_t size)
{
	int sockfd;
	struct eth_frame *frame;

	sockfd = eth_socket("eth0");  // 使用 eth0 网卡

	frame = eth_alloc_frame(dest_mac, src_mac, proto, data, size);
	eth_send(sockfd, frame, sizeof(struct eth_frame) + size, 0);

	eth_free_packet(&frame);	
	eth_close(sockfd);
}

int main(int argc, char *argv[])
{
	const char *data = "aaaaaaaaaaaaaaaaaaaaa";
    test_eth(DEST_MAC, SRC_MAC, ARP_PROTO, data, strlen(data));
	return 0;
}
192.168.1.200> sudo tcpdump -nt -i eth0 -XX arp 
	0x0000:  6161 6161 6161 6161 6161 6161 6161 6161  aaaaaaaaaaaaaaaa
	0x0010:  6161 6161 6100 0000 0000 0000 0000 0000  aaaaa...........
	0x0020:  0000 0000 0000 0000 0000 0000 0000       ..............
	0x0000:  ffff ffff ffff 000c 0c0c 0c0c 0806 6161  ..............aa
	0x0010:  6161 6161 6161 6161 6161 6161 6161 6161  aaaaaaaaaaaaaaaa
	0x0020:  6161 6100 0000 0000 0000 0000 0000 0000  aaa.............
	0x0030:  0000 0000 0000 0000 0000 0000            ............

192.168.1.100> make run

3. 以太网攻击

3.1 以太网泛洪

  • 利用交换机的自动学习 mac 地址机制,通过发送大量无效以太网包给交换机学习,造成交换机 mac 地址表爆表,因为存放 mac 表的存储介质容量有限
  • 当 mac 地址表爆掉之后,交换机不能再学习新的 mac 地址,转发数据只能像集线器广播给所有接口
# 泛洪交换机
192.168.2.100> sudo macof -i eth0
74:3c:ad:76:25:f7 66:8a:79:31:dd:6c 0.0.0.0.61458 > 0.0.0.0.33095: S 183231136:183231136(0) win 512
1:1c:2:6a:eb:9b 92:e3:a0:5e:b9:74 0.0.0.0.28555 > 0.0.0.0.62737: S 1570780083:1570780083(0) win 512
f4:e5:86:33:a0:14 e6:6e:15:70:73:bb 0.0.0.0.22104 > 0.0.0.0.34019: S 745631263:745631263(0) win 512

# 查看交换机 mac 表
192.168.2.3> sudo brctl showmacs br0
port no	mac addr		is local?	ageing timer
  1	00:0b:0b:0b:0b:0b	yes		   0.00
  1	00:0b:0b:0b:0b:0b	yes		   0.00
  1	00:0c:0c:0c:0c:0c	no		  38.39
  1	00:50:56:c0:00:01	no		   6.30
  1	74:3c:ad:76:25:f7	no		   5.59
  1	f4:e5:86:33:a0:14	no		   5.59
  .............
  
# 监听 200 主机的数据,网卡必须开启混杂模式
192.168.2.100> sudo tcpdum -nt -X 'host 192.168.2.200'

# 200 访问 ftp 服务器
192.168.2.200> ftp 8.8.8.8 21
参考链接

http://www.networksorcery.com/enp/protocol/IEEE8023.htm

https://zh.wikipedia.org/wiki/%E4%BB%A5%E5%A4%AA%E7%BD%91

https://linux-network-programming.readthedocs.io/zh_CN/latest/protocols/data-link-layer.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值