功能如题所述,查询出连接了相同wifi的手机的品牌信息,可以使用作为检测蹭网功能的核心功能。
首先介绍一下实现原理,安卓系统采用ARP协议,ARP协议即地址解析协议,是一种根据IP地址获取物理地址(MAC地址)的协议。主机发送报文信息到指定的IP地址病获得返回信息后写入到本地的ARP缓存,结果信息在本地ARP文件中保存一定时间。查询品牌功能的实现基于arp协议。当对于局域网中一个IP发送报文后,安卓会将返回的信息写入本地的ARP文件中,而返回的信息中包括了设备的mac地址信息。由于mac地址的前六位都是唯一对应厂商的,所以根据IEEE提供的mac地址文档即可查找出对应的厂商信息,做好中文适配即可。
代码实现分为以下步骤:
1.读取手机当前IP地址
2.读取当前子网掩码
3.根据子网掩码和IP地址即可计算当前wifi的有效IP地址集合
4.对生成的IP集合中的每一个IP发送udp报文
5.读取本地ARP表格获取有效的mac地址信息
6.根据mac地址信息查找对应厂商信息
给出各个步骤关键代码实现,后续会给出demo以供下载。
1.读取手机当前IP地址
/**
* 获取本机ip地址
*
* @return
*/
public static String getLocalIPAddress() {
String ip = "";
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
en.hasMoreElements(); ) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses();
enumIpAddr.hasMoreElements(); ) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
ip = inetAddress.getHostAddress();
break;
}
}
if (!TextUtils.isEmpty(ip)) break;
}
} catch (Exception e) {
ip = "";
}
return ip;
}
2.读取当前子网掩码
/**
* 获取本机子网掩码
*
* @return
*/
public static String getNetMask() {
try {
Enumeration<NetworkInterface> eni = NetworkInterface
.getNetworkInterfaces();
while (eni.hasMoreElements()) {
NetworkInterface networkCard = eni.nextElement();
List<InterfaceAddress> ncAddrList = networkCard
.getInterfaceAddresses();
for (InterfaceAddress networkCardAddress : ncAddrList) {
InetAddress address = networkCardAddress.getAddress();
if (!address.isLoopbackAddress()) {
String hostAddress = address.getHostAddress();
if (hostAddress.indexOf(":") <= 0) {
return calcMaskByPrefixLength(networkCardAddress.getNetworkPrefixLength());
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return "not found";
}
3.根据子网掩码和IP地址即可计算当前wifi的有效IP地址集合
public static List<String> parseIpMaskRange(String ip, String MASK) {
String mask = getNetMask(MASK) + "";
Log.i("scanner", mask);
List<String> list = new ArrayList<String>();
if ("32".equals(mask)) {
list.add(ip);
} else {
String startIp = getBeginIpStr(ip, mask);
String endIp = getEndIpStr(ip, mask);
if (!"31".equals(mask)) {
String subStart = startIp.split("\\.")[0] + "." + startIp.split("\\.")[1] + "." + startIp.split("\\.")[2] + ".";
String subEnd = endIp.split("\\.")[0] + "." + endIp.split("\\.")[1] + "." + endIp.split("\\.")[2] + ".";
startIp = subStart + (Integer.valueOf(startIp.split("\\.")[3]) + 1);
endIp = subEnd + (Integer.valueOf(endIp.split("\\.")[3]) - 1);
}
list = parseIpRange(startIp, endIp);
}
return list;
}
public static List<String> parseIpRange(String ipfrom, String ipto) {
List<String> ips = new ArrayList<String>();
String[] ipfromd = ipfrom.split("\\.");
String[] iptod = ipto.split("\\.");
int[] int_ipf = new int[4];
int[] int_ipt = new int[4];
for (int i = 0; i < 4; i++) {
int_ipf[i] = Integer.parseInt(ipfromd[i]);
int_ipt[i] = Integer.parseInt(iptod[i]);
}
for (int A = int_ipf[0]; A <= int_ipt[0]; A++) {
for (int B = (A == int_ipf[0] ? int_ipf[1] : 0); B <= (A == int_ipt[0] ? int_ipt[1]
: 255); B++) {
for (int C = (B == int_ipf[1] ? int_ipf[2] : 0); C <= (B == int_ipt[1] ? int_ipt[2]
: 255); C++) {
for (int D = (C == int_ipf[2] ? int_ipf[3] : 0); D <= (C == int_ipt[2] ? int_ipt[3]
: 255); D++) {
ips.add(new String(A + "." + B + "." + C + "." + D));
}
}
}
}
return ips;
}
4.对生成的IP集合中的每一个IP发送udp报文
private class UDPThread extends Thread {
private String target_ip = "";
final byte[] NBREQ = {(byte) 0x82, (byte) 0x28, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1,
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x20, (byte) 0x43, (byte) 0x4B,
(byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41,
(byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41,
(byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x41,
(byte) 0x41, (byte) 0x41, (byte) 0x41, (byte) 0x0, (byte) 0x0, (byte) 0x21, (byte) 0x0, (byte) 0x1};
static final short NBUDPP = 137;
UDPThread(String target_ip) {
this.target_ip = target_ip;
}
@Override
public synchronized void run() {
if (target_ip == null || target_ip.equals("")) return;
DatagramSocket socket = null;
InetAddress address = null;
DatagramPacket packet = null;
try {
address = InetAddress.getByName(target_ip);
packet = new DatagramPacket(NBREQ, NBREQ.length, address, NBUDPP);
socket = new DatagramSocket();
socket.setSoTimeout(200);
socket.send(packet);
socket.close();
} catch (Exception se) {
se.printStackTrace();
} finally {
if (socket != null) {
socket.close();
}
}
}
}
/**
* 读取arp信息
*/
private void readArp() {
macListFromRead = new ArrayList<TerminalBean>();
try {
BufferedReader br = new BufferedReader(
new FileReader("/proc/net/arp"));
String line = "";
String ip = "";
String flag = "";
String mac = "";
String gateWay = new WifiInfoUtil(getApplicationContext()).getGateWay();
Log.i("wangguan", "网关" + gateWay);
while ((line = br.readLine()) != null) {
try {
line = line.trim();
Log.i("scanner", line);
if (line.length() < 63) continue;
if (line.toUpperCase(Locale.US).contains("IP")) continue;
ip = line.substring(0, 17).trim();
flag = line.substring(29, 32).trim();
mac = line.substring(41, 63).trim();
if (mac.contains("00:00:00:00:00:00")) continue;
if (gateWay.equals(ip)) continue;//过滤网关
Log.i("scanner", "readArp: mac= " + mac + " ; ip= " + ip + " ;flag= " + flag);
TerminalBean terminalBean = new TerminalBean();
terminalBean.setMac(mac);
terminalBean.setIp(ip);
macListFromRead.add(terminalBean);//读出的所有mac地址信息保存
} catch (Exception e) {
e.printStackTrace();
}
}
br.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.i("scanner", "end");
}
/**
* 根据mac地址从txt文件中查询品牌信息
*
* @param mac mac地址
* @return 品牌信息
*/
private static String findCompanyFromTxt(Context context, String mac, int id) {
InputStream inputStream = context.getResources().openRawResource(id);
InputStreamReader inputStreamReader = null;
inputStreamReader = new InputStreamReader(inputStream);
BufferedReader reader = null;
reader = new BufferedReader(inputStreamReader);
String line;
try {
while ((line = reader.readLine()) != null) {
if (line.contains(mac)) {
return line;//获取到型号行
}
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}