操作系统:Ubuntu18.04.4LTS
以太网数据链路层
ipv4协议
arp.h(Linux有相应头文件,这是我自己定义的)
#pragma once
struct arppacket
{
struct arphdr ar_head;
unsigned char ar_sha[ETH_ALEN];
struct in_addr ar_sip;
unsigned char ar_tha[ETH_ALEN];
struct in_addr ar_tip;
};
arp.c
#pragma pack (1)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "arp.h"
void printMac(const char* p_head, const unsigned char* p_mac);
int main()
{
// 组织以太网帧
char ef[ETH_FRAME_LEN];
unsigned char eth_source[ETH_ALEN] = { 0x10, 0x7b, 0x44, 0xd8, 0xcd, 0x09 };
unsigned char eth_dest[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
unsigned char eth_null[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
struct in_addr ip_source;
struct in_addr ip_dest;
inet_aton("192.168.100.254", &ip_source);
inet_aton("192.168.100.5", &ip_dest);
struct ethhdr* p_ethhdr;
p_ethhdr = (struct ethhdr*)ef;
memcpy(p_ethhdr->h_dest, eth_dest, ETH_ALEN);
memcpy(p_ethhdr->h_source, eth_source, ETH_ALEN);
p_ethhdr->h_proto = htons(ETH_P_ARP);
struct arppacket* p_arp;
p_arp = (struct arppacket*)(ef + ETH_HLEN);
p_arp->ar_head.ar_hrd = htons(0x1);
p_arp->ar_head.ar_pro = htons(ETH_P_IP);
p_arp->ar_head.ar_hln = ETH_ALEN;
p_arp->ar_head.ar_pln = 4;
p_arp->ar_head.ar_op = htons(ARPOP_REQUEST);
memcpy(p_arp->ar_sha, eth_source, ETH_ALEN);
p_arp->ar_sip = ip_source;
memcpy(p_arp->ar_tha, eth_null, ETH_ALEN);
p_arp->ar_tip = ip_dest;
// 注册原始套接字
int fd;
if ((fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) < 0)
{
perror("raw socket create error!\n");
exit(-1);
}
// 获取设置网卡信息
char* ethname = "enp2s0";
struct ifreq ifr;
strcpy(ifr.ifr_name, ethname);
int i = ioctl(fd, SIOCGIFINDEX, &ifr);
if (i < 0)
{
close(fd);
perror("can't get index\n");
exit(-1);
}
int index = ifr.ifr_ifindex;
// 设置sockaddr_ll地址
struct sockaddr_ll addr;
addr.sll_family = AF_PACKET;
addr.sll_protocol = htons(ETH_P_ARP);
addr.sll_ifindex = index;
addr.sll_hatype = ARPHRD_ETHER;
addr.sll_pkttype = PACKET_OTHERHOST;
addr.sll_halen = ETH_ALEN;
memcpy(addr.sll_addr, eth_source, ETH_ALEN);
// 绑定网卡
int flag;
if((flag = bind(fd, (struct sockaddr*)&addr, sizeof(addr))) == -1)
{
perror("bind fail\n");
exit(-1);
}
// 发出以太网帧
while(1)
{
int size = write(fd, ef, 60);
}
// 关闭套接字
close(fd);
return 0;
}
void printMac(const char* p_head, const unsigned char* p_mac)
{
printf("%s", p_head);
for (int i = 0; i < ETH_ALEN - 1; i++)
printf("%02x-", p_mac[i]);
printf("%02x\n", p_mac[ETH_ALEN - 1]);
}
//
// Created by hs on 2020/4/13.
//
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct arppacket
{
struct arphdr ar_head;
unsigned char ar_sha[ETH_ALEN];
struct in_addr ar_sip;
unsigned char ar_tha[ETH_ALEN];
struct in_addr ar_tip;
}__attribute__((packed));
void printMac(const char* p_head, const unsigned char* p_mac);
int main(int argc, char **argv)
{
struct in_addr pingaddr;
struct in_addr netaddr;
struct in_addr netmask;
struct sockaddr_ll hwaddr;
memset(&netaddr, 0, sizeof(netaddr));
memset(&netmask, 0, sizeof(netmask));
memset(&hwaddr, 0, sizeof(hwaddr));
if(argc != 2)
{
perror("Usage: arp 127.0.0.1\n");
exit(-1);
}
if(inet_aton(argv[1], &pingaddr) < 0)
{
perror("not a correct ip address\n");
exit(-1);
}
// create sock_packet socket
int fd = socket(PF_PACKET, SOCK_RAW, htonl(ETH_P_ARP));
if(fd == -1)
{
perror("create socket error\n");
exit(-1);
}
// get net interface info
char buf[1024];
struct ifconf ifc;
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if(ioctl(fd, SIOCGIFCONF, &ifc) == -1)
{
perror("get net interface error\n");
exit(-1);
}
// get correct net interface
int flag = 0;
struct ifreq *ifrPtr;
int networkNum = ifc.ifc_len / sizeof(struct ifreq);
for(int i = 0; i < networkNum; i++)
{
ifrPtr = ((struct ifreq*)buf) + i;
if(ioctl(fd, SIOCGIFADDR, ifrPtr) == -1)
{
perror("get ip address error\n");
exit(-1);
}
netaddr = ((struct sockaddr_in*)&(ifrPtr->ifr_addr))->sin_addr;
if(ioctl(fd, SIOCGIFNETMASK, ifrPtr) == -1)
{
perror("get netmask error\n");
exit(-1);
}
netmask = ((struct sockaddr_in*)&(ifrPtr->ifr_netmask))->sin_addr;
if((pingaddr.s_addr & netmask.s_addr) == (netaddr.s_addr & netmask.s_addr))
{
hwaddr.sll_family = PF_PACKET;
hwaddr.sll_protocol = htons(ETH_P_ARP);
hwaddr.sll_hatype = ARPHRD_ETHER;
hwaddr.sll_pkttype = PACKET_OTHERHOST;
hwaddr.sll_halen = ETH_ALEN;
if(ioctl(fd, SIOCGIFINDEX, ifrPtr) == -1)
{
perror("get net interface index error\n");
exit(-1);
}
hwaddr.sll_ifindex = ifrPtr->ifr_ifindex;
if(ioctl(fd, SIOCGIFHWADDR, ifrPtr) == -1)
{
perror("get net interface hwaddr error\n");
exit(-1);
}
memcpy(hwaddr.sll_addr, ifrPtr->ifr_hwaddr.sa_data, ETH_ALEN);
flag = 1;
break;
}
}
if(flag != 1)
{
perror("can not find correct net interface\n");
exit(-1);
}
// send arp
char ef[ETH_FRAME_LEN];
struct ethhdr *p_eth = (struct ethhdr*)ef;
memset(p_eth->h_dest, 0xff, ETH_ALEN);
memcpy(p_eth->h_source, hwaddr.sll_addr, ETH_ALEN);
p_eth->h_proto = htons(ETH_P_ARP);
struct arppacket *p_arp = (struct arppacket*)(ef + ETH_HLEN);
p_arp->ar_head.ar_hrd = htons(ARPHRD_ETHER);
p_arp->ar_head.ar_pro = htons(ETH_P_IP);
p_arp->ar_head.ar_hln = ETH_ALEN;
p_arp->ar_head.ar_pln = 4;
p_arp->ar_head.ar_op = htons(ARPOP_REQUEST);
memcpy(p_arp->ar_sha, hwaddr.sll_addr, ETH_ALEN);
p_arp->ar_sip = netaddr;
memset(p_arp->ar_tha, 0, ETH_ALEN);
p_arp->ar_tip = pingaddr;
if(bind(fd, (struct sockaddr*)&hwaddr, sizeof(struct sockaddr_ll)) == -1)
{
perror("bind network error\n");
exit(-1);
}
write(fd, ef, 60);
while(1)
{
read(fd, ef, sizeof(ef));
struct arppacket *recv_arp = (struct arppacket*)(ef+ETH_HLEN);
if(recv_arp->ar_tip.s_addr == netaddr.s_addr)
{
printMac("mac: ", recv_arp->ar_sha);
break;
}
}
return 0;
}
void printMac(const char* p_head, const unsigned char* p_mac)
{
printf("%s", p_head);
for (int i = 0; i < ETH_ALEN - 1; i++)
printf("%02x-", p_mac[i]);
printf("%02x\n", p_mac[ETH_ALEN - 1]);
}