88#include <sys/socket.h>
99#include <netinet/in.h>
1010#include <linux/tcp.h>
11+ #include <arpa/inet.h>
1112
1213#include <unistd.h>
1314#include <stdlib.h>
1920#define IPPROTO_MPTCP 262
2021#endif
2122
23+ #define parse_rtattr_nested (tb , max , rta ) \
24+ (parse_rtattr_flags((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta), \
25+ NLA_F_NESTED))
26+
2227struct params {
2328 __u32 target_token ;
29+ char subflow_addr [1024 ];
2430};
2531
2632struct mptcp_info {
@@ -58,7 +64,9 @@ static void die_perror(const char *msg)
5864
5965static void die_usage (int r )
6066{
61- fprintf (stderr , "Usage: mptcp_diag -t\n" );
67+ fprintf (stderr , "Usage:\n"
68+ "mptcp_diag -t <token>\n"
69+ "mptcp_diag -s \"<saddr> <sport> <daddr> <dport>\"\n" );
6270 exit (r );
6371}
6472
@@ -182,6 +190,21 @@ static void parse_nlmsg(struct nlmsghdr *nlh, __u32 proto)
182190 }
183191 print_info_msg (info );
184192 }
193+ if (proto == IPPROTO_TCP && tb [INET_DIAG_ULP_INFO ]) {
194+ struct rtattr * ulpinfo [INET_ULP_INFO_MAX + 1 ] = { 0 };
195+
196+ parse_rtattr_nested (ulpinfo , INET_ULP_INFO_MAX ,
197+ tb [INET_DIAG_ULP_INFO ]);
198+
199+ if (ulpinfo [INET_ULP_INFO_MPTCP ]) {
200+ struct rtattr * sfinfo [MPTCP_SUBFLOW_ATTR_MAX + 1 ] = { 0 };
201+
202+ parse_rtattr_nested (sfinfo , MPTCP_SUBFLOW_ATTR_MAX ,
203+ ulpinfo [INET_ULP_INFO_MPTCP ]);
204+ } else {
205+ printf ("It's a normal TCP!\n" );
206+ }
207+ }
185208}
186209
187210static void recv_nlmsg (int fd , __u32 proto )
@@ -244,21 +267,59 @@ static void get_mptcpinfo(__u32 token)
244267 close (fd );
245268}
246269
270+ static void get_subflow_info (char * subflow_addr )
271+ {
272+ struct inet_diag_req_v2 r = {
273+ .sdiag_family = AF_INET ,
274+ .sdiag_protocol = IPPROTO_TCP ,
275+ };
276+ int sport , dport ;
277+ char saddr [64 ]; // Take ipv6 into consideration
278+ char daddr [64 ];
279+ int ret ;
280+ int fd ;
281+
282+ ret = sscanf (subflow_addr , "%s %d %s %d" , saddr , & sport , daddr , & dport );
283+ if (ret != 4 )
284+ die_perror ("IP PORT Pairs has style problems!" );
285+
286+ printf ("%s:%d -> %s:%d\n" , saddr , sport , daddr , dport );
287+
288+ fd = socket (AF_NETLINK , SOCK_RAW , NETLINK_SOCK_DIAG );
289+ if (fd < 0 )
290+ die_perror ("Netlink socket" );
291+
292+ r .id .idiag_cookie [0 ] = INET_DIAG_NOCOOKIE ;
293+ r .id .idiag_cookie [1 ] = INET_DIAG_NOCOOKIE ;
294+ r .id .idiag_sport = htons (sport );
295+ r .id .idiag_dport = htons (dport );
296+ r .id .idiag_if = 0 ;
297+
298+ inet_pton (AF_INET , saddr , & r .id .idiag_src );
299+ inet_pton (AF_INET , daddr , & r .id .idiag_dst );
300+ r .idiag_ext |= (1 << (INET_DIAG_INFO - 1 ));
301+ send_query (fd , & r , IPPROTO_TCP );
302+ recv_nlmsg (fd , IPPROTO_TCP );
303+ }
304+
247305static void parse_opts (int argc , char * * argv , struct params * p )
248306{
249307 int c ;
250308
251309 if (argc < 2 )
252310 die_usage (1 );
253311
254- while ((c = getopt (argc , argv , "ht:" )) != -1 ) {
312+ while ((c = getopt (argc , argv , "ht:s: " )) != -1 ) {
255313 switch (c ) {
256314 case 'h' :
257315 die_usage (0 );
258316 break ;
259317 case 't' :
260318 sscanf (optarg , "%x" , & p -> target_token );
261319 break ;
320+ case 's' :
321+ snprintf (p -> subflow_addr , strlen (optarg ) + 1 , "%s" , optarg );
322+ break ;
262323 default :
263324 die_usage (1 );
264325 break ;
@@ -275,6 +336,9 @@ int main(int argc, char *argv[])
275336 if (p .target_token )
276337 get_mptcpinfo (p .target_token );
277338
339+ if (strlen (p .subflow_addr ) != 0 )
340+ get_subflow_info (p .subflow_addr );
341+
278342 return 0 ;
279343}
280344
0 commit comments