Blame view
net/netfilter/nf_conntrack_proto_sctp.c
23 KB
9fb9cbb10
|
1 2 |
/* * Connection tracking protocol helper module for SCTP. |
601e68e10
|
3 |
* |
f229f6ce4
|
4 5 6 |
* Copyright (c) 2004 Kiran Kumar Immidi <immidi_kiran@yahoo.com> * Copyright (c) 2004-2012 Patrick McHardy <kaber@trash.net> * |
601e68e10
|
7 |
* SCTP is defined in RFC 2960. References to various sections in this code |
9fb9cbb10
|
8 |
* are to this RFC. |
601e68e10
|
9 |
* |
9fb9cbb10
|
10 11 12 |
* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. |
9fb9cbb10
|
13 14 15 |
*/ #include <linux/types.h> |
9fb9cbb10
|
16 17 |
#include <linux/timer.h> #include <linux/netfilter.h> |
9fb9cbb10
|
18 19 20 21 22 |
#include <linux/in.h> #include <linux/ip.h> #include <linux/sctp.h> #include <linux/string.h> #include <linux/seq_file.h> |
40a839fdb
|
23 24 |
#include <linux/spinlock.h> #include <linux/interrupt.h> |
cf6e007ee
|
25 |
#include <net/sctp/checksum.h> |
9fb9cbb10
|
26 |
|
cf6e007ee
|
27 |
#include <net/netfilter/nf_log.h> |
9fb9cbb10
|
28 |
#include <net/netfilter/nf_conntrack.h> |
605dcad6c
|
29 |
#include <net/netfilter/nf_conntrack_l4proto.h> |
f61801218
|
30 |
#include <net/netfilter/nf_conntrack_ecache.h> |
c779e8496
|
31 |
#include <net/netfilter/nf_conntrack_timeout.h> |
9fb9cbb10
|
32 |
|
9fb9cbb10
|
33 |
/* FIXME: Examine ipfilter's timeouts and conntrack transitions more |
601e68e10
|
34 |
closely. They're more complex. --RR |
9fb9cbb10
|
35 36 |
And so for me for SCTP :D -Kiran */ |
12c33aa20
|
37 |
static const char *const sctp_conntrack_names[] = { |
9fb9cbb10
|
38 39 40 41 42 43 44 45 |
"NONE", "CLOSED", "COOKIE_WAIT", "COOKIE_ECHOED", "ESTABLISHED", "SHUTDOWN_SENT", "SHUTDOWN_RECD", "SHUTDOWN_ACK_SENT", |
d7ee35190
|
46 47 |
"HEARTBEAT_SENT", "HEARTBEAT_ACKED", |
9fb9cbb10
|
48 49 50 51 52 53 |
}; #define SECS * HZ #define MINS * 60 SECS #define HOURS * 60 MINS #define DAYS * 24 HOURS |
2c9e8637e
|
54 |
static const unsigned int sctp_timeouts[SCTP_CONNTRACK_MAX] = { |
86c0bf409
|
55 56 57 58 59 60 61 |
[SCTP_CONNTRACK_CLOSED] = 10 SECS, [SCTP_CONNTRACK_COOKIE_WAIT] = 3 SECS, [SCTP_CONNTRACK_COOKIE_ECHOED] = 3 SECS, [SCTP_CONNTRACK_ESTABLISHED] = 5 DAYS, [SCTP_CONNTRACK_SHUTDOWN_SENT] = 300 SECS / 1000, [SCTP_CONNTRACK_SHUTDOWN_RECD] = 300 SECS / 1000, [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT] = 3 SECS, |
d7ee35190
|
62 63 |
[SCTP_CONNTRACK_HEARTBEAT_SENT] = 30 SECS, [SCTP_CONNTRACK_HEARTBEAT_ACKED] = 210 SECS, |
86c0bf409
|
64 |
}; |
9fb9cbb10
|
65 66 67 68 69 70 71 72 73 |
#define sNO SCTP_CONNTRACK_NONE #define sCL SCTP_CONNTRACK_CLOSED #define sCW SCTP_CONNTRACK_COOKIE_WAIT #define sCE SCTP_CONNTRACK_COOKIE_ECHOED #define sES SCTP_CONNTRACK_ESTABLISHED #define sSS SCTP_CONNTRACK_SHUTDOWN_SENT #define sSR SCTP_CONNTRACK_SHUTDOWN_RECD #define sSA SCTP_CONNTRACK_SHUTDOWN_ACK_SENT |
d7ee35190
|
74 75 |
#define sHS SCTP_CONNTRACK_HEARTBEAT_SENT #define sHA SCTP_CONNTRACK_HEARTBEAT_ACKED |
9fb9cbb10
|
76 |
#define sIV SCTP_CONNTRACK_MAX |
601e68e10
|
77 |
/* |
9fb9cbb10
|
78 |
These are the descriptions of the states: |
601e68e10
|
79 |
NOTE: These state names are tantalizingly similar to the states of an |
9fb9cbb10
|
80 |
SCTP endpoint. But the interpretation of the states is a little different, |
601e68e10
|
81 |
considering that these are the states of the connection and not of an end |
9fb9cbb10
|
82 83 84 |
point. Please note the subtleties. -Kiran NONE - Nothing so far. |
601e68e10
|
85 86 |
COOKIE WAIT - We have seen an INIT chunk in the original direction, or also an INIT_ACK chunk in the reply direction. |
9fb9cbb10
|
87 88 89 90 91 |
COOKIE ECHOED - We have seen a COOKIE_ECHO chunk in the original direction. ESTABLISHED - We have seen a COOKIE_ACK in the reply direction. SHUTDOWN_SENT - We have seen a SHUTDOWN chunk in the original direction. SHUTDOWN_RECD - We have seen a SHUTDOWN chunk in the reply directoin. SHUTDOWN_ACK_SENT - We have seen a SHUTDOWN_ACK chunk in the direction opposite |
601e68e10
|
92 93 94 |
to that of the SHUTDOWN chunk. CLOSED - We have seen a SHUTDOWN_COMPLETE chunk in the direction of the SHUTDOWN chunk. Connection is closed. |
d7ee35190
|
95 96 97 98 |
HEARTBEAT_SENT - We have seen a HEARTBEAT in a new flow. HEARTBEAT_ACKED - We have seen a HEARTBEAT-ACK in the direction opposite to that of the HEARTBEAT chunk. Secondary connection is established. |
9fb9cbb10
|
99 100 101 |
*/ /* TODO |
601e68e10
|
102 |
- I have assumed that the first INIT is in the original direction. |
9fb9cbb10
|
103 104 |
This messes things when an INIT comes in the reply direction in CLOSED state. |
601e68e10
|
105 |
- Check the error type in the reply dir before transitioning from |
9fb9cbb10
|
106 107 |
cookie echoed to closed. - Sec 5.2.4 of RFC 2960 |
d7ee35190
|
108 |
- Full Multi Homing support. |
9fb9cbb10
|
109 110 111 |
*/ /* SCTP conntrack state transitions */ |
d7ee35190
|
112 |
static const u8 sctp_conntracks[2][11][SCTP_CONNTRACK_MAX] = { |
9fb9cbb10
|
113 114 |
{ /* ORIGINAL */ |
d7ee35190
|
115 116 117 118 119 120 121 122 123 124 125 126 |
/* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA */ /* init */ {sCW, sCW, sCW, sCE, sES, sSS, sSR, sSA, sCW, sHA}, /* init_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL, sHA}, /* abort */ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL}, /* shutdown */ {sCL, sCL, sCW, sCE, sSS, sSS, sSR, sSA, sCL, sSS}, /* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA, sSA, sHA}, /* error */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL, sHA},/* Can't have Stale cookie*/ /* cookie_echo */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA, sCL, sHA},/* 5.2.4 - Big TODO */ /* cookie_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL, sHA},/* Can't come in orig dir */ /* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL, sCL, sHA}, /* heartbeat */ {sHS, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA}, /* heartbeat_ack*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA} |
9fb9cbb10
|
127 128 129 |
}, { /* REPLY */ |
d7ee35190
|
130 131 132 133 134 135 136 137 138 139 140 141 |
/* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA */ /* init */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV, sHA},/* INIT in sCL Big TODO */ /* init_ack */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV, sHA}, /* abort */ {sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV, sCL}, /* shutdown */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA, sIV, sSR}, /* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA, sIV, sHA}, /* error */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA, sIV, sHA}, /* cookie_echo */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV, sHA},/* Can't come in reply dir */ /* cookie_ack */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA, sIV, sHA}, /* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL, sIV, sHA}, /* heartbeat */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA}, /* heartbeat_ack*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHA, sHA} |
9fb9cbb10
|
142 143 |
} }; |
ea48cc83c
|
144 |
#ifdef CONFIG_NF_CONNTRACK_PROCFS |
9fb9cbb10
|
145 |
/* Print out the private part of the conntrack. */ |
37246a583
|
146 |
static void sctp_print_conntrack(struct seq_file *s, struct nf_conn *ct) |
9fb9cbb10
|
147 |
{ |
a163f2cb3
|
148 |
seq_printf(s, "%s ", sctp_conntrack_names[ct->proto.sctp.state]); |
9fb9cbb10
|
149 |
} |
ea48cc83c
|
150 |
#endif |
9fb9cbb10
|
151 152 |
#define for_each_sctp_chunk(skb, sch, _sch, offset, dataoff, count) \ |
ae146d9b7
|
153 |
for ((offset) = (dataoff) + sizeof(struct sctphdr), (count) = 0; \ |
e79ec50b9
|
154 155 156 |
(offset) < (skb)->len && \ ((sch) = skb_header_pointer((skb), (offset), sizeof(_sch), &(_sch))); \ (offset) += (ntohs((sch)->length) + 3) & ~3, (count)++) |
9fb9cbb10
|
157 158 |
/* Some validity checks to make sure the chunks are fine */ |
112f35c9c
|
159 |
static int do_basic_checks(struct nf_conn *ct, |
9fb9cbb10
|
160 161 |
const struct sk_buff *skb, unsigned int dataoff, |
35c6d3cbe
|
162 |
unsigned long *map) |
9fb9cbb10
|
163 164 |
{ u_int32_t offset, count; |
922dbc5be
|
165 |
struct sctp_chunkhdr _sch, *sch; |
9fb9cbb10
|
166 |
int flag; |
9fb9cbb10
|
167 168 169 |
flag = 0; for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) { |
0d53778e8
|
170 171 |
pr_debug("Chunk Num: %d Type: %d ", count, sch->type); |
9fb9cbb10
|
172 |
|
5447d4777
|
173 174 175 |
if (sch->type == SCTP_CID_INIT || sch->type == SCTP_CID_INIT_ACK || sch->type == SCTP_CID_SHUTDOWN_COMPLETE) |
9fb9cbb10
|
176 |
flag = 1; |
9fb9cbb10
|
177 |
|
e17df688f
|
178 179 180 181 182 |
/* * Cookie Ack/Echo chunks not the first OR * Init / Init Ack / Shutdown compl chunks not the only chunks * OR zero-length. */ |
5447d4777
|
183 184 185 186 |
if (((sch->type == SCTP_CID_COOKIE_ACK || sch->type == SCTP_CID_COOKIE_ECHO || flag) && count != 0) || !sch->length) { |
0d53778e8
|
187 188 |
pr_debug("Basic checks failed "); |
9fb9cbb10
|
189 190 |
return 1; } |
5447d4777
|
191 |
if (map) |
35c6d3cbe
|
192 |
set_bit(sch->type, map); |
9fb9cbb10
|
193 |
} |
0d53778e8
|
194 195 |
pr_debug("Basic checks passed "); |
dd7271feb
|
196 |
return count == 0; |
9fb9cbb10
|
197 |
} |
efe9f68af
|
198 199 200 |
static int sctp_new_state(enum ip_conntrack_dir dir, enum sctp_conntrack cur_state, int chunk_type) |
9fb9cbb10
|
201 202 |
{ int i; |
0d53778e8
|
203 204 |
pr_debug("Chunk type: %d ", chunk_type); |
9fb9cbb10
|
205 206 |
switch (chunk_type) { |
5447d4777
|
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
case SCTP_CID_INIT: pr_debug("SCTP_CID_INIT "); i = 0; break; case SCTP_CID_INIT_ACK: pr_debug("SCTP_CID_INIT_ACK "); i = 1; break; case SCTP_CID_ABORT: pr_debug("SCTP_CID_ABORT "); i = 2; break; case SCTP_CID_SHUTDOWN: pr_debug("SCTP_CID_SHUTDOWN "); i = 3; break; case SCTP_CID_SHUTDOWN_ACK: pr_debug("SCTP_CID_SHUTDOWN_ACK "); i = 4; break; case SCTP_CID_ERROR: pr_debug("SCTP_CID_ERROR "); i = 5; break; case SCTP_CID_COOKIE_ECHO: pr_debug("SCTP_CID_COOKIE_ECHO "); i = 6; break; case SCTP_CID_COOKIE_ACK: pr_debug("SCTP_CID_COOKIE_ACK "); i = 7; break; case SCTP_CID_SHUTDOWN_COMPLETE: pr_debug("SCTP_CID_SHUTDOWN_COMPLETE "); i = 8; break; |
d7ee35190
|
252 253 254 255 256 257 258 259 |
case SCTP_CID_HEARTBEAT: pr_debug("SCTP_CID_HEARTBEAT"); i = 9; break; case SCTP_CID_HEARTBEAT_ACK: pr_debug("SCTP_CID_HEARTBEAT_ACK"); i = 10; break; |
5447d4777
|
260 |
default: |
d7ee35190
|
261 |
/* Other chunks like DATA or SACK do not change the state */ |
5447d4777
|
262 263 264 265 |
pr_debug("Unknown chunk type, Will stay in %s ", sctp_conntrack_names[cur_state]); return cur_state; |
9fb9cbb10
|
266 |
} |
0d53778e8
|
267 268 269 270 |
pr_debug("dir: %d cur_state: %s chunk_type: %d new_state: %s ", dir, sctp_conntrack_names[cur_state], chunk_type, sctp_conntrack_names[sctp_conntracks[dir][i][cur_state]]); |
9fb9cbb10
|
271 272 273 |
return sctp_conntracks[dir][i][cur_state]; } |
9976fc6e6
|
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
/* Don't need lock here: this conntrack not in circulation yet */ static noinline bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb, const struct sctphdr *sh, unsigned int dataoff) { enum sctp_conntrack new_state; const struct sctp_chunkhdr *sch; struct sctp_chunkhdr _sch; u32 offset, count; memset(&ct->proto.sctp, 0, sizeof(ct->proto.sctp)); new_state = SCTP_CONNTRACK_MAX; for_each_sctp_chunk(skb, sch, _sch, offset, dataoff, count) { new_state = sctp_new_state(IP_CT_DIR_ORIGINAL, SCTP_CONNTRACK_NONE, sch->type); /* Invalid: delete conntrack */ if (new_state == SCTP_CONNTRACK_NONE || new_state == SCTP_CONNTRACK_MAX) { pr_debug("nf_conntrack_sctp: invalid new deleting. "); return false; } /* Copy the vtag into the state info */ if (sch->type == SCTP_CID_INIT) { struct sctp_inithdr _inithdr, *ih; /* Sec 8.5.1 (A) */ if (sh->vtag) return false; ih = skb_header_pointer(skb, offset + sizeof(_sch), sizeof(_inithdr), &_inithdr); if (!ih) return false; pr_debug("Setting vtag %x for new conn ", ih->init_tag); ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = ih->init_tag; } else if (sch->type == SCTP_CID_HEARTBEAT) { pr_debug("Setting vtag %x for secondary conntrack ", sh->vtag); ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = sh->vtag; } else { /* If it is a shutdown ack OOTB packet, we expect a return shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */ pr_debug("Setting vtag %x for new conn OOTB ", sh->vtag); ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = sh->vtag; } ct->proto.sctp.state = new_state; } return true; } |
0150ffbac
|
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 |
static bool sctp_error(struct sk_buff *skb, unsigned int dataoff, const struct nf_hook_state *state) { const struct sctphdr *sh; const char *logmsg; if (skb->len < dataoff + sizeof(struct sctphdr)) { logmsg = "nf_ct_sctp: short packet "; goto out_invalid; } if (state->hook == NF_INET_PRE_ROUTING && state->net->ct.sysctl_checksum && skb->ip_summed == CHECKSUM_NONE) { if (!skb_make_writable(skb, dataoff + sizeof(struct sctphdr))) { logmsg = "nf_ct_sctp: failed to read header "; goto out_invalid; } sh = (const struct sctphdr *)(skb->data + dataoff); if (sh->checksum != sctp_compute_cksum(skb, dataoff)) { logmsg = "nf_ct_sctp: bad CRC "; goto out_invalid; } skb->ip_summed = CHECKSUM_UNNECESSARY; } return false; out_invalid: nf_l4proto_log_invalid(skb, state->net, state->pf, IPPROTO_SCTP, "%s", logmsg); return true; } |
b37e933ac
|
364 |
/* Returns verdict for packet, or -NF_ACCEPT for invalid. */ |
a47c54048
|
365 366 367 368 369 |
int nf_conntrack_sctp_packet(struct nf_conn *ct, struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, const struct nf_hook_state *state) |
9fb9cbb10
|
370 |
{ |
efe9f68af
|
371 |
enum sctp_conntrack new_state, old_state; |
8528819ad
|
372 |
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
12c33aa20
|
373 374 375 376 |
const struct sctphdr *sh; struct sctphdr _sctph; const struct sctp_chunkhdr *sch; struct sctp_chunkhdr _sch; |
9fb9cbb10
|
377 |
u_int32_t offset, count; |
c779e8496
|
378 |
unsigned int *timeouts; |
35c6d3cbe
|
379 |
unsigned long map[256 / sizeof(unsigned long)] = { 0 }; |
9fb9cbb10
|
380 |
|
0150ffbac
|
381 382 |
if (sctp_error(skb, dataoff, state)) return -NF_ACCEPT; |
9fb9cbb10
|
383 384 |
sh = skb_header_pointer(skb, dataoff, sizeof(_sctph), &_sctph); if (sh == NULL) |
b37e933ac
|
385 |
goto out; |
9fb9cbb10
|
386 |
|
112f35c9c
|
387 |
if (do_basic_checks(ct, skb, dataoff, map) != 0) |
b37e933ac
|
388 |
goto out; |
9fb9cbb10
|
389 |
|
9976fc6e6
|
390 391 392 393 394 395 396 397 398 399 |
if (!nf_ct_is_confirmed(ct)) { /* If an OOTB packet has any of these chunks discard (Sec 8.4) */ if (test_bit(SCTP_CID_ABORT, map) || test_bit(SCTP_CID_SHUTDOWN_COMPLETE, map) || test_bit(SCTP_CID_COOKIE_ACK, map)) return -NF_ACCEPT; if (!sctp_new(ct, skb, sh, dataoff)) return -NF_ACCEPT; } |
9fb9cbb10
|
400 |
/* Check the verification tag (Sec 8.5) */ |
35c6d3cbe
|
401 402 403 404 405 |
if (!test_bit(SCTP_CID_INIT, map) && !test_bit(SCTP_CID_SHUTDOWN_COMPLETE, map) && !test_bit(SCTP_CID_COOKIE_ECHO, map) && !test_bit(SCTP_CID_ABORT, map) && !test_bit(SCTP_CID_SHUTDOWN_ACK, map) && |
d7ee35190
|
406 407 |
!test_bit(SCTP_CID_HEARTBEAT, map) && !test_bit(SCTP_CID_HEARTBEAT_ACK, map) && |
8528819ad
|
408 |
sh->vtag != ct->proto.sctp.vtag[dir]) { |
0d53778e8
|
409 410 |
pr_debug("Verification tag check failed "); |
b37e933ac
|
411 |
goto out; |
9fb9cbb10
|
412 |
} |
328bd8997
|
413 |
old_state = new_state = SCTP_CONNTRACK_NONE; |
440f0d588
|
414 |
spin_lock_bh(&ct->lock); |
9fb9cbb10
|
415 |
for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) { |
9fb9cbb10
|
416 417 418 |
/* Special cases of Verification tag check (Sec 8.5.1) */ if (sch->type == SCTP_CID_INIT) { /* Sec 8.5.1 (A) */ |
b37e933ac
|
419 420 |
if (sh->vtag != 0) goto out_unlock; |
9fb9cbb10
|
421 422 |
} else if (sch->type == SCTP_CID_ABORT) { /* Sec 8.5.1 (B) */ |
8528819ad
|
423 |
if (sh->vtag != ct->proto.sctp.vtag[dir] && |
b37e933ac
|
424 425 |
sh->vtag != ct->proto.sctp.vtag[!dir]) goto out_unlock; |
9fb9cbb10
|
426 427 |
} else if (sch->type == SCTP_CID_SHUTDOWN_COMPLETE) { /* Sec 8.5.1 (C) */ |
8528819ad
|
428 429 |
if (sh->vtag != ct->proto.sctp.vtag[dir] && sh->vtag != ct->proto.sctp.vtag[!dir] && |
9b1c2cfd7
|
430 |
sch->flags & SCTP_CHUNK_FLAG_T) |
b37e933ac
|
431 |
goto out_unlock; |
9fb9cbb10
|
432 433 |
} else if (sch->type == SCTP_CID_COOKIE_ECHO) { /* Sec 8.5.1 (D) */ |
b37e933ac
|
434 435 |
if (sh->vtag != ct->proto.sctp.vtag[dir]) goto out_unlock; |
d7ee35190
|
436 437 438 439 440 441 442 443 444 445 446 447 |
} else if (sch->type == SCTP_CID_HEARTBEAT || sch->type == SCTP_CID_HEARTBEAT_ACK) { if (ct->proto.sctp.vtag[dir] == 0) { pr_debug("Setting vtag %x for dir %d ", sh->vtag, dir); ct->proto.sctp.vtag[dir] = sh->vtag; } else if (sh->vtag != ct->proto.sctp.vtag[dir]) { pr_debug("Verification tag check failed "); goto out_unlock; } |
9fb9cbb10
|
448 |
} |
efe9f68af
|
449 450 |
old_state = ct->proto.sctp.state; new_state = sctp_new_state(dir, old_state, sch->type); |
9fb9cbb10
|
451 452 |
/* Invalid */ |
efe9f68af
|
453 |
if (new_state == SCTP_CONNTRACK_MAX) { |
0d53778e8
|
454 455 456 |
pr_debug("nf_conntrack_sctp: Invalid dir=%i ctype=%u " "conntrack=%u ", |
efe9f68af
|
457 |
dir, sch->type, old_state); |
b37e933ac
|
458 |
goto out_unlock; |
9fb9cbb10
|
459 460 461 |
} /* If it is an INIT or an INIT ACK note down the vtag */ |
5447d4777
|
462 463 |
if (sch->type == SCTP_CID_INIT || sch->type == SCTP_CID_INIT_ACK) { |
4ae70c084
|
464 |
struct sctp_inithdr _inithdr, *ih; |
9fb9cbb10
|
465 |
|
922dbc5be
|
466 |
ih = skb_header_pointer(skb, offset + sizeof(_sch), |
601e68e10
|
467 |
sizeof(_inithdr), &_inithdr); |
b37e933ac
|
468 469 |
if (ih == NULL) goto out_unlock; |
0d53778e8
|
470 471 |
pr_debug("Setting vtag %x for dir %d ", |
8528819ad
|
472 473 |
ih->init_tag, !dir); ct->proto.sctp.vtag[!dir] = ih->init_tag; |
9fb9cbb10
|
474 |
} |
efe9f68af
|
475 476 |
ct->proto.sctp.state = new_state; if (old_state != new_state) |
a71996fcc
|
477 |
nf_conntrack_event_cache(IPCT_PROTOINFO, ct); |
9fb9cbb10
|
478 |
} |
440f0d588
|
479 |
spin_unlock_bh(&ct->lock); |
9fb9cbb10
|
480 |
|
c779e8496
|
481 482 |
timeouts = nf_ct_timeout_lookup(ct); if (!timeouts) |
a95a7774d
|
483 |
timeouts = nf_sctp_pernet(nf_ct_net(ct))->timeouts; |
c779e8496
|
484 |
|
2c8503f55
|
485 |
nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]); |
9fb9cbb10
|
486 |
|
efe9f68af
|
487 |
if (old_state == SCTP_CONNTRACK_COOKIE_ECHOED && |
8528819ad
|
488 |
dir == IP_CT_DIR_REPLY && |
efe9f68af
|
489 |
new_state == SCTP_CONNTRACK_ESTABLISHED) { |
0d53778e8
|
490 491 |
pr_debug("Setting assured bit "); |
112f35c9c
|
492 |
set_bit(IPS_ASSURED_BIT, &ct->status); |
858b31330
|
493 |
nf_conntrack_event_cache(IPCT_ASSURED, ct); |
9fb9cbb10
|
494 495 496 |
} return NF_ACCEPT; |
b37e933ac
|
497 498 |
out_unlock: |
440f0d588
|
499 |
spin_unlock_bh(&ct->lock); |
b37e933ac
|
500 501 |
out: return -NF_ACCEPT; |
9fb9cbb10
|
502 |
} |
c6dd940b1
|
503 504 505 506 507 508 509 510 511 512 513 514 515 |
static bool sctp_can_early_drop(const struct nf_conn *ct) { switch (ct->proto.sctp.state) { case SCTP_CONNTRACK_SHUTDOWN_SENT: case SCTP_CONNTRACK_SHUTDOWN_RECD: case SCTP_CONNTRACK_SHUTDOWN_ACK_SENT: return true; default: break; } return false; } |
c0cd11566
|
516 |
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
a258860e0
|
517 518 519 520 521 |
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink_conntrack.h> static int sctp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, |
440f0d588
|
522 |
struct nf_conn *ct) |
a258860e0
|
523 524 |
{ struct nlattr *nest_parms; |
440f0d588
|
525 |
spin_lock_bh(&ct->lock); |
a258860e0
|
526 527 528 |
nest_parms = nla_nest_start(skb, CTA_PROTOINFO_SCTP | NLA_F_NESTED); if (!nest_parms) goto nla_put_failure; |
5e8d1eb5f
|
529 530 531 532 533 534 |
if (nla_put_u8(skb, CTA_PROTOINFO_SCTP_STATE, ct->proto.sctp.state) || nla_put_be32(skb, CTA_PROTOINFO_SCTP_VTAG_ORIGINAL, ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL]) || nla_put_be32(skb, CTA_PROTOINFO_SCTP_VTAG_REPLY, ct->proto.sctp.vtag[IP_CT_DIR_REPLY])) goto nla_put_failure; |
a258860e0
|
535 |
|
440f0d588
|
536 |
spin_unlock_bh(&ct->lock); |
a258860e0
|
537 538 539 540 541 542 |
nla_nest_end(skb, nest_parms); return 0; nla_put_failure: |
440f0d588
|
543 |
spin_unlock_bh(&ct->lock); |
a258860e0
|
544 545 546 547 548 549 550 551 |
return -1; } static const struct nla_policy sctp_nla_policy[CTA_PROTOINFO_SCTP_MAX+1] = { [CTA_PROTOINFO_SCTP_STATE] = { .type = NLA_U8 }, [CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] = { .type = NLA_U32 }, [CTA_PROTOINFO_SCTP_VTAG_REPLY] = { .type = NLA_U32 }, }; |
392158467
|
552 553 554 555 |
#define SCTP_NLATTR_SIZE ( \ NLA_ALIGN(NLA_HDRLEN + 1) + \ NLA_ALIGN(NLA_HDRLEN + 4) + \ NLA_ALIGN(NLA_HDRLEN + 4)) |
a258860e0
|
556 557 558 559 560 561 562 563 564 |
static int nlattr_to_sctp(struct nlattr *cda[], struct nf_conn *ct) { struct nlattr *attr = cda[CTA_PROTOINFO_SCTP]; struct nlattr *tb[CTA_PROTOINFO_SCTP_MAX+1]; int err; /* updates may not contain the internal protocol info, skip parsing */ if (!attr) return 0; |
fceb6435e
|
565 566 |
err = nla_parse_nested(tb, CTA_PROTOINFO_SCTP_MAX, attr, sctp_nla_policy, NULL); |
a258860e0
|
567 568 569 570 571 572 573 |
if (err < 0) return err; if (!tb[CTA_PROTOINFO_SCTP_STATE] || !tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] || !tb[CTA_PROTOINFO_SCTP_VTAG_REPLY]) return -EINVAL; |
440f0d588
|
574 |
spin_lock_bh(&ct->lock); |
a258860e0
|
575 576 |
ct->proto.sctp.state = nla_get_u8(tb[CTA_PROTOINFO_SCTP_STATE]); ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = |
5547cd0ae
|
577 |
nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL]); |
a258860e0
|
578 |
ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = |
5547cd0ae
|
579 |
nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_REPLY]); |
440f0d588
|
580 |
spin_unlock_bh(&ct->lock); |
a258860e0
|
581 582 583 584 |
return 0; } #endif |
a874752a1
|
585 |
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
509784623
|
586 587 588 |
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink_cttimeout.h> |
8264deb81
|
589 590 |
static int sctp_timeout_nlattr_to_obj(struct nlattr *tb[], struct net *net, void *data) |
509784623
|
591 592 |
{ unsigned int *timeouts = data; |
a95a7774d
|
593 |
struct nf_sctp_net *sn = nf_sctp_pernet(net); |
509784623
|
594 595 596 597 |
int i; /* set default SCTP timeouts. */ for (i=0; i<SCTP_CONNTRACK_MAX; i++) |
8264deb81
|
598 |
timeouts[i] = sn->timeouts[i]; |
509784623
|
599 600 601 602 603 604 605 |
/* there's a 1:1 mapping between attributes and protocol states. */ for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++) { if (tb[i]) { timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ; } } |
ef39078d6
|
606 607 |
timeouts[CTA_TIMEOUT_SCTP_UNSPEC] = timeouts[CTA_TIMEOUT_SCTP_CLOSED]; |
509784623
|
608 609 610 611 612 613 614 615 |
return 0; } static int sctp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) { const unsigned int *timeouts = data; int i; |
5e8d1eb5f
|
616 617 618 619 |
for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++) { if (nla_put_be32(skb, i, htonl(timeouts[i] / HZ))) goto nla_put_failure; } |
509784623
|
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 |
return 0; nla_put_failure: return -ENOSPC; } static const struct nla_policy sctp_timeout_nla_policy[CTA_TIMEOUT_SCTP_MAX+1] = { [CTA_TIMEOUT_SCTP_CLOSED] = { .type = NLA_U32 }, [CTA_TIMEOUT_SCTP_COOKIE_WAIT] = { .type = NLA_U32 }, [CTA_TIMEOUT_SCTP_COOKIE_ECHOED] = { .type = NLA_U32 }, [CTA_TIMEOUT_SCTP_ESTABLISHED] = { .type = NLA_U32 }, [CTA_TIMEOUT_SCTP_SHUTDOWN_SENT] = { .type = NLA_U32 }, [CTA_TIMEOUT_SCTP_SHUTDOWN_RECD] = { .type = NLA_U32 }, [CTA_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT] = { .type = NLA_U32 }, |
d7ee35190
|
635 636 |
[CTA_TIMEOUT_SCTP_HEARTBEAT_SENT] = { .type = NLA_U32 }, [CTA_TIMEOUT_SCTP_HEARTBEAT_ACKED] = { .type = NLA_U32 }, |
509784623
|
637 |
}; |
a874752a1
|
638 |
#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
509784623
|
639 |
|
9fb9cbb10
|
640 |
#ifdef CONFIG_SYSCTL |
933a41e7e
|
641 |
static struct ctl_table sctp_sysctl_table[] = { |
9fb9cbb10
|
642 |
{ |
9fb9cbb10
|
643 |
.procname = "nf_conntrack_sctp_timeout_closed", |
9fb9cbb10
|
644 645 |
.maxlen = sizeof(unsigned int), .mode = 0644, |
6d9f239a1
|
646 |
.proc_handler = proc_dointvec_jiffies, |
9fb9cbb10
|
647 648 |
}, { |
9fb9cbb10
|
649 |
.procname = "nf_conntrack_sctp_timeout_cookie_wait", |
9fb9cbb10
|
650 651 |
.maxlen = sizeof(unsigned int), .mode = 0644, |
6d9f239a1
|
652 |
.proc_handler = proc_dointvec_jiffies, |
9fb9cbb10
|
653 654 |
}, { |
9fb9cbb10
|
655 |
.procname = "nf_conntrack_sctp_timeout_cookie_echoed", |
9fb9cbb10
|
656 657 |
.maxlen = sizeof(unsigned int), .mode = 0644, |
6d9f239a1
|
658 |
.proc_handler = proc_dointvec_jiffies, |
9fb9cbb10
|
659 660 |
}, { |
9fb9cbb10
|
661 |
.procname = "nf_conntrack_sctp_timeout_established", |
9fb9cbb10
|
662 663 |
.maxlen = sizeof(unsigned int), .mode = 0644, |
6d9f239a1
|
664 |
.proc_handler = proc_dointvec_jiffies, |
9fb9cbb10
|
665 666 |
}, { |
9fb9cbb10
|
667 |
.procname = "nf_conntrack_sctp_timeout_shutdown_sent", |
9fb9cbb10
|
668 669 |
.maxlen = sizeof(unsigned int), .mode = 0644, |
6d9f239a1
|
670 |
.proc_handler = proc_dointvec_jiffies, |
9fb9cbb10
|
671 672 |
}, { |
9fb9cbb10
|
673 |
.procname = "nf_conntrack_sctp_timeout_shutdown_recd", |
9fb9cbb10
|
674 675 |
.maxlen = sizeof(unsigned int), .mode = 0644, |
6d9f239a1
|
676 |
.proc_handler = proc_dointvec_jiffies, |
9fb9cbb10
|
677 678 |
}, { |
9fb9cbb10
|
679 |
.procname = "nf_conntrack_sctp_timeout_shutdown_ack_sent", |
9fb9cbb10
|
680 681 |
.maxlen = sizeof(unsigned int), .mode = 0644, |
6d9f239a1
|
682 |
.proc_handler = proc_dointvec_jiffies, |
9fb9cbb10
|
683 |
}, |
d7ee35190
|
684 685 686 687 688 689 690 691 692 693 694 695 |
{ .procname = "nf_conntrack_sctp_timeout_heartbeat_sent", .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_sctp_timeout_heartbeat_acked", .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec_jiffies, }, |
f8572d8f2
|
696 |
{ } |
9fb9cbb10
|
697 |
}; |
933a41e7e
|
698 |
#endif |
9fb9cbb10
|
699 |
|
f42c4183c
|
700 |
static int sctp_kmemdup_sysctl_table(struct nf_proto_net *pn, |
a85406afe
|
701 |
struct nf_sctp_net *sn) |
49d485a30
|
702 703 |
{ #ifdef CONFIG_SYSCTL |
49d485a30
|
704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 |
if (pn->ctl_table) return 0; pn->ctl_table = kmemdup(sctp_sysctl_table, sizeof(sctp_sysctl_table), GFP_KERNEL); if (!pn->ctl_table) return -ENOMEM; pn->ctl_table[0].data = &sn->timeouts[SCTP_CONNTRACK_CLOSED]; pn->ctl_table[1].data = &sn->timeouts[SCTP_CONNTRACK_COOKIE_WAIT]; pn->ctl_table[2].data = &sn->timeouts[SCTP_CONNTRACK_COOKIE_ECHOED]; pn->ctl_table[3].data = &sn->timeouts[SCTP_CONNTRACK_ESTABLISHED]; pn->ctl_table[4].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_SENT]; pn->ctl_table[5].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_RECD]; pn->ctl_table[6].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_ACK_SENT]; |
d7ee35190
|
720 721 |
pn->ctl_table[7].data = &sn->timeouts[SCTP_CONNTRACK_HEARTBEAT_SENT]; pn->ctl_table[8].data = &sn->timeouts[SCTP_CONNTRACK_HEARTBEAT_ACKED]; |
49d485a30
|
722 723 724 |
#endif return 0; } |
ca2ca6e1c
|
725 |
static int sctp_init_net(struct net *net) |
49d485a30
|
726 |
{ |
a95a7774d
|
727 |
struct nf_sctp_net *sn = nf_sctp_pernet(net); |
f42c4183c
|
728 |
struct nf_proto_net *pn = &sn->pn; |
49d485a30
|
729 |
|
f42c4183c
|
730 731 |
if (!pn->users) { int i; |
49d485a30
|
732 |
|
f42c4183c
|
733 734 |
for (i = 0; i < SCTP_CONNTRACK_MAX; i++) sn->timeouts[i] = sctp_timeouts[i]; |
ef39078d6
|
735 736 737 738 739 |
/* timeouts[0] is unused, init it so ->timeouts[0] contains * 'new' timeout, like udp or icmp. */ sn->timeouts[0] = sctp_timeouts[SCTP_CONNTRACK_CLOSED]; |
f42c4183c
|
740 |
} |
49d485a30
|
741 |
|
adf051684
|
742 |
return sctp_kmemdup_sysctl_table(pn, sn); |
49d485a30
|
743 |
} |
deaa0a976
|
744 745 746 747 |
static struct nf_proto_net *sctp_get_net_proto(struct net *net) { return &net->ct.nf_ct_proto.sctp.pn; } |
dd2934a95
|
748 |
const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp = { |
933a41e7e
|
749 |
.l4proto = IPPROTO_SCTP, |
ea48cc83c
|
750 |
#ifdef CONFIG_NF_CONNTRACK_PROCFS |
933a41e7e
|
751 |
.print_conntrack = sctp_print_conntrack, |
ea48cc83c
|
752 |
#endif |
c6dd940b1
|
753 |
.can_early_drop = sctp_can_early_drop, |
c0cd11566
|
754 |
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
392158467
|
755 |
.nlattr_size = SCTP_NLATTR_SIZE, |
a258860e0
|
756 757 |
.to_nlattr = sctp_to_nlattr, .from_nlattr = nlattr_to_sctp, |
c7212e9d3
|
758 |
.tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
a400c30ed
|
759 |
.nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, |
c7212e9d3
|
760 761 762 |
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, .nla_policy = nf_ct_port_nla_policy, #endif |
a874752a1
|
763 |
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
509784623
|
764 765 766 767 768 769 770 |
.ctnl_timeout = { .nlattr_to_obj = sctp_timeout_nlattr_to_obj, .obj_to_nlattr = sctp_timeout_obj_to_nlattr, .nlattr_max = CTA_TIMEOUT_SCTP_MAX, .obj_size = sizeof(unsigned int) * SCTP_CONNTRACK_MAX, .nla_policy = sctp_timeout_nla_policy, }, |
a874752a1
|
771 |
#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
f42c4183c
|
772 |
.init_net = sctp_init_net, |
deaa0a976
|
773 |
.get_net_proto = sctp_get_net_proto, |
9fb9cbb10
|
774 |
}; |