Refer to the source code of ss
And netlink related information: http://blog.csdn.net/scdxmoe/article/details/27711205
Implementation result:
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 |
The experiment in this article does not implement how to obtain the TCP Window values cwnd and RTT values. In the ss source code, I saw that he used/proc.
File to obtain the window and RTT value, how to use netlink socket to implement it? For more information, see
Source code:
# 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; _ s1 6 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 sk; int rto, ato, qack, cwnd, ssthresh ;}; Enum {SS_UNKNOWN, cosine, SS_SYN_SENT, SS_SYN_RECV, SS_FIN_WAIT1, SS_FIN_WAIT2, SS_TIME_WAIT, SS_CLOSE, cosine, cosine, 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_l En; // Length of message including header _ XHTML nlmsg_type; // Message content _ XHTML 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 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 (0 xffff) {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, }}; me Mcpy (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; // store the IP address char buf2 [1024]; const char * ap2 = buf2; // store the IP address 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. fam Ily = r-> idiag_family; if (s. local. family = AF_INET) {// print s here. 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 \ 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. rp Ort); // 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); Memory = AF_NETLINK; memset (& dest_addr, 0, sizeof (dest_addr); dest_addr.nl_family = AF_NETLINK; latency = 0; latency = 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 erro R \ n "); return-1 ;} printf ("\ n %-* 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); // the return value of the recvmsg function is the number of bytes read, if (stat Us <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 I Net_diag_msg * pkg = NULL;/* struct inet_diag_msg * pkg = NULL;/* struct detail {_ u8 idiag_family; _ u8 idiag_state; _ u8 idiag_timer; _ u8 break; struct inet_diag_sockid; _ 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 = NLM SG_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 \ 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) + NLMSG_ALIGNTO-1 )&~ (NLMSG_ALIGNTO-1)} // while // whileclose (fd); return 0 ;}