8
8
#include <sys/socket.h>
9
9
#include <netinet/in.h>
10
10
#include <linux/tcp.h>
11
+ #include <arpa/inet.h>
11
12
12
13
#include <unistd.h>
13
14
#include <stdlib.h>
19
20
#define IPPROTO_MPTCP 262
20
21
#endif
21
22
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
+
22
27
struct params {
23
28
__u32 target_token ;
29
+ char subflow_addrs [1024 ];
24
30
};
25
31
26
32
struct mptcp_info {
@@ -50,6 +56,37 @@ struct mptcp_info {
50
56
__u32 mptcpi_last_ack_recv ;
51
57
};
52
58
59
+ enum {
60
+ MPTCP_SUBFLOW_ATTR_UNSPEC ,
61
+ MPTCP_SUBFLOW_ATTR_TOKEN_REM ,
62
+ MPTCP_SUBFLOW_ATTR_TOKEN_LOC ,
63
+ MPTCP_SUBFLOW_ATTR_RELWRITE_SEQ ,
64
+ MPTCP_SUBFLOW_ATTR_MAP_SEQ ,
65
+ MPTCP_SUBFLOW_ATTR_MAP_SFSEQ ,
66
+ MPTCP_SUBFLOW_ATTR_SSN_OFFSET ,
67
+ MPTCP_SUBFLOW_ATTR_MAP_DATALEN ,
68
+ MPTCP_SUBFLOW_ATTR_FLAGS ,
69
+ MPTCP_SUBFLOW_ATTR_ID_REM ,
70
+ MPTCP_SUBFLOW_ATTR_ID_LOC ,
71
+ MPTCP_SUBFLOW_ATTR_PAD ,
72
+
73
+ __MPTCP_SUBFLOW_ATTR_MAX
74
+ };
75
+
76
+ #define MPTCP_SUBFLOW_ATTR_MAX (__MPTCP_SUBFLOW_ATTR_MAX - 1)
77
+
78
+ #define MPTCP_SUBFLOW_FLAG_MCAP_REM _BITUL(0)
79
+ #define MPTCP_SUBFLOW_FLAG_MCAP_LOC _BITUL(1)
80
+ #define MPTCP_SUBFLOW_FLAG_JOIN_REM _BITUL(2)
81
+ #define MPTCP_SUBFLOW_FLAG_JOIN_LOC _BITUL(3)
82
+ #define MPTCP_SUBFLOW_FLAG_BKUP_REM _BITUL(4)
83
+ #define MPTCP_SUBFLOW_FLAG_BKUP_LOC _BITUL(5)
84
+ #define MPTCP_SUBFLOW_FLAG_FULLY_ESTABLISHED _BITUL(6)
85
+ #define MPTCP_SUBFLOW_FLAG_CONNECTED _BITUL(7)
86
+ #define MPTCP_SUBFLOW_FLAG_MAPVALID _BITUL(8)
87
+
88
+ #define rta_getattr (type , value ) (*(type *)RTA_DATA(value))
89
+
53
90
static void die_perror (const char * msg )
54
91
{
55
92
perror (msg );
@@ -58,7 +95,9 @@ static void die_perror(const char *msg)
58
95
59
96
static void die_usage (int r )
60
97
{
61
- fprintf (stderr , "Usage: mptcp_diag -t\n" );
98
+ fprintf (stderr , "Usage:\n"
99
+ "mptcp_diag -t <token>\n"
100
+ "mptcp_diag -s \"<saddr>:<sport> <daddr>:<dport>\"\n" );
62
101
exit (r );
63
102
}
64
103
@@ -159,6 +198,66 @@ static void print_info_msg(struct mptcp_info *info)
159
198
printf ("bytes_acked: %llu\n" , info -> mptcpi_bytes_acked );
160
199
}
161
200
201
+ /*
202
+ * 'print_subflow_info' is from 'mptcp_subflow_info'
203
+ * which is a function in 'misc/ss.c' of iproute2.
204
+ */
205
+ static void print_subflow_info (struct rtattr * tb [])
206
+ {
207
+ u_int32_t flags = 0 ;
208
+
209
+ printf ("It's a mptcp subflow, the subflow info:\n" );
210
+ if (tb [MPTCP_SUBFLOW_ATTR_FLAGS ]) {
211
+ char caps [32 + 1 ] = { 0 }, * cap = & caps [0 ];
212
+
213
+ flags = rta_getattr (__u32 , tb [MPTCP_SUBFLOW_ATTR_FLAGS ]);
214
+
215
+ if (flags & MPTCP_SUBFLOW_FLAG_MCAP_REM )
216
+ * cap ++ = 'M' ;
217
+ if (flags & MPTCP_SUBFLOW_FLAG_MCAP_LOC )
218
+ * cap ++ = 'm' ;
219
+ if (flags & MPTCP_SUBFLOW_FLAG_JOIN_REM )
220
+ * cap ++ = 'J' ;
221
+ if (flags & MPTCP_SUBFLOW_FLAG_JOIN_LOC )
222
+ * cap ++ = 'j' ;
223
+ if (flags & MPTCP_SUBFLOW_FLAG_BKUP_REM )
224
+ * cap ++ = 'B' ;
225
+ if (flags & MPTCP_SUBFLOW_FLAG_BKUP_LOC )
226
+ * cap ++ = 'b' ;
227
+ if (flags & MPTCP_SUBFLOW_FLAG_FULLY_ESTABLISHED )
228
+ * cap ++ = 'e' ;
229
+ if (flags & MPTCP_SUBFLOW_FLAG_CONNECTED )
230
+ * cap ++ = 'c' ;
231
+ if (flags & MPTCP_SUBFLOW_FLAG_MAPVALID )
232
+ * cap ++ = 'v' ;
233
+
234
+ if (flags )
235
+ printf (" flags:%s" , caps );
236
+ }
237
+ if (tb [MPTCP_SUBFLOW_ATTR_TOKEN_REM ] &&
238
+ tb [MPTCP_SUBFLOW_ATTR_TOKEN_LOC ] &&
239
+ tb [MPTCP_SUBFLOW_ATTR_ID_REM ] &&
240
+ tb [MPTCP_SUBFLOW_ATTR_ID_LOC ])
241
+ printf (" token:%04x(id:%u)/%04x(id:%u)" ,
242
+ rta_getattr (__u32 , tb [MPTCP_SUBFLOW_ATTR_TOKEN_REM ]),
243
+ rta_getattr (__u8 , tb [MPTCP_SUBFLOW_ATTR_ID_REM ]),
244
+ rta_getattr (__u32 , tb [MPTCP_SUBFLOW_ATTR_TOKEN_LOC ]),
245
+ rta_getattr (__u8 , tb [MPTCP_SUBFLOW_ATTR_ID_LOC ]));
246
+ if (tb [MPTCP_SUBFLOW_ATTR_MAP_SEQ ])
247
+ printf (" seq:%llu" ,
248
+ rta_getattr (__u64 , tb [MPTCP_SUBFLOW_ATTR_MAP_SEQ ]));
249
+ if (tb [MPTCP_SUBFLOW_ATTR_MAP_SFSEQ ])
250
+ printf (" sfseq:%u" ,
251
+ rta_getattr (__u32 , tb [MPTCP_SUBFLOW_ATTR_MAP_SFSEQ ]));
252
+ if (tb [MPTCP_SUBFLOW_ATTR_SSN_OFFSET ])
253
+ printf (" ssnoff:%u" ,
254
+ rta_getattr (__u32 , tb [MPTCP_SUBFLOW_ATTR_SSN_OFFSET ]));
255
+ if (tb [MPTCP_SUBFLOW_ATTR_MAP_DATALEN ])
256
+ printf (" maplen:%u" ,
257
+ rta_getattr (__u32 , tb [MPTCP_SUBFLOW_ATTR_MAP_DATALEN ]));
258
+ printf ("\n" );
259
+ }
260
+
162
261
static void parse_nlmsg (struct nlmsghdr * nlh , __u32 proto )
163
262
{
164
263
struct inet_diag_msg * r = NLMSG_DATA (nlh );
@@ -182,6 +281,22 @@ static void parse_nlmsg(struct nlmsghdr *nlh, __u32 proto)
182
281
}
183
282
print_info_msg (info );
184
283
}
284
+ if (proto == IPPROTO_TCP && tb [INET_DIAG_ULP_INFO ]) {
285
+ struct rtattr * ulpinfo [INET_ULP_INFO_MAX + 1 ] = { 0 };
286
+
287
+ parse_rtattr_nested (ulpinfo , INET_ULP_INFO_MAX ,
288
+ tb [INET_DIAG_ULP_INFO ]);
289
+
290
+ if (ulpinfo [INET_ULP_INFO_MPTCP ]) {
291
+ struct rtattr * sfinfo [MPTCP_SUBFLOW_ATTR_MAX + 1 ] = { 0 };
292
+
293
+ parse_rtattr_nested (sfinfo , MPTCP_SUBFLOW_ATTR_MAX ,
294
+ ulpinfo [INET_ULP_INFO_MPTCP ]);
295
+ print_subflow_info (sfinfo );
296
+ } else {
297
+ printf ("It's a normal TCP!\n" );
298
+ }
299
+ }
185
300
}
186
301
187
302
static void recv_nlmsg (int fd , __u32 proto )
@@ -244,21 +359,58 @@ static void get_mptcpinfo(__u32 token)
244
359
close (fd );
245
360
}
246
361
362
+ static void get_subflow_info (char * subflow_addrs )
363
+ {
364
+ struct inet_diag_req_v2 r = {
365
+ .sdiag_family = AF_INET ,
366
+ .sdiag_protocol = IPPROTO_TCP ,
367
+ .id .idiag_cookie [0 ] = INET_DIAG_NOCOOKIE ,
368
+ .id .idiag_cookie [1 ] = INET_DIAG_NOCOOKIE ,
369
+ };
370
+ char saddr [64 ], daddr [64 ];
371
+ int sport , dport ;
372
+ int ret ;
373
+ int fd ;
374
+
375
+ ret = sscanf (subflow_addrs , "%[^:]:%d %[^:]:%d" , saddr , & sport , daddr , & dport );
376
+ if (ret != 4 )
377
+ die_perror ("IP PORT Pairs has style problems!" );
378
+
379
+ printf ("%s:%d -> %s:%d\n" , saddr , sport , daddr , dport );
380
+
381
+ fd = socket (AF_NETLINK , SOCK_RAW , NETLINK_SOCK_DIAG );
382
+ if (fd < 0 )
383
+ die_perror ("Netlink socket" );
384
+
385
+ r .id .idiag_sport = htons (sport );
386
+ r .id .idiag_dport = htons (dport );
387
+
388
+ inet_pton (AF_INET , saddr , & r .id .idiag_src );
389
+ inet_pton (AF_INET , daddr , & r .id .idiag_dst );
390
+ r .idiag_ext |= (1 << (INET_DIAG_INFO - 1 ));
391
+ send_query (fd , & r , IPPROTO_TCP );
392
+ recv_nlmsg (fd , IPPROTO_TCP );
393
+ }
394
+
247
395
static void parse_opts (int argc , char * * argv , struct params * p )
248
396
{
249
397
int c ;
250
398
251
399
if (argc < 2 )
252
400
die_usage (1 );
253
401
254
- while ((c = getopt (argc , argv , "ht:" )) != -1 ) {
402
+ while ((c = getopt (argc , argv , "ht:s: " )) != -1 ) {
255
403
switch (c ) {
256
404
case 'h' :
257
405
die_usage (0 );
258
406
break ;
259
407
case 't' :
260
408
sscanf (optarg , "%x" , & p -> target_token );
261
409
break ;
410
+ case 's' :
411
+ snprintf (p -> subflow_addrs , strlen (optarg ) + 1 ,
412
+ "%s" , optarg );
413
+ break ;
262
414
default :
263
415
die_usage (1 );
264
416
break ;
@@ -275,6 +427,9 @@ int main(int argc, char *argv[])
275
427
if (p .target_token )
276
428
get_mptcpinfo (p .target_token );
277
429
430
+ if (strlen (p .subflow_addrs ) != 0 )
431
+ get_subflow_info (p .subflow_addrs );
432
+
278
433
return 0 ;
279
434
}
280
435
0 commit comments