事情是这样的,我需要在 App 里面集成 traceroute ,不是直接执行脚本命令那种(因为没有 ROOT 权限),而是通过 NDK 直接编译成依赖模块。
于是找到 traceroute 源码,没想到 2023 年还在更新呢,下载下来自己写一下 CMakeList 或者 mk 文件是可以编译并运行在 App 中的。
GitHub 上也有一些现成的项目(traceroute-for-android),基本都能跑。traceroute 默认用 UDP 发数据包,加 -T(参数说明原文:Use TCP SYN for tracerouting )可以切换成用 TCP 发包,但是一旦加这个参数就会出错。
在 Linux 系统(比如 Ubuntu )上直接执行 traceroute -T baidu.com 这种命令是不会有问题的,但是编译集成到 Android App 里面,就没法执行带 T 参数的。调试发现,切换成 TCP 发包后,会调用 socket 函数创建原始套接字并且失败,报错提示没有权限,下面是 traceroute 源码:
static int tcp_init (const sockaddr_any *dest,
unsigned int port_seq, size_t *packet_len_p) {
// ...省略
/* Create raw socket for tcp */
raw_sk = socket (af, SOCK_RAW, IPPROTO_TCP); // SOCK_RAW 表示原始套接字,区别于 SOCK_STREAM ,SOCK_DGRAM 之类的
if (raw_sk < 0)
error_or_perm ("socket"); // 会创建失败,走到这里,导致整个 traceroute 无法执行
void error_or_perm (const char *str) {
if (errno == EPERM)
fprintf (stderr, "You do not have enough privileges to use "
"this traceroute method.");
error (str);
}
UDP 模式没报错,我看源码就是 SOCK_DGRAM 这种方式创建的套接字:
static void udp_send_probe (probe *pb, int ttl) {
int sk;
int af = dest_addr.sa.sa_family;
sk = socket (af, SOCK_DGRAM, protocol);
所以说我是没有办法在应用层(即便是 JNI 这层)去创建原始套接字吗?为什么呢?原始套接字和其他类型的 socket 有啥区别?
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.