2

こんにちは、ユニキャスト (src_addr.nl_groups = 0;) ですべて正常に動作するネット リンク ユーザー コードとカーネル コードを実装しようとしています。マルチキャストの場合、ゼロ以外の src_addr.nl_groups 値の場合、ユーザー コード バインド呼び出しは常に失敗します。マルチキャストにどのような価値を置き、さらにどのように進めるかは本当にわかりません。カーネル ソース ツリーで netlink_broadcast の使用状況を確認したので、同じグループ ID 値 (RTMGRP_LINK) をここに入れます。ユニキャストの場合、インターネットで多くのヘルプが見つかりましたが、マルチキャストの場合はそうではないと思います。だから私がさらに進むのを手伝ってください。

取得中のエラーは次のとおりです。

bind: そのようなファイルやディレクトリはありません

./a.out: ソケット (3) をバインドできません。エラー: -1: そのようなファイルまたはディレクトリはありません

#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdio.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#define NETLINK_TEST 28
#define GROUP_IB 1
#define MAX_PAYLOAD 1024
struct sockaddr_nl src_addr, dst_addr;
struct nlmsghdr *nlh = NULL;
struct msghdr msg;
struct iovec iov;
int sock_fd;


int main(int argc, char ** argv)
{
    int err;
    sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
    if (sock_fd<0) {
            char s[BUFSIZ];
            sprintf( s, "%s: can't assign fd for socket", argv[0] );
            perror(s);
            return -1;
    }

    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.nl_family = AF_NETLINK;
    src_addr.nl_pid = getpid();
    src_addr.nl_groups = 0; // Unicast
    //src_addr.nl_groups = RTMGRP_LINK; /* Multicast, bind call always fails for non zero values */

    err = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
    perror("bind");
    if (err<0) {
            char s[BUFSIZ];
            sprintf( s, "%s: can't bind socket (%d)and err : %d", argv[0], sock_fd,err );
            perror(s);
            return -1;
    }

    memset(&dst_addr, 0, sizeof(dst_addr));
    nlh = (struct nlhmsghdr *) malloc(NLMSG_SPACE(MAX_PAYLOAD));
    memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));

    iov.iov_base = (void *)nlh;
    iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);
    msg.msg_name = (void *)&dst_addr;
    msg.msg_namelen = sizeof(dst_addr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;


    printf("pid : %d\n Waiting for messages from kernel...\n",getpid());
    recvmsg(sock_fd, &msg, 0);
    printf("Message : %s\n", NLMSG_DATA(nlh));
    close(sock_fd);

    return 0;

}
4

2 に答える 2

1

Netlink ソケット バインドは、ユーザーが何であるかに敏感です。少なくとも RedHat 6 では、問題のプログラムを「ルート」として実行していない場合、確実に失敗することがわかりました。

ロジックを変更する前に、最初にルートとして実行してみてください。通常の操作と同じ障害が発生した場合は、(必ずしも) アクセス許可の問題ではないことがわかります。

于 2015-04-01T23:21:59.507 に答える
1

問題は

sock_fd = ソケット (AF_NETLINK、SOCK_RAW、NETLINK_TEST);

カーネルモジュールは NETLINK_TEST ファミリーを定義していますか? 独自のファミリがカーネル モジュールでサポートされている必要があり、nlmsg_multicast() RTMGRP_LINK を使用して適切なグループにメッセージを投稿する必要があります。これは NETLINK_ROUTE で定義されたグループです。

このサンプルコードはマルチキャストの例です

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <sys/socket.h>
 #include <linux/netlink.h>
 #include <unistd.h>

 #define MYPROTO NETLINK_USERSOCK
 #define MYMGRP 21

 int open_netlink(void)
 {
    int sock;
    struct sockaddr_nl addr;
    int group = MYMGRP;

    sock = socket(AF_NETLINK, SOCK_RAW, MYPROTO);
    if (sock < 0) {
        printf("sock < 0.\n");
        return sock;
    }

    memset((void *) &addr, 0, sizeof(addr));
    addr.nl_family = AF_NETLINK;
    addr.nl_pid = getpid();

    /* addr.nl_groups = MYMGRP; */

    if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
        printf("bind < 0.\n");
        return -1;
    }

    if (setsockopt(sock, 270, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)) < 0) {
        printf("setsockopt < 0\n");
        return -1;
    }

    return sock;
}

void read_event(int sock)
{
    struct sockaddr_nl nladdr;
    struct msghdr msg;
    struct iovec iov;
    char buffer[65536];
    int ret;

    iov.iov_base = (void *) buffer;
    iov.iov_len = sizeof(buffer);
    msg.msg_name = (void *) &(nladdr);
    msg.msg_namelen = sizeof(nladdr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    printf("Ok, listening.\n");
    ret = recvmsg(sock, &msg, 0);
    if (ret < 0)
        printf("ret < 0.\n");
    else
        printf("Received message payload: %s\n", NLMSG_DATA((struct nlmsghdr *) &buffer));
}

int main(int argc, char *argv[])
{
    int nls;

    nls = open_netlink();
    if (nls < 0)
        return nls;

    while (1)
        read_event(nls);

    return 0;
}

カーネルモジュール:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netlink.h>
#include <net/netlink.h>
#include <net/net_namespace.h>


#define MYPROTO NETLINK_USERSOCK

#define MYGRP 21

static struct sock *nl_sk = NULL;

static void send_to_user(void)
{
    struct sk_buff *skb;
    struct nlmsghdr *nlh;
    char *msg = "Hello from kernel";
    int msg_size = strlen(msg) + 1;
    int res;

    pr_info("Creating skb.\n");
    skb = nlmsg_new(NLMSG_ALIGN(msg_size + 1), GFP_KERNEL);
    if (!skb) {
        pr_err("Allocation failure.\n");
        return;
    }

    nlh = nlmsg_put(skb, 0, 1, NLMSG_DONE, msg_size + 1, 0);
    strcpy(nlmsg_data(nlh), msg);

    pr_info("Sending skb.\n");
    res = nlmsg_multicast(nl_sk, skb, 0, MYGRP, GFP_KERNEL);
    if (res < 0)
        pr_info("nlmsg_multicast() error: %d\n", res);
    else
        pr_info("Success.\n");
}

static int __init hello_init(void)
{
    pr_info("Inserting hello module.\n");

    nl_sk = netlink_kernel_create(&init_net, MYPROTO, NULL);
    if (!nl_sk) {
        pr_err("Error creating socket.\n");
        return -10;
    }

    send_to_user();

    netlink_kernel_release(nl_sk);
    return 0;
}

static void __exit hello_exit(void)
{
    pr_info("Exiting hello module.\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
于 2016-05-09T09:47:36.700 に答える