使用网络监控来自所有应用程序的连接的IP地址,而无需植根Android手机(Monitor the IP addresses from connections being made from all apps using the network without rooting the Android phone)

我正在尝试构建一个Android应用程序(无需根电话),该应用程序从手机的所有应用程序的网络连接中收集IP地址。

我一直负责这个项目,关键是电话必须保持无根 - 这(据我所知)意味着我不能使用tcpdump或libpcap,因为两者似乎都需要手机根植。 另外一点,我找到了使用VPN服务的解决方案,但是,如果可能的话,我也不认为也可以使用这个功能,因为应用程序假设可以独立工作 - 没有任何“外部”帮助。

我已经遍布堆栈溢出和许多其他网站,试图找到一种方法来监控/收集IP地址和我发现需要生根Android手机的所有解决方案。 这让我相信这是不可能的,直到我在Google Play上找到以下应用。

https://play.google.com/store/apps/details?id=com.borgshell.connectiontrackerfree&hl=en

这个应用程序比我需要的更多,但它以某种方式显示每个应用程序正在进行的网络连接的IP地址。

总结一下:

有没有人知道从内部应用程序的网络连接收集IP地址的方法

没有生根电话

不使用VPN服务

谢谢

I am attempting to build an Android app (without having to root the phone) which collects the IP addresses from all the apps' network connections to and from the phone.

I have been tasked with this project and the key point is that the phone must stay unrooted - this (to my knowledge) means I can't use tcpdump or libpcap, since both seem to need the phone to be rooted. One other point, I have found solutions where a VPN Service is used, but, if possible, I am not suppose to use this feature as well, since the app is suppose to work on it's own - without any 'outside' help.

I have been all over stack overflow and many many other sites, trying to find a method to monitor/collect IP addresses and all the solutions I've found required rooting the Android phone. This led me to believe that it wasn't possible, until I found the following app on Google Play.

https://play.google.com/store/apps/details?id=com.borgshell.connectiontrackerfree&hl=en

This app does much more than I need, but it somehow shows the IP addresses of network connections each app is making.

To summarize:

Does anyone know a way to collect IP addresses from internal app's network connections

without rooting the phone

without using a VPN service

Thank you

最满意答案

对于那些对同一问题感到好奇的人,我终于弄明白了如何完成这项任务,而无需使用手机或使用VPN服务。

解决此问题的关键是查看手机上的以下目录:

/ proc / net /(tcp,tcp6,udp,udp6等)

此外,这里有一些来自开源项目的代码,它基本上完成了我所寻找的内容。

/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.cts; import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.List; import java.util.Scanner; import java.util.regex.Pattern; import junit.framework.AssertionFailedError; import junit.framework.TestCase; public class ListeningPortsTest extends TestCase { /** Address patterns used to check whether we're checking the right column in /proc/net. */ private static final List<String> ADDRESS_PATTERNS = new ArrayList<String>(2); static { ADDRESS_PATTERNS.add("[0-9A-F]{8}:[0-9A-F]{4}"); ADDRESS_PATTERNS.add("[0-9A-F]{32}:[0-9A-F]{4}"); } /** Ports that are allowed to be listening on the emulator. */ private static final List<String> EXCEPTION_PATTERNS = new ArrayList<String>(6); static { // IPv4 exceptions EXCEPTION_PATTERNS.add("00000000:15B3"); // 0.0.0.0:5555 - emulator port EXCEPTION_PATTERNS.add("0F02000A:15B3"); // 10.0.2.15:5555 - net forwarding for emulator EXCEPTION_PATTERNS.add("[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4 Loopback // IPv6 exceptions EXCEPTION_PATTERNS.add("[0]{31}1:[0-9A-F]{4}"); // IPv6 Loopback EXCEPTION_PATTERNS.add("[0]{16}[0]{4}[0]{4}[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4-6 Conversion EXCEPTION_PATTERNS.add("[0]{16}[F]{4}[0]{4}[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4-6 Conversion } public void testNoListeningTcpPorts() { assertNoListeningPorts("/proc/net/tcp", true); } public void testNoListeningTcp6Ports() { assertNoListeningPorts("/proc/net/tcp6", true); } public void testNoListeningUdpPorts() throws Exception { assertNoListeningUdpPorts("/proc/net/udp"); } public void testNoListeningUdp6Ports() throws Exception { assertNoListeningUdpPorts("/proc/net/udp6"); } private static final int RETRIES_MAX = 6; /** * UDP tests can be flaky due to DNS lookups. Compensate. */ private static void assertNoListeningUdpPorts(String procFilePath) throws Exception { for (int i = 0; i < RETRIES_MAX; i++) { try { assertNoListeningPorts(procFilePath, false); return; } catch (ListeningPortsAssertionError e) { if (i == RETRIES_MAX - 1) { throw e; } Thread.sleep(2 * 1000 * i); } } throw new IllegalStateException("unreachable"); } private static void assertNoListeningPorts(String procFilePath, boolean isTcp) { /* * Sample output of "cat /proc/net/tcp" on emulator: * * sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid ... * 0: 0100007F:13AD 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 ... * 1: 00000000:15B3 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 ... * 2: 0F02000A:15B3 0202000A:CE8A 01 00000000:00000000 00:00000000 00000000 0 ... * */ File procFile = new File(procFilePath); Scanner scanner = null; try { scanner = new Scanner(procFile); while (scanner.hasNextLine()) { String line = scanner.nextLine().trim(); // Skip column headers if (line.startsWith("sl")) { continue; } String[] fields = line.split("\\s+"); final int expectedNumColumns = 12; assertTrue(procFilePath + " should have at least " + expectedNumColumns + " columns of output " + fields, fields.length >= expectedNumColumns); String localAddress = fields[1]; String state = fields[3]; assertTrue(procFilePath + " should have an IP address in the second column", isAddress(localAddress)); if (!isException(localAddress) && isPortListening(state, isTcp)) { throw new ListeningPortsAssertionError( "Found port listening on " + localAddress + " in " + procFilePath); } } } catch (FileNotFoundException notFound) { fail("Could not open file " + procFilePath + " to check for listening ports."); } finally { if (scanner != null) { scanner.close(); } } } private static boolean isAddress(String localAddress) { return isPatternMatch(ADDRESS_PATTERNS, localAddress); } private static boolean isException(String localAddress) { return isPatternMatch(EXCEPTION_PATTERNS, localAddress); } private static boolean isPatternMatch(List<String> patterns, String input) { for (String pattern : patterns) { if (Pattern.matches(pattern, input)) { return true; } } return false; } private static boolean isPortListening(String state, boolean isTcp) { // 0A = TCP_LISTEN from include/net/tcp_states.h String listeningState = isTcp ? "0A" : "07"; return listeningState.equals(state); } private static class ListeningPortsAssertionError extends AssertionFailedError { private ListeningPortsAssertionError(String msg) { super(msg); } } }

For all those who are curious about this same issue, I was able to finally figure out how to accomplish this task, without rooting the phone or using a VPN service.

The key to solving this issue, is to look in the following directory on the phone:

/proc/net/(tcp, tcp6, udp, udp6, etc)

Also, here is some code from an open source project that does basically what I was looking for.

/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.cts; import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.List; import java.util.Scanner; import java.util.regex.Pattern; import junit.framework.AssertionFailedError; import junit.framework.TestCase; public class ListeningPortsTest extends TestCase { /** Address patterns used to check whether we're checking the right column in /proc/net. */ private static final List<String> ADDRESS_PATTERNS = new ArrayList<String>(2); static { ADDRESS_PATTERNS.add("[0-9A-F]{8}:[0-9A-F]{4}"); ADDRESS_PATTERNS.add("[0-9A-F]{32}:[0-9A-F]{4}"); } /** Ports that are allowed to be listening on the emulator. */ private static final List<String> EXCEPTION_PATTERNS = new ArrayList<String>(6); static { // IPv4 exceptions EXCEPTION_PATTERNS.add("00000000:15B3"); // 0.0.0.0:5555 - emulator port EXCEPTION_PATTERNS.add("0F02000A:15B3"); // 10.0.2.15:5555 - net forwarding for emulator EXCEPTION_PATTERNS.add("[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4 Loopback // IPv6 exceptions EXCEPTION_PATTERNS.add("[0]{31}1:[0-9A-F]{4}"); // IPv6 Loopback EXCEPTION_PATTERNS.add("[0]{16}[0]{4}[0]{4}[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4-6 Conversion EXCEPTION_PATTERNS.add("[0]{16}[F]{4}[0]{4}[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4-6 Conversion } public void testNoListeningTcpPorts() { assertNoListeningPorts("/proc/net/tcp", true); } public void testNoListeningTcp6Ports() { assertNoListeningPorts("/proc/net/tcp6", true); } public void testNoListeningUdpPorts() throws Exception { assertNoListeningUdpPorts("/proc/net/udp"); } public void testNoListeningUdp6Ports() throws Exception { assertNoListeningUdpPorts("/proc/net/udp6"); } private static final int RETRIES_MAX = 6; /** * UDP tests can be flaky due to DNS lookups. Compensate. */ private static void assertNoListeningUdpPorts(String procFilePath) throws Exception { for (int i = 0; i < RETRIES_MAX; i++) { try { assertNoListeningPorts(procFilePath, false); return; } catch (ListeningPortsAssertionError e) { if (i == RETRIES_MAX - 1) { throw e; } Thread.sleep(2 * 1000 * i); } } throw new IllegalStateException("unreachable"); } private static void assertNoListeningPorts(String procFilePath, boolean isTcp) { /* * Sample output of "cat /proc/net/tcp" on emulator: * * sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid ... * 0: 0100007F:13AD 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 ... * 1: 00000000:15B3 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 ... * 2: 0F02000A:15B3 0202000A:CE8A 01 00000000:00000000 00:00000000 00000000 0 ... * */ File procFile = new File(procFilePath); Scanner scanner = null; try { scanner = new Scanner(procFile); while (scanner.hasNextLine()) { String line = scanner.nextLine().trim(); // Skip column headers if (line.startsWith("sl")) { continue; } String[] fields = line.split("\\s+"); final int expectedNumColumns = 12; assertTrue(procFilePath + " should have at least " + expectedNumColumns + " columns of output " + fields, fields.length >= expectedNumColumns); String localAddress = fields[1]; String state = fields[3]; assertTrue(procFilePath + " should have an IP address in the second column", isAddress(localAddress)); if (!isException(localAddress) && isPortListening(state, isTcp)) { throw new ListeningPortsAssertionError( "Found port listening on " + localAddress + " in " + procFilePath); } } } catch (FileNotFoundException notFound) { fail("Could not open file " + procFilePath + " to check for listening ports."); } finally { if (scanner != null) { scanner.close(); } } } private static boolean isAddress(String localAddress) { return isPatternMatch(ADDRESS_PATTERNS, localAddress); } private static boolean isException(String localAddress) { return isPatternMatch(EXCEPTION_PATTERNS, localAddress); } private static boolean isPatternMatch(List<String> patterns, String input) { for (String pattern : patterns) { if (Pattern.matches(pattern, input)) { return true; } } return false; } private static boolean isPortListening(String state, boolean isTcp) { // 0A = TCP_LISTEN from include/net/tcp_states.h String listeningState = isTcp ? "0A" : "07"; return listeningState.equals(state); } private static class ListeningPortsAssertionError extends AssertionFailedError { private ListeningPortsAssertionError(String msg) { super(msg); } } }

更多推荐