事情是这样的,我需要在 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 有啥区别?
1
0o0O0o0O0o 2023-04-08 19:24:23 +08:00
cap_net_raw
|
2
RikkaW 2023-04-08 19:26:32 +08:00
印象里 SELiunx 不允许,可以看一下 avc: 的 log (
|
3
ysy950803 OP 求 Linux 网络编程大佬解惑呀!
|
4
tomychen 2023-04-10 15:25:13 +08:00
创建 raw socket 的前置条件就是 root
允许非 root 的创建 raw socket 的方法就是用 root 用户给这个进程+s 位 |
5
julyclyde 2023-04-10 16:20:59 +08:00
为什么 tcp 还需要 raw 呢
|