博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux netlink套接字实现类似ss命令 ,统计套接字以及TCP信息
阅读量:4030 次
发布时间:2019-05-24

本文共 8471 字,大约阅读时间需要 28 分钟。

参考了 ss的源代码

以及 netlink相关资料:http://blog.csdn.net/scdxmoe/article/details/27711205

实现结果为:

gcc netlink_dig_530_7.c -o netlink_dig_530_7

./netlink_dig_530_7

state      family     l.addr     l.port       r.addr     r.rport   
LISTEN     AF_INET   localhost      53         0.0.0.0        0         
LISTEN     AF_INET   (null)         21         0.0.0.0        0         
LISTEN     AF_INET   (null)         22         0.0.0.0        0         
LISTEN     AF_INET   (null)         22         0.0.0.0        0         
LISTEN     AF_INET   localhost      631        0.0.0.0        0         
LISTEN     AF_INET   (null)         12865      0.0.0.0        0         
ESTAB      AF_INET   ubuntu.local   59208      91.189.89.134  80        
ESTAB      AF_INET   ubuntu.local   22         192.168.0.248  9689      
ESTAB      AF_INET   ubuntu.local   22         192.168.0.248  9295      
ESTAB      AF_INET   ubuntu.local   35531      91.189.94.25   80        
ESTAB      AF_INET   ubuntu.local   22         192.168.0.248  9691  

本文的实验 并没有实现怎么样获取TCP的窗口值cwnd和RTT值,在ss源码中我看到了他利用了/proc

文件来实现获取窗口和RTT值,怎么样用netlink套接字实现呢?还请教各位指点
源代码:

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct sk_req { struct nlmsghdr nlh; struct inet_diag_req r;};typedef struct{ __u8 family; __u8 bytelen; __s16 bitlen; __u32 flags; __u32 data[8];} inet_prefix;/*struct namerec{ struct namerec *next; const char *name; inet_prefix addr;};*/struct tcpstat{ inet_prefix local; inet_prefix remote; int lport; int rport; int state; int rq, wq; int timer; int rq, wq; int timer; int timeout; int retrs; unsigned ino; int probes; unsigned uid; int refcnt; unsigned long long sk; int rto, ato, qack, cwnd, ssthresh;};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};static const char *sstate_name[] = { "UNKNOWN", [SS_ESTABLISHED] = "ESTAB", [SS_SYN_SENT] = "SYN-SENT", [SS_SYN_RECV] = "SYN-RECV", [SS_FIN_WAIT1] = "FIN-WAIT-1", [SS_FIN_WAIT2] = "FIN-WAIT-2", [SS_TIME_WAIT] = "TIME-WAIT", [SS_CLOSE] = "UNCONN", [SS_CLOSE_WAIT] = "CLOSE-WAIT", [SS_LAST_ACK] = "LAST-ACK", [SS_LISTEN] = "LISTEN", [SS_CLOSING] = "CLOSING",};/* Base info structure. It contains socket identity (addrs/ports/cookie) * and, alas, the information shown by netstat./* Base info structure. It contains socket identity (addrs/ports/cookie) * and, alas, the information shown by netstat. struct nlmsghdr { __u32 nlmsg_len; // Length of message including header __u16 nlmsg_type; // Message content __u16 nlmsg_flags; //Additional flags __u32 nlmsg_seq; // Sequence number __u32 nlmsg_pid; // Sending process port ID };*///#ifdef RESOLVE_HOSTNAMESstruct namerec{ struct namerec *next; const char *name; inet_prefix addr;};#define NHASH 257static struct namerec *nht[NHASH];static const char *resolve_address(const void *addr, int len, int af){ struct namerec *n; struct hostent *h_ent; unsigned hash; static int notfirst; if (af == AF_INET6 && ((__u32*)addr)[0] == 0 && ((__u32*)addr)[1] == 0 && ((__u32*)addr)[2] == htonl(0xffff)) { af = AF_INET; addr += 12; len = 4; } hash = *(__u32 *)(addr + len - 4) % NHASH; for (n = nht[hash]; n; n = n->next) { if (n->addr.family == af && n->addr.bytelen == len && memcmp(n->addr.data, addr, len) == 0) return n->name; memcmp(n->addr.data, addr, len) == 0) return n->name; } if ((n = malloc(sizeof(*n))) == NULL) return NULL; n->addr.family = af; n->addr.bytelen = len; n->name = NULL; memcpy(n->addr.data, addr, len); n->next = nht[hash]; nht[hash] = n; if (++notfirst == 1) sethostent(1); fflush(stdout); if ((h_ent = gethostbyaddr(addr, len, af)) != NULL) n->name = strdup(h_ent->h_name); /* Even if we fail, "negative" entry is remembered. */ return n->name;}//#endifconst char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen){ switch (af) { case AF_INET: case AF_INET6: return inet_ntop(af, addr, buf, buflen); /*case AF_IPX: return ipx_ntop(af, addr, buf, buflen); case AF_DECnet: { struct dn_naddr dna = { 2, { 0, 0, }}; memcpy(dna.a_addr, addr, 2); return dnet_ntop(af, &dna, buf, buflen); }*/ default: return "???"; }}void print_info(struct inet_diag_msg *pkg,struct nlmsghdr *h){ struct tcpstat s; char buf[1024]; const char *ap = buf;//存放ip地址 char buf2[1024]; const char *ap2 = buf2;//存放ip地址 struct inet_diag_msg *r = NLMSG_DATA(h); s.state = r->idiag_state; s.local.family = s.remote.family = r->idiag_family; s.lport = ntohs(r->id.idiag_sport); s.rport = ntohs(r->id.idiag_dport); s.local.family = s.remote.family = r->idiag_family; if (s.local.family == AF_INET) { //这里 打印 s.local.bytelen = s.remote.bytelen = 4; } else { s.local.bytelen = s.remote.bytelen = 16; } memcpy(s.local.data, r->id.idiag_src, s.local.bytelen); memcpy(s.remote.data, r->id.idiag_dst, s.local.bytelen); //printf("\n%-*s %-*s %-*s %-*s %-*s %-*s\n", 10,"state",10,"family",10,"l.addr",10,"l.port",10,"r.addr",10,"r.rport"); printf("%-*s ", 10, sstate_name[s.state]); printf("%-*s",10,"AF_INET" ); //printf("\n--------------\n"); const inet_prefix *a=&s.remote; const void *addr = a->data; ap=resolve_address(&s.local.data,4,AF_INET); printf("%-*s",15, ap); printf("%-*d ", 10,s.lport ); //ap2=resolve_address(&s.remote.data,4,AF_INET); ap2=rt_addr_n2a(AF_INET,4,addr,buf2,sizeof(buf2)); printf("%-*s", 15, ap2); printf("%-*d\n",10,s.rport); //printf("L.port:%-*d R.prot:%-*d\n", 10,s.lport ,10,s.rport); //printf("idiag_state:%d\n", pkg->idiag_state); //printf("idiag_state:%d\n", pkg->idiag_state); //printf("Family:%s\n", pkg->idiag_family == AF_INET ? "AF_INET" : "AF_INET6"); // printf("dport:%d, sprot:%d\n", ntohs(pkg->id.idiag_sport), ntohs(pkg->id.idiag_sport)); //printf("idiag_state:%d\n", pkg->idiag_state);}int main(int argc, char **argv){ int fd; struct sk_req req; struct sockaddr_nl dest_addr; 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) { //eprint(__LINE__, errno, "socket"); printf("socket error\n"); return -1; }req.nlh.nlmsg_len = sizeof(req);req.nlh.nlmsg_type = TCPDIAG_GETSOCK;req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;req.nlh.nlmsg_pid = 0;memset(&req.r, 0, sizeof(req.r));req.r.idiag_family = AF_INET;req.r.idiag_states = ((1 << TCP_CLOSING + 1) - 1);iov.iov_base = &req;iov.iov_len = sizeof(req);memset(&dest_addr, 0, sizeof(dest_addr));dest_addr.nl_family = AF_NETLINK;memset(&dest_addr, 0, sizeof(dest_addr));dest_addr.nl_family = AF_NETLINK;dest_addr.nl_pid = 0;dest_addr.nl_groups = 0;memset(&msg, 0, sizeof(msg));msg.msg_name = (void *)&dest_addr;msg.msg_namelen = sizeof(dest_addr);msg.msg_iov = &iov;msg.msg_iovlen = 1;if (sendmsg(fd, &msg, 0) < 0) { //eprint(__LINE__, errno, "sendmsg"); printf("socket error\n"); return -1;}printf("\n%-*s %-*s %-*s %-*s %-*s %-*s\n", 10,"state",10,"family",10,"l.addr",10,"l.port",10,"r.addr",10,"r.rport");memset(buf, 0 ,sizeof(buf));iov.iov_base = buf;iov.iov_len = sizeof(buf);while (1) { int status; struct nlmsghdr *h; msg = (struct msghdr) { (void *)&dest_addr, sizeof(dest_addr), &iov, 1, NULL, 0, 0 }; status = recvmsg(fd, &msg, 0);//recvmsg函数的返回值是读取的字节数, if (status < 0) { if (errno == EINTR) continue; //eprint(__LINE__, errno, "recvmsg"); printf("socket error\n"); continue; } if (status == 0) { printf("EOF on netlink\n"); close(fd); return 0; } h = (struct nlmsghdr *)buf;// #define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \ (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \ (nlh)->nlmsg_len <= (len)) while (NLMSG_OK(h, status)) { struct inet_diag_msg *pkg = NULL; /* struct inet_diag_msg *pkg = NULL; /* 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;}; */ 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); //print_skinfo(pkg); //printf("\n%-*s %-*s %-*s %-*s %-*s %-*s\n", 10,"state",10,"family",10,"l.addr",10,"l.port",10,"r.addr",10,"r.rport"); print_info(pkg,h); //get_tcp_state(pkg->idiag_state); h = NLMSG_NEXT(h, status); //#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))) //#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) ) }//while}//whileclose(fd);return 0;}

你可能感兴趣的文章
Linux系统信息查看
查看>>
用find命令查找最近修改过的文件
查看>>
Android2.1消息应用(Messaging)源码学习笔记
查看>>
在android上运行native可执行程序
查看>>
Phone双模修改涉及文件列表
查看>>
android UI小知识点
查看>>
Android之TelephonyManager类的方法详解
查看>>
android raw读取超过1M文件的方法
查看>>
ubuntu下SVN服务器安装配置
查看>>
MPMoviePlayerViewController和MPMoviePlayerController的使用
查看>>
CocoaPods实践之制作篇
查看>>
[Mac]Mac 操作系统 常见技巧
查看>>
苹果Swift编程语言入门教程【中文版】
查看>>
捕鱼忍者(ninja fishing)之游戏指南+游戏攻略+游戏体验
查看>>
iphone开发基础之objective-c学习
查看>>
iphone开发之SDK研究(待续)
查看>>
计算机网络复习要点
查看>>
Variable property attributes or Modifiers in iOS
查看>>
NSNotificationCenter 用法总结
查看>>
C primer plus 基础总结(一)
查看>>