linux系统中使用socket直接发送ARP数据
这个重点是如这样创建socket: sock_send = socket ( PF_PACKET , SOCK_PACKET , htons ( ETH_P_ARP) ) ;
其后所有收发的数据都是原始的网络数据包。
代码如下:在X86和ARM平台上都测试通过。调用arp_scaner_init之后 ,调用send_arp来发送ARP数据包,thread_read_arp中就会收到对端的反馈,并将其保存。
在此非常感谢其他同仁的分享,使我学会了这个用法。
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <netinet/if_ether.h>
#include <net/if_arp.h>
#include <netinet/udp.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdarg.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <string.h>
#include "adapter.h"
struct arp_msg {
/* Ethernet header */
uint8_t h_dest[ 6] ; /* 00 destination ether addr */
uint8_t h_source[ 6] ; /* 06 source ether addr */
uint16_t h_proto; /* 0c packet type ID field */
/* ARP packet */
uint16_t htype; /* 0e hardware type (must be ARPHRD_ETHER) */
uint16_t ptype; /* 10 protocol type (must be ETH_P_IP) */
uint8_t hwAddrLen; /* 12 hardware address length (must be 6) */
uint8_t protoAddrLen; /* 13 protocol address length (must be 4) */
uint16_t operation; /* 14 ARP opcode */
uint8_t srcMac[ 6] ; /* 16 sender's hardware address */
uint8_t srcIP[ 4] ; /* 1c sender's IP address */
uint8_t dstMac[ 6] ; /* 20 target's hardware address */
uint8_t dstIP[ 4] ; /* 26 target's IP address */
// uint8_t pad[ 18] ; /* 2a pad for min. ethernet payload (60 bytes) */
}PACKED;
bool g_system_running=true;
uint32_t local_ip;
uint8_t local_mac[ 6 ];
pthread_mutex_t g_cfglock;
volatile uint32_t g_mac_count=0;
char (*mac_list)[18];
int mac_list_max=0;
uint8_t raw_mac[64][6];
int setsockopt_broadcast( int fd)
{
const int const_int_1 =1;
return setsockopt ( fd,SOL_SOCKET,SO_BROADCAST, & const_int_1, sizeof ( const_int_1) ) ;
}
void prmac(u_char *ptr)
{
printf("MAC is: %02x:%02x:%02x:%02x:%02x:%02x\n",*ptr,*(ptr+1),*(ptr+2),*(ptr+3),*(ptr+4),*(ptr+5));
}
void printIP(const char *msg, uint8_t* ip)
{
printf("%s IP:%d.%d.%d.%d\n",msg,ip[0],ip[1],ip[2],ip[3]);
}
int send_arp( uint32_t test_ip, uint32_t from_ip, uint8_t * my_mac, const char * interface)
{
int sock_send;
int rv =1; /* "no reply received" yet */
struct sockaddr addr; /* for interface name */
struct arp_msg arp;
sock_send = socket ( PF_PACKET , SOCK_PACKET , htons ( ETH_P_ARP) ) ;
if ( sock_send == - 1) {
perror ( "raw_socket" ) ;
return - 1;
}
if ( setsockopt_broadcast( sock_send ) == - 1) {
perror ( "cannot enable bcast on raw socket" ) ;
goto ret;
}
/* send arp request */
memset ( & arp,0, sizeof ( arp) ) ;
memset ( arp. h_dest,0xff,6) ; /* MAC DA */
memcpy ( arp. h_source,my_mac,6) ; /* MAC SA */
arp. h_proto = htons ( ETH_P_ARP) ; /* protocol type (Ethernet) */
arp. htype = htons ( ARPHRD_ETHER) ; /* hardware type */
arp. ptype = htons ( ETH_P_IP) ; /* protocol type (ARP message) */
arp. hwAddrLen =6; /* hardware address length */
arp. protoAddrLen =4; /* protocol address length */
arp. operation = htons ( ARPOP_REQUEST) ; /* ARP op code */
memcpy ( arp. srcMac,my_mac,6) ; /* source hardware address */
memcpy ( arp. srcIP, & from_ip, sizeof ( from_ip) ) ; /* source IP address */
memcpy ( arp. dstIP, & test_ip, sizeof ( test_ip) ) ; /* target IP address */
memset ( & addr,0, sizeof ( addr) ) ;
strncpy( addr. sa_data,interface, sizeof ( addr. sa_data) ) ;
if ( sendto ( sock_send, & arp, sizeof ( arp) ,0, & addr, sizeof ( addr) ) <0) {
perror("sendto error");
}
ret:
close (sock_send) ;
return rv;
}
int read_interface( const char * interface, int * i, uint32_t * addr, uint8_t * arp)
{
int fd;
struct ifreq ifr;
struct sockaddr_in * our_ip;
memset ( & ifr,0, sizeof ( ifr) ) ;
fd = socket(AF_INET, SOCK_DGRAM, 0);
ifr. ifr_addr. sa_family = AF_INET ;
strncpy( ifr.ifr_name,interface, sizeof(ifr.ifr_name) );
if ( arp) {
if ( ioctl( fd, SIOCGIFHWADDR , & ifr) !=0) {
printf("SIOCGIFHWADDR error\n");
close ( fd) ;
return - 1;
}
memcpy ( arp,ifr. ifr_hwaddr. sa_data,6) ;
prmac ( arp ) ;
}
if ( addr) {
if ( ioctl( fd, SIOCGIFADDR , & ifr) !=0) {
perror ( "ioctl" ) ;
close ( fd) ;
return - 1;
}
our_ip = ( struct sockaddr_in * ) & ifr. ifr_addr;
* addr =our_ip-> sin_addr. s_addr;
}
close ( fd);
return 0;
}
void* thread_read_arp(void* param)
{
struct sockaddr repsa;
socklen_t salen, recved_len ;
struct arp_msg response;
int recvfd = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP));
bzero(&response, sizeof(response));
bzero(&repsa, sizeof(repsa));
salen = sizeof(repsa);
while(g_system_running){
if((recved_len = recvfrom(recvfd, &response, sizeof(response), 0, (struct sockaddr *)&repsa, &salen)) <= 0) {
perror("Recvfrom error");
break;
}
printf("Response %d bytes received\n",recved_len);
printIP("response", response.srcIP);
if( memcmp(response.dstIP ,&local_ip, 4 ) ==0
&& memcmp(response.dstMac,local_mac, 6 ) ==0){
printf("get a data\n");
}
}
close(recvfd);
}
int arp_scaner_init( const char * interface )
{
pthread_t tid;
read_interface( interface, NULL,&local_ip,local_mac);
printf("local IP");
printIP("", (uint8_t*)&local_ip );
pthread_mutex_init(&g_cfglock, NULL);
ipc_createthread(&tid, thread_read_arp, NULL, "arp-reading");
send_arp( find_ip,local_ip,local_mac,interface);
}
linux系统中使用socket直接发送ARP数据的更多相关文章
- 如何从Linux系统中获取带宽、流量网络数据
引入 国外的云主机厂商,例如AWS提供的网络数据是以流量为单位的,例如下面的图片: 从上图来看,其取值方式为 每隔5分钟取值1次,(每次)每个点显示为1分钟内的流量字节数(Bytes) 带宽与流量 我 ...
- linux系统中的进程状态分析
转载地址:https://blog.csdn.net/shenwansangz/article/details/51981459 linux是一个多用户,多任务的系统,可以同时运行多个用户的多个程序, ...
- Linux 系统中僵尸进程
Linux 系统中僵尸进程和现实中僵尸(虽然我也没见过)类似,虽然已经死了,但是由于没人给它们收尸,还能四处走动.僵尸进程指的是那些虽然已经终止的进程,但仍然保留一些信息,等待其父进程为其收尸.配图源 ...
- 获得Unix/Linux系统中的IP、MAC地址等信息
获得Unix/Linux系统中的IP.MAC地址等信息 中高级 | 2010-07-13 16:03 | 分类:①C语言. Unix/Linux. 网络编程 ②手册 | 4,471 次阅读 ...
- 为什么在 Linux 系统中,不建议超频
CPU 是一部计算机内的心脏啦!因为不论你做什么事情都需要 CPU 来加以运作的!(虽然有时工作量大.有时工作量小!),在 586 以前的计算机( 包含 386, 486, 与 586 ) ,CPU ...
- (转)浅谈 Linux 系统中的 SNMP Trap
原文:https://www.ibm.com/developerworks/cn/linux/l-cn-snmp/index.html 简介 本文讲解 SNMP Trap,在介绍 Trap 概念之前, ...
- 详解Linux系统中的文件名和文件种类以及文件权限
Linux文件种类与副文件名 一直强调一个概念,那就是:任何装置在Linux底下都是文件, 不仅如此,连资料沟通的介面也有专属的文件在负责-所以,你会瞭解到,Linux的文件种类真的很多- 除了前面提 ...
- linux系统中文件的几种类型
Linux系统是以文件的形式来进行管理的.Linux文件类型常见的有:普通文件.目录.字符设备文件.块设备文件.符号链接文件等,如果想了解这方面知识的弟兄,就进来了解了解. Linux系统不同于win ...
- Linux系统中的Device Mapper学习
在linux系统中你使用一些命令时(例如nmon.iostat 如下截图所示),有可能会看到一些名字为dm-xx的设备,那么这些设备到底是什么设备呢,跟磁盘有什么关系呢?以前不了解的时候,我也很纳闷. ...
随机推荐
- 微信小程序 project.config.json 配置
可以在项目根目录使用 project.config.json 文件对项目进行配置. miniprogramRoot Path String 指定小程序源码的目录(需为相对路径) qcloudRoot ...
- 软件工程小组讨论设计NABCD
项目名称:失物招领平台 项目工作小组:冰淇淋队 项目简介:目前同学们丢了东西都qq空间转发或者某个特定的qq群发消息,qq空间转发浪费了别人的时间,qq群发消息也浪费了别人的时间.怎么样才能浪费最少的 ...
- C#客户端和服务端数据的同步传输 (转载)
客户端: using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;u ...
- Swagger2 header 添加token
@Bean public Docket apiDocument() { return new Docket(DocumentationType.SWAGGER_2) .groupName(" ...
- Redis部署说明
一.普通部署 将Redis-x64-3.2.100解压,修改配置文件,一般不需要修改,直接使用默认,具体要修改可自行百度. 打开命令行,定位到解压目录,执行命令: redis-server.exe r ...
- 使用Fiddle抓取IOS手机
1.配置Fiddle (Tools->Options) 勾选后,按照提示下载安装一个认证 Fiddle默认8888端口 2.电脑开个热点,手机连上后,在该wifi的代理配置中,选择手动,服务器输 ...
- 为sqlserver数据库添加专用用户名
在安全里面右键添加登录名,输入登录名与密码(可以取消强制密码策略)然后选择用户映射的数据库,勾选db_owner即可.
- STM32的命名规范
STM32F407VET6 STM32F407代表的是芯片的型号后面的字符表示芯片的信息 V这一项代表引脚数,其中T代表36脚,C代表48脚,R代表64脚,V代表100脚,Z代表144脚,I代表176 ...
- Linux 对信号的总结
Linux信号_总结 对信号本质的理解: 类似于中断,区别在于中断是由硬件产生的,而信号是由软件实现的. 信号的来源: 触发硬件(触发键盘,或是硬件故障):软件信号函数kill .alarm.seti ...
- 使用SQL语句查询表及表字段类型说明
今天突然遇到有人要数据库表及表字段说明,数据库表太多又不能一个个表去找,就想想SQL是否能直接查询出来. 经过查询资料,加上一些自己的一些调整写了一个sql语句,在此记录一下,以方便日后查找使用. S ...