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) (((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) (((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 static const struct tok mptcp_addr_subecho_bits[] = { 117 { 0x6, "v0-ip6" }, 118 { 0x4, "v0-ip4" }, 119 { 0x1, "v1-echo" }, 120 { 0x0, "v1" }, 121 { 0, NULL } 122 }; 123 124 struct mp_add_addr { 125 nd_uint8_t kind; 126 nd_uint8_t len; 127 nd_uint8_t sub_echo; 128 nd_uint8_t addr_id; 129 union { 130 struct { 131 nd_ipv4 addr; 132 nd_uint16_t port; 133 nd_uint64_t mac; 134 } v4; 135 struct { 136 nd_ipv4 addr; 137 nd_uint64_t mac; 138 } v4np; 139 struct { 140 nd_ipv6 addr; 141 nd_uint16_t port; 142 nd_uint64_t mac; 143 } v6; 144 struct { 145 nd_ipv6 addr; 146 nd_uint64_t mac; 147 } v6np; 148 } u; 149 }; 150 151 struct mp_remove_addr { 152 nd_uint8_t kind; 153 nd_uint8_t len; 154 nd_uint8_t sub; 155 /* list of addr_id */ 156 nd_uint8_t addrs_id[1]; 157 }; 158 159 struct mp_fail { 160 nd_uint8_t kind; 161 nd_uint8_t len; 162 nd_uint8_t sub; 163 nd_uint8_t resv; 164 nd_uint64_t data_seq; 165 }; 166 167 struct mp_close { 168 nd_uint8_t kind; 169 nd_uint8_t len; 170 nd_uint8_t sub; 171 nd_uint8_t rsv; 172 nd_byte key[8]; 173 }; 174 175 struct mp_prio { 176 nd_uint8_t kind; 177 nd_uint8_t len; 178 nd_uint8_t sub_b; 179 nd_uint8_t addr_id; 180 }; 181 182 #define MP_PRIO_B 0x01 183 184 static int 185 dummy_print(netdissect_options *ndo _U_, 186 const u_char *opt _U_, u_int opt_len _U_, u_char flags _U_) 187 { 188 return 1; 189 } 190 191 static int 192 mp_capable_print(netdissect_options *ndo, 193 const u_char *opt, u_int opt_len, u_char flags) 194 { 195 const struct mp_capable *mpc = (const struct mp_capable *) opt; 196 uint8_t version; 197 198 if (!((opt_len == 12 || opt_len == 4) && flags & TH_SYN) && 199 !((opt_len == 20 || opt_len == 22) && (flags & (TH_SYN | TH_ACK)) == 200 TH_ACK)) 201 return 0; 202 203 version = MP_CAPABLE_OPT_VERSION(GET_U_1(mpc->sub_ver)); 204 switch (version) { 205 case 0: /* fall through */ 206 case 1: 207 ND_PRINT(" v%u", version); 208 break; 209 default: 210 ND_PRINT(" Unknown Version (%u)", version); 211 return 1; 212 } 213 214 if (GET_U_1(mpc->flags) & MP_CAPABLE_C) 215 ND_PRINT(" csum"); 216 if (opt_len == 12 || opt_len >= 20) { 217 ND_PRINT(" {0x%" PRIx64, GET_BE_U_8(mpc->sender_key)); 218 if (opt_len >= 20) 219 ND_PRINT(",0x%" PRIx64, GET_BE_U_8(mpc->receiver_key)); 220 ND_PRINT("}"); 221 } 222 return 1; 223 } 224 225 static int 226 mp_join_print(netdissect_options *ndo, 227 const u_char *opt, u_int opt_len, u_char flags) 228 { 229 const struct mp_join *mpj = (const struct mp_join *) opt; 230 231 if (!(opt_len == 12 && (flags & TH_SYN)) && 232 !(opt_len == 16 && (flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) && 233 !(opt_len == 24 && (flags & TH_ACK))) 234 return 0; 235 236 if (opt_len != 24) { 237 if (GET_U_1(mpj->sub_b) & MP_JOIN_B) 238 ND_PRINT(" backup"); 239 ND_PRINT(" id %u", GET_U_1(mpj->addr_id)); 240 } 241 242 switch (opt_len) { 243 case 12: /* SYN */ 244 ND_PRINT(" token 0x%x" " nonce 0x%x", 245 GET_BE_U_4(mpj->u.syn.token), 246 GET_BE_U_4(mpj->u.syn.nonce)); 247 break; 248 case 16: /* SYN/ACK */ 249 ND_PRINT(" hmac 0x%" PRIx64 " nonce 0x%x", 250 GET_BE_U_8(mpj->u.synack.mac), 251 GET_BE_U_4(mpj->u.synack.nonce)); 252 break; 253 case 24: {/* ACK */ 254 size_t i; 255 ND_PRINT(" hmac 0x"); 256 for (i = 0; i < sizeof(mpj->u.ack.mac); ++i) 257 ND_PRINT("%02x", mpj->u.ack.mac[i]); 258 } 259 default: 260 break; 261 } 262 return 1; 263 } 264 265 static int 266 mp_dss_print(netdissect_options *ndo, 267 const u_char *opt, u_int opt_len, u_char flags) 268 { 269 const struct mp_dss *mdss = (const struct mp_dss *) opt; 270 uint8_t mdss_flags; 271 272 /* We need the flags, at a minimum. */ 273 if (opt_len < 4) 274 return 0; 275 276 if (flags & TH_SYN) 277 return 0; 278 279 mdss_flags = GET_U_1(mdss->flags); 280 if (mdss_flags & MP_DSS_F) 281 ND_PRINT(" fin"); 282 283 opt += 4; 284 opt_len -= 4; 285 if (mdss_flags & MP_DSS_A) { 286 /* Ack present */ 287 ND_PRINT(" ack "); 288 /* 289 * If the a flag is set, we have an 8-byte ack; if it's 290 * clear, we have a 4-byte ack. 291 */ 292 if (mdss_flags & MP_DSS_a) { 293 if (opt_len < 8) 294 return 0; 295 ND_PRINT("%" PRIu64, GET_BE_U_8(opt)); 296 opt += 8; 297 opt_len -= 8; 298 } else { 299 if (opt_len < 4) 300 return 0; 301 ND_PRINT("%u", GET_BE_U_4(opt)); 302 opt += 4; 303 opt_len -= 4; 304 } 305 } 306 307 if (mdss_flags & MP_DSS_M) { 308 /* 309 * Data Sequence Number (DSN), Subflow Sequence Number (SSN), 310 * Data-Level Length present, and Checksum possibly present. 311 */ 312 ND_PRINT(" seq "); 313 /* 314 * If the m flag is set, we have an 8-byte NDS; if it's clear, 315 * we have a 4-byte DSN. 316 */ 317 if (mdss_flags & MP_DSS_m) { 318 if (opt_len < 8) 319 return 0; 320 ND_PRINT("%" PRIu64, GET_BE_U_8(opt)); 321 opt += 8; 322 opt_len -= 8; 323 } else { 324 if (opt_len < 4) 325 return 0; 326 ND_PRINT("%u", GET_BE_U_4(opt)); 327 opt += 4; 328 opt_len -= 4; 329 } 330 if (opt_len < 4) 331 return 0; 332 ND_PRINT(" subseq %u", GET_BE_U_4(opt)); 333 opt += 4; 334 opt_len -= 4; 335 if (opt_len < 2) 336 return 0; 337 ND_PRINT(" len %u", GET_BE_U_2(opt)); 338 opt += 2; 339 opt_len -= 2; 340 341 /* 342 * The Checksum is present only if negotiated. 343 * If there are at least 2 bytes left, process the next 2 344 * bytes as the Checksum. 345 */ 346 if (opt_len >= 2) { 347 ND_PRINT(" csum 0x%x", GET_BE_U_2(opt)); 348 opt_len -= 2; 349 } 350 } 351 if (opt_len != 0) 352 return 0; 353 return 1; 354 } 355 356 static int 357 add_addr_print(netdissect_options *ndo, 358 const u_char *opt, u_int opt_len, u_char flags _U_) 359 { 360 const struct mp_add_addr *add_addr = (const struct mp_add_addr *) opt; 361 362 if (!(opt_len == 8 || opt_len == 10 || opt_len == 16 || opt_len == 18 || 363 opt_len == 20 || opt_len == 22 || opt_len == 28 || opt_len == 30)) 364 return 0; 365 366 ND_PRINT(" %s", 367 tok2str(mptcp_addr_subecho_bits, "[bad version/echo]", 368 GET_U_1(add_addr->sub_echo) & 0xF)); 369 ND_PRINT(" id %u", GET_U_1(add_addr->addr_id)); 370 if (opt_len == 8 || opt_len == 10 || opt_len == 16 || opt_len == 18) { 371 ND_PRINT(" %s", GET_IPADDR_STRING(add_addr->u.v4.addr)); 372 if (opt_len == 10 || opt_len == 18) 373 ND_PRINT(":%u", GET_BE_U_2(add_addr->u.v4.port)); 374 if (opt_len == 16) 375 ND_PRINT(" hmac 0x%" PRIx64, GET_BE_U_8(add_addr->u.v4np.mac)); 376 if (opt_len == 18) 377 ND_PRINT(" hmac 0x%" PRIx64, GET_BE_U_8(add_addr->u.v4.mac)); 378 } 379 380 if (opt_len == 20 || opt_len == 22 || opt_len == 28 || opt_len == 30) { 381 ND_PRINT(" %s", GET_IP6ADDR_STRING(add_addr->u.v6.addr)); 382 if (opt_len == 22 || opt_len == 30) 383 ND_PRINT(":%u", GET_BE_U_2(add_addr->u.v6.port)); 384 if (opt_len == 28) 385 ND_PRINT(" hmac 0x%" PRIx64, GET_BE_U_8(add_addr->u.v6np.mac)); 386 if (opt_len == 30) 387 ND_PRINT(" hmac 0x%" PRIx64, GET_BE_U_8(add_addr->u.v6.mac)); 388 } 389 390 return 1; 391 } 392 393 static int 394 remove_addr_print(netdissect_options *ndo, 395 const u_char *opt, u_int opt_len, u_char flags _U_) 396 { 397 const struct mp_remove_addr *remove_addr = (const struct mp_remove_addr *) opt; 398 u_int i; 399 400 if (opt_len < 4) 401 return 0; 402 403 opt_len -= 3; 404 ND_PRINT(" id"); 405 for (i = 0; i < opt_len; i++) 406 ND_PRINT(" %u", GET_U_1(remove_addr->addrs_id[i])); 407 return 1; 408 } 409 410 static int 411 mp_prio_print(netdissect_options *ndo, 412 const u_char *opt, u_int opt_len, u_char flags _U_) 413 { 414 const struct mp_prio *mpp = (const struct mp_prio *) opt; 415 416 if (opt_len != 3 && opt_len != 4) 417 return 0; 418 419 if (GET_U_1(mpp->sub_b) & MP_PRIO_B) 420 ND_PRINT(" backup"); 421 else 422 ND_PRINT(" non-backup"); 423 if (opt_len == 4) 424 ND_PRINT(" id %u", GET_U_1(mpp->addr_id)); 425 426 return 1; 427 } 428 429 static int 430 mp_fail_print(netdissect_options *ndo, 431 const u_char *opt, u_int opt_len, u_char flags _U_) 432 { 433 if (opt_len != 12) 434 return 0; 435 436 ND_PRINT(" seq %" PRIu64, GET_BE_U_8(opt + 4)); 437 return 1; 438 } 439 440 static int 441 mp_fast_close_print(netdissect_options *ndo, 442 const u_char *opt, u_int opt_len, u_char flags _U_) 443 { 444 if (opt_len != 12) 445 return 0; 446 447 ND_PRINT(" key 0x%" PRIx64, GET_BE_U_8(opt + 4)); 448 return 1; 449 } 450 451 static const struct { 452 const char *name; 453 int (*print)(netdissect_options *, const u_char *, u_int, u_char); 454 } mptcp_options[] = { 455 { "capable", mp_capable_print }, 456 { "join", mp_join_print }, 457 { "dss", mp_dss_print }, 458 { "add-addr", add_addr_print }, 459 { "rem-addr", remove_addr_print }, 460 { "prio", mp_prio_print }, 461 { "fail", mp_fail_print }, 462 { "fast-close", mp_fast_close_print }, 463 { "unknown", dummy_print }, 464 }; 465 466 int 467 mptcp_print(netdissect_options *ndo, 468 const u_char *cp, u_int len, u_char flags) 469 { 470 const struct mptcp_option *opt; 471 u_int subtype; 472 473 ndo->ndo_protocol = "mptcp"; 474 if (len < 3) 475 return 0; 476 477 opt = (const struct mptcp_option *) cp; 478 subtype = MPTCP_OPT_SUBTYPE(GET_U_1(opt->sub_etc)); 479 subtype = ND_MIN(subtype, MPTCP_SUB_FCLOSE + 1); 480 481 ND_PRINT(" %u", len); 482 483 ND_PRINT(" %s", mptcp_options[subtype].name); 484 return mptcp_options[subtype].print(ndo, cp, len, flags); 485 } 486