]> The Tcpdump Group git mirrors - tcpdump/blob - print-mptcp.c
CI: Add warning exemptions for Sun C (suncc-5.14) on Solaris 10
[tcpdump] / print-mptcp.c
1 /**
2 * Copyright (c) 2012
3 *
4 * Gregory Detal <gregory.detal@uclouvain.be>
5 * Christoph Paasch <christoph.paasch@uclouvain.be>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * 3. Neither the name of the University nor of the Laboratory may be used
19 * to endorse or promote products derived from this software without
20 * specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 /* \summary: Multipath TCP (MPTCP) printer */
36
37 /* specification: RFC 6824 */
38
39 #include <config.h>
40
41 #include "netdissect-stdinc.h"
42
43 #include "netdissect.h"
44 #include "extract.h"
45 #include "addrtoname.h"
46
47 #include "tcp.h"
48
49 #define MPTCP_SUB_CAPABLE 0x0
50 #define MPTCP_SUB_JOIN 0x1
51 #define MPTCP_SUB_DSS 0x2
52 #define MPTCP_SUB_ADD_ADDR 0x3
53 #define MPTCP_SUB_REMOVE_ADDR 0x4
54 #define MPTCP_SUB_PRIO 0x5
55 #define MPTCP_SUB_FAIL 0x6
56 #define MPTCP_SUB_FCLOSE 0x7
57 #define MPTCP_SUB_TCPRST 0x8
58
59 struct mptcp_option {
60 nd_uint8_t kind;
61 nd_uint8_t len;
62 nd_uint8_t sub_etc; /* subtype upper 4 bits, other stuff lower 4 bits */
63 };
64
65 #define MPTCP_OPT_SUBTYPE(sub_etc) (((sub_etc) >> 4) & 0xF)
66
67 #define MP_CAPABLE_A 0x80
68
69 static const struct tok mp_capable_flags[] = {
70 { MP_CAPABLE_A, "A" },
71 { 0x40, "B" },
72 { 0x20, "C" },
73 { 0x10, "D" },
74 { 0x08, "E" },
75 { 0x04, "F" },
76 { 0x02, "G" },
77 { 0x01, "H" },
78 { 0, NULL }
79 };
80
81 struct mp_capable {
82 nd_uint8_t kind;
83 nd_uint8_t len;
84 nd_uint8_t sub_ver;
85 nd_uint8_t flags;
86 nd_uint64_t sender_key;
87 nd_uint64_t receiver_key;
88 nd_uint16_t data_len;
89 };
90
91 #define MP_CAPABLE_OPT_VERSION(sub_ver) (((sub_ver) >> 0) & 0xF)
92
93 struct mp_join {
94 nd_uint8_t kind;
95 nd_uint8_t len;
96 nd_uint8_t sub_b;
97 nd_uint8_t addr_id;
98 union {
99 struct {
100 nd_uint32_t token;
101 nd_uint32_t nonce;
102 } syn;
103 struct {
104 nd_uint64_t mac;
105 nd_uint32_t nonce;
106 } synack;
107 struct {
108 nd_byte mac[20];
109 } ack;
110 } u;
111 };
112
113 #define MP_JOIN_B 0x01
114
115 struct mp_dss {
116 nd_uint8_t kind;
117 nd_uint8_t len;
118 nd_uint8_t sub;
119 nd_uint8_t flags;
120 };
121
122 #define MP_DSS_F 0x10
123 #define MP_DSS_m 0x08
124 #define MP_DSS_M 0x04
125 #define MP_DSS_a 0x02
126 #define MP_DSS_A 0x01
127
128 static const struct tok mptcp_addr_subecho_bits[] = {
129 { 0x6, "v0-ip6" },
130 { 0x4, "v0-ip4" },
131 { 0x1, "v1-echo" },
132 { 0x0, "v1" },
133 { 0, NULL }
134 };
135
136 struct mp_add_addr {
137 nd_uint8_t kind;
138 nd_uint8_t len;
139 nd_uint8_t sub_echo;
140 nd_uint8_t addr_id;
141 union {
142 struct {
143 nd_ipv4 addr;
144 nd_uint16_t port;
145 nd_uint64_t mac;
146 } v4;
147 struct {
148 nd_ipv4 addr;
149 nd_uint64_t mac;
150 } v4np;
151 struct {
152 nd_ipv6 addr;
153 nd_uint16_t port;
154 nd_uint64_t mac;
155 } v6;
156 struct {
157 nd_ipv6 addr;
158 nd_uint64_t mac;
159 } v6np;
160 } u;
161 };
162
163 struct mp_remove_addr {
164 nd_uint8_t kind;
165 nd_uint8_t len;
166 nd_uint8_t sub;
167 /* list of addr_id */
168 nd_uint8_t addrs_id[1];
169 };
170
171 struct mp_fail {
172 nd_uint8_t kind;
173 nd_uint8_t len;
174 nd_uint8_t sub;
175 nd_uint8_t resv;
176 nd_uint64_t data_seq;
177 };
178
179 struct mp_close {
180 nd_uint8_t kind;
181 nd_uint8_t len;
182 nd_uint8_t sub;
183 nd_uint8_t rsv;
184 nd_byte key[8];
185 };
186
187 struct mp_prio {
188 nd_uint8_t kind;
189 nd_uint8_t len;
190 nd_uint8_t sub_b;
191 nd_uint8_t addr_id;
192 };
193
194 #define MP_PRIO_B 0x01
195
196 static const struct tok mp_tcprst_flags[] = {
197 { 0x08, "U" },
198 { 0x04, "V" },
199 { 0x02, "W" },
200 { 0x01, "T" },
201 { 0, NULL }
202 };
203
204 static const struct tok mp_tcprst_reasons[] = {
205 { 0x06, "Middlebox interference" },
206 { 0x05, "Unacceptable performance" },
207 { 0x04, "Too much outstanding data" },
208 { 0x03, "Administratively prohibited" },
209 { 0x02, "Lack of resources" },
210 { 0x01, "MPTCP-specific error" },
211 { 0x00, "Unspecified error" },
212 { 0, NULL }
213 };
214
215 struct mp_tcprst {
216 nd_uint8_t kind;
217 nd_uint8_t len;
218 nd_uint8_t sub_b;
219 nd_uint8_t reason;
220 };
221
222 static int
223 dummy_print(netdissect_options *ndo _U_,
224 const u_char *opt _U_, u_int opt_len _U_, u_char flags _U_)
225 {
226 return 1;
227 }
228
229 static int
230 mp_capable_print(netdissect_options *ndo,
231 const u_char *opt, u_int opt_len, u_char flags)
232 {
233 const struct mp_capable *mpc = (const struct mp_capable *) opt;
234 uint8_t version, csum_enabled;
235
236 if (!((opt_len == 12 || opt_len == 4) && flags & TH_SYN) &&
237 !((opt_len == 20 || opt_len == 22 || opt_len == 24) && (flags & (TH_SYN | TH_ACK)) ==
238 TH_ACK))
239 return 0;
240
241 version = MP_CAPABLE_OPT_VERSION(GET_U_1(mpc->sub_ver));
242 switch (version) {
243 case 0: /* fall through */
244 case 1:
245 ND_PRINT(" v%u", version);
246 break;
247 default:
248 ND_PRINT(" Unknown Version (%u)", version);
249 return 1;
250 }
251
252 ND_PRINT(" flags [%s]", bittok2str_nosep(mp_capable_flags, "none",
253 GET_U_1(mpc->flags)));
254
255 csum_enabled = GET_U_1(mpc->flags) & MP_CAPABLE_A;
256 if (csum_enabled)
257 ND_PRINT(" csum");
258 if (opt_len == 12 || opt_len >= 20) {
259 ND_PRINT(" {0x%" PRIx64, GET_BE_U_8(mpc->sender_key));
260 if (opt_len >= 20)
261 ND_PRINT(",0x%" PRIx64, GET_BE_U_8(mpc->receiver_key));
262
263 /* RFC 8684 Section 3.1 */
264 if ((opt_len == 22 && !csum_enabled) || opt_len == 24)
265 ND_PRINT(",data_len=%u", GET_BE_U_2(mpc->data_len));
266 ND_PRINT("}");
267 }
268 return 1;
269 }
270
271 static int
272 mp_join_print(netdissect_options *ndo,
273 const u_char *opt, u_int opt_len, u_char flags)
274 {
275 const struct mp_join *mpj = (const struct mp_join *) opt;
276
277 if (!(opt_len == 12 && (flags & TH_SYN)) &&
278 !(opt_len == 16 && (flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) &&
279 !(opt_len == 24 && (flags & TH_ACK)))
280 return 0;
281
282 if (opt_len != 24) {
283 if (GET_U_1(mpj->sub_b) & MP_JOIN_B)
284 ND_PRINT(" backup");
285 ND_PRINT(" id %u", GET_U_1(mpj->addr_id));
286 }
287
288 switch (opt_len) {
289 case 12: /* SYN */
290 ND_PRINT(" token 0x%x" " nonce 0x%x",
291 GET_BE_U_4(mpj->u.syn.token),
292 GET_BE_U_4(mpj->u.syn.nonce));
293 break;
294 case 16: /* SYN/ACK */
295 ND_PRINT(" hmac 0x%" PRIx64 " nonce 0x%x",
296 GET_BE_U_8(mpj->u.synack.mac),
297 GET_BE_U_4(mpj->u.synack.nonce));
298 break;
299 case 24: {/* ACK */
300 size_t i;
301 ND_PRINT(" hmac 0x");
302 for (i = 0; i < sizeof(mpj->u.ack.mac); ++i)
303 ND_PRINT("%02x", mpj->u.ack.mac[i]);
304 }
305 default:
306 break;
307 }
308 return 1;
309 }
310
311 static int
312 mp_dss_print(netdissect_options *ndo,
313 const u_char *opt, u_int opt_len, u_char flags)
314 {
315 const struct mp_dss *mdss = (const struct mp_dss *) opt;
316 uint8_t mdss_flags;
317
318 /* We need the flags, at a minimum. */
319 if (opt_len < 4)
320 return 0;
321
322 if (flags & TH_SYN)
323 return 0;
324
325 mdss_flags = GET_U_1(mdss->flags);
326 if (mdss_flags & MP_DSS_F)
327 ND_PRINT(" fin");
328
329 opt += 4;
330 opt_len -= 4;
331 if (mdss_flags & MP_DSS_A) {
332 /* Ack present */
333 ND_PRINT(" ack ");
334 /*
335 * If the a flag is set, we have an 8-byte ack; if it's
336 * clear, we have a 4-byte ack.
337 */
338 if (mdss_flags & MP_DSS_a) {
339 if (opt_len < 8)
340 return 0;
341 ND_PRINT("%" PRIu64, GET_BE_U_8(opt));
342 opt += 8;
343 opt_len -= 8;
344 } else {
345 if (opt_len < 4)
346 return 0;
347 ND_PRINT("%u", GET_BE_U_4(opt));
348 opt += 4;
349 opt_len -= 4;
350 }
351 }
352
353 if (mdss_flags & MP_DSS_M) {
354 /*
355 * Data Sequence Number (DSN), Subflow Sequence Number (SSN),
356 * Data-Level Length present, and Checksum possibly present.
357 */
358 ND_PRINT(" seq ");
359 /*
360 * If the m flag is set, we have an 8-byte NDS; if it's clear,
361 * we have a 4-byte DSN.
362 */
363 if (mdss_flags & MP_DSS_m) {
364 if (opt_len < 8)
365 return 0;
366 ND_PRINT("%" PRIu64, GET_BE_U_8(opt));
367 opt += 8;
368 opt_len -= 8;
369 } else {
370 if (opt_len < 4)
371 return 0;
372 ND_PRINT("%u", GET_BE_U_4(opt));
373 opt += 4;
374 opt_len -= 4;
375 }
376 if (opt_len < 4)
377 return 0;
378 ND_PRINT(" subseq %u", GET_BE_U_4(opt));
379 opt += 4;
380 opt_len -= 4;
381 if (opt_len < 2)
382 return 0;
383 ND_PRINT(" len %u", GET_BE_U_2(opt));
384 opt += 2;
385 opt_len -= 2;
386
387 /*
388 * The Checksum is present only if negotiated.
389 * If there are at least 2 bytes left, process the next 2
390 * bytes as the Checksum.
391 */
392 if (opt_len >= 2) {
393 ND_PRINT(" csum 0x%x", GET_BE_U_2(opt));
394 opt_len -= 2;
395 }
396 }
397 if (opt_len != 0)
398 return 0;
399 return 1;
400 }
401
402 static int
403 add_addr_print(netdissect_options *ndo,
404 const u_char *opt, u_int opt_len, u_char flags _U_)
405 {
406 const struct mp_add_addr *add_addr = (const struct mp_add_addr *) opt;
407
408 if (!(opt_len == 8 || opt_len == 10 || opt_len == 16 || opt_len == 18 ||
409 opt_len == 20 || opt_len == 22 || opt_len == 28 || opt_len == 30))
410 return 0;
411
412 ND_PRINT(" %s",
413 tok2str(mptcp_addr_subecho_bits, "[bad version/echo]",
414 GET_U_1(add_addr->sub_echo) & 0xF));
415 ND_PRINT(" id %u", GET_U_1(add_addr->addr_id));
416 if (opt_len == 8 || opt_len == 10 || opt_len == 16 || opt_len == 18) {
417 ND_PRINT(" %s", GET_IPADDR_STRING(add_addr->u.v4.addr));
418 if (opt_len == 10 || opt_len == 18)
419 ND_PRINT(":%u", GET_BE_U_2(add_addr->u.v4.port));
420 if (opt_len == 16)
421 ND_PRINT(" hmac 0x%" PRIx64, GET_BE_U_8(add_addr->u.v4np.mac));
422 if (opt_len == 18)
423 ND_PRINT(" hmac 0x%" PRIx64, GET_BE_U_8(add_addr->u.v4.mac));
424 }
425
426 if (opt_len == 20 || opt_len == 22 || opt_len == 28 || opt_len == 30) {
427 ND_PRINT(" %s", GET_IP6ADDR_STRING(add_addr->u.v6.addr));
428 if (opt_len == 22 || opt_len == 30)
429 ND_PRINT(":%u", GET_BE_U_2(add_addr->u.v6.port));
430 if (opt_len == 28)
431 ND_PRINT(" hmac 0x%" PRIx64, GET_BE_U_8(add_addr->u.v6np.mac));
432 if (opt_len == 30)
433 ND_PRINT(" hmac 0x%" PRIx64, GET_BE_U_8(add_addr->u.v6.mac));
434 }
435
436 return 1;
437 }
438
439 static int
440 remove_addr_print(netdissect_options *ndo,
441 const u_char *opt, u_int opt_len, u_char flags _U_)
442 {
443 const struct mp_remove_addr *remove_addr = (const struct mp_remove_addr *) opt;
444 u_int i;
445
446 if (opt_len < 4)
447 return 0;
448
449 opt_len -= 3;
450 ND_PRINT(" id");
451 for (i = 0; i < opt_len; i++)
452 ND_PRINT(" %u", GET_U_1(remove_addr->addrs_id[i]));
453 return 1;
454 }
455
456 static int
457 mp_prio_print(netdissect_options *ndo,
458 const u_char *opt, u_int opt_len, u_char flags _U_)
459 {
460 const struct mp_prio *mpp = (const struct mp_prio *) opt;
461
462 if (opt_len != 3 && opt_len != 4)
463 return 0;
464
465 if (GET_U_1(mpp->sub_b) & MP_PRIO_B)
466 ND_PRINT(" backup");
467 else
468 ND_PRINT(" non-backup");
469 if (opt_len == 4)
470 ND_PRINT(" id %u", GET_U_1(mpp->addr_id));
471
472 return 1;
473 }
474
475 static int
476 mp_fail_print(netdissect_options *ndo,
477 const u_char *opt, u_int opt_len, u_char flags _U_)
478 {
479 if (opt_len != 12)
480 return 0;
481
482 ND_PRINT(" seq %" PRIu64, GET_BE_U_8(opt + 4));
483 return 1;
484 }
485
486 static int
487 mp_fast_close_print(netdissect_options *ndo,
488 const u_char *opt, u_int opt_len, u_char flags _U_)
489 {
490 if (opt_len != 12)
491 return 0;
492
493 ND_PRINT(" key 0x%" PRIx64, GET_BE_U_8(opt + 4));
494 return 1;
495 }
496
497 static int
498 mp_tcprst_print(netdissect_options *ndo,
499 const u_char *opt, u_int opt_len, u_char flags _U_)
500 {
501 const struct mp_tcprst *mpr = (const struct mp_tcprst *)opt;
502
503 if (opt_len != 4)
504 return 0;
505
506 ND_PRINT(" flags [%s]", bittok2str_nosep(mp_tcprst_flags, "none",
507 GET_U_1(mpr->sub_b)));
508
509 ND_PRINT(" reason %s", tok2str(mp_tcprst_reasons, "unknown (0x%02x)",
510 GET_U_1(mpr->reason)));
511 return 1;
512 }
513
514 static const struct {
515 const char *name;
516 int (*print)(netdissect_options *, const u_char *, u_int, u_char);
517 } mptcp_options[] = {
518 { "capable", mp_capable_print },
519 { "join", mp_join_print },
520 { "dss", mp_dss_print },
521 { "add-addr", add_addr_print },
522 { "rem-addr", remove_addr_print },
523 { "prio", mp_prio_print },
524 { "fail", mp_fail_print },
525 { "fast-close", mp_fast_close_print },
526 { "tcprst", mp_tcprst_print },
527 { "unknown", dummy_print },
528 };
529
530 int
531 mptcp_print(netdissect_options *ndo,
532 const u_char *cp, u_int len, u_char flags)
533 {
534 const struct mptcp_option *opt;
535 u_int subtype;
536
537 ndo->ndo_protocol = "mptcp";
538 if (len < 3)
539 return 0;
540
541 opt = (const struct mptcp_option *) cp;
542 subtype = MPTCP_OPT_SUBTYPE(GET_U_1(opt->sub_etc));
543 subtype = ND_MIN(subtype, MPTCP_SUB_TCPRST + 1);
544
545 ND_PRINT(" %u", len);
546
547 ND_PRINT(" %s", mptcp_options[subtype].name);
548 return mptcp_options[subtype].print(ndo, cp, len, flags);
549 }