参考了 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
#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>
#include <netdb.h>
#include<arpa/inet.h>
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_HOSTNAMES
struct namerec
{
struct namerec *next;
const char *name;
inet_prefix addr;
};
#define NHASH 257
static 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;
}
//#endif
const 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
}//while
close(fd);
return 0;
}
linux netlink套接字实现类似ss命令 ,统计套接字以及TCP信息,布布扣,bubuko.com
linux netlink套接字实现类似ss命令 ,统计套接字以及TCP信息
原文地址:http://blog.csdn.net/scdxmoe/article/details/27820093