sock_diag(7)

الاسم
sock_diag - الحصول على معلومات حول المقابس

موجز
#include <sys/socket.h>
#include <linux/sock_diag.h>
#include <linux/unix_diag.h> /* for UNIX domain sockets */
#include <linux/inet_diag.h> /* for IPv4 and IPv6 sockets */

diag_socket = socket(AF_NETLINK, socket_type, NETLINK_SOCK_DIAG);

الوصف
النظام الفرعي sock_diag netlink يوفر آلية للحصول على معلومات حول مقابس من عائلات عناوين مختلفة من النواة. يمكن استخدام هذا النظام الفرعي للحصول على معلومات حول مقابس فردية أو طلب قائمة بالمقابس.

في الطلب، يمكن للمتصل تحديد معلومات إضافية يرغب في الحصول عليها حول المقبس، على سبيل المثال، معلومات الذاكرة أو معلومات خاصة بعائلة العنوان.

عند طلب قائمة بالمقابس، يمكن للمتصل تحديد مرشحات تطبقها النواة لاختيار مجموعة فرعية من المقابس للإبلاغ عنها. حالياً، توجد فقط القدرة على تصفية المقابس حسب الحالة (متصل، مستمع، وهكذا).

لاحظ أن sock_diag يبلغ فقط عن تلك المقابس التي لها اسم؛ أي إما مقابس مربوطة صراحةً بـ bind(2) أو مقابس رُبطت آلياً بعنوان (مثلاً، بواسطة connect(2)). هذه هي نفس مجموعة المقابس المتاحة عبر /proc/net/unix، /proc/net/tcp، /proc/net/udp، وهكذا.

  طلب
يبدأ الطلب برأس struct nlmsghdr الموصوف في netlink(7) مع حقل nlmsg_type مضبوط على SOCK_DIAG_BY_FAMILY. يتبعه رأس خاص بعائلة العنوان يبدأ بجزء مشترك بين جميع عائلات العناوين:

    struct sock_diag_req {
        __u8 sdiag_family;
        __u8 sdiag_protocol;
    };

حقول هذا الهيكل هي كالتالي:

sdiag_family
    عائلة عنوان. يجب ضبطها على الثابت AF_* المناسب.

sdiag_protocol
    يعتمد على sdiag_family. يجب ضبطه على الثابت IPPROTO_* المناسب لـ AF_INET و AF_INET6، وإلى 0 خلاف ذلك.

إذا كان حقل nlmsg_flags لرأس struct nlmsghdr يحتوي على العلم NLM_F_DUMP مضبوطاً، فهذا يعني أن قائمة بالمقابس تُطلب؛ وإلا فهو استعلام عن مقبس فردي.

  استجابة
تبدأ الاستجابة برأس struct nlmsghdr ويتبعها مصفوفة من الكائنات الخاصة بعائلة العنوان. يتم الوصول إلى المصفوفة باستخدام وحدات الماكرو القياسية NLMSG_* من واجهة برمجة التطبيقات netlink(3).

كل كائن هو قائمة NLA (سمات netlink) يتم الوصول إليها باستخدام وحدات الماكرو RTA_* من واجهة برمجة التطبيقات rtnetlink(3).

  مقابس نطاق UNIX
بالنسبة لمقابس نطاق UNIX، يتم تمثيل الطلب في البنية التالية:

    struct unix_diag_req {
        __u8    sdiag_family;
        __u8    sdiag_protocol;
        __u16   pad;
        __u32   udiag_states;
        __u32   udiag_ino;
        __u32   udiag_show;
        __u32   udiag_cookie[2];
    };

حقول هذا الهيكل هي كالتالي:

sdiag_family
    عائلة العنوان؛ يجب ضبطها على AF_UNIX.

sdiag_protocol
pad يجب ضبط هذه الحقول على 0.

udiag_states
    هذه قناع بتات يحدد مرشحًا لحالات المقابس. سيتم الإبلاغ فقط عن المقابس التي تكون حالاتها ضمن هذا القناع. يُتجاهل عند الاستعلام عن مقبس فردي. القيم المدعومة هي:

    1 << TCP_ESTABLISHED

    1 << TCP_LISTEN

udiag_ino
    هذا رقم عقدة (inode) عند الاستعلام عن مقبس فردي. يُتجاهل عند الاستعلام عن قائمة مقابس.

udiag_show
    هذه مجموعة من الأعلام تحدد نوع المعلومات المراد الإبلاغ عنها. يُبلغ عن كل نوع مطلوب من المعلومات كخاصية netlink كما هو موضح أدناه:

    UDIAG_SHOW_NAME
        الخاصية المبلغ عنها ردًا على هذا الطلب هي UNIX_DIAG_NAME. المحتوى المرتبط بهذه الخاصية هو اسم المسار الذي رُبط به المقبس (سلسلة من البايتات يصل حجمها إلى UNIX_PATH_MAX).

    UDIAG_SHOW_VFS
        الخاصية المبلغ عنها ردًا على هذا الطلب هي UNIX_DIAG_VFS. المحتوى المرتبط بهذه الخاصية ممثل في البنية التالية:

            struct unix_diag_vfs {
                __u32 udiag_vfs_dev;
                __u32 udiag_vfs_ino;
            };

        حقول هذا الهيكل هي كالتالي:

        udiag_vfs_dev
            رقم الجهاز لعقدة المقبس المقابلة على القرص.

        udiag_vfs_ino
            رقم عقدة المقبس المقابلة على القرص.

    UDIAG_SHOW_PEER
        الخاصية المبلغ عنها ردًا على هذا الطلب هي UNIX_DIAG_PEER. المحتوى المرتبط بهذه الخاصية هو قيمة __u32 تمثل رقم عقدة النظير. تُبلغ هذه الخاصية للمقابس المتصلة فقط.

    UDIAG_SHOW_ICONS
        الخاصية المبلغ عنها ردًا على هذا الطلب هي UNIX_DIAG_ICONS. المحتوى المرتبط بهذه الخاصية هو مصفوفة من قيم __u32 تمثل أرقام عقد المقابس التي مرت باستدعاء connect(2) ولكن لم تُعالج بعد باستخدام accept(2). تُبلغ هذه الخاصية لمقابس الاستماع فقط.

    UDIAG_SHOW_RQLEN
        الخاصية المبلغ عنها ردًا على هذا الطلب هي UNIX_DIAG_RQLEN. المحتوى المرتبط بهذه الخاصية ممثل في البنية التالية:

            struct unix_diag_rqlen {
                __u32 udiag_rqueue;
                __u32 udiag_wqueue;
            };

        حقول هذا الهيكل هي كالتالي:

        udiag_rqueue
            لمقابس الاستماع: عدد الاتصالات المعلقة. حجم المصفوفة المرتبطة بخاصية الاستجابة UNIX_DIAG_ICONS يساوي هذه القيمة.

            للمقابس المنشأة: كمية البيانات في قائمة الانتظار الواردة.

        udiag_wqueue
            للمقابس المستمعة: حجم التراكم الذي يساوي القيمة الممررة كوسيط ثانٍ إلى listen(2).

            للمقابس المنشأة: كمية الذاكرة المتاحة للإرسال.

    UDIAG_SHOW_MEMINFO
        السمة المبلغ عنها ردًا على هذا الطلب هي UNIX_DIAG_MEMINFO. الحمولة المرتبطة بهذه السمة هي مصفوفة من قيم __u32 الموصوفة أدناه في القسم الفرعي "معلومات ذاكرة المقبس".

    السمات التالية تُبلغ دون أي طلب محدد:

    UNIX_DIAG_SHUTDOWN
        الحمولة المرتبطة بهذه السمة هي قيمة __u8 تمثل بتات حالة shutdown(2).

udiag_cookie
    هذه مصفوفة من معرفات غير شفافة يمكن استخدامها مع udiag_ino لتحديد مقبس فردي. تُتجاهل عند الاستعلام عن قائمة مقابس، وكذلك عندما تُضبط جميع عناصرها على -1.

الاستجابة لاستعلام عن مقابس نطاق UNIX تمثل كمصفوفة من

    struct unix_diag_msg {
        __u8    udiag_family;
        __u8    udiag_type;
        __u8    udiag_state;
        __u8    pad;
        __u32   udiag_ino;
        __u32   udiag_cookie[2];
    };

متبوعة بسمات netlink.

حقول هذا الهيكل هي كالتالي:

udiag_family
    لهذا الحقل نفس المعنى كما في struct unix_diag_req.

udiag_type
    يُضبط هذا على واحد من SOCK_PACKET أو SOCK_STREAM أو SOCK_SEQPACKET.

udiag_state
    يُضبط هذا على واحد من TCP_LISTEN أو TCP_ESTABLISHED.

pad يُضبط هذا الحقل على 0.

udiag_ino
    هذا هو رقم inode للمقبس.

udiag_cookie
    هذه مصفوفة من معرفات غير شفافة يمكن استخدامها في استعلامات لاحقة.

  مقابس IPv4 و IPv6
لمقابس IPv4 و IPv6، يُعرض الطلب في البنية التالية:

    struct inet_diag_req_v2 {
        __u8    sdiag_family;
        __u8    sdiag_protocol;
        __u8    idiag_ext;
        __u8    pad;
        __u32   idiag_states;
        struct inet_diag_sockid id;
    };

حيث يُعرّف struct inet_diag_sockid كالتالي:

    struct inet_diag_sockid {
        __be16  idiag_sport;
        __be16  idiag_dport;
        __be32  idiag_src[4];
        __be32  idiag_dst[4];
        __u32   idiag_if;
        __u32   idiag_cookie[2];
    };

حقول struct inet_diag_req_v2 هي كالتالي:

sdiag_family
    يجب ضبط هذا على AF_INET أو AF_INET6 لمقابس IPv4 أو IPv6 على التوالي.

sdiag_protocol
    يجب ضبط هذا على أحد IPPROTO_TCP أو IPPROTO_UDP أو IPPROTO_UDPLITE.

idiag_ext
    هذه مجموعة من الأعلام تُعرّف نوع المعلومات الموسعة المطلوب الإبلاغ عنها. يُبلَغ عن كل نوع مطلوب من المعلومات كخاصية netlink كما هو موصوف أدناه:

    INET_DIAG_TOS
        الحمولة المرتبطة بهذه الخاصية هي قيمة __u8 تمثل TOS للمقبس.

    INET_DIAG_TCLASS
        الحمولة المرتبطة بهذه الخاصية هي قيمة __u8 تمثل TClass للمقبس. مقابس IPv6 فقط. بالنسبة لمقابس LISTEN و CLOSE، يتبع ذلك خاصية INET_DIAG_SKV6ONLY مع قيمة حمولة __u8 تشير إلى ما إذا كان المقبس مخصصًا لـ IPv6 فقط أم لا.

    INET_DIAG_MEMINFO
        الحمولة المرتبطة بهذه الخاصية ممثلة في الهيكل التالي:

            struct inet_diag_meminfo {
                __u32 idiag_rmem;
                __u32 idiag_wmem;
                __u32 idiag_fmem;
                __u32 idiag_tmem;
            };

        حقول هذا الهيكل هي كالتالي:

        idiag_rmem
            كمية البيانات في طابور الاستقبال.

        idiag_wmem
            كمية البيانات المُصطفة بواسطة TCP ولكن لم تُرسَل بعد.

        idiag_fmem
            كمية الذاكرة المُجدوَلة للاستخدام المستقبلي (TCP فقط).

        idiag_tmem
            كمية البيانات في طابور الإرسال.

    INET_DIAG_SKMEMINFO
        الحمولة المرتبطة بهذه الخاصية هي مصفوفة من قيم __u32 موصوفة أدناه في القسم الفرعي "معلومات ذاكرة المقبس".

    INET_DIAG_INFO
        الحمولة المرتبطة بهذه السمة خاصة بعائلة العنوان. لمقابس TCP، هي كائن من النوع struct tcp_info.

    INET_DIAG_CONG
        الحمولة المرتبطة بهذه السمة هي سلسلة تصف خوارزمية التحكم في الازدحام المستخدمة. لمقابس TCP فقط.

pad يجب ضبط هذا على 0.

idiag_states
    هذه قناع بتات يعرّف مرشحًا لحالات المقبس. فقط تلك المقابس التي حالاتها ضمن هذا القناع سيتم الإبلاغ عنها. يتم تجاهله عند الاستعلام عن مقبس فردي.

id  هذا كائن معرف مقبس يُستخدم في طلبات التفريغ، وفي الاستعلامات عن مقابس فردية، ويُبلغ عنه في كل استجابة. على عكس مقابس نطاق UNIX، يتم تعريف مقابس IPv4 و IPv6 باستخدام العناوين والمنافذ. جميع القيم بترتيب بايت الشبكة.

حقول struct inet_diag_sockid هي كما يلي:

idiag_sport
    منفذ المصدر.

idiag_dport
    منفذ الوجهة.

idiag_src
    عنوان المصدر.

idiag_dst
    عنوان الوجهة.

idiag_if
    رقم الواجهة الذي يرتبط به المقبس.

idiag_cookie
    هذه مصفوفة من المعرفات المعتمة التي يمكن استخدامها مع حقول أخرى من هذه البنية لتحديد مقبس فردي. يتم تجاهلها عند الاستعلام عن قائمة مقابس، وكذلك عندما تكون جميع عناصرها مضبوطة على -1.

الاستجابة لاستعلام عن مقابس IPv4 أو IPv6 ممثلة كمصفوفة من

    struct inet_diag_msg {
        __u8    idiag_family;
        __u8    idiag_state;
        __u8    idiag_timer;
        __u8    idiag_retrans;

        struct inet_diag_sockid id;

        __u32   idiag_expires;
        __u32   idiag_rqueue;
        __u32   idiag_wqueue;
        __u32   idiag_uid;
        __u32   idiag_inode;
    };

متبوعة بسمات netlink.

حقول هذا الهيكل هي كالتالي:

idiag_family
    هذا هو نفس الحقل الموجود في struct inet_diag_req_v2.

idiag_state
    يشير هذا إلى حالة المقبس كما في struct inet_diag_req_v2.

idiag_timer
    بالنسبة لمقابس TCP، يصف هذا الحقل نوع المؤقت النشط حالياً للمقبس. يُضبط على أحد الثوابت التالية:

    0   لا يوجد مؤقت نشط
    1   مؤقت إعادة إرسال
    2   مؤقت البقاء على قيد الحياة
    3   مؤقت TIME_WAIT
    4   مؤقت استقصاء النافذة الصفرية

    بالنسبة للمقابس غير TCP، يُضبط هذا الحقل على 0.

idiag_retrans
    بالنسبة لقيم idiag_timer 1 و2 و4، يحتوي هذا الحقل على عدد عمليات إعادة الإرسال. بالنسبة لقيم idiag_timer الأخرى، يُضبط هذا الحقل على 0.

idiag_expires
    بالنسبة لمقابس TCP التي تحتوي على مؤقت نشط، يصف هذا الحقل وقت انتهاء صلاحيته بالمللي ثانية. بالنسبة للمقابس الأخرى، يُضبط هذا الحقل على 0.

idiag_rqueue
    بالنسبة لمقابس الاستماع: عدد الاتصالات المعلقة.

    بالنسبة للمقابس الأخرى: كمية البيانات في قائمة الانتظار الواردة.

idiag_wqueue
    بالنسبة لمقابس الاستماع: حجم التراكم.

    بالنسبة للمقابس الأخرى: مقدار الذاكرة المتاحة للإرسال.

idiag_uid
    هذا هو UID مالك المقبس.

idiag_inode
    هذا هو رقم inode للمقبس.

  معلومات ذاكرة المقبس
الحمولة المرتبطة بسمات netlink UNIX_DIAG_MEMINFO و INET_DIAG_SKMEMINFO هي مصفوفة من قيم __u32 التالية:

SK_MEMINFO_RMEM_ALLOC
    كمية البيانات في طابور الاستقبال.

SK_MEMINFO_RCVBUF
    مخزن المقبس المؤقت للاستقبال كما هو مضبوط بواسطة SO_RCVBUF.

SK_MEMINFO_WMEM_ALLOC
    كمية البيانات في طابور الإرسال.

SK_MEMINFO_SNDBUF
    مخزن المقبس المؤقت للإرسال كما هو مضبوط بواسطة SO_SNDBUF.

SK_MEMINFO_FWD_ALLOC
    كمية الذاكرة المُجدوَلة للاستخدام المستقبلي (TCP فقط).

SK_MEMINFO_WMEM_QUEUED
    كمية البيانات المصفوفة بواسطة TCP، ولكن لم تُرسل بعد.

SK_MEMINFO_OPTMEM
    كمية الذاكرة المخصصة لاحتياجات خدمة المقبس (مثل، مرشح المقبس).

SK_MEMINFO_BACKLOG
    كمية الحزم في backlog (لم تُعالج بعد).

الإصدارات
NETLINK_INET_DIAG أُدخل في Linux 2.6.14 ودعم مقابس AF_INET و AF_INET6 فقط. في Linux 3.3، أُعيدت تسميته إلى NETLINK_SOCK_DIAG ووُسع لدعم مقابس AF_UNIX.

UNIX_DIAG_MEMINFO و INET_DIAG_SKMEMINFO أُدخلا في Linux 3.6.

المعايير
لينكس.

أمثلة
يطبع برنامج المثال التالي رقم inode، ورقم inode النظير، واسم جميع مقابس نطاق UNIX في مساحة الأسماء الحالية.

    #include <errno.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <sys/un.h>
    #include <linux/netlink.h>
    #include <linux/rtnetlink.h>
    #include <linux/sock_diag.h>
    #include <linux/unix_diag.h>

    static int
    send_query(int fd)
    {
        struct sockaddr_nl nladdr = {
            .nl_family = AF_NETLINK
        };
        struct
        {
            struct nlmsghdr nlh;
            struct unix_diag_req udr;
        } req = {
            .nlh = {
                .nlmsg_len = sizeof(req),
                .nlmsg_type = SOCK_DIAG_BY_FAMILY,
                .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP
            },
            .udr = {
                .sdiag_family = AF_UNIX,
                .udiag_states = -1,
                .udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER
            }
        };
        struct iovec iov = {
            .iov_base = &req,
            .iov_len = sizeof(req)
        };
        struct msghdr msg = {
            .msg_name = &nladdr,
            .msg_namelen = sizeof(nladdr),
            .msg_iov = &iov,
            .msg_iovlen = 1
        };

        for (;;) {
            if (sendmsg(fd, &msg, 0) < 0) {
                if (errno == EINTR)
                    continue;

                perror("sendmsg");
                return -1;
            }

            return 0;
        }
    }

    static int
    print_diag(const struct unix_diag_msg *diag, unsigned int size)
    {
        if (size < NLMSG_LENGTH(sizeof(*diag))) {
            fputs("short response\n", stderr);
            return -1;
        }
        if (diag->udiag_family != AF_UNIX) {
            fprintf(stderr, "unexpected family %u\n", diag->udiag_family);
            return -1;
        }

        unsigned int rta_len = size - NLMSG_LENGTH(sizeof(*diag));
        unsigned int peer = 0;
        size_t path_len = 0;
        char path[sizeof(((struct sockaddr_un *) 0)->sun_path) + 1];

        for (struct rtattr *attr = (struct rtattr *) (diag + 1);
                 RTA_OK(attr, rta_len); attr = RTA_NEXT(attr, rta_len)) {
            switch (attr->rta_type) {
            case UNIX_DIAG_NAME:
                if (!path_len) {
                    path_len = RTA_PAYLOAD(attr);
                    if (path_len > sizeof(path) - 1)
                        path_len = sizeof(path) - 1;
                    memcpy(path, RTA_DATA(attr), path_len);
                    path[path_len] = '\0';
                }
                break;

            case UNIX_DIAG_PEER:
                if (RTA_PAYLOAD(attr) >= sizeof(peer))
                    peer = *(unsigned int *) RTA_DATA(attr);
                break;
            }
        }

        printf("inode=%u", diag->udiag_ino);

        if (peer)
            printf(", peer=%u", peer);

        if (path_len)
            printf(", name=%s%s", *path ? "" : "@",
                    *path ? path : path + 1);

        putchar('\n');
        return 0;
    }

    static int
    receive_responses(int fd)
    {
        long buf[8192 / sizeof(long)];
        struct sockaddr_nl nladdr;
        struct iovec iov = {
            .iov_base = buf,
            .iov_len = sizeof(buf)
        };
        int flags = 0;

        for (;;) {
            struct msghdr msg = {
                .msg_name = &nladdr,
                .msg_namelen = sizeof(nladdr),
                .msg_iov = &iov,
                .msg_iovlen = 1
            };

            ssize_t ret = recvmsg(fd, &msg, flags);

            if (ret < 0) {
                if (errno == EINTR)
                    continue;

                perror("recvmsg");
                return -1;
            }
            if (ret == 0)
                return 0;

            if (nladdr.nl_family != AF_NETLINK) {
                fputs("!AF_NETLINK\n", stderr);
                return -1;
            }

            const struct nlmsghdr *h = (struct nlmsghdr *) buf;

            if (!NLMSG_OK(h, ret)) {
                fputs("!NLMSG_OK\n", stderr);
                return -1;
            }

            for (; NLMSG_OK(h, ret); h = NLMSG_NEXT(h, ret)) {
                if (h->nlmsg_type == NLMSG_DONE)
                    return 0;

                if (h->nlmsg_type == NLMSG_ERROR) {
                    const struct nlmsgerr *err = NLMSG_DATA(h);

                    if (h->nlmsg_len < NLMSG_LENGTH(sizeof(*err))) {
                        fputs("NLMSG_ERROR\n", stderr);
                    } else {
                        errno = -err->error;
                        perror("NLMSG_ERROR");
                    }

                    return -1;
                }

                if (h->nlmsg_type != SOCK_DIAG_BY_FAMILY) {
                    fprintf(stderr, "unexpected nlmsg_type %u\n",
                            (unsigned) h->nlmsg_type);
                    return -1;
                }

                if (print_diag(NLMSG_DATA(h), h->nlmsg_len))
                    return -1;
            }
        }
    }

    int
    main(void)
    {
        int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);

        if (fd < 0) {
            perror("socket");
            return 1;
        }

        int ret = send_query(fd) || receive_responses(fd);

        close(fd);
        return ret;
    }

انظر أيضًا
netlink(3)، rtnetlink(3)، netlink(7)، tcp(7)

ترجمة
تُرجمت هذه الصفحة من الدليل بواسطة زايد السعيدي <zayed.alsaidi@gmail.com>

هذه الترجمة هي وثيقة مجانية؛ راجع رخصة جنو العامة الإصدار 3 (https://www.gnu.org/licenses/gpl-3.0.html) أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات.

إذا وجدت أي أخطاء في ترجمة صفحة الدليل هذه، يرجى إرسال بريد إلكتروني إلى قائمة بريد المترجمين: kde-l10n-ar@kde.org.