亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 5935 | 回復: 1
打印 上一主題 下一主題

[網(wǎng)絡] (已解決)使用netlink的NETLINK_INET_DIAG協(xié)議獲取所有套接字信息出錯 [復制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2012-08-22 13:31 |只看該作者 |倒序瀏覽
本帖最后由 edsionte 于 2012-08-23 12:51 編輯

我想通過netlink的NETLINK_INET_DIAG協(xié)議獲取當前系統(tǒng)所有tcp連接的狀態(tài)信息,類似ss -ta后的效果。具體為用戶進程向內(nèi)核發(fā)送消息后,內(nèi)核一次性將多條包含tcp連接 的消息發(fā)送至用戶進程,然后再依次讀取單條消息。

下面的程序是仿照ss命令源碼tcp_show_netlink寫的,但是運行結(jié)果是不正確的:

~/netlink $ ./a.out
while1
status=76
while2
Get a PKG..
Family:AF_INET
dport:0, sprot:0
0.0.0.0,0.0.0.0
status=0
while1
status=-1

另外,源碼中的兩個循環(huán)是什么意思啊?我的理解是,外層循環(huán)不斷接受內(nèi)核發(fā)來的信息,內(nèi)層循環(huán)將本次接受的信息按條讀取。

源碼如下:


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <asm/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/inet_diag.h>
#include <netinet/tcp.h>

int main(int argc, char **argv)
{
        int fd;
        struct sockaddr_nl src_addr, dest_addr;
        struct {
                struct nlmsghdr nlh;
                struct inet_diag_req r;
        } req;
        struct inet_diag_msg *pkg;
        struct msghdr msg;
        char buf[8192];
        char src_ip[20];
        char dest_ip[20];
        struct iovec iov;

        if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0)
                return -1;

        int ret;
        ret = fcntl (fd, F_SETFL, O_NONBLOCK );  
        if ( ret < 0 ) {  
                fprintf ( stderr,  "Can't set socket flags");  
                close (fd);  
                return -1;  
        }
        //src addr
        memset(&src_addr, 0, sizeof(struct sockaddr_nl));
        src_addr.nl_family = AF_NETLINK;
        src_addr.nl_pid = getpid();
        src_addr.nl_groups = 0;

        if (bind(fd, (struct sockaddr *)&src_addr, sizeof(struct sockaddr_nl)) < 0) {
                fprintf(stderr, "bind socket error %s\n", strerror(errno));
        }

        memset(&req, 0, sizeof(req));
        req.nlh.nlmsg_len = sizeof(req);
        req.nlh.nlmsg_type = TCPDIAG_GETSOCK;
        req.nlh.nlmsg_flags = NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ROOT;
//        req.nlh.nlmsg_flags = NLM_F_REQUEST ;
        req.nlh.nlmsg_pid = 0;

        memset(&req.r, 0, sizeof(req.r));
        req.r.idiag_family = AF_INET;
        //req.r.idiag_states = 0; //states to dump

        //send msg to kernel
        iov.iov_base = &req;
        iov.iov_len = sizeof(req);

        msg.msg_name = (void *)&src_addr;
        msg.msg_namelen = sizeof(struct sockaddr_nl);
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;

        if (sendmsg(fd, &msg, 0) < 0) {
                printf("%s\n", strerror(errno));
                return -1;
        }
        //recv msg from kernel
        iov.iov_base = buf;
        iov.iov_len = sizeof(buf);

        //dest addr
        memset(&src_addr, 0, sizeof(struct sockaddr_nl));
        dest_addr.nl_family = AF_NETLINK;
        dest_addr.nl_pid = 0;
        dest_addr.nl_groups = 0;

        while (1) {
                printf("while1\n");
                int status;
                struct nlmsghdr *h;

                msg = (struct msghdr) {
                        (void *)&dest_addr, sizeof(struct sockaddr_nl),
                                &iov, 1, NULL, 0, 0
                };

                //length of recv data
                status = recvmsg(fd, &msg, 0);
                //                status = recv(fd, buf, sizeof(buf), 0);       
                printf("status=%d\n", status);
                if (status < 0)
                        break;
       
                h = (struct nlmsghdr *)buf;

                while (NLMSG_OK(h, status)) {
                        printf("while2\n");
                        if (h->nlmsg_type == NLMSG_DONE) {
                                close(fd);
                                printf("NLMSG_DONE\n");
                                return 0;
                        }

                        if (h->nlmsg_type == NLMSG_ERROR) {
                                struct nlmsgerr *err;
                                err = (struct nlmsgerr*)NLMSG_DATA(h);
                                fprintf(stderr, "%d Error %d:%s\n", __LINE__, -(err->error), strerror(-(err->error)));
                                close(fd);
                                printf("NLMSG_ERROR\n");
                                return 0;
                        }

                        pkg = (struct inet_diag_msg *)NLMSG_DATA(h);
                        printf("Get a PKG..\n");
                        printf("Family:%s\n", pkg->idiag_family == AF_INET ? "AF_INET" : "AF_INET6");
                        printf("dport:%d, sprot:%d\n", pkg->id.idiag_sport, pkg->id.idiag_sport);
                        memset(src_ip, 0, sizeof(src_ip));
                        memset(dest_ip, 0, sizeof(dest_ip));
                        inet_ntop(AF_INET, pkg->id.idiag_src, src_ip, 20);
                        inet_ntop(AF_INET, pkg->id.idiag_dst, dest_ip, 20);
                        printf("%s,%s\n", src_ip, dest_ip);
                        //                get_tcp_state(pkg->idiag_state);
                        h = NLMSG_NEXT(h, status);
                        printf("status=%d\n", status);


                }//while
        }//while
        close(fd);
        return 0;
}

論壇徽章:
0
2 [報告]
發(fā)表于 2012-08-23 12:51 |只看該作者
之前一直忽略了這個字段,它的含義是向內(nèi)核指明應該向用戶態(tài)導出那些狀態(tài)的套接字。

SS命令的實現(xiàn)方法是:
states = SS_ALL & ~((1<<SS_LISTEN)|(1<<SS_CLOSE)|(1<<SS_TIME_WAIT)|(1<<SS_SYN_RECV)),
再看SS_ALL的定義:
#define SS_ALL ((1<<SS_MAX)-1)
SS_MAX是什么?請看下面的結(jié)果:
enum {
        SS_UNKNOWN,
        SS_ESTABLISHED,
        SS_SYN_SENT,
        SS_SYN_RECV,
        SS_FIN_WAIT1,
        SS_FIN_WAIT2,
        SS_TIME_WAIT,
        SS_CLOSE,
        SS_CLOSE_WAIT,
        SS_LAST_ACK,
        SS_LISTEN,
        SS_CLOSING,
        SS_MAX
};


因此,按照ss的實現(xiàn)方法,TCP套接字也有類似表示狀態(tài)的枚舉類型:
enum
{
  TCP_ESTABLISHED = 1,
  TCP_SYN_SENT,
  TCP_SYN_RECV,
  TCP_FIN_WAIT1,
  TCP_FIN_WAIT2,
  TCP_TIME_WAIT,
  TCP_CLOSE,
  TCP_CLOSE_WAIT,
  TCP_LAST_ACK,
  TCP_LISTEN,
  TCP_CLOSING   /* now a valid state */
};

因此我這樣實現(xiàn):

req.r.idiag_states = ((1 << TCP_CLOSING + 1) -1);
這樣就可以獲得所有狀態(tài)的套接字。
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP