]> The Tcpdump Group git mirrors - tcpdump/blob - print-mptcp.c
4dd450b9f52ad70931f215e144fe0ff37f42d9de
[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 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42
43 #include "netdissect-stdinc.h"
44
45 #include "netdissect.h"
46 #include "extract.h"
47 #include "addrtoname.h"
48
49 #include "tcp.h"
50
51 #define MPTCP_SUB_CAPABLE 0x0
52 #define MPTCP_SUB_JOIN 0x1
53 #define MPTCP_SUB_DSS 0x2
54 #define MPTCP_SUB_ADD_ADDR 0x3
55 #define MPTCP_SUB_REMOVE_ADDR 0x4
56 #define MPTCP_SUB_PRIO 0x5
57 #define MPTCP_SUB_FAIL 0x6
58 #define MPTCP_SUB_FCLOSE 0x7
59
60 struct mptcp_option {
61 nd_uint8_t kind;
62 nd_uint8_t len;
63 nd_uint8_t sub_etc; /* subtype upper 4 bits, other stuff lower 4 bits */
64 };
65
66 #define MPTCP_OPT_SUBTYPE(sub_etc) ((EXTRACT_U_1(sub_etc) >> 4) & 0xF)
67
68 struct mp_capable {
69 nd_uint8_t kind;
70 nd_uint8_t len;
71 nd_uint8_t sub_ver;
72 nd_uint8_t flags;
73 nd_uint64_t sender_key;
74 nd_uint64_t receiver_key;
75 };
76
77 #define MP_CAPABLE_OPT_VERSION(sub_ver) ((EXTRACT_U_1(sub_ver) >> 0) & 0xF)
78 #define MP_CAPABLE_C 0x80
79 #define MP_CAPABLE_S 0x01
80
81 struct mp_join {
82 nd_uint8_t kind;
83 nd_uint8_t len;
84 nd_uint8_t sub_b;
85 nd_uint8_t addr_id;
86 union {
87 struct {
88 nd_uint32_t token;
89 nd_uint32_t nonce;
90 } syn;
91 struct {
92 nd_uint64_t mac;
93 nd_uint32_t nonce;
94 } synack;
95 struct {
96 nd_byte mac[20];
97 } ack;
98 } u;
99 };
100
101 #define MP_JOIN_B 0x01
102
103 struct mp_dss {
104 nd_uint8_t kind;
105 nd_uint8_t len;
106 nd_uint8_t sub;
107 nd_uint8_t flags;
108 };
109
110 #define MP_DSS_F 0x10
111 #define MP_DSS_m 0x08
112 #define MP_DSS_M 0x04
113 #define MP_DSS_a 0x02
114 #define MP_DSS_A 0x01
115
116 struct mp_add_addr {
117 nd_uint8_t kind;
118 nd_uint8_t len;
119 nd_uint8_t sub_ipver;
120 nd_uint8_t addr_id;
121 union {
122 struct {
123 nd_ipv4 addr;
124 nd_uint16_t port;
125 } v4;
126 struct {
127 nd_ipv6 addr;
128 nd_uint16_t port;
129 } v6;
130 } u;
131 };
132
133 #define MP_ADD_ADDR_IPVER(sub_ipver) ((EXTRACT_U_1(sub_ipver) >> 0) & 0xF)
134
135 struct mp_remove_addr {
136 nd_uint8_t kind;
137 nd_uint8_t len;
138 nd_uint8_t sub;
139 /* list of addr_id */
140 nd_uint8_t addrs_id[1];
141 };
142
143 struct mp_fail {
144 nd_uint8_t kind;
145 nd_uint8_t len;
146 nd_uint8_t sub;
147 nd_uint8_t resv;
148 nd_uint64_t data_seq;
149 };
150
151 struct mp_close {
152 nd_uint8_t kind;
153 nd_uint8_t len;
154 nd_uint8_t sub;
155 nd_uint8_t rsv;
156 nd_byte key[8];
157 };
158
159 struct mp_prio {
160 nd_uint8_t kind;
161 nd_uint8_t len;
162 nd_uint8_t sub_b;
163 nd_uint8_t addr_id;
164 };
165
166 #define MP_PRIO_B 0x01
167
168 static int
169 dummy_print(netdissect_options *ndo _U_,
170 const u_char *opt _U_, u_int opt_len _U_, u_char flags _U_)
171 {
172 return 1;
173 }
174
175 static int
176 mp_capable_print(netdissect_options *ndo,
177 const u_char *opt, u_int opt_len, u_char flags)
178 {
179 const struct mp_capable *mpc = (const struct mp_capable *) opt;
180
181 if (!(opt_len == 12 && (flags & TH_SYN)) &&
182 !(opt_len == 20 && (flags & (TH_SYN | TH_ACK)) == TH_ACK))
183 return 0;
184
185 if (MP_CAPABLE_OPT_VERSION(mpc->sub_ver) != 0) {
186 ND_PRINT(" Unknown Version (%u)", MP_CAPABLE_OPT_VERSION(mpc->sub_ver));
187 return 1;
188 }
189
190 if (EXTRACT_U_1(mpc->flags) & MP_CAPABLE_C)
191 ND_PRINT(" csum");
192 ND_PRINT(" {0x%" PRIx64, EXTRACT_BE_U_8(mpc->sender_key));
193 if (opt_len == 20) /* ACK */
194 ND_PRINT(",0x%" PRIx64, EXTRACT_BE_U_8(mpc->receiver_key));
195 ND_PRINT("}");
196 return 1;
197 }
198
199 static int
200 mp_join_print(netdissect_options *ndo,
201 const u_char *opt, u_int opt_len, u_char flags)
202 {
203 const struct mp_join *mpj = (const struct mp_join *) opt;
204
205 if (!(opt_len == 12 && (flags & TH_SYN)) &&
206 !(opt_len == 16 && (flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) &&
207 !(opt_len == 24 && (flags & TH_ACK)))
208 return 0;
209
210 if (opt_len != 24) {
211 if (EXTRACT_U_1(mpj->sub_b) & MP_JOIN_B)
212 ND_PRINT(" backup");
213 ND_PRINT(" id %u", EXTRACT_U_1(mpj->addr_id));
214 }
215
216 switch (opt_len) {
217 case 12: /* SYN */
218 ND_PRINT(" token 0x%x" " nonce 0x%x",
219 EXTRACT_BE_U_4(mpj->u.syn.token),
220 EXTRACT_BE_U_4(mpj->u.syn.nonce));
221 break;
222 case 16: /* SYN/ACK */
223 ND_PRINT(" hmac 0x%" PRIx64 " nonce 0x%x",
224 EXTRACT_BE_U_8(mpj->u.synack.mac),
225 EXTRACT_BE_U_4(mpj->u.synack.nonce));
226 break;
227 case 24: {/* ACK */
228 size_t i;
229 ND_PRINT(" hmac 0x");
230 for (i = 0; i < sizeof(mpj->u.ack.mac); ++i)
231 ND_PRINT("%02x", mpj->u.ack.mac[i]);
232 }
233 default:
234 break;
235 }
236 return 1;
237 }
238
239 static int
240 mp_dss_print(netdissect_options *ndo,
241 const u_char *opt, u_int opt_len, u_char flags)
242 {
243 const struct mp_dss *mdss = (const struct mp_dss *) opt;
244 uint8_t mdss_flags;
245
246 /* We need the flags, at a minimum. */
247 if (opt_len < 4)
248 return 0;
249
250 if (flags & TH_SYN)
251 return 0;
252
253 mdss_flags = EXTRACT_U_1(mdss->flags);
254 if (mdss_flags & MP_DSS_F)
255 ND_PRINT(" fin");
256
257 opt += 4;
258 opt_len -= 4;
259 if (mdss_flags & MP_DSS_A) {
260 /* Ack present */
261 ND_PRINT(" ack ");
262 /*
263 * If the a flag is set, we have an 8-byte ack; if it's
264 * clear, we have a 4-byte ack.
265 */
266 if (mdss_flags & MP_DSS_a) {
267 if (opt_len < 8)
268 return 0;
269 ND_PRINT("%" PRIu64, EXTRACT_BE_U_8(opt));
270 opt += 8;
271 opt_len -= 8;
272 } else {
273 if (opt_len < 4)
274 return 0;
275 ND_PRINT("%u", EXTRACT_BE_U_4(opt));
276 opt += 4;
277 opt_len -= 4;
278 }
279 }
280
281 if (mdss_flags & MP_DSS_M) {
282 /*
283 * Data Sequence Number (DSN), Subflow Sequence Number (SSN),
284 * Data-Level Length present, and Checksum possibly present.
285 */
286 ND_PRINT(" seq ");
287 /*
288 * If the m flag is set, we have an 8-byte NDS; if it's clear,
289 * we have a 4-byte DSN.
290 */
291 if (mdss_flags & MP_DSS_m) {
292 if (opt_len < 8)
293 return 0;
294 ND_PRINT("%" PRIu64, EXTRACT_BE_U_8(opt));
295 opt += 8;
296 opt_len -= 8;
297 } else {
298 if (opt_len < 4)
299 return 0;
300 ND_PRINT("%u", EXTRACT_BE_U_4(opt));
301 opt += 4;
302 opt_len -= 4;
303 }
304 if (opt_len < 4)
305 return 0;
306 ND_PRINT(" subseq %u", EXTRACT_BE_U_4(opt));
307 opt += 4;
308 opt_len -= 4;
309 if (opt_len < 2)
310 return 0;
311 ND_PRINT(" len %u", EXTRACT_BE_U_2(opt));
312 opt += 2;
313 opt_len -= 2;
314
315 /*
316 * The Checksum is present only if negotiated.
317 * If there are at least 2 bytes left, process the next 2
318 * bytes as the Checksum.
319 */
320 if (opt_len >= 2) {
321 ND_PRINT(" csum 0x%x", EXTRACT_BE_U_2(opt));
322 opt_len -= 2;
323 }
324 }
325 if (opt_len != 0)
326 return 0;
327 return 1;
328 }
329
330 static int
331 add_addr_print(netdissect_options *ndo,
332 const u_char *opt, u_int opt_len, u_char flags _U_)
333 {
334 const struct mp_add_addr *add_addr = (const struct mp_add_addr *) opt;
335 u_int ipver = MP_ADD_ADDR_IPVER(add_addr->sub_ipver);
336
337 if (!((opt_len == 8 || opt_len == 10) && ipver == 4) &&
338 !((opt_len == 20 || opt_len == 22) && ipver == 6))
339 return 0;
340
341 ND_PRINT(" id %u", EXTRACT_U_1(add_addr->addr_id));
342 switch (ipver) {
343 case 4:
344 ND_PRINT(" %s", ipaddr_string(ndo, add_addr->u.v4.addr));
345 if (opt_len == 10)
346 ND_PRINT(":%u", EXTRACT_BE_U_2(add_addr->u.v4.port));
347 break;
348 case 6:
349 ND_PRINT(" %s", ip6addr_string(ndo, add_addr->u.v6.addr));
350 if (opt_len == 22)
351 ND_PRINT(":%u", EXTRACT_BE_U_2(add_addr->u.v6.port));
352 break;
353 default:
354 return 0;
355 }
356
357 return 1;
358 }
359
360 static int
361 remove_addr_print(netdissect_options *ndo,
362 const u_char *opt, u_int opt_len, u_char flags _U_)
363 {
364 const struct mp_remove_addr *remove_addr = (const struct mp_remove_addr *) opt;
365 u_int i;
366
367 if (opt_len < 4)
368 return 0;
369
370 opt_len -= 3;
371 ND_PRINT(" id");
372 for (i = 0; i < opt_len; i++)
373 ND_PRINT(" %u", EXTRACT_U_1(remove_addr->addrs_id[i]));
374 return 1;
375 }
376
377 static int
378 mp_prio_print(netdissect_options *ndo,
379 const u_char *opt, u_int opt_len, u_char flags _U_)
380 {
381 const struct mp_prio *mpp = (const struct mp_prio *) opt;
382
383 if (opt_len != 3 && opt_len != 4)
384 return 0;
385
386 if (EXTRACT_U_1(mpp->sub_b) & MP_PRIO_B)
387 ND_PRINT(" backup");
388 else
389 ND_PRINT(" non-backup");
390 if (opt_len == 4)
391 ND_PRINT(" id %u", EXTRACT_U_1(mpp->addr_id));
392
393 return 1;
394 }
395
396 static int
397 mp_fail_print(netdissect_options *ndo,
398 const u_char *opt, u_int opt_len, u_char flags _U_)
399 {
400 if (opt_len != 12)
401 return 0;
402
403 ND_PRINT(" seq %" PRIu64, EXTRACT_BE_U_8(opt + 4));
404 return 1;
405 }
406
407 static int
408 mp_fast_close_print(netdissect_options *ndo,
409 const u_char *opt, u_int opt_len, u_char flags _U_)
410 {
411 if (opt_len != 12)
412 return 0;
413
414 ND_PRINT(" key 0x%" PRIx64, EXTRACT_BE_U_8(opt + 4));
415 return 1;
416 }
417
418 static const struct {
419 const char *name;
420 int (*print)(netdissect_options *, const u_char *, u_int, u_char);
421 } mptcp_options[] = {
422 { "capable", mp_capable_print},
423 { "join", mp_join_print },
424 { "dss", mp_dss_print },
425 { "add-addr", add_addr_print },
426 { "rem-addr", remove_addr_print },
427 { "prio", mp_prio_print },
428 { "fail", mp_fail_print },
429 { "fast-close", mp_fast_close_print },
430 { "unknown", dummy_print },
431 };
432
433 int
434 mptcp_print(netdissect_options *ndo,
435 const u_char *cp, u_int len, u_char flags)
436 {
437 const struct mptcp_option *opt;
438 u_int subtype;
439
440 if (len < 3)
441 return 0;
442
443 opt = (const struct mptcp_option *) cp;
444 subtype = min(MPTCP_OPT_SUBTYPE(opt->sub_etc), MPTCP_SUB_FCLOSE + 1);
445
446 ND_PRINT(" %s", mptcp_options[subtype].name);
447 return mptcp_options[subtype].print(ndo, cp, len, flags);
448 }