Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[NETFILTER]: nf_conntrack: add DCCP protocol support

Add DCCP conntrack helper. Thanks to Gerrit Renker <gerrit@erg.abdn.ac.uk>
for review and testing.

Signed-off-by: Patrick McHardy <kaber@trash.net>

+883
+40
include/linux/netfilter/nf_conntrack_dccp.h
··· 1 + #ifndef _NF_CONNTRACK_DCCP_H 2 + #define _NF_CONNTRACK_DCCP_H 3 + 4 + /* Exposed to userspace over nfnetlink */ 5 + enum ct_dccp_states { 6 + CT_DCCP_NONE, 7 + CT_DCCP_REQUEST, 8 + CT_DCCP_RESPOND, 9 + CT_DCCP_PARTOPEN, 10 + CT_DCCP_OPEN, 11 + CT_DCCP_CLOSEREQ, 12 + CT_DCCP_CLOSING, 13 + CT_DCCP_TIMEWAIT, 14 + CT_DCCP_IGNORE, 15 + CT_DCCP_INVALID, 16 + __CT_DCCP_MAX 17 + }; 18 + #define CT_DCCP_MAX (__CT_DCCP_MAX - 1) 19 + 20 + enum ct_dccp_roles { 21 + CT_DCCP_ROLE_CLIENT, 22 + CT_DCCP_ROLE_SERVER, 23 + __CT_DCCP_ROLE_MAX 24 + }; 25 + #define CT_DCCP_ROLE_MAX (__CT_DCCP_ROLE_MAX - 1) 26 + 27 + #ifdef __KERNEL__ 28 + #include <net/netfilter/nf_conntrack_tuple.h> 29 + 30 + struct nf_ct_dccp { 31 + u_int8_t role[IP_CT_DIR_MAX]; 32 + u_int8_t state; 33 + u_int8_t last_pkt; 34 + u_int8_t last_dir; 35 + u_int64_t handshake_seq; 36 + }; 37 + 38 + #endif /* __KERNEL__ */ 39 + 40 + #endif /* _NF_CONNTRACK_DCCP_H */
+2
include/net/netfilter/nf_conntrack.h
··· 20 20 #include <asm/atomic.h> 21 21 22 22 #include <linux/netfilter/nf_conntrack_tcp.h> 23 + #include <linux/netfilter/nf_conntrack_dccp.h> 23 24 #include <linux/netfilter/nf_conntrack_sctp.h> 24 25 #include <linux/netfilter/nf_conntrack_proto_gre.h> 25 26 #include <net/netfilter/ipv4/nf_conntrack_icmp.h> ··· 31 30 /* per conntrack: protocol private data */ 32 31 union nf_conntrack_proto { 33 32 /* insert conntrack proto private data here */ 33 + struct nf_ct_dccp dccp; 34 34 struct ip_ct_sctp sctp; 35 35 struct ip_ct_tcp tcp; 36 36 struct ip_ct_icmp icmp;
+6
include/net/netfilter/nf_conntrack_tuple.h
··· 41 41 } icmp; 42 42 struct { 43 43 __be16 port; 44 + } dccp; 45 + struct { 46 + __be16 port; 44 47 } sctp; 45 48 struct { 46 49 __be16 key; /* GRE key is 32bit, PPtP only uses 16bit */ ··· 80 77 struct { 81 78 u_int8_t type, code; 82 79 } icmp; 80 + struct { 81 + __be16 port; 82 + } dccp; 83 83 struct { 84 84 __be16 port; 85 85 } sctp;
+10
net/netfilter/Kconfig
··· 86 86 87 87 If unsure, say `N'. 88 88 89 + config NF_CT_PROTO_DCCP 90 + tristate 'DCCP protocol connection tracking support (EXPERIMENTAL)' 91 + depends on EXPERIMENTAL && NF_CONNTRACK 92 + depends on NETFILTER_ADVANCED 93 + help 94 + With this option enabled, the layer 3 independent connection 95 + tracking code will be able to do state tracking on DCCP connections. 96 + 97 + If unsure, say 'N'. 98 + 89 99 config NF_CT_PROTO_GRE 90 100 tristate 91 101 depends on NF_CONNTRACK
+1
net/netfilter/Makefile
··· 13 13 obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o 14 14 15 15 # SCTP protocol connection tracking 16 + obj-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o 16 17 obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o 17 18 obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o 18 19 obj-$(CONFIG_NF_CT_PROTO_UDPLITE) += nf_conntrack_proto_udplite.o
+816
net/netfilter/nf_conntrack_proto_dccp.c
··· 1 + /* 2 + * DCCP connection tracking protocol helper 3 + * 4 + * Copyright (c) 2005, 2006, 2008 Patrick McHardy <kaber@trash.net> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + * 10 + */ 11 + #include <linux/kernel.h> 12 + #include <linux/module.h> 13 + #include <linux/init.h> 14 + #include <linux/sysctl.h> 15 + #include <linux/spinlock.h> 16 + #include <linux/skbuff.h> 17 + #include <linux/dccp.h> 18 + 19 + #include <linux/netfilter/nfnetlink_conntrack.h> 20 + #include <net/netfilter/nf_conntrack.h> 21 + #include <net/netfilter/nf_conntrack_l4proto.h> 22 + #include <net/netfilter/nf_log.h> 23 + 24 + static DEFINE_RWLOCK(dccp_lock); 25 + 26 + static int nf_ct_dccp_loose __read_mostly = 1; 27 + 28 + /* Timeouts are based on values from RFC4340: 29 + * 30 + * - REQUEST: 31 + * 32 + * 8.1.2. Client Request 33 + * 34 + * A client MAY give up on its DCCP-Requests after some time 35 + * (3 minutes, for example). 36 + * 37 + * - RESPOND: 38 + * 39 + * 8.1.3. Server Response 40 + * 41 + * It MAY also leave the RESPOND state for CLOSED after a timeout of 42 + * not less than 4MSL (8 minutes); 43 + * 44 + * - PARTOPEN: 45 + * 46 + * 8.1.5. Handshake Completion 47 + * 48 + * If the client remains in PARTOPEN for more than 4MSL (8 minutes), 49 + * it SHOULD reset the connection with Reset Code 2, "Aborted". 50 + * 51 + * - OPEN: 52 + * 53 + * The DCCP timestamp overflows after 11.9 hours. If the connection 54 + * stays idle this long the sequence number won't be recognized 55 + * as valid anymore. 56 + * 57 + * - CLOSEREQ/CLOSING: 58 + * 59 + * 8.3. Termination 60 + * 61 + * The retransmission timer should initially be set to go off in two 62 + * round-trip times and should back off to not less than once every 63 + * 64 seconds ... 64 + * 65 + * - TIMEWAIT: 66 + * 67 + * 4.3. States 68 + * 69 + * A server or client socket remains in this state for 2MSL (4 minutes) 70 + * after the connection has been town down, ... 71 + */ 72 + 73 + #define DCCP_MSL (2 * 60 * HZ) 74 + 75 + static unsigned int dccp_timeout[CT_DCCP_MAX + 1] __read_mostly = { 76 + [CT_DCCP_REQUEST] = 2 * DCCP_MSL, 77 + [CT_DCCP_RESPOND] = 4 * DCCP_MSL, 78 + [CT_DCCP_PARTOPEN] = 4 * DCCP_MSL, 79 + [CT_DCCP_OPEN] = 12 * 3600 * HZ, 80 + [CT_DCCP_CLOSEREQ] = 64 * HZ, 81 + [CT_DCCP_CLOSING] = 64 * HZ, 82 + [CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL, 83 + }; 84 + 85 + static const char * const dccp_state_names[] = { 86 + [CT_DCCP_NONE] = "NONE", 87 + [CT_DCCP_REQUEST] = "REQUEST", 88 + [CT_DCCP_RESPOND] = "RESPOND", 89 + [CT_DCCP_PARTOPEN] = "PARTOPEN", 90 + [CT_DCCP_OPEN] = "OPEN", 91 + [CT_DCCP_CLOSEREQ] = "CLOSEREQ", 92 + [CT_DCCP_CLOSING] = "CLOSING", 93 + [CT_DCCP_TIMEWAIT] = "TIMEWAIT", 94 + [CT_DCCP_IGNORE] = "IGNORE", 95 + [CT_DCCP_INVALID] = "INVALID", 96 + }; 97 + 98 + #define sNO CT_DCCP_NONE 99 + #define sRQ CT_DCCP_REQUEST 100 + #define sRS CT_DCCP_RESPOND 101 + #define sPO CT_DCCP_PARTOPEN 102 + #define sOP CT_DCCP_OPEN 103 + #define sCR CT_DCCP_CLOSEREQ 104 + #define sCG CT_DCCP_CLOSING 105 + #define sTW CT_DCCP_TIMEWAIT 106 + #define sIG CT_DCCP_IGNORE 107 + #define sIV CT_DCCP_INVALID 108 + 109 + /* 110 + * DCCP state transistion table 111 + * 112 + * The assumption is the same as for TCP tracking: 113 + * 114 + * We are the man in the middle. All the packets go through us but might 115 + * get lost in transit to the destination. It is assumed that the destination 116 + * can't receive segments we haven't seen. 117 + * 118 + * The following states exist: 119 + * 120 + * NONE: Initial state, expecting Request 121 + * REQUEST: Request seen, waiting for Response from server 122 + * RESPOND: Response from server seen, waiting for Ack from client 123 + * PARTOPEN: Ack after Response seen, waiting for packet other than Response, 124 + * Reset or Sync from server 125 + * OPEN: Packet other than Response, Reset or Sync seen 126 + * CLOSEREQ: CloseReq from server seen, expecting Close from client 127 + * CLOSING: Close seen, expecting Reset 128 + * TIMEWAIT: Reset seen 129 + * IGNORE: Not determinable whether packet is valid 130 + * 131 + * Some states exist only on one side of the connection: REQUEST, RESPOND, 132 + * PARTOPEN, CLOSEREQ. For the other side these states are equivalent to 133 + * the one it was in before. 134 + * 135 + * Packets are marked as ignored (sIG) if we don't know if they're valid 136 + * (for example a reincarnation of a connection we didn't notice is dead 137 + * already) and the server may send back a connection closing Reset or a 138 + * Response. They're also used for Sync/SyncAck packets, which we don't 139 + * care about. 140 + */ 141 + static const u_int8_t 142 + dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = { 143 + [CT_DCCP_ROLE_CLIENT] = { 144 + [DCCP_PKT_REQUEST] = { 145 + /* 146 + * sNO -> sRQ Regular Request 147 + * sRQ -> sRQ Retransmitted Request or reincarnation 148 + * sRS -> sRS Retransmitted Request (apparently Response 149 + * got lost after we saw it) or reincarnation 150 + * sPO -> sIG Ignore, conntrack might be out of sync 151 + * sOP -> sIG Ignore, conntrack might be out of sync 152 + * sCR -> sIG Ignore, conntrack might be out of sync 153 + * sCG -> sIG Ignore, conntrack might be out of sync 154 + * sTW -> sRQ Reincarnation 155 + * 156 + * sNO, sRQ, sRS, sPO. sOP, sCR, sCG, sTW, */ 157 + sRQ, sRQ, sRS, sIG, sIG, sIG, sIG, sRQ, 158 + }, 159 + [DCCP_PKT_RESPONSE] = { 160 + /* 161 + * sNO -> sIV Invalid 162 + * sRQ -> sIG Ignore, might be response to ignored Request 163 + * sRS -> sIG Ignore, might be response to ignored Request 164 + * sPO -> sIG Ignore, might be response to ignored Request 165 + * sOP -> sIG Ignore, might be response to ignored Request 166 + * sCR -> sIG Ignore, might be response to ignored Request 167 + * sCG -> sIG Ignore, might be response to ignored Request 168 + * sTW -> sIV Invalid, reincarnation in reverse direction 169 + * goes through sRQ 170 + * 171 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 172 + sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIV, 173 + }, 174 + [DCCP_PKT_ACK] = { 175 + /* 176 + * sNO -> sIV No connection 177 + * sRQ -> sIV No connection 178 + * sRS -> sPO Ack for Response, move to PARTOPEN (8.1.5.) 179 + * sPO -> sPO Retransmitted Ack for Response, remain in PARTOPEN 180 + * sOP -> sOP Regular ACK, remain in OPEN 181 + * sCR -> sCR Ack in CLOSEREQ MAY be processed (8.3.) 182 + * sCG -> sCG Ack in CLOSING MAY be processed (8.3.) 183 + * sTW -> sIV 184 + * 185 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 186 + sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV 187 + }, 188 + [DCCP_PKT_DATA] = { 189 + /* 190 + * sNO -> sIV No connection 191 + * sRQ -> sIV No connection 192 + * sRS -> sIV No connection 193 + * sPO -> sIV MUST use DataAck in PARTOPEN state (8.1.5.) 194 + * sOP -> sOP Regular Data packet 195 + * sCR -> sCR Data in CLOSEREQ MAY be processed (8.3.) 196 + * sCG -> sCG Data in CLOSING MAY be processed (8.3.) 197 + * sTW -> sIV 198 + * 199 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 200 + sIV, sIV, sIV, sIV, sOP, sCR, sCG, sIV, 201 + }, 202 + [DCCP_PKT_DATAACK] = { 203 + /* 204 + * sNO -> sIV No connection 205 + * sRQ -> sIV No connection 206 + * sRS -> sPO Ack for Response, move to PARTOPEN (8.1.5.) 207 + * sPO -> sPO Remain in PARTOPEN state 208 + * sOP -> sOP Regular DataAck packet in OPEN state 209 + * sCR -> sCR DataAck in CLOSEREQ MAY be processed (8.3.) 210 + * sCG -> sCG DataAck in CLOSING MAY be processed (8.3.) 211 + * sTW -> sIV 212 + * 213 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 214 + sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV 215 + }, 216 + [DCCP_PKT_CLOSEREQ] = { 217 + /* 218 + * CLOSEREQ may only be sent by the server. 219 + * 220 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 221 + sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV 222 + }, 223 + [DCCP_PKT_CLOSE] = { 224 + /* 225 + * sNO -> sIV No connection 226 + * sRQ -> sIV No connection 227 + * sRS -> sIV No connection 228 + * sPO -> sCG Client-initiated close 229 + * sOP -> sCG Client-initiated close 230 + * sCR -> sCG Close in response to CloseReq (8.3.) 231 + * sCG -> sCG Retransmit 232 + * sTW -> sIV Late retransmit, already in TIME_WAIT 233 + * 234 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 235 + sIV, sIV, sIV, sCG, sCG, sCG, sIV, sIV 236 + }, 237 + [DCCP_PKT_RESET] = { 238 + /* 239 + * sNO -> sIV No connection 240 + * sRQ -> sTW Sync received or timeout, SHOULD send Reset (8.1.1.) 241 + * sRS -> sTW Response received without Request 242 + * sPO -> sTW Timeout, SHOULD send Reset (8.1.5.) 243 + * sOP -> sTW Connection reset 244 + * sCR -> sTW Connection reset 245 + * sCG -> sTW Connection reset 246 + * sTW -> sIG Ignore (don't refresh timer) 247 + * 248 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 249 + sIV, sTW, sTW, sTW, sTW, sTW, sTW, sIG 250 + }, 251 + [DCCP_PKT_SYNC] = { 252 + /* 253 + * We currently ignore Sync packets 254 + * 255 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 256 + sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, 257 + }, 258 + [DCCP_PKT_SYNCACK] = { 259 + /* 260 + * We currently ignore SyncAck packets 261 + * 262 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 263 + sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, 264 + }, 265 + }, 266 + [CT_DCCP_ROLE_SERVER] = { 267 + [DCCP_PKT_REQUEST] = { 268 + /* 269 + * sNO -> sIV Invalid 270 + * sRQ -> sIG Ignore, conntrack might be out of sync 271 + * sRS -> sIG Ignore, conntrack might be out of sync 272 + * sPO -> sIG Ignore, conntrack might be out of sync 273 + * sOP -> sIG Ignore, conntrack might be out of sync 274 + * sCR -> sIG Ignore, conntrack might be out of sync 275 + * sCG -> sIG Ignore, conntrack might be out of sync 276 + * sTW -> sRQ Reincarnation, must reverse roles 277 + * 278 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 279 + sIV, sIG, sIG, sIG, sIG, sIG, sIG, sRQ 280 + }, 281 + [DCCP_PKT_RESPONSE] = { 282 + /* 283 + * sNO -> sIV Response without Request 284 + * sRQ -> sRS Response to clients Request 285 + * sRS -> sRS Retransmitted Response (8.1.3. SHOULD NOT) 286 + * sPO -> sIG Response to an ignored Request or late retransmit 287 + * sOP -> sIG Ignore, might be response to ignored Request 288 + * sCR -> sIG Ignore, might be response to ignored Request 289 + * sCG -> sIG Ignore, might be response to ignored Request 290 + * sTW -> sIV Invalid, Request from client in sTW moves to sRQ 291 + * 292 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 293 + sIV, sRS, sRS, sIG, sIG, sIG, sIG, sIV 294 + }, 295 + [DCCP_PKT_ACK] = { 296 + /* 297 + * sNO -> sIV No connection 298 + * sRQ -> sIV No connection 299 + * sRS -> sIV No connection 300 + * sPO -> sOP Enter OPEN state (8.1.5.) 301 + * sOP -> sOP Regular Ack in OPEN state 302 + * sCR -> sIV Waiting for Close from client 303 + * sCG -> sCG Ack in CLOSING MAY be processed (8.3.) 304 + * sTW -> sIV 305 + * 306 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 307 + sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV 308 + }, 309 + [DCCP_PKT_DATA] = { 310 + /* 311 + * sNO -> sIV No connection 312 + * sRQ -> sIV No connection 313 + * sRS -> sIV No connection 314 + * sPO -> sOP Enter OPEN state (8.1.5.) 315 + * sOP -> sOP Regular Data packet in OPEN state 316 + * sCR -> sIV Waiting for Close from client 317 + * sCG -> sCG Data in CLOSING MAY be processed (8.3.) 318 + * sTW -> sIV 319 + * 320 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 321 + sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV 322 + }, 323 + [DCCP_PKT_DATAACK] = { 324 + /* 325 + * sNO -> sIV No connection 326 + * sRQ -> sIV No connection 327 + * sRS -> sIV No connection 328 + * sPO -> sOP Enter OPEN state (8.1.5.) 329 + * sOP -> sOP Regular DataAck in OPEN state 330 + * sCR -> sIV Waiting for Close from client 331 + * sCG -> sCG Data in CLOSING MAY be processed (8.3.) 332 + * sTW -> sIV 333 + * 334 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 335 + sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV 336 + }, 337 + [DCCP_PKT_CLOSEREQ] = { 338 + /* 339 + * sNO -> sIV No connection 340 + * sRQ -> sIV No connection 341 + * sRS -> sIV No connection 342 + * sPO -> sOP -> sCR Move directly to CLOSEREQ (8.1.5.) 343 + * sOP -> sCR CloseReq in OPEN state 344 + * sCR -> sCR Retransmit 345 + * sCG -> sCR Simultaneous close, client sends another Close 346 + * sTW -> sIV Already closed 347 + * 348 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 349 + sIV, sIV, sIV, sCR, sCR, sCR, sCR, sIV 350 + }, 351 + [DCCP_PKT_CLOSE] = { 352 + /* 353 + * sNO -> sIV No connection 354 + * sRQ -> sIV No connection 355 + * sRS -> sIV No connection 356 + * sPO -> sOP -> sCG Move direcly to CLOSING 357 + * sOP -> sCG Move to CLOSING 358 + * sCR -> sIV Close after CloseReq is invalid 359 + * sCG -> sCG Retransmit 360 + * sTW -> sIV Already closed 361 + * 362 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 363 + sIV, sIV, sIV, sCG, sCG, sIV, sCG, sIV 364 + }, 365 + [DCCP_PKT_RESET] = { 366 + /* 367 + * sNO -> sIV No connection 368 + * sRQ -> sTW Reset in response to Request 369 + * sRS -> sTW Timeout, SHOULD send Reset (8.1.3.) 370 + * sPO -> sTW Timeout, SHOULD send Reset (8.1.3.) 371 + * sOP -> sTW 372 + * sCR -> sTW 373 + * sCG -> sTW 374 + * sTW -> sIG Ignore (don't refresh timer) 375 + * 376 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW, sTW */ 377 + sIV, sTW, sTW, sTW, sTW, sTW, sTW, sTW, sIG 378 + }, 379 + [DCCP_PKT_SYNC] = { 380 + /* 381 + * We currently ignore Sync packets 382 + * 383 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 384 + sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, 385 + }, 386 + [DCCP_PKT_SYNCACK] = { 387 + /* 388 + * We currently ignore SyncAck packets 389 + * 390 + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 391 + sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, 392 + }, 393 + }, 394 + }; 395 + 396 + static int dccp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, 397 + struct nf_conntrack_tuple *tuple) 398 + { 399 + struct dccp_hdr _hdr, *dh; 400 + 401 + dh = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); 402 + if (dh == NULL) 403 + return 0; 404 + 405 + tuple->src.u.dccp.port = dh->dccph_sport; 406 + tuple->dst.u.dccp.port = dh->dccph_dport; 407 + return 1; 408 + } 409 + 410 + static int dccp_invert_tuple(struct nf_conntrack_tuple *inv, 411 + const struct nf_conntrack_tuple *tuple) 412 + { 413 + inv->src.u.dccp.port = tuple->dst.u.dccp.port; 414 + inv->dst.u.dccp.port = tuple->src.u.dccp.port; 415 + return 1; 416 + } 417 + 418 + static int dccp_new(struct nf_conn *ct, const struct sk_buff *skb, 419 + unsigned int dataoff) 420 + { 421 + int pf = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; 422 + struct dccp_hdr _dh, *dh; 423 + const char *msg; 424 + u_int8_t state; 425 + 426 + dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); 427 + BUG_ON(dh == NULL); 428 + 429 + state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE]; 430 + switch (state) { 431 + default: 432 + if (nf_ct_dccp_loose == 0) { 433 + msg = "nf_ct_dccp: not picking up existing connection "; 434 + goto out_invalid; 435 + } 436 + case CT_DCCP_REQUEST: 437 + break; 438 + case CT_DCCP_INVALID: 439 + msg = "nf_ct_dccp: invalid state transition "; 440 + goto out_invalid; 441 + } 442 + 443 + ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT; 444 + ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER; 445 + ct->proto.dccp.state = CT_DCCP_NONE; 446 + return 1; 447 + 448 + out_invalid: 449 + if (LOG_INVALID(IPPROTO_DCCP)) 450 + nf_log_packet(pf, 0, skb, NULL, NULL, NULL, msg); 451 + return 0; 452 + } 453 + 454 + static u64 dccp_ack_seq(const struct dccp_hdr *dh) 455 + { 456 + const struct dccp_hdr_ack_bits *dhack; 457 + 458 + dhack = (void *)dh + __dccp_basic_hdr_len(dh); 459 + return ((u64)ntohs(dhack->dccph_ack_nr_high) << 32) + 460 + ntohl(dhack->dccph_ack_nr_low); 461 + } 462 + 463 + static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, 464 + unsigned int dataoff, enum ip_conntrack_info ctinfo, 465 + int pf, unsigned int hooknum) 466 + { 467 + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 468 + struct dccp_hdr _dh, *dh; 469 + u_int8_t type, old_state, new_state; 470 + enum ct_dccp_roles role; 471 + 472 + dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); 473 + BUG_ON(dh == NULL); 474 + type = dh->dccph_type; 475 + 476 + if (type == DCCP_PKT_RESET && 477 + !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { 478 + /* Tear down connection immediately if only reply is a RESET */ 479 + if (del_timer(&ct->timeout)) 480 + ct->timeout.function((unsigned long)ct); 481 + return NF_ACCEPT; 482 + } 483 + 484 + write_lock_bh(&dccp_lock); 485 + 486 + role = ct->proto.dccp.role[dir]; 487 + old_state = ct->proto.dccp.state; 488 + new_state = dccp_state_table[role][type][old_state]; 489 + 490 + switch (new_state) { 491 + case CT_DCCP_REQUEST: 492 + if (old_state == CT_DCCP_TIMEWAIT && 493 + role == CT_DCCP_ROLE_SERVER) { 494 + /* Reincarnation in the reverse direction: reopen and 495 + * reverse client/server roles. */ 496 + ct->proto.dccp.role[dir] = CT_DCCP_ROLE_CLIENT; 497 + ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_SERVER; 498 + } 499 + break; 500 + case CT_DCCP_RESPOND: 501 + if (old_state == CT_DCCP_REQUEST) 502 + ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh); 503 + break; 504 + case CT_DCCP_PARTOPEN: 505 + if (old_state == CT_DCCP_RESPOND && 506 + type == DCCP_PKT_ACK && 507 + dccp_ack_seq(dh) == ct->proto.dccp.handshake_seq) 508 + set_bit(IPS_ASSURED_BIT, &ct->status); 509 + break; 510 + case CT_DCCP_IGNORE: 511 + /* 512 + * Connection tracking might be out of sync, so we ignore 513 + * packets that might establish a new connection and resync 514 + * if the server responds with a valid Response. 515 + */ 516 + if (ct->proto.dccp.last_dir == !dir && 517 + ct->proto.dccp.last_pkt == DCCP_PKT_REQUEST && 518 + type == DCCP_PKT_RESPONSE) { 519 + ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_CLIENT; 520 + ct->proto.dccp.role[dir] = CT_DCCP_ROLE_SERVER; 521 + ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh); 522 + new_state = CT_DCCP_RESPOND; 523 + break; 524 + } 525 + ct->proto.dccp.last_dir = dir; 526 + ct->proto.dccp.last_pkt = type; 527 + 528 + write_unlock_bh(&dccp_lock); 529 + if (LOG_INVALID(IPPROTO_DCCP)) 530 + nf_log_packet(pf, 0, skb, NULL, NULL, NULL, 531 + "nf_ct_dccp: invalid packet ignored "); 532 + return NF_ACCEPT; 533 + case CT_DCCP_INVALID: 534 + write_unlock_bh(&dccp_lock); 535 + if (LOG_INVALID(IPPROTO_DCCP)) 536 + nf_log_packet(pf, 0, skb, NULL, NULL, NULL, 537 + "nf_ct_dccp: invalid state transition "); 538 + return -NF_ACCEPT; 539 + } 540 + 541 + ct->proto.dccp.last_dir = dir; 542 + ct->proto.dccp.last_pkt = type; 543 + ct->proto.dccp.state = new_state; 544 + write_unlock_bh(&dccp_lock); 545 + nf_ct_refresh_acct(ct, ctinfo, skb, dccp_timeout[new_state]); 546 + 547 + return NF_ACCEPT; 548 + } 549 + 550 + static int dccp_error(struct sk_buff *skb, unsigned int dataoff, 551 + enum ip_conntrack_info *ctinfo, int pf, 552 + unsigned int hooknum) 553 + { 554 + struct dccp_hdr _dh, *dh; 555 + unsigned int dccp_len = skb->len - dataoff; 556 + unsigned int cscov; 557 + const char *msg; 558 + 559 + dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); 560 + if (dh == NULL) { 561 + msg = "nf_ct_dccp: short packet "; 562 + goto out_invalid; 563 + } 564 + 565 + if (dh->dccph_doff * 4 < sizeof(struct dccp_hdr) || 566 + dh->dccph_doff * 4 > dccp_len) { 567 + msg = "nf_ct_dccp: truncated/malformed packet "; 568 + goto out_invalid; 569 + } 570 + 571 + cscov = dccp_len; 572 + if (dh->dccph_cscov) { 573 + cscov = (dh->dccph_cscov - 1) * 4; 574 + if (cscov > dccp_len) { 575 + msg = "nf_ct_dccp: bad checksum coverage "; 576 + goto out_invalid; 577 + } 578 + } 579 + 580 + if (nf_conntrack_checksum && hooknum == NF_INET_PRE_ROUTING && 581 + nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_DCCP, 582 + pf)) { 583 + msg = "nf_ct_dccp: bad checksum "; 584 + goto out_invalid; 585 + } 586 + 587 + if (dh->dccph_type >= DCCP_PKT_INVALID) { 588 + msg = "nf_ct_dccp: reserved packet type "; 589 + goto out_invalid; 590 + } 591 + 592 + return NF_ACCEPT; 593 + 594 + out_invalid: 595 + if (LOG_INVALID(IPPROTO_DCCP)) 596 + nf_log_packet(pf, 0, skb, NULL, NULL, NULL, msg); 597 + return -NF_ACCEPT; 598 + } 599 + 600 + static int dccp_print_tuple(struct seq_file *s, 601 + const struct nf_conntrack_tuple *tuple) 602 + { 603 + return seq_printf(s, "sport=%hu dport=%hu ", 604 + ntohs(tuple->src.u.dccp.port), 605 + ntohs(tuple->dst.u.dccp.port)); 606 + } 607 + 608 + static int dccp_print_conntrack(struct seq_file *s, const struct nf_conn *ct) 609 + { 610 + return seq_printf(s, "%s ", dccp_state_names[ct->proto.dccp.state]); 611 + } 612 + 613 + #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 614 + static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, 615 + const struct nf_conn *ct) 616 + { 617 + struct nlattr *nest_parms; 618 + 619 + read_lock_bh(&dccp_lock); 620 + nest_parms = nla_nest_start(skb, CTA_PROTOINFO_DCCP | NLA_F_NESTED); 621 + if (!nest_parms) 622 + goto nla_put_failure; 623 + NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state); 624 + nla_nest_end(skb, nest_parms); 625 + read_unlock_bh(&dccp_lock); 626 + return 0; 627 + 628 + nla_put_failure: 629 + read_unlock_bh(&dccp_lock); 630 + return -1; 631 + } 632 + 633 + static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = { 634 + [CTA_PROTOINFO_DCCP_STATE] = { .type = NLA_U8 }, 635 + }; 636 + 637 + static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) 638 + { 639 + struct nlattr *attr = cda[CTA_PROTOINFO_DCCP]; 640 + struct nlattr *tb[CTA_PROTOINFO_DCCP_MAX + 1]; 641 + int err; 642 + 643 + if (!attr) 644 + return 0; 645 + 646 + err = nla_parse_nested(tb, CTA_PROTOINFO_DCCP_MAX, attr, 647 + dccp_nla_policy); 648 + if (err < 0) 649 + return err; 650 + 651 + if (!tb[CTA_PROTOINFO_DCCP_STATE] || 652 + nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]) >= CT_DCCP_IGNORE) 653 + return -EINVAL; 654 + 655 + write_lock_bh(&dccp_lock); 656 + ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]); 657 + write_unlock_bh(&dccp_lock); 658 + return 0; 659 + } 660 + #endif 661 + 662 + #ifdef CONFIG_SYSCTL 663 + static unsigned int dccp_sysctl_table_users; 664 + static struct ctl_table_header *dccp_sysctl_header; 665 + static ctl_table dccp_sysctl_table[] = { 666 + { 667 + .ctl_name = CTL_UNNUMBERED, 668 + .procname = "nf_conntrack_dccp_timeout_request", 669 + .data = &dccp_timeout[CT_DCCP_REQUEST], 670 + .maxlen = sizeof(unsigned int), 671 + .mode = 0644, 672 + .proc_handler = proc_dointvec_jiffies, 673 + }, 674 + { 675 + .ctl_name = CTL_UNNUMBERED, 676 + .procname = "nf_conntrack_dccp_timeout_respond", 677 + .data = &dccp_timeout[CT_DCCP_RESPOND], 678 + .maxlen = sizeof(unsigned int), 679 + .mode = 0644, 680 + .proc_handler = proc_dointvec_jiffies, 681 + }, 682 + { 683 + .ctl_name = CTL_UNNUMBERED, 684 + .procname = "nf_conntrack_dccp_timeout_partopen", 685 + .data = &dccp_timeout[CT_DCCP_PARTOPEN], 686 + .maxlen = sizeof(unsigned int), 687 + .mode = 0644, 688 + .proc_handler = proc_dointvec_jiffies, 689 + }, 690 + { 691 + .ctl_name = CTL_UNNUMBERED, 692 + .procname = "nf_conntrack_dccp_timeout_open", 693 + .data = &dccp_timeout[CT_DCCP_OPEN], 694 + .maxlen = sizeof(unsigned int), 695 + .mode = 0644, 696 + .proc_handler = proc_dointvec_jiffies, 697 + }, 698 + { 699 + .ctl_name = CTL_UNNUMBERED, 700 + .procname = "nf_conntrack_dccp_timeout_closereq", 701 + .data = &dccp_timeout[CT_DCCP_CLOSEREQ], 702 + .maxlen = sizeof(unsigned int), 703 + .mode = 0644, 704 + .proc_handler = proc_dointvec_jiffies, 705 + }, 706 + { 707 + .ctl_name = CTL_UNNUMBERED, 708 + .procname = "nf_conntrack_dccp_timeout_closing", 709 + .data = &dccp_timeout[CT_DCCP_CLOSING], 710 + .maxlen = sizeof(unsigned int), 711 + .mode = 0644, 712 + .proc_handler = proc_dointvec_jiffies, 713 + }, 714 + { 715 + .ctl_name = CTL_UNNUMBERED, 716 + .procname = "nf_conntrack_dccp_timeout_timewait", 717 + .data = &dccp_timeout[CT_DCCP_TIMEWAIT], 718 + .maxlen = sizeof(unsigned int), 719 + .mode = 0644, 720 + .proc_handler = proc_dointvec_jiffies, 721 + }, 722 + { 723 + .ctl_name = CTL_UNNUMBERED, 724 + .procname = "nf_conntrack_dccp_loose", 725 + .data = &nf_ct_dccp_loose, 726 + .maxlen = sizeof(nf_ct_dccp_loose), 727 + .mode = 0644, 728 + .proc_handler = proc_dointvec, 729 + }, 730 + { 731 + .ctl_name = 0, 732 + } 733 + }; 734 + #endif /* CONFIG_SYSCTL */ 735 + 736 + static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = { 737 + .l3proto = AF_INET, 738 + .l4proto = IPPROTO_DCCP, 739 + .name = "dccp", 740 + .pkt_to_tuple = dccp_pkt_to_tuple, 741 + .invert_tuple = dccp_invert_tuple, 742 + .new = dccp_new, 743 + .packet = dccp_packet, 744 + .error = dccp_error, 745 + .print_tuple = dccp_print_tuple, 746 + .print_conntrack = dccp_print_conntrack, 747 + #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 748 + .to_nlattr = dccp_to_nlattr, 749 + .from_nlattr = nlattr_to_dccp, 750 + .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, 751 + .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, 752 + .nla_policy = nf_ct_port_nla_policy, 753 + #endif 754 + #ifdef CONFIG_SYSCTL 755 + .ctl_table_users = &dccp_sysctl_table_users, 756 + .ctl_table_header = &dccp_sysctl_header, 757 + .ctl_table = dccp_sysctl_table, 758 + #endif 759 + }; 760 + 761 + static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { 762 + .l3proto = AF_INET6, 763 + .l4proto = IPPROTO_DCCP, 764 + .name = "dccp", 765 + .pkt_to_tuple = dccp_pkt_to_tuple, 766 + .invert_tuple = dccp_invert_tuple, 767 + .new = dccp_new, 768 + .packet = dccp_packet, 769 + .error = dccp_error, 770 + .print_tuple = dccp_print_tuple, 771 + .print_conntrack = dccp_print_conntrack, 772 + #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 773 + .to_nlattr = dccp_to_nlattr, 774 + .from_nlattr = nlattr_to_dccp, 775 + .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, 776 + .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, 777 + .nla_policy = nf_ct_port_nla_policy, 778 + #endif 779 + #ifdef CONFIG_SYSCTL 780 + .ctl_table_users = &dccp_sysctl_table_users, 781 + .ctl_table_header = &dccp_sysctl_header, 782 + .ctl_table = dccp_sysctl_table, 783 + #endif 784 + }; 785 + 786 + static int __init nf_conntrack_proto_dccp_init(void) 787 + { 788 + int err; 789 + 790 + err = nf_conntrack_l4proto_register(&dccp_proto4); 791 + if (err < 0) 792 + goto err1; 793 + 794 + err = nf_conntrack_l4proto_register(&dccp_proto6); 795 + if (err < 0) 796 + goto err2; 797 + return 0; 798 + 799 + err2: 800 + nf_conntrack_l4proto_unregister(&dccp_proto4); 801 + err1: 802 + return err; 803 + } 804 + 805 + static void __exit nf_conntrack_proto_dccp_fini(void) 806 + { 807 + nf_conntrack_l4proto_unregister(&dccp_proto6); 808 + nf_conntrack_l4proto_unregister(&dccp_proto4); 809 + } 810 + 811 + module_init(nf_conntrack_proto_dccp_init); 812 + module_exit(nf_conntrack_proto_dccp_fini); 813 + 814 + MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 815 + MODULE_DESCRIPTION("DCCP connection tracking protocol helper"); 816 + MODULE_LICENSE("GPL");