【问题标题】:why cant get the message response from kernel module when using netlink socket to communicate with python user为什么使用netlink套接字与python用户通信时无法从内核模块获得消息响应
【发布时间】:2021-09-23 01:11:11
【问题描述】:

我正在使用 netlink 套接字将用户 python 代码与 linux 内核通信,我可以正确地从用户向内核发送消息,但我无法从内核返回响应。 它在我的内核代码中显示:“向用户发送 bak 时出错..”

我尝试了所有方法来获取响应消息: recvrecvfrom recvmsg ,然后我的目的是打开它以获取响应的有效负载,格式为: response_message = header + payload, 但用户始终未能得到响应。 我在执行用户 python 代码时得到这个:

pid of sock : 1
seq number of sock : 0
pid of the message send to kernel:  1
seq number of the message send to kernel :  0
return of send  21
waiting for kernel ..

在内核端检查 syslog 文件时我发现:

Jul 14 03:57:32 Bob kernel: [12381.663131] Kernel received :hello  id:XXXX!
Jul 14 03:57:32 Bob kernel: [12381.663132] python pid :1 XXXX
Jul 14 03:57:32 Bob kernel: [12381.663133] seq newsock : 0 id:XXXX!
Jul 14 03:57:32 Bob kernel: [12381.663134] Error while sending back to user  id:XXXX!

我在想这个问题可能是由于发送者和接收者的消息之间的seq号可能无效 所以我尝试添加标志(NLM_F_REQUEST)并使用其他消息类型(MSG_SETCFG = 11,MSG_GETCFG = 12)但它没有工作

任何熟悉 netlink socket 的人都可以帮我找出解决这种情况的人

这里是我的用户 python 代码:

import os
import socket
import struct
import ctypes


# types
NLMSG_NOOP = 1
NLMSG_ERROR = 2
NLMSG_DONE = 3
NLMSG_OVERRUN = 4
MSG_SETCFG = 11
MSG_GETCFG = 12
NLMSG_MIN_TYPE = 0x10

# flags
NLM_F_REQUEST = 1
NLM_F_MULTI = 2
NLM_F_ACK = 4
NLM_F_ECHO = 8



class Message:
    def __init__(self, msg_type, flags=0, seq=-1, payload=None):
        self.type = msg_type
        self.flags = flags
        self.seq = seq
        self.pid = 1
        payload = payload or []
        if isinstance(payload, list):
            contents = []
            for attr in payload:
                contents.append(attr._dump())
            self.payload = b''.join(contents)
        else:
            self.payload = payload

    def send(self, conn):
        if self.seq == -1:
            self.seq = conn.seq()

        self.pid = conn.pid
        length = len(self.payload)

        hdr = struct.pack("IHHII", length + 4 * 4, self.type,
                          self.flags, self.seq, self.pid)
        conn.send(hdr + bytes(self.payload, 'utf-8'))

 
class Connection(object):
    """
    Object representing Netlink socket connection to the kernel.
    """
    def __init__(self, nlservice=31, groups=0):
        # nlservice = Netlink IP service
        self.fd = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, nlservice)
        self.fd.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
        self.fd.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
        self.fd.bind((0, groups)) # pid=0 lets kernel assign socket PID
        self.pid, self.groups = self.fd.getsockname()
        self.pid = 1
        self._seq = 0
        
    def send(self, msg):
        if isinstance(msg, Message):
            if msg.seq == -1: 
                msg.seq = self.seq()
            #msg.seq = 1
            msg.pid = self.pid
            length = len(msg.payload)
            hdr = struct.pack("IHHII", length + 4 * 4, msg.type,
                          msg.flags, msg.seq, msg.pid) 
            msg = hdr + msg.payload.encode('utf-8')
            return self.fd.send(msg)
     
    def recve(self):
        #data, (nlpid, nlgrps) =  self.fd.recvfrom(16384)
        data = self.fd.recv(16384)
        msglen, msg_type, flags, seq, pid = struct.unpack("IHHII", data[:16])
        msg = Message(msg_type, flags, seq, data[16:])
        msg.pid = pid
        if msg_type == NLMSG_DONE:
           print("payload :", msg.payload)
           print("msg.pid :", msg.pid)
           print("msg.seq :", msg.seq)
        if msg.type == NLMSG_ERROR:
            errno = -struct.unpack("i", msg.payload[:4])[0]
            if errno != 0:
                err = OSError("Netlink error: %s (%d)" % (
                                                    os.strerror(errno), errno))
                err.errno = errno
                print("err :",err)
                raise err
        
        #return msg.payload 
         return msg 
        
    def seq(self):
        self._seq += 1
        return self._seq


sock = Connection()

var = 'hello'
msg1 = Message(3,0,-1,var) 
print("pid of sock :", sock.pid)
print ("seq number of sock :",sock._seq)

#res1 = msg1.send(sock)
res1 = sock.send(msg1)
print("pid of the message send to kernel: ", msg1.pid)
print("seq number of the message send to kernel : ", msg1.seq)

print("return of send ", res1)

while 1:
   print("waiting for kernel ..")
   #msgreply = sock.fd.recvmsg(16384)
   res2 = sock.recve()
   print("return of recive ", res2)

这是我的内核代码:

#include <linux/module.h>
#include <net/mptcp.h>


/********Test deb***********/

#include <linux/module.h>  
#include <linux/kernel.h>  
#include <linux/init.h>  
#include <net/sock.h>  
#include <linux/socket.h>  
#include <linux/net.h>  
#include <asm/types.h>  
#include <linux/netlink.h>  
#include <linux/netlink.h>  
#include <linux/skbuff.h> 
#include <linux/inetdevice.h>
#include <linux/uio.h>
/****** other lib for other test github ******/
#include <linux/gfp.h>
#include <linux/kprobes.h>
#include <linux/ptrace.h>
#include <linux/time.h>
#include <net/net_namespace.h>


#define NETLINK_USER 31

#define MSG_SETCFG      0x11

#define MSG_GETCFG      0x12

//#define NETLINK_USERROCK 31

struct sock *nl_sk = NULL;


static void hello_nl_recv_msg(struct sk_buff *skb) {

struct nlmsghdr *nlh;
int pid, seq;
struct sk_buff *skb_out;
int msg_size;
char *msg="Helloo";
char *msgg;
int res;
char *recive;

//printk(KERN_DEBUG "KERNEL MODE id:XXXX!\n");
printk(KERN_INFO "Entering: %s  id:XXXX!\n", __FUNCTION__);
msg_size = strlen(msg);

////recive ////

nlh=(struct nlmsghdr*)skb->data;
//nlh = nlmsg_hdr(skb);
msgg=(char *)NLMSG_DATA(nlh);

printk(KERN_INFO "Kernel received :%s  id:XXXX!\n",msgg);

pid = nlh->nlmsg_pid; //pid of sending process /
//pid = 1; //just set it to 1 like we did in python
printk(KERN_INFO "python pid :%d XXXX", pid);

////////end recive /


///////sending message /

skb_out = nlmsg_new(msg_size,0);

if(!skb_out) {
    printk(KERN_ERR "Failed to allocate new skb  id:XXXX!\n");
    return;
}

//nlh = nlmsg_put(skb, 0, 1, NLMSG_DONE, msg_size + 1, 0);
nlh=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size, 0);

NETLINK_CB(skb_out).dst_group = 0; //not in mcast group /
strncpy(nlmsg_data(nlh),msg,msg_size);

seq = nlh->nlmsg_seq;
printk(KERN_INFO "seq newsock : %d id:XXXX!\n", seq);

if(!nlmsg_data(nlh)) {
    printk(KERN_ERR "Failed to copy the message skbout id:XXXX!\n");
    return;
}
   
//printk(KERN_INFO "copied message :" , nlmsg_data(nlh));
//changed pid to 0
res=nlmsg_unicast(nl_sk,skb_out, pid);

if(res<0)
    printk(KERN_INFO "Error while sending back to user  id:XXXX!\n");

/////end send /

}


static int __init hello_init(void) {

printk("Entering: %s id:XXXX!\n",__FUNCTION__);
//This is for 3.6 kernels and above.
struct netlink_kernel_cfg cfg = {
    .input = hello_nl_recv_msg,
};

nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
//nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, 0, hello_nl_recv_msg,NULL,THIS_MODULE);
if(!nl_sk)
{
    printk(KERN_ALERT "Error creating socket.  id:XXXX!\n");
    return -10;

}

return 0;
}

static void __exit hello_exit(void) {

printk(KERN_INFO "exiting hello module  id:XXXX!\n");
netlink_kernel_release(nl_sk);
}

module_init(hello_init); module_exit(hello_exit);

MODULE_LICENSE("GPL");

【问题讨论】:

    标签: python sockets linux-kernel kernel-module netlink


    【解决方案1】:

    内核模块需要注意的两点

    1. “if(!nlmsg_data(nlh))”行的用途是什么,因为我们已经关联了有效负载
    2. 什么是 nlmsg_unicast 的返回值,因为它可以让我们知道为什么它返回错误

    【讨论】:

    • 感谢您的回复,我在调试时添加了“if(!nlmsg_data(nlh)) 行,以了解 nlmsg_unicast 之前的所有行是否正确并且没有导致任何错误,所以我'确保套接字的创建和发送给用户的消息运行正常。我只是忘记在发布我的问题之前将其删除
    • 当然@Bob。 nlmsg_unicast 的返回值是什么,以进一步了解此问题
    • 我做了一些研究,发现 nlmsg_unicast() 生成的 errno -111 表示连接被拒绝,这可能是因为内核响应了 a2 mssgs 从用户收到的消息(一个 ack 和实际响应),并且因为我们的内核不会立即发送响应,所以用户接收到 ack 并错误地解析它,就好像它是真正的响应并“关闭套接字”(idk 但这似乎不像我的情况我在 while 1) 中执行 recv()。内核在尝试发送实际响应时没有发现用户在 lestening。
    • stackoverflow.com/questions/34066680/… 中提出的解决方案是让客户期望响应,因此忽略第一个( ack )并接收第二个,这是实际响应,但我知道如何在我的代码
    • 否则我认为禁用从内核返回的 ack 但仍然找不到合适的代码。 ps:这只是我的代码的第一个版本。实际上我的目标是从用户发送 mssg 到内核只是为了启动通信,然后内核将重复发送请求并接收响应
    【解决方案2】:

    在将self.pid = 1 更改为self.pid = os.getpid() 之后,我使用Netlink 尝试了使用我自己的内核模块的python 代码。

    我能够从内核模块获得响应。当设置为1 时,我遇到了同样的问题,内核模块给出了错误-111

    【讨论】:

      猜你喜欢
      • 2011-03-18
      • 2014-05-05
      • 1970-01-01
      • 2015-01-04
      • 2023-03-18
      • 1970-01-01
      • 2022-01-12
      • 1970-01-01
      • 2017-04-08
      相关资源
      最近更新 更多