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 |
| 10Gbps | 10吉比特以太网 | 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 :(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 :(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 :(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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/21997.html