Android设备被搜索之RawSocket

背景,初衷

1.需要完成一个设备搜索功能,及通过PC工具可以搜索到局域网中的设备
2.就算IP冲突也能搜索到设备
3.有Android系统源码可以进行系统开发条件。

Raw Socket

raw socket,就是原始套接字,可以接收本机网卡上的数据帧或者数据包,相比正常使用的socket来说,它更底层,数据更原始。

编译环境

在Android系统源码根目录下创建一个文件夹rawSocket,在其中新建两个文件,一个是rawSocket.c (源码),一个是Android.mk(编译脚本)。
文件夹及文件
想要编译代码,就需要编译mk文件。如下是我的配置:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
#编译后的模块名称
LOCAL_MODULE := rawSocket
#源码全称,有多少都要加上
LOCAL_SRC_FILES := rawSocket.c
LOCAL_MODULE_TAGS := optional
#此处是代码导入的必需包,用来获取系统版本等相关信息
LOCAL_STATIC_LIBRARIES :=libcutils 
#编译成可执行文件
include $(BUILD_EXECUTABLE)

需要编译代码前,还需要建立编译环境,及在根目录下执行下面代码:

$  . build/envsetup.sh 

然后切换到rawSocket目录下,输入 mm 即可进行模块编译,编译后的文件会生成到system/bin/路径下,名字就是LOCAL_MODULE对应名字。

RawSocket.c重点代码描述

建立raw socket服务

使用如下代码实现:

int sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

这里说明一下:

  1. 第一个参数使用 PF_PACKET 可以操作链路层的数据
  2. 第二个参数 SOCK_RAW,它表示是包含了MAC层头部信息的原始分组,当然这种类型的套接字在发送的时候需要自己加上一个MAC头部
  3. 第三个参数 htons(ETH_P_ALL) (ETH_P_ALL宏定义为0)时表示收发所有的协议

接收socket数据

使用如下代码实现:

#define BUF_SIZE 2048

char buf[BUF_SIZE]while (1)
{
		int len = recvfrom(sockfd, buf, BUF_SIZE, 0, NULL, NULL);
		//解析buf
		//todo somthing
}

发送socket数据

使用如下代码实现:

ret = send(sockfd, (const char*)buf , len , MSG_NOSIGNAL | MSG_DONTWAIT);

其中 buf 就是要发送的数据,len 表示发送的数据长度,
ret > 0 表示数据发送成功,ret 结果是多少,表示发送成功多少长度,如果ret比len小,则需要补充发送。
封装后大致如下:

int socket_send(int sockfd, const void *buf, int len)
{
    int sent = 0, ret;
    while (sent < len)
    {
        ret = send(sockfd, (const char*)buf + sent, 
			len - sent, MSG_NOSIGNAL | MSG_DONTWAIT);
        if (ret > 0)
        {
            sent += ret;
        }
    }
}

注意:最好设置一个超时时间在里面,避免在while里面死循环

获取本机的IP、MAC

这里是使用了一个内部循环的socket来获取ip及mac的。

int get_addr(uint32_t *ip, char *mac)
{
    int sockfd;
	struct ifreq ir;
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == sockfd)
		return -1;
    strcpy(ir.ifr_name, "eth0");//eth0
	ioctl(sockfd, SIOCGIFHWADDR, &ir);
	memcpy(mac, ir.ifr_hwaddr.sa_data, 6);
	ioctl(sockfd, SIOCGIFADDR, &ir);
	close(sockfd);
	*ip = ((struct sockaddr_in*)&ir.ifr_addr)->sin_addr.s_addr;
	return 0;
}

如果要获取 wifi 的IP,则可以替换 “eth0” -> “wlan0”

设置开机自启动

想要让系统开机就启动你自己的可执行文件,可以进行如下配置:
找到 源码根目录\system\core\rootdir\init.rc 文件
追加如下代码即可:

service rawSocket /system/bin/rawSocket
    class main
    user root
	oneshot

到此就基本可以满足你的设备开机就能收到指定的 buf ,然后发送自身的 IP 和 MAC 出去的基本功能需求了。


顺便学习记录以下函数:

memcpy(buf + 6, mac, 6);//拷贝,将mac拷贝到指针第6个位置开始,长度为6
memset(buf + 18, 0, 60);//数据填充,用0,将buf指针第16个位置开始填充60个长度
strcpy(buf + 78, prop); //字符串拷贝,将指定字符串拷贝到从buf第78开始位置
sprintf(buf + 78 + len, "test = %s", "xxxx");//格式化字符串拷贝,最后一个参数填充到%s位置,再拷贝到buf指针位置

//下面是和Android系统相关
system(" reboot "); 相当于系统执行 reboot,就是重启功能
//使用system基本可以参考adb shell 后的指令
//例如使用 adb 发送广播 adb shell am broadcast -a com.android.test 对应代码如下:
system(" am broadcast -a com.android.test ")


参考资料:
百度百科
链路层套接字PF_PACKET简介
PF_PACKET说开去

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值