如何获取Unix套接字路径及连接套接字对应的原始监听套接字
现有代码问题说明
- 你用
O_PATH标志打开的文件描述符仅支持路径相关操作(如fstat、读取软链接),不支持任何IO类系统调用,getsockname当然会返回EBADF错误,这是调用失败的核心原因。 - 部分场景下open返回-1,通常是因为你没有对应
/proc/<pid>/fd/<n>的访问权限,比如目标进程与当前进程euid不一致、缺少CAP_SYS_PTRACE权限。
如何正确检查/proc//fd/是否指向指定路径的套接字
按以下步骤实现即可:
- 调用
stat检查目标/proc路径的st_mode,用S_ISSOCK确认是套接字类型 - 调用
readlink读取该/proc路径的软链接内容,解析出套接字的inode号 - 对要对比的目标套接字路径(如
/run/user/%n/my_socket)执行stat,同样拿到inode号,二者一致即说明是同一个套接字 - 如果是检查连接套接字是否对应某监听套接字,可分别调用
getsockname获取二者的绑定地址,地址完全一致即可确认对应关系
核心问题解答:从连接套接字获取对应原始监听套接字
用户态没有直接的系统调用可以直接从连接套接字拿到监听套接字的fd,可分场景实现:
- 同进程内场景:调用
listen启动监听时,把所有监听套接字的fd、绑定地址、inode号存在全局映射表中,后续拿到连接套接字后,调用getsockname取本地地址去映射表匹配即可 - 跨进程查询场景:遍历/proc下所有进程的fd,筛选出
S_ISSOCK且getsockopt(SO_ACCEPTCONN)返回为真的监听套接字,依次取绑定地址和待查连接套接字的本地地址匹配,匹配成功的就是对应的原始监听套接字
修正后的示例代码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/stat.h> #include <sys/socket.h> #include <sys/un.h> #include <errno.h> #include <string.h> #include <stdbool.h> // 检查是否为指定路径的套接字 bool check_socket_path(const char* proc_fd_path, const char* target_sock_path) { struct stat stat_buf; if (stat(proc_fd_path, &stat_buf) != 0 || !S_ISSOCK(stat_buf.st_mode)) { return false; } // 不要用O_PATH,正常打开套接字才能调用套接字相关接口 int sock = open(proc_fd_path, O_RDWR); if (sock == -1) { perror("open socket failed"); return false; } struct sockaddr_un local_addr; socklen_t len = sizeof(local_addr); if (getsockname(sock, (struct sockaddr*)&local_addr, &len) != 0) { perror("getsockname failed"); close(sock); return false; } close(sock); // 对比UNIX域套接字路径 if (local_addr.sun_family == AF_UNIX) { return strcmp(local_addr.sun_path, target_sock_path) == 0; } return false; }
内容的提问来源于stack exchange,提问作者nintyfan
相关产品推荐
相关产品推荐

