Linux错误(3)Linux里IP套接字sendmsg出现EPERM错误

Linux错误(3)之Linux里IP套接字sendmsg出现EPERM错误

Author: Once Day Date: 2024年2月21日

漫漫长路才刚刚开始…

全系列文章可参考专栏: Mermaid使用指南_Once_day的博客-CSDN博客

参考文档:

  • c - How to fix EPERM error when trying to use sendto() with Ethernet socket(AF_INET, ..., ...) (IP output packets) on Linux - Stack Overflow
  • linux ping 报错 sendmsg: Operation not permitted_ping: sendmsg: operation not permitted-CSDN博客

文章目录

      • Linux错误(3)之Linux里IP套接字sendmsg出现EPERM错误
        • 1. 问题分析
          • 1.1 现象介绍
          • 1.2 分析原因
          • 1.3 解决方法
        • 2. 实例验证
          • 2.1 测试代码
          • 2.2 复现故障
        • 3. Linux源码总结

1. 问题分析
1.1 现象介绍

当执行一段IP套接字的sendmsg函数(或者类似函数)时,出现EPERM错误,如下所示:

ubuntu->perf-ana:$ sudo python3 sendmsg-eperm.py 
Traceback (most recent call last):File "/home/ubuntu/tdata/perf-ana/sendmsg-eperm.py", line 14, in <module>so.sendmsg([icmp_bytes], [], socket.MSG_DONTWAIT, ("6.6.6.6", 0))
PermissionError: [Errno 1] Operation not permitted

这类错误大部分是因为程序执行用户的权限不够,比如对比ICMP报文,需要root权限才能执行,例如下面这种:

ubuntu->perf-ana:$ python3 sendmsg-eperm.py 
Traceback (most recent call last):File "/home/ubuntu/tdata/perf-ana/sendmsg-eperm.py", line 4, in <module>so = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)File "/usr/lib/python3.10/socket.py", line 232, in __init___socket.socket.__init__(self, family, type, proto, fileno)
PermissionError: [Errno 1] Operation not permitted
ubuntu->perf-ana:$ sudo python3 sendmsg-eperm.py 

这类权限不够的问题,在创建套接字时,就可以发现。除了权限不够,更多的原因是被内核中过滤规则拦截。

1.2 分析原因

Linux中使用sendmsg系统调用通过IP socket发送数据时,如果出现EPERM错误,通常有以下几种可能原因:

  1. 进程没有足够的权限,发送原始IP数据包需要root或CAP_NET_RAW权限,普通用户进程没有该权限会导致EPERM错误。解决办法是以root权限运行进程,或者赋予进程CAP_NET_RAW权限。
  2. 使用了无效的socket选项,有些socket选项只能由特权进程设置,如IP_HDRINCL。普通进程设置这些选项会引发EPERM错误。
  3. 企图伪造数据包的源地址,普通进程构造IP头部时,不能随意指定源IP地址,否则内核会拒绝发送并返回EPERM错误,以防止IP欺骗,只有root用户可以任意指定源IP。
  4. 发往无效的目的地址,例如目的IP不在本地路由表中,或者目的端口没有进程监听。
  5. AppArmor或SELinux等安全模块的限制,这些安全框架可以配置规则来阻止某些进程的网络访问。
  6. 其他内核模块的限制,如iptables规则对发出的数据包进行过滤。
1.3 解决方法

遇到这类问题,一般是先检查执行程序的权限,尝试以root权限运行。

如果失败,再分析报文是否比较特殊,去看看设备上的防火墙、iptables等报文过滤规则(也有可能是其他软件)。

逐一关闭这些防火墙类规则验证,找到最终的拦截程序,然后修改相关配置。

2. 实例验证
2.1 测试代码
import socket
from scapy.all import IP, ICMP, Raw, raw
# 以AF_INET原始套接字发送ICMP数据包
so = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)# 构造ICMP数据包
# 例如:ICMP Time Exceeded message, type = 11
# 使用scapy构造ICMP数据包
icmp_packet = ICMP(type=11, code=0) / Raw(b"ICMP Time Exceeded")
# 发送数据包, 配置iptables规则丢包, sudo iptables -A OUTPUT -p icmp --icmp-type 11 -j DROP
icmp_bytes = raw(icmp_packet)
# https://docs.python.org/3/library/socket.html#socket-objects
so.sendmsg([icmp_bytes], [], socket.MSG_DONTWAIT, ("6.6.6.6", 0))# 关闭套接字
so.close()

这段Python代码的含义是使用原始套接字发送一个ICMP数据包:

  1. socket库用于创建套接字,而scapy库用于构造和处理网络数据包。
  2. 创建了一个原始套接字对象so,使用socket.socket()函数,并指定了协议类型为AF_INET(IPv4)和套接字类型为SOCK_RAW(原始套接字)。这意味着可以直接发送和接收原始的网络数据包。
  3. 使用scapy库构造了一个ICMP数据包。在这个例子中,构造的ICMP数据包的类型为11(参数问题),代码中使用了ICMP(type=12, code=0)来创建ICMP数据包对象。此外,还添加了一个原始负载(payload)为"ICMP Time Exceeded"。
  4. 使用scapy库的raw()函数将ICMP数据包转换为字节表示形式。raw()函数是一个辅助函数,用于构建数据包并返回其字节表示形式。
  5. 使用原始套接字的sendmsg()方法发送数据包。sendmsg()方法接受一个参数列表,其中第一个参数是要发送的数据包的字节表示形式。这里将ICMP数据包的字节表示形式作为参数传递给sendmsg()方法。

这个代码在root权限下,可以正常发送报文,并且可以用tcpdump抓包到其报文,如下:

onceday->~:# sudo tcpdump -xx -vv -i eth0 icmp
23:32:51.738303 IP (tos 0x0, ttl 64, id 58934, offset 0, flags [DF], proto ICMP (1), length 46)VM-4-17-ubuntu > 6.6.6.6: ICMP parameter problem - octet 0, length 26IP  [|ip]0x0000:  feee 8fbf 8699 5254 0085 f022 0800 45000x0010:  002e e636 4000 4001 3a7c 0a00 0411 06060x0020:  0606 0c00 fae3 0000 0000 4943 4d50 20540x0030:  696d 6520 4578 6365 6564 6564
2.2 复现故障

在Ubuntu设备上添加iptables规则,如下所示:

ubuntu->tdata:$ sudo iptables -A OUTPUT -p icmp --icmp-type 11 -j DROP
ubuntu->tdata:$ sudo iptables -L OUTPUT -n -v
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)pkts bytes target     prot opt in     out     source               destination         0     0 DROP       icmp --  *      *       0.0.0.0/0            0.0.0.0/0            icmptype 11

添加的iptables规则在出口OUTPUT拦截type类型为11的报文,所以构建的ICMP超时报文将无法发送出去,即使以root权限运行。

ubuntu->perf-ana:$ sudo iptables -A OUTPUT -p icmp --icmp-type 11 -j DROP
ubuntu->perf-ana:$ sudo python3 sendmsg-eperm.py 
Traceback (most recent call last):File "/home/ubuntu/tdata/perf-ana/sendmsg-eperm.py", line 13, in <module>so.sendmsg([icmp_bytes], [], socket.MSG_DONTWAIT, ("6.6.6.6", 0))
PermissionError: [Errno 1] Operation not permitted

被iptables拦截之后,显示的错误也是EPERM,这非常具有疑惑性,iptables的统计计数也能验证这点

ubuntu->perf-ana:$ sudo iptables -L -vn
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)pkts bytes target     prot opt in     out     source               destination         Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)pkts bytes target     prot opt in     out     source               destination         Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)pkts bytes target     prot opt in     out     source               destination         1    46 DROP       icmp --  *      *       0.0.0.0/0            0.0.0.0/0            icmptype 11Chain YJ-FIREWALL-INPUT (0 references)pkts bytes target     prot opt in     out     source               destination  

注意,OUTPUT的过滤规则拦截了一个ICMP类型为11的报文,这正是上面尝试发送的报文。

3. Linux源码总结

一般这类问题,最好的解决方法就是查阅Linux源码,IP套接字sendmsg函数多用于数据报类,其函数位于net/ipv4/udp.c,如下这段是大概率返回EPERM的代码:

// net/ipv4/udp.c 1041 ~1318
int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
{//......if (cgroup_bpf_enabled(CGROUP_UDP4_SENDMSG) && !connected) {err = BPF_CGROUP_RUN_PROG_UDP4_SENDMSG_LOCK(sk,(struct sockaddr *)usin, &ipc.addr);if (err)goto out_free;if (usin) {if (usin->sin_port == 0) {/* BPF program set invalid port. Reject it. */err = -EINVAL;goto out_free;}daddr = usin->sin_addr.s_addr;dport = usin->sin_port;}}//......
}

BPF_CGROUP_RUN_PROG_UDP4_SENDMSG_LOCK这个宏里面会跑很多验证程序,其最终执行到:

// kernel/bpf/cgroup.c 1081~1127
/*** __cgroup_bpf_run_filter_sock_addr() - Run a program on a sock and*                                       provided by user sockaddr* @sk: sock struct that will use sockaddr* @uaddr: sockaddr struct provided by user* @type: The type of program to be exectuted* @t_ctx: Pointer to attach type specific context* @flags: Pointer to u32 which contains higher bits of BPF program*         return value (OR'ed together).** socket is expected to be of type INET or INET6.** This function will return %-EPERM if an attached program is found and* returned value != 1 during execution. In all other cases, 0 is returned.*/
int __cgroup_bpf_run_filter_sock_addr(struct sock *sk,struct sockaddr *uaddr,enum cgroup_bpf_attach_type atype,void *t_ctx,u32 *flags)
{struct bpf_sock_addr_kern ctx = {.sk = sk,.uaddr = uaddr,.t_ctx = t_ctx,};struct sockaddr_storage unspec;struct cgroup *cgrp;int ret;/* Check socket family since not all sockets represent network* endpoint (e.g. AF_UNIX).*/if (sk->sk_family != AF_INET && sk->sk_family != AF_INET6)return 0;if (!ctx.uaddr) {memset(&unspec, 0, sizeof(unspec));ctx.uaddr = (struct sockaddr *)&unspec;}cgrp = sock_cgroup_ptr(&sk->sk_cgrp_data);ret = BPF_PROG_RUN_ARRAY_CG_FLAGS(cgrp->bpf.effective[atype], &ctx,bpf_prog_run, flags);return ret == 1 ? 0 : -EPERM;
}

可以看到,这个函数里会跑BPF指令码,并且根据结果返回0或者-EPERM,这正是遇到的错误码

这里调用的是动态的BPF执行程序,并且实际上内核的过滤位点也不只这些,比如iptables在IP层发送出口OUTPUT还有过滤函数回调位点。从这个特征出发,可以推断出EPERM基本是由过滤规则拦截的特征,并且以此构造报文验证测试。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/438.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024_GAMES101作业环境配置Mac(intel)_VSCode_Clion

目录 VSCodeClionCMakeList.txt VSCode brew install cmake 更换下载源为阿里云下载 opencv&#xff0c;不然会很慢 cd "$(brew --repo)" git remote -v cd "$(brew --repo)" git remote set-url origin https://mirrors.aliyun.com/homebrew/brew.git…

linux中 关于操作Tomcat、Apache、Nginx、Mysql 的操作命令

a. 控制Apache 的操作命令 # 启动Apache命令 service httpd start # 重新 启动Apache命令 service httpd restart # 停止Apache命令 service httpd stop # 启动Apache命令 service httpd statusb. 控制Tomcat的操作命令 # 启动Tomcat命令 sh startup.sh# 停止Tomcat命令 s…

Ubuntu 24.04 LTS (Noble Numbat) 下载

Ubuntu 24.04 LTS (Noble Numbat) 下载 Ubuntu 24.04 LTS 开启 Beta 测试, 正式版即将发布 请访问原文链接&#xff1a;Ubuntu 24.04 LTS (Noble Numbat)&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org Ubuntu 24.04 LTS 首个…

如果出现这7个现象,别犹豫,是时候更换你的海外仓系统了

不知不觉&#xff0c;即使是曾经让你觉得很有用的海外仓系统也出现了问题。 曾经看似可以简化海外仓运营的管理系统&#xff0c;现在却难以满足你的需求。你是否注意到你的仓库管理效率低下的情况已经开始蔓延&#xff0c;甚至影响了公司的盈利&#xff1f; 仓库日常的管理工…

力扣(leetcode) 42. 接雨水 (带你逐步思考)

力扣(leetcode) 42. 接雨水 &#xff08;带你逐步思考&#xff09; 链接&#xff1a;https://leetcode.cn/problems/trapping-rain-water/ 难度&#xff1a;hard 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多…

鸿蒙开发踩坑与理解

基于 studio dev3.1,api 9 总结:现在的鸿蒙,感觉就像是用eclipse开发android的时候的android4.0或者4.0以下 持续更新中… 申请next,可能没通过? 没下文了。可能华为还不希望普通开发者进行开发吧。 兼容性问题 鸿蒙4.0,华为mate40E当前版本有黑屏、卡顿问题,客服说a…

【正点原子Linux连载】 第三十三章 Linux CAN驱动实验 摘自【正点原子】ATK-DLRK3568嵌入式Linux驱动开发指南

1&#xff09;实验平台&#xff1a;正点原子ATK-DLRK3568开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id731866264428 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/docs/boards/xiaoxitongban 第三十…

https通信流程

HTTPS通信流程通常包括以下几个关键步骤&#xff1a; 客户端发起请求&#xff1a;客户端&#xff08;通常是Web浏览器&#xff09;向服务器发起HTTPS连接请求&#xff0c;并连接到服务器的443端口&#xff08;HTTPS的默认端口&#xff09;。SSL/TLS握手&#xff1a;在数据传输…

Word目录格式的编辑记录

1、整体风格 鼠标右键&#xff0c;编辑域 选择目录&#xff0c;风格可以根据自己的喜好选择古典、优雅、正式等 2、字段、段落样式调整 更新整个目录 加载出样式侧框&#xff0c;选中某一级目录&#xff0c;侧框会定位到其样式 然后修改对应的样式&#xff0c;比如字体和段…

vscode自动生成返回值的快捷键

vscode中类似idea的altenter功能&#xff0c;可以添加返回值 idea中是Introduce local variable&#xff0c; vscode中按下command.(句号) 然后选extract to local variable或者 Assign statement to new local variable都行&#xff0c; 光标在分号前如图&#xff1a; 光标在…

如何安装和使用Yarn管理JavaScript依赖

在JavaScript开发中&#xff0c;依赖管理是一个至关重要的环节。Yarn是一个强大的包管理工具&#xff0c;旨在提供快速、可靠和安全的依赖解决方案。本文将介绍如何安装和使用Yarn&#xff0c;让你轻松管理JavaScript项目的依赖。 1. 安装Yarn 首先&#xff0c;我们需要在系统…

探索直播+电商系统中台架构:连接消费者与商品的智能纽带

随着直播电商的崛起&#xff0c;电商行业进入了全新的智能时代。直播形式的互动性和即时性为消费者提供了全新的购物体验&#xff0c;而电商平台则为商品的展示、销售和配送提供了强大的支持。在这一背景下&#xff0c;直播电商系统中台架构成为了连接消费者与商品的智能纽带&a…

Java基于微信小程序的电影院订票系统,附源码

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

C语言简单的数据结构:双向链表的实现

目录&#xff1a; 1.双向链表的结构和初始化1.1双向链表的结构1.2双向链表的初始化 2.双向链表的相关操作2.1双向链表的尾插、打印和头插2.11双向链表的尾插2.12双向链表的打印2.13双向链表的头插 2.2双向链表的尾删和头删2.21双向链表的尾删2.22双向链表的头删 2.3双向链表查找…

前后端系统开发之——文章管理

原文地址&#xff1a;前后端系统开发之——文章管理 - Pleasure的博客 下面是正文内容&#xff1a; 前言 主要使用的技术&#xff1a;前端使用的是Vue.js&#xff0c;后端使用的是SpringBoot。如不雷同可以直接跳过了。 文章管理是这个系统最主要的一个功能也是最常规的一个功…

如何寻找可靠的第三方软件检测机构

随着科技的飞速发展和数字化进程的加速&#xff0c;软件质量成为了企业竞争的关键。为了确保软件的质量和性能&#xff0c;许多企业选择寻找第三方的软件检测机构来进行软件的质量控制和评估。那么&#xff0c;如何找到一家可靠的第三方软件检测机构呢&#xff1f; 1.明确检测…

怎么设置启用远程桌面? 如何让外网电脑远程本地内网?

如何远程控制电脑&#xff1f;最简单实用的方案是开启电脑系统自带的远程桌面功能&#xff0c;如果涉及跨网、内外网互通&#xff0c;可以同时用快解析内网映射外网。下面是方案的具体实施步骤&#xff0c;供大家参考。 怎么打开设置启用远程桌面&#xff1f; 1.在目标需要远…

05—js对象

一、初识对象 JavaScript是面向对象编程&#xff08;Object Oriented Programming&#xff0c;OOP&#xff09;语言。 面对象是一种复合值&#xff1a;它将很多值集合在一起&#xff0c;可通过名字访问这些值。对象也可看做一种无序的数据集合&#xff0c;由若干个“键值对”…

数据库--Sqlite3

1、思维导图 2sqlite3在linux中是实现数据的增删&#xff0c;改 #include<myhead.h> int main(int argc, const char *argv[]) { //1、定义一个数据库句柄指针 sqlite3* ppDb NULL; //2、创建或打开数据库 if(sqlite3_open("./mydb…

通过两道题理解哈夫曼树

哈夫曼树定义 哈夫曼树&#xff08;Huffman Tree&#xff09;&#xff0c;又称最优二叉树&#xff0c;是一种带权路径长度最短的二叉树。所谓带权路径长度是指树中所有的叶子结点的权值乘以其到根结点的路径长度&#xff08;边数&#xff09;。哈夫曼树广泛应用于数据压缩等领…