blob: 17be82fae0a8b938b59a6b290dd909e6b86fe9ca [file] [log] [blame]
JP Abgrall53f17a92014-02-12 14:02:41 -08001/**
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#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#include <tcpdump-stdinc.h>
40
41#include <stdio.h>
42#include <string.h>
43
44#include "interface.h"
45#include "extract.h"
46#include "addrtoname.h"
47
48#include "ipproto.h"
49#include "mptcp.h"
50#include "tcp.h"
51
52static int dummy_print(const u_char *opt _U_, u_int opt_len _U_, u_char flags _U_)
53{
54 return 1;
55}
56
57static int mp_capable_print(const u_char *opt, u_int opt_len, u_char flags)
58{
59 struct mp_capable *mpc = (struct mp_capable *) opt;
60
61 if (!(opt_len == 12 && flags & TH_SYN) &&
62 !(opt_len == 20 && (flags & (TH_SYN | TH_ACK)) == TH_ACK))
63 return 0;
64
65 if (MP_CAPABLE_OPT_VERSION(mpc->sub_ver) != 0) {
66 printf(" Unknown Version (%d)", MP_CAPABLE_OPT_VERSION(mpc->sub_ver));
67 return 1;
68 }
69
70 if (mpc->flags & MP_CAPABLE_C)
71 printf(" csum");
72 printf(" {0x%" PRIx64, EXTRACT_64BITS(mpc->sender_key));
73 if (opt_len == 20) /* ACK */
74 printf(",0x%" PRIx64, EXTRACT_64BITS(mpc->receiver_key));
75 printf("}");
76 return 1;
77}
78
79static int mp_join_print(const u_char *opt, u_int opt_len, u_char flags)
80{
81 struct mp_join *mpj = (struct mp_join *) opt;
82
83 if (!(opt_len == 12 && flags & TH_SYN) &&
84 !(opt_len == 16 && (flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) &&
85 !(opt_len == 24 && flags & TH_ACK))
86 return 0;
87
88 if (opt_len != 24) {
89 if (mpj->sub_b & MP_JOIN_B)
90 printf(" backup");
91 printf(" id %u", mpj->addr_id);
92 }
93
94 switch (opt_len) {
95 case 12: /* SYN */
96 printf(" token 0x%x" " nonce 0x%x",
97 EXTRACT_32BITS(mpj->u.syn.token),
98 EXTRACT_32BITS(mpj->u.syn.nonce));
99 break;
100 case 16: /* SYN/ACK */
101 printf(" hmac 0x%" PRIx64 " nonce 0x%x",
102 EXTRACT_64BITS(mpj->u.synack.mac),
103 EXTRACT_32BITS(mpj->u.synack.nonce));
104 break;
105 case 24: {/* ACK */
106 size_t i;
107 printf(" hmac 0x");
108 for (i = 0; i < sizeof(mpj->u.ack.mac); ++i)
109 printf("%02x", mpj->u.ack.mac[i]);
110 }
111 default:
112 break;
113 }
114 return 1;
115}
116
117static u_int mp_dss_len(struct mp_dss *m, int csum)
118{
119 u_int len;
120
121 len = 4;
122 if (m->flags & MP_DSS_A) {
123 /* Ack present - 4 or 8 octets */
124 len += (m->flags & MP_DSS_a) ? 8 : 4;
125 }
126 if (m->flags & MP_DSS_M) {
127 /*
128 * Data Sequence Number (DSN), Subflow Sequence Number (SSN),
129 * Data-Level Length present, and Checksum possibly present.
130 * All but the Checksum are 10 bytes if the m flag is
131 * clear (4-byte DSN) and 14 bytes if the m flag is set
132 * (8-byte DSN).
133 */
134 len += (m->flags & MP_DSS_m) ? 14 : 10;
135
136 /*
137 * The Checksum is present only if negotiated.
138 */
139 if (csum)
140 len += 2;
141 }
142 return len;
143}
144
145static int mp_dss_print(const u_char *opt, u_int opt_len, u_char flags)
146{
147 struct mp_dss *mdss = (struct mp_dss *) opt;
148
149 if ((opt_len != mp_dss_len(mdss, 1) &&
150 opt_len != mp_dss_len(mdss, 0)) || flags & TH_SYN)
151 return 0;
152
153 if (mdss->flags & MP_DSS_F)
154 printf(" fin");
155
156 opt += 4;
157 if (mdss->flags & MP_DSS_A) {
158 printf(" ack ");
159 if (mdss->flags & MP_DSS_a) {
160 printf("%" PRIu64, EXTRACT_64BITS(opt));
161 opt += 8;
162 } else {
163 printf("%u", EXTRACT_32BITS(opt));
164 opt += 4;
165 }
166 }
167
168 if (mdss->flags & MP_DSS_M) {
169 printf(" seq ");
170 if (mdss->flags & MP_DSS_m) {
171 printf("%" PRIu64, EXTRACT_64BITS(opt));
172 opt += 8;
173 } else {
174 printf("%u", EXTRACT_32BITS(opt));
175 opt += 4;
176 }
177 printf(" subseq %u", EXTRACT_32BITS(opt));
178 opt += 4;
179 printf(" len %u", EXTRACT_16BITS(opt));
180 opt += 2;
181
182 if (opt_len == mp_dss_len(mdss, 1))
183 printf(" csum 0x%x", EXTRACT_16BITS(opt));
184 }
185 return 1;
186}
187
188static int add_addr_print(const u_char *opt, u_int opt_len, u_char flags _U_)
189{
190 struct mp_add_addr *add_addr = (struct mp_add_addr *) opt;
191 u_int ipver = MP_ADD_ADDR_IPVER(add_addr->sub_ipver);
192
193 if (!((opt_len == 8 || opt_len == 10) && ipver == 4) &&
194 !((opt_len == 20 || opt_len == 22) && ipver == 6))
195 return 0;
196
197 printf(" id %u", add_addr->addr_id);
198 switch (ipver) {
199 case 4:
200 printf(" %s", ipaddr_string(add_addr->u.v4.addr));
201 if (opt_len == 10)
202 printf(":%u", EXTRACT_16BITS(add_addr->u.v4.port));
203 break;
204 case 6:
205#ifdef INET6
206 printf(" %s", ip6addr_string(add_addr->u.v6.addr));
207#endif
208 if (opt_len == 22)
209 printf(":%u", EXTRACT_16BITS(add_addr->u.v6.port));
210 break;
211 default:
212 return 0;
213 }
214
215 return 1;
216}
217
218static int remove_addr_print(const u_char *opt, u_int opt_len, u_char flags _U_)
219{
220 struct mp_remove_addr *remove_addr = (struct mp_remove_addr *) opt;
221 u_int8_t *addr_id = &remove_addr->addrs_id;
222
223 if (opt_len < 4)
224 return 0;
225
226 opt_len -= 3;
227 printf(" id");
228 while (opt_len--)
229 printf(" %u", *addr_id++);
230 return 1;
231}
232
233static int mp_prio_print(const u_char *opt, u_int opt_len, u_char flags _U_)
234{
235 struct mp_prio *mpp = (struct mp_prio *) opt;
236
237 if (opt_len != 3 && opt_len != 4)
238 return 0;
239
240 if (mpp->sub_b & MP_PRIO_B)
241 printf(" backup");
242 else
243 printf(" non-backup");
244 if (opt_len == 4)
245 printf(" id %u", mpp->addr_id);
246
247 return 1;
248}
249
250static int mp_fail_print(const u_char *opt, u_int opt_len, u_char flags _U_)
251{
252 if (opt_len != 12)
253 return 0;
254
255 printf(" seq %" PRIu64, EXTRACT_64BITS(opt + 4));
256 return 1;
257}
258
259static int mp_fast_close_print(const u_char *opt, u_int opt_len, u_char flags _U_)
260{
261 if (opt_len != 12)
262 return 0;
263
264 printf(" key 0x%" PRIx64, EXTRACT_64BITS(opt + 4));
265 return 1;
266}
267
268static struct {
269 const char *name;
270 int (*print)(const u_char *, u_int, u_char);
271} mptcp_options[] = {
272 { "capable", mp_capable_print},
273 { "join", mp_join_print },
274 { "dss", mp_dss_print },
275 { "add-addr", add_addr_print },
276 { "rem-addr", remove_addr_print },
277 { "prio", mp_prio_print },
278 { "fail", mp_fail_print },
279 { "fast-close", mp_fast_close_print },
280 { "unknown", dummy_print },
281};
282
283int mptcp_print(const u_char *cp, u_int len, u_char flags)
284{
285 struct mptcp_option *opt;
286 u_int subtype;
287
288 if (len < 3)
289 return 0;
290
291 opt = (struct mptcp_option *) cp;
292 subtype = min(MPTCP_OPT_SUBTYPE(opt->sub_etc), MPTCP_SUB_FCLOSE + 1);
293
294 printf(" %s", mptcp_options[subtype].name);
295 return mptcp_options[subtype].print(cp, len, flags);
296}