1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22bc78049SPatrick McHardy /*
32bc78049SPatrick McHardy * DCCP connection tracking protocol helper
42bc78049SPatrick McHardy *
52bc78049SPatrick McHardy * Copyright (c) 2005, 2006, 2008 Patrick McHardy <kaber@trash.net>
62bc78049SPatrick McHardy */
72bc78049SPatrick McHardy #include <linux/kernel.h>
82bc78049SPatrick McHardy #include <linux/init.h>
92bc78049SPatrick McHardy #include <linux/sysctl.h>
102bc78049SPatrick McHardy #include <linux/spinlock.h>
112bc78049SPatrick McHardy #include <linux/skbuff.h>
122bc78049SPatrick McHardy #include <linux/dccp.h>
135a0e3ad6STejun Heo #include <linux/slab.h>
142bc78049SPatrick McHardy
151546000fSCyrill Gorcunov #include <net/net_namespace.h>
161546000fSCyrill Gorcunov #include <net/netns/generic.h>
171546000fSCyrill Gorcunov
182bc78049SPatrick McHardy #include <linux/netfilter/nfnetlink_conntrack.h>
192bc78049SPatrick McHardy #include <net/netfilter/nf_conntrack.h>
202bc78049SPatrick McHardy #include <net/netfilter/nf_conntrack_l4proto.h>
21b38b1f61SPablo Neira Ayuso #include <net/netfilter/nf_conntrack_ecache.h>
22c779e849SFlorian Westphal #include <net/netfilter/nf_conntrack_timeout.h>
232bc78049SPatrick McHardy #include <net/netfilter/nf_log.h>
242bc78049SPatrick McHardy
252bc78049SPatrick McHardy /* Timeouts are based on values from RFC4340:
262bc78049SPatrick McHardy *
272bc78049SPatrick McHardy * - REQUEST:
282bc78049SPatrick McHardy *
292bc78049SPatrick McHardy * 8.1.2. Client Request
302bc78049SPatrick McHardy *
312bc78049SPatrick McHardy * A client MAY give up on its DCCP-Requests after some time
322bc78049SPatrick McHardy * (3 minutes, for example).
332bc78049SPatrick McHardy *
342bc78049SPatrick McHardy * - RESPOND:
352bc78049SPatrick McHardy *
362bc78049SPatrick McHardy * 8.1.3. Server Response
372bc78049SPatrick McHardy *
382bc78049SPatrick McHardy * It MAY also leave the RESPOND state for CLOSED after a timeout of
392bc78049SPatrick McHardy * not less than 4MSL (8 minutes);
402bc78049SPatrick McHardy *
412bc78049SPatrick McHardy * - PARTOPEN:
422bc78049SPatrick McHardy *
432bc78049SPatrick McHardy * 8.1.5. Handshake Completion
442bc78049SPatrick McHardy *
452bc78049SPatrick McHardy * If the client remains in PARTOPEN for more than 4MSL (8 minutes),
462bc78049SPatrick McHardy * it SHOULD reset the connection with Reset Code 2, "Aborted".
472bc78049SPatrick McHardy *
482bc78049SPatrick McHardy * - OPEN:
492bc78049SPatrick McHardy *
502bc78049SPatrick McHardy * The DCCP timestamp overflows after 11.9 hours. If the connection
512bc78049SPatrick McHardy * stays idle this long the sequence number won't be recognized
522bc78049SPatrick McHardy * as valid anymore.
532bc78049SPatrick McHardy *
542bc78049SPatrick McHardy * - CLOSEREQ/CLOSING:
552bc78049SPatrick McHardy *
562bc78049SPatrick McHardy * 8.3. Termination
572bc78049SPatrick McHardy *
582bc78049SPatrick McHardy * The retransmission timer should initially be set to go off in two
592bc78049SPatrick McHardy * round-trip times and should back off to not less than once every
602bc78049SPatrick McHardy * 64 seconds ...
612bc78049SPatrick McHardy *
622bc78049SPatrick McHardy * - TIMEWAIT:
632bc78049SPatrick McHardy *
642bc78049SPatrick McHardy * 4.3. States
652bc78049SPatrick McHardy *
662bc78049SPatrick McHardy * A server or client socket remains in this state for 2MSL (4 minutes)
672bc78049SPatrick McHardy * after the connection has been town down, ...
682bc78049SPatrick McHardy */
692bc78049SPatrick McHardy
702bc78049SPatrick McHardy #define DCCP_MSL (2 * 60 * HZ)
712bc78049SPatrick McHardy
72*a927d777SZhu Wang #ifdef CONFIG_NF_CONNTRACK_PROCFS
732bc78049SPatrick McHardy static const char * const dccp_state_names[] = {
742bc78049SPatrick McHardy [CT_DCCP_NONE] = "NONE",
752bc78049SPatrick McHardy [CT_DCCP_REQUEST] = "REQUEST",
762bc78049SPatrick McHardy [CT_DCCP_RESPOND] = "RESPOND",
772bc78049SPatrick McHardy [CT_DCCP_PARTOPEN] = "PARTOPEN",
782bc78049SPatrick McHardy [CT_DCCP_OPEN] = "OPEN",
792bc78049SPatrick McHardy [CT_DCCP_CLOSEREQ] = "CLOSEREQ",
802bc78049SPatrick McHardy [CT_DCCP_CLOSING] = "CLOSING",
812bc78049SPatrick McHardy [CT_DCCP_TIMEWAIT] = "TIMEWAIT",
822bc78049SPatrick McHardy [CT_DCCP_IGNORE] = "IGNORE",
832bc78049SPatrick McHardy [CT_DCCP_INVALID] = "INVALID",
842bc78049SPatrick McHardy };
85*a927d777SZhu Wang #endif
862bc78049SPatrick McHardy
872bc78049SPatrick McHardy #define sNO CT_DCCP_NONE
882bc78049SPatrick McHardy #define sRQ CT_DCCP_REQUEST
892bc78049SPatrick McHardy #define sRS CT_DCCP_RESPOND
902bc78049SPatrick McHardy #define sPO CT_DCCP_PARTOPEN
912bc78049SPatrick McHardy #define sOP CT_DCCP_OPEN
922bc78049SPatrick McHardy #define sCR CT_DCCP_CLOSEREQ
932bc78049SPatrick McHardy #define sCG CT_DCCP_CLOSING
942bc78049SPatrick McHardy #define sTW CT_DCCP_TIMEWAIT
952bc78049SPatrick McHardy #define sIG CT_DCCP_IGNORE
962bc78049SPatrick McHardy #define sIV CT_DCCP_INVALID
972bc78049SPatrick McHardy
982bc78049SPatrick McHardy /*
9925985edcSLucas De Marchi * DCCP state transition table
1002bc78049SPatrick McHardy *
1012bc78049SPatrick McHardy * The assumption is the same as for TCP tracking:
1022bc78049SPatrick McHardy *
1032bc78049SPatrick McHardy * We are the man in the middle. All the packets go through us but might
1042bc78049SPatrick McHardy * get lost in transit to the destination. It is assumed that the destination
1052bc78049SPatrick McHardy * can't receive segments we haven't seen.
1062bc78049SPatrick McHardy *
1072bc78049SPatrick McHardy * The following states exist:
1082bc78049SPatrick McHardy *
1092bc78049SPatrick McHardy * NONE: Initial state, expecting Request
1102bc78049SPatrick McHardy * REQUEST: Request seen, waiting for Response from server
1112bc78049SPatrick McHardy * RESPOND: Response from server seen, waiting for Ack from client
1122bc78049SPatrick McHardy * PARTOPEN: Ack after Response seen, waiting for packet other than Response,
1132bc78049SPatrick McHardy * Reset or Sync from server
1142bc78049SPatrick McHardy * OPEN: Packet other than Response, Reset or Sync seen
1152bc78049SPatrick McHardy * CLOSEREQ: CloseReq from server seen, expecting Close from client
1162bc78049SPatrick McHardy * CLOSING: Close seen, expecting Reset
1172bc78049SPatrick McHardy * TIMEWAIT: Reset seen
1182bc78049SPatrick McHardy * IGNORE: Not determinable whether packet is valid
1192bc78049SPatrick McHardy *
1202bc78049SPatrick McHardy * Some states exist only on one side of the connection: REQUEST, RESPOND,
1212bc78049SPatrick McHardy * PARTOPEN, CLOSEREQ. For the other side these states are equivalent to
1222bc78049SPatrick McHardy * the one it was in before.
1232bc78049SPatrick McHardy *
1242bc78049SPatrick McHardy * Packets are marked as ignored (sIG) if we don't know if they're valid
1252bc78049SPatrick McHardy * (for example a reincarnation of a connection we didn't notice is dead
1262bc78049SPatrick McHardy * already) and the server may send back a connection closing Reset or a
1272bc78049SPatrick McHardy * Response. They're also used for Sync/SyncAck packets, which we don't
1282bc78049SPatrick McHardy * care about.
1292bc78049SPatrick McHardy */
1302bc78049SPatrick McHardy static const u_int8_t
1312bc78049SPatrick McHardy dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = {
1322bc78049SPatrick McHardy [CT_DCCP_ROLE_CLIENT] = {
1332bc78049SPatrick McHardy [DCCP_PKT_REQUEST] = {
1342bc78049SPatrick McHardy /*
1352bc78049SPatrick McHardy * sNO -> sRQ Regular Request
1362bc78049SPatrick McHardy * sRQ -> sRQ Retransmitted Request or reincarnation
1372bc78049SPatrick McHardy * sRS -> sRS Retransmitted Request (apparently Response
1382bc78049SPatrick McHardy * got lost after we saw it) or reincarnation
1392bc78049SPatrick McHardy * sPO -> sIG Ignore, conntrack might be out of sync
1402bc78049SPatrick McHardy * sOP -> sIG Ignore, conntrack might be out of sync
1412bc78049SPatrick McHardy * sCR -> sIG Ignore, conntrack might be out of sync
1422bc78049SPatrick McHardy * sCG -> sIG Ignore, conntrack might be out of sync
1432bc78049SPatrick McHardy * sTW -> sRQ Reincarnation
1442bc78049SPatrick McHardy *
1452bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO. sOP, sCR, sCG, sTW, */
1462bc78049SPatrick McHardy sRQ, sRQ, sRS, sIG, sIG, sIG, sIG, sRQ,
1472bc78049SPatrick McHardy },
1482bc78049SPatrick McHardy [DCCP_PKT_RESPONSE] = {
1492bc78049SPatrick McHardy /*
1502bc78049SPatrick McHardy * sNO -> sIV Invalid
1512bc78049SPatrick McHardy * sRQ -> sIG Ignore, might be response to ignored Request
1522bc78049SPatrick McHardy * sRS -> sIG Ignore, might be response to ignored Request
1532bc78049SPatrick McHardy * sPO -> sIG Ignore, might be response to ignored Request
1542bc78049SPatrick McHardy * sOP -> sIG Ignore, might be response to ignored Request
1552bc78049SPatrick McHardy * sCR -> sIG Ignore, might be response to ignored Request
1562bc78049SPatrick McHardy * sCG -> sIG Ignore, might be response to ignored Request
1572bc78049SPatrick McHardy * sTW -> sIV Invalid, reincarnation in reverse direction
1582bc78049SPatrick McHardy * goes through sRQ
1592bc78049SPatrick McHardy *
1602bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
1612bc78049SPatrick McHardy sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIV,
1622bc78049SPatrick McHardy },
1632bc78049SPatrick McHardy [DCCP_PKT_ACK] = {
1642bc78049SPatrick McHardy /*
1652bc78049SPatrick McHardy * sNO -> sIV No connection
1662bc78049SPatrick McHardy * sRQ -> sIV No connection
1672bc78049SPatrick McHardy * sRS -> sPO Ack for Response, move to PARTOPEN (8.1.5.)
1682bc78049SPatrick McHardy * sPO -> sPO Retransmitted Ack for Response, remain in PARTOPEN
1692bc78049SPatrick McHardy * sOP -> sOP Regular ACK, remain in OPEN
1702bc78049SPatrick McHardy * sCR -> sCR Ack in CLOSEREQ MAY be processed (8.3.)
1712bc78049SPatrick McHardy * sCG -> sCG Ack in CLOSING MAY be processed (8.3.)
1722bc78049SPatrick McHardy * sTW -> sIV
1732bc78049SPatrick McHardy *
1742bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
1752bc78049SPatrick McHardy sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV
1762bc78049SPatrick McHardy },
1772bc78049SPatrick McHardy [DCCP_PKT_DATA] = {
1782bc78049SPatrick McHardy /*
1792bc78049SPatrick McHardy * sNO -> sIV No connection
1802bc78049SPatrick McHardy * sRQ -> sIV No connection
1812bc78049SPatrick McHardy * sRS -> sIV No connection
1822bc78049SPatrick McHardy * sPO -> sIV MUST use DataAck in PARTOPEN state (8.1.5.)
1832bc78049SPatrick McHardy * sOP -> sOP Regular Data packet
1842bc78049SPatrick McHardy * sCR -> sCR Data in CLOSEREQ MAY be processed (8.3.)
1852bc78049SPatrick McHardy * sCG -> sCG Data in CLOSING MAY be processed (8.3.)
1862bc78049SPatrick McHardy * sTW -> sIV
1872bc78049SPatrick McHardy *
1882bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
1892bc78049SPatrick McHardy sIV, sIV, sIV, sIV, sOP, sCR, sCG, sIV,
1902bc78049SPatrick McHardy },
1912bc78049SPatrick McHardy [DCCP_PKT_DATAACK] = {
1922bc78049SPatrick McHardy /*
1932bc78049SPatrick McHardy * sNO -> sIV No connection
1942bc78049SPatrick McHardy * sRQ -> sIV No connection
1952bc78049SPatrick McHardy * sRS -> sPO Ack for Response, move to PARTOPEN (8.1.5.)
1962bc78049SPatrick McHardy * sPO -> sPO Remain in PARTOPEN state
1972bc78049SPatrick McHardy * sOP -> sOP Regular DataAck packet in OPEN state
1982bc78049SPatrick McHardy * sCR -> sCR DataAck in CLOSEREQ MAY be processed (8.3.)
1992bc78049SPatrick McHardy * sCG -> sCG DataAck in CLOSING MAY be processed (8.3.)
2002bc78049SPatrick McHardy * sTW -> sIV
2012bc78049SPatrick McHardy *
2022bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2032bc78049SPatrick McHardy sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV
2042bc78049SPatrick McHardy },
2052bc78049SPatrick McHardy [DCCP_PKT_CLOSEREQ] = {
2062bc78049SPatrick McHardy /*
2072bc78049SPatrick McHardy * CLOSEREQ may only be sent by the server.
2082bc78049SPatrick McHardy *
2092bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2102bc78049SPatrick McHardy sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV
2112bc78049SPatrick McHardy },
2122bc78049SPatrick McHardy [DCCP_PKT_CLOSE] = {
2132bc78049SPatrick McHardy /*
2142bc78049SPatrick McHardy * sNO -> sIV No connection
2152bc78049SPatrick McHardy * sRQ -> sIV No connection
2162bc78049SPatrick McHardy * sRS -> sIV No connection
2172bc78049SPatrick McHardy * sPO -> sCG Client-initiated close
2182bc78049SPatrick McHardy * sOP -> sCG Client-initiated close
2192bc78049SPatrick McHardy * sCR -> sCG Close in response to CloseReq (8.3.)
2202bc78049SPatrick McHardy * sCG -> sCG Retransmit
2212bc78049SPatrick McHardy * sTW -> sIV Late retransmit, already in TIME_WAIT
2222bc78049SPatrick McHardy *
2232bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2242bc78049SPatrick McHardy sIV, sIV, sIV, sCG, sCG, sCG, sIV, sIV
2252bc78049SPatrick McHardy },
2262bc78049SPatrick McHardy [DCCP_PKT_RESET] = {
2272bc78049SPatrick McHardy /*
2282bc78049SPatrick McHardy * sNO -> sIV No connection
2292bc78049SPatrick McHardy * sRQ -> sTW Sync received or timeout, SHOULD send Reset (8.1.1.)
2302bc78049SPatrick McHardy * sRS -> sTW Response received without Request
2312bc78049SPatrick McHardy * sPO -> sTW Timeout, SHOULD send Reset (8.1.5.)
2322bc78049SPatrick McHardy * sOP -> sTW Connection reset
2332bc78049SPatrick McHardy * sCR -> sTW Connection reset
2342bc78049SPatrick McHardy * sCG -> sTW Connection reset
2352bc78049SPatrick McHardy * sTW -> sIG Ignore (don't refresh timer)
2362bc78049SPatrick McHardy *
2372bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2382bc78049SPatrick McHardy sIV, sTW, sTW, sTW, sTW, sTW, sTW, sIG
2392bc78049SPatrick McHardy },
2402bc78049SPatrick McHardy [DCCP_PKT_SYNC] = {
2412bc78049SPatrick McHardy /*
2422bc78049SPatrick McHardy * We currently ignore Sync packets
2432bc78049SPatrick McHardy *
2442bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2456613b617SFlorian Westphal sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG,
2462bc78049SPatrick McHardy },
2472bc78049SPatrick McHardy [DCCP_PKT_SYNCACK] = {
2482bc78049SPatrick McHardy /*
2492bc78049SPatrick McHardy * We currently ignore SyncAck packets
2502bc78049SPatrick McHardy *
2512bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2526613b617SFlorian Westphal sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG,
2532bc78049SPatrick McHardy },
2542bc78049SPatrick McHardy },
2552bc78049SPatrick McHardy [CT_DCCP_ROLE_SERVER] = {
2562bc78049SPatrick McHardy [DCCP_PKT_REQUEST] = {
2572bc78049SPatrick McHardy /*
2582bc78049SPatrick McHardy * sNO -> sIV Invalid
2592bc78049SPatrick McHardy * sRQ -> sIG Ignore, conntrack might be out of sync
2602bc78049SPatrick McHardy * sRS -> sIG Ignore, conntrack might be out of sync
2612bc78049SPatrick McHardy * sPO -> sIG Ignore, conntrack might be out of sync
2622bc78049SPatrick McHardy * sOP -> sIG Ignore, conntrack might be out of sync
2632bc78049SPatrick McHardy * sCR -> sIG Ignore, conntrack might be out of sync
2642bc78049SPatrick McHardy * sCG -> sIG Ignore, conntrack might be out of sync
2652bc78049SPatrick McHardy * sTW -> sRQ Reincarnation, must reverse roles
2662bc78049SPatrick McHardy *
2672bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2682bc78049SPatrick McHardy sIV, sIG, sIG, sIG, sIG, sIG, sIG, sRQ
2692bc78049SPatrick McHardy },
2702bc78049SPatrick McHardy [DCCP_PKT_RESPONSE] = {
2712bc78049SPatrick McHardy /*
2722bc78049SPatrick McHardy * sNO -> sIV Response without Request
2732bc78049SPatrick McHardy * sRQ -> sRS Response to clients Request
2742bc78049SPatrick McHardy * sRS -> sRS Retransmitted Response (8.1.3. SHOULD NOT)
2752bc78049SPatrick McHardy * sPO -> sIG Response to an ignored Request or late retransmit
2762bc78049SPatrick McHardy * sOP -> sIG Ignore, might be response to ignored Request
2772bc78049SPatrick McHardy * sCR -> sIG Ignore, might be response to ignored Request
2782bc78049SPatrick McHardy * sCG -> sIG Ignore, might be response to ignored Request
2792bc78049SPatrick McHardy * sTW -> sIV Invalid, Request from client in sTW moves to sRQ
2802bc78049SPatrick McHardy *
2812bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2822bc78049SPatrick McHardy sIV, sRS, sRS, sIG, sIG, sIG, sIG, sIV
2832bc78049SPatrick McHardy },
2842bc78049SPatrick McHardy [DCCP_PKT_ACK] = {
2852bc78049SPatrick McHardy /*
2862bc78049SPatrick McHardy * sNO -> sIV No connection
2872bc78049SPatrick McHardy * sRQ -> sIV No connection
2882bc78049SPatrick McHardy * sRS -> sIV No connection
2892bc78049SPatrick McHardy * sPO -> sOP Enter OPEN state (8.1.5.)
2902bc78049SPatrick McHardy * sOP -> sOP Regular Ack in OPEN state
2912bc78049SPatrick McHardy * sCR -> sIV Waiting for Close from client
2922bc78049SPatrick McHardy * sCG -> sCG Ack in CLOSING MAY be processed (8.3.)
2932bc78049SPatrick McHardy * sTW -> sIV
2942bc78049SPatrick McHardy *
2952bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
2962bc78049SPatrick McHardy sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV
2972bc78049SPatrick McHardy },
2982bc78049SPatrick McHardy [DCCP_PKT_DATA] = {
2992bc78049SPatrick McHardy /*
3002bc78049SPatrick McHardy * sNO -> sIV No connection
3012bc78049SPatrick McHardy * sRQ -> sIV No connection
3022bc78049SPatrick McHardy * sRS -> sIV No connection
3032bc78049SPatrick McHardy * sPO -> sOP Enter OPEN state (8.1.5.)
3042bc78049SPatrick McHardy * sOP -> sOP Regular Data packet in OPEN state
3052bc78049SPatrick McHardy * sCR -> sIV Waiting for Close from client
3062bc78049SPatrick McHardy * sCG -> sCG Data in CLOSING MAY be processed (8.3.)
3072bc78049SPatrick McHardy * sTW -> sIV
3082bc78049SPatrick McHardy *
3092bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3102bc78049SPatrick McHardy sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV
3112bc78049SPatrick McHardy },
3122bc78049SPatrick McHardy [DCCP_PKT_DATAACK] = {
3132bc78049SPatrick McHardy /*
3142bc78049SPatrick McHardy * sNO -> sIV No connection
3152bc78049SPatrick McHardy * sRQ -> sIV No connection
3162bc78049SPatrick McHardy * sRS -> sIV No connection
3172bc78049SPatrick McHardy * sPO -> sOP Enter OPEN state (8.1.5.)
3182bc78049SPatrick McHardy * sOP -> sOP Regular DataAck in OPEN state
3192bc78049SPatrick McHardy * sCR -> sIV Waiting for Close from client
3202bc78049SPatrick McHardy * sCG -> sCG Data in CLOSING MAY be processed (8.3.)
3212bc78049SPatrick McHardy * sTW -> sIV
3222bc78049SPatrick McHardy *
3232bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3242bc78049SPatrick McHardy sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV
3252bc78049SPatrick McHardy },
3262bc78049SPatrick McHardy [DCCP_PKT_CLOSEREQ] = {
3272bc78049SPatrick McHardy /*
3282bc78049SPatrick McHardy * sNO -> sIV No connection
3292bc78049SPatrick McHardy * sRQ -> sIV No connection
3302bc78049SPatrick McHardy * sRS -> sIV No connection
3312bc78049SPatrick McHardy * sPO -> sOP -> sCR Move directly to CLOSEREQ (8.1.5.)
3322bc78049SPatrick McHardy * sOP -> sCR CloseReq in OPEN state
3332bc78049SPatrick McHardy * sCR -> sCR Retransmit
3342bc78049SPatrick McHardy * sCG -> sCR Simultaneous close, client sends another Close
3352bc78049SPatrick McHardy * sTW -> sIV Already closed
3362bc78049SPatrick McHardy *
3372bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3382bc78049SPatrick McHardy sIV, sIV, sIV, sCR, sCR, sCR, sCR, sIV
3392bc78049SPatrick McHardy },
3402bc78049SPatrick McHardy [DCCP_PKT_CLOSE] = {
3412bc78049SPatrick McHardy /*
3422bc78049SPatrick McHardy * sNO -> sIV No connection
3432bc78049SPatrick McHardy * sRQ -> sIV No connection
3442bc78049SPatrick McHardy * sRS -> sIV No connection
3452bc78049SPatrick McHardy * sPO -> sOP -> sCG Move direcly to CLOSING
3462bc78049SPatrick McHardy * sOP -> sCG Move to CLOSING
3472bc78049SPatrick McHardy * sCR -> sIV Close after CloseReq is invalid
3482bc78049SPatrick McHardy * sCG -> sCG Retransmit
3492bc78049SPatrick McHardy * sTW -> sIV Already closed
3502bc78049SPatrick McHardy *
3512bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3522bc78049SPatrick McHardy sIV, sIV, sIV, sCG, sCG, sIV, sCG, sIV
3532bc78049SPatrick McHardy },
3542bc78049SPatrick McHardy [DCCP_PKT_RESET] = {
3552bc78049SPatrick McHardy /*
3562bc78049SPatrick McHardy * sNO -> sIV No connection
3572bc78049SPatrick McHardy * sRQ -> sTW Reset in response to Request
3582bc78049SPatrick McHardy * sRS -> sTW Timeout, SHOULD send Reset (8.1.3.)
3592bc78049SPatrick McHardy * sPO -> sTW Timeout, SHOULD send Reset (8.1.3.)
3602bc78049SPatrick McHardy * sOP -> sTW
3612bc78049SPatrick McHardy * sCR -> sTW
3622bc78049SPatrick McHardy * sCG -> sTW
3632bc78049SPatrick McHardy * sTW -> sIG Ignore (don't refresh timer)
3642bc78049SPatrick McHardy *
3652bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW, sTW */
3662bc78049SPatrick McHardy sIV, sTW, sTW, sTW, sTW, sTW, sTW, sTW, sIG
3672bc78049SPatrick McHardy },
3682bc78049SPatrick McHardy [DCCP_PKT_SYNC] = {
3692bc78049SPatrick McHardy /*
3702bc78049SPatrick McHardy * We currently ignore Sync packets
3712bc78049SPatrick McHardy *
3722bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3736613b617SFlorian Westphal sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG,
3742bc78049SPatrick McHardy },
3752bc78049SPatrick McHardy [DCCP_PKT_SYNCACK] = {
3762bc78049SPatrick McHardy /*
3772bc78049SPatrick McHardy * We currently ignore SyncAck packets
3782bc78049SPatrick McHardy *
3792bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
3806613b617SFlorian Westphal sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG,
3812bc78049SPatrick McHardy },
3822bc78049SPatrick McHardy },
3832bc78049SPatrick McHardy };
3842bc78049SPatrick McHardy
3859976fc6eSFlorian Westphal static noinline bool
dccp_new(struct nf_conn * ct,const struct sk_buff * skb,const struct dccp_hdr * dh,const struct nf_hook_state * hook_state)3869976fc6eSFlorian Westphal dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
38762eec0d7SFlorian Westphal const struct dccp_hdr *dh,
38862eec0d7SFlorian Westphal const struct nf_hook_state *hook_state)
3892bc78049SPatrick McHardy {
390c2a2c7e0SAlexey Dobriyan struct net *net = nf_ct_net(ct);
391c51d3901SDavide Caratti struct nf_dccp_net *dn;
3922bc78049SPatrick McHardy const char *msg;
3932bc78049SPatrick McHardy u_int8_t state;
3942bc78049SPatrick McHardy
3952bc78049SPatrick McHardy state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE];
3962bc78049SPatrick McHardy switch (state) {
3972bc78049SPatrick McHardy default:
398a95a7774SPablo Neira Ayuso dn = nf_dccp_pernet(net);
3991546000fSCyrill Gorcunov if (dn->dccp_loose == 0) {
4003d0b527bSFlorian Westphal msg = "not picking up existing connection ";
4012bc78049SPatrick McHardy goto out_invalid;
4022bc78049SPatrick McHardy }
403c2168e6bSGustavo A. R. Silva break;
4042bc78049SPatrick McHardy case CT_DCCP_REQUEST:
4052bc78049SPatrick McHardy break;
4062bc78049SPatrick McHardy case CT_DCCP_INVALID:
4073d0b527bSFlorian Westphal msg = "invalid state transition ";
4082bc78049SPatrick McHardy goto out_invalid;
4092bc78049SPatrick McHardy }
4102bc78049SPatrick McHardy
4112bc78049SPatrick McHardy ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT;
4122bc78049SPatrick McHardy ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER;
4132bc78049SPatrick McHardy ct->proto.dccp.state = CT_DCCP_NONE;
414e5fc9e7aSChangli Gao ct->proto.dccp.last_pkt = DCCP_PKT_REQUEST;
415e5fc9e7aSChangli Gao ct->proto.dccp.last_dir = IP_CT_DIR_ORIGINAL;
416e5fc9e7aSChangli Gao ct->proto.dccp.handshake_seq = 0;
41709f263cdSJan Engelhardt return true;
4182bc78049SPatrick McHardy
4192bc78049SPatrick McHardy out_invalid:
42062eec0d7SFlorian Westphal nf_ct_l4proto_log_invalid(skb, ct, hook_state, "%s", msg);
42109f263cdSJan Engelhardt return false;
4222bc78049SPatrick McHardy }
4232bc78049SPatrick McHardy
dccp_ack_seq(const struct dccp_hdr * dh)4242bc78049SPatrick McHardy static u64 dccp_ack_seq(const struct dccp_hdr *dh)
4252bc78049SPatrick McHardy {
4262bc78049SPatrick McHardy const struct dccp_hdr_ack_bits *dhack;
4272bc78049SPatrick McHardy
4282bc78049SPatrick McHardy dhack = (void *)dh + __dccp_basic_hdr_len(dh);
4292bc78049SPatrick McHardy return ((u64)ntohs(dhack->dccph_ack_nr_high) << 32) +
4302bc78049SPatrick McHardy ntohl(dhack->dccph_ack_nr_low);
4312bc78049SPatrick McHardy }
4322bc78049SPatrick McHardy
dccp_error(const struct dccp_hdr * dh,struct sk_buff * skb,unsigned int dataoff,const struct nf_hook_state * state)4330150ffbaSFlorian Westphal static bool dccp_error(const struct dccp_hdr *dh,
4340150ffbaSFlorian Westphal struct sk_buff *skb, unsigned int dataoff,
4350150ffbaSFlorian Westphal const struct nf_hook_state *state)
4360150ffbaSFlorian Westphal {
437ff0a3a7dSFlorian Westphal static const unsigned long require_seq48 = 1 << DCCP_PKT_REQUEST |
438ff0a3a7dSFlorian Westphal 1 << DCCP_PKT_RESPONSE |
439ff0a3a7dSFlorian Westphal 1 << DCCP_PKT_CLOSEREQ |
440ff0a3a7dSFlorian Westphal 1 << DCCP_PKT_CLOSE |
441ff0a3a7dSFlorian Westphal 1 << DCCP_PKT_RESET |
442ff0a3a7dSFlorian Westphal 1 << DCCP_PKT_SYNC |
443ff0a3a7dSFlorian Westphal 1 << DCCP_PKT_SYNCACK;
4440150ffbaSFlorian Westphal unsigned int dccp_len = skb->len - dataoff;
4450150ffbaSFlorian Westphal unsigned int cscov;
4460150ffbaSFlorian Westphal const char *msg;
447ff0a3a7dSFlorian Westphal u8 type;
448ff0a3a7dSFlorian Westphal
449ff0a3a7dSFlorian Westphal BUILD_BUG_ON(DCCP_PKT_INVALID >= BITS_PER_LONG);
4500150ffbaSFlorian Westphal
4510150ffbaSFlorian Westphal if (dh->dccph_doff * 4 < sizeof(struct dccp_hdr) ||
4520150ffbaSFlorian Westphal dh->dccph_doff * 4 > dccp_len) {
4530150ffbaSFlorian Westphal msg = "nf_ct_dccp: truncated/malformed packet ";
4540150ffbaSFlorian Westphal goto out_invalid;
4550150ffbaSFlorian Westphal }
4560150ffbaSFlorian Westphal
4570150ffbaSFlorian Westphal cscov = dccp_len;
4580150ffbaSFlorian Westphal if (dh->dccph_cscov) {
4590150ffbaSFlorian Westphal cscov = (dh->dccph_cscov - 1) * 4;
4600150ffbaSFlorian Westphal if (cscov > dccp_len) {
4610150ffbaSFlorian Westphal msg = "nf_ct_dccp: bad checksum coverage ";
4620150ffbaSFlorian Westphal goto out_invalid;
4630150ffbaSFlorian Westphal }
4640150ffbaSFlorian Westphal }
4650150ffbaSFlorian Westphal
4660150ffbaSFlorian Westphal if (state->hook == NF_INET_PRE_ROUTING &&
4670150ffbaSFlorian Westphal state->net->ct.sysctl_checksum &&
4680150ffbaSFlorian Westphal nf_checksum_partial(skb, state->hook, dataoff, cscov,
4690150ffbaSFlorian Westphal IPPROTO_DCCP, state->pf)) {
4700150ffbaSFlorian Westphal msg = "nf_ct_dccp: bad checksum ";
4710150ffbaSFlorian Westphal goto out_invalid;
4720150ffbaSFlorian Westphal }
4730150ffbaSFlorian Westphal
474ff0a3a7dSFlorian Westphal type = dh->dccph_type;
475ff0a3a7dSFlorian Westphal if (type >= DCCP_PKT_INVALID) {
4760150ffbaSFlorian Westphal msg = "nf_ct_dccp: reserved packet type ";
4770150ffbaSFlorian Westphal goto out_invalid;
4780150ffbaSFlorian Westphal }
479ff0a3a7dSFlorian Westphal
480ff0a3a7dSFlorian Westphal if (test_bit(type, &require_seq48) && !dh->dccph_x) {
481ff0a3a7dSFlorian Westphal msg = "nf_ct_dccp: type lacks 48bit sequence numbers";
482ff0a3a7dSFlorian Westphal goto out_invalid;
483ff0a3a7dSFlorian Westphal }
484ff0a3a7dSFlorian Westphal
4850150ffbaSFlorian Westphal return false;
4860150ffbaSFlorian Westphal out_invalid:
48762eec0d7SFlorian Westphal nf_l4proto_log_invalid(skb, state, IPPROTO_DCCP, "%s", msg);
4880150ffbaSFlorian Westphal return true;
4890150ffbaSFlorian Westphal }
4900150ffbaSFlorian Westphal
491ff0a3a7dSFlorian Westphal struct nf_conntrack_dccp_buf {
492ff0a3a7dSFlorian Westphal struct dccp_hdr dh; /* generic header part */
493ff0a3a7dSFlorian Westphal struct dccp_hdr_ext ext; /* optional depending dh->dccph_x */
494ff0a3a7dSFlorian Westphal union { /* depends on header type */
495ff0a3a7dSFlorian Westphal struct dccp_hdr_ack_bits ack;
496ff0a3a7dSFlorian Westphal struct dccp_hdr_request req;
497ff0a3a7dSFlorian Westphal struct dccp_hdr_response response;
498ff0a3a7dSFlorian Westphal struct dccp_hdr_reset rst;
499ff0a3a7dSFlorian Westphal } u;
500ff0a3a7dSFlorian Westphal };
501ff0a3a7dSFlorian Westphal
502ff0a3a7dSFlorian Westphal static struct dccp_hdr *
dccp_header_pointer(const struct sk_buff * skb,int offset,const struct dccp_hdr * dh,struct nf_conntrack_dccp_buf * buf)503ff0a3a7dSFlorian Westphal dccp_header_pointer(const struct sk_buff *skb, int offset, const struct dccp_hdr *dh,
504ff0a3a7dSFlorian Westphal struct nf_conntrack_dccp_buf *buf)
505ff0a3a7dSFlorian Westphal {
506ff0a3a7dSFlorian Westphal unsigned int hdrlen = __dccp_hdr_len(dh);
507ff0a3a7dSFlorian Westphal
508ff0a3a7dSFlorian Westphal if (hdrlen > sizeof(*buf))
509ff0a3a7dSFlorian Westphal return NULL;
510ff0a3a7dSFlorian Westphal
511ff0a3a7dSFlorian Westphal return skb_header_pointer(skb, offset, hdrlen, buf);
512ff0a3a7dSFlorian Westphal }
513ff0a3a7dSFlorian Westphal
nf_conntrack_dccp_packet(struct nf_conn * ct,struct sk_buff * skb,unsigned int dataoff,enum ip_conntrack_info ctinfo,const struct nf_hook_state * state)514a47c5404SFlorian Westphal int nf_conntrack_dccp_packet(struct nf_conn *ct, struct sk_buff *skb,
515a47c5404SFlorian Westphal unsigned int dataoff,
516a47c5404SFlorian Westphal enum ip_conntrack_info ctinfo,
51793e66024SFlorian Westphal const struct nf_hook_state *state)
5182bc78049SPatrick McHardy {
5192bc78049SPatrick McHardy enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
520ff0a3a7dSFlorian Westphal struct nf_conntrack_dccp_buf _dh;
5212bc78049SPatrick McHardy u_int8_t type, old_state, new_state;
5222bc78049SPatrick McHardy enum ct_dccp_roles role;
523c779e849SFlorian Westphal unsigned int *timeouts;
524ff0a3a7dSFlorian Westphal struct dccp_hdr *dh;
5252bc78049SPatrick McHardy
526ff0a3a7dSFlorian Westphal dh = skb_header_pointer(skb, dataoff, sizeof(*dh), &_dh.dh);
5279976fc6eSFlorian Westphal if (!dh)
5289976fc6eSFlorian Westphal return NF_DROP;
5299976fc6eSFlorian Westphal
5300150ffbaSFlorian Westphal if (dccp_error(dh, skb, dataoff, state))
5310150ffbaSFlorian Westphal return -NF_ACCEPT;
5320150ffbaSFlorian Westphal
533ff0a3a7dSFlorian Westphal /* pull again, including possible 48 bit sequences and subtype header */
534ff0a3a7dSFlorian Westphal dh = dccp_header_pointer(skb, dataoff, dh, &_dh);
535ff0a3a7dSFlorian Westphal if (!dh)
536ff0a3a7dSFlorian Westphal return NF_DROP;
537ff0a3a7dSFlorian Westphal
5382bc78049SPatrick McHardy type = dh->dccph_type;
53962eec0d7SFlorian Westphal if (!nf_ct_is_confirmed(ct) && !dccp_new(ct, skb, dh, state))
5409976fc6eSFlorian Westphal return -NF_ACCEPT;
5412bc78049SPatrick McHardy
5422bc78049SPatrick McHardy if (type == DCCP_PKT_RESET &&
5432bc78049SPatrick McHardy !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
5442bc78049SPatrick McHardy /* Tear down connection immediately if only reply is a RESET */
545718d4ad9SFabian Hugelshofer nf_ct_kill_acct(ct, ctinfo, skb);
5462bc78049SPatrick McHardy return NF_ACCEPT;
5472bc78049SPatrick McHardy }
5482bc78049SPatrick McHardy
549440f0d58SPatrick McHardy spin_lock_bh(&ct->lock);
5502bc78049SPatrick McHardy
5512bc78049SPatrick McHardy role = ct->proto.dccp.role[dir];
5522bc78049SPatrick McHardy old_state = ct->proto.dccp.state;
5532bc78049SPatrick McHardy new_state = dccp_state_table[role][type][old_state];
5542bc78049SPatrick McHardy
5552bc78049SPatrick McHardy switch (new_state) {
5562bc78049SPatrick McHardy case CT_DCCP_REQUEST:
5572bc78049SPatrick McHardy if (old_state == CT_DCCP_TIMEWAIT &&
5582bc78049SPatrick McHardy role == CT_DCCP_ROLE_SERVER) {
5592bc78049SPatrick McHardy /* Reincarnation in the reverse direction: reopen and
5602bc78049SPatrick McHardy * reverse client/server roles. */
5612bc78049SPatrick McHardy ct->proto.dccp.role[dir] = CT_DCCP_ROLE_CLIENT;
5622bc78049SPatrick McHardy ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_SERVER;
5632bc78049SPatrick McHardy }
5642bc78049SPatrick McHardy break;
5652bc78049SPatrick McHardy case CT_DCCP_RESPOND:
5662bc78049SPatrick McHardy if (old_state == CT_DCCP_REQUEST)
5672bc78049SPatrick McHardy ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh);
5682bc78049SPatrick McHardy break;
5692bc78049SPatrick McHardy case CT_DCCP_PARTOPEN:
5702bc78049SPatrick McHardy if (old_state == CT_DCCP_RESPOND &&
5712bc78049SPatrick McHardy type == DCCP_PKT_ACK &&
5722bc78049SPatrick McHardy dccp_ack_seq(dh) == ct->proto.dccp.handshake_seq)
5732bc78049SPatrick McHardy set_bit(IPS_ASSURED_BIT, &ct->status);
5742bc78049SPatrick McHardy break;
5752bc78049SPatrick McHardy case CT_DCCP_IGNORE:
5762bc78049SPatrick McHardy /*
5772bc78049SPatrick McHardy * Connection tracking might be out of sync, so we ignore
5782bc78049SPatrick McHardy * packets that might establish a new connection and resync
5792bc78049SPatrick McHardy * if the server responds with a valid Response.
5802bc78049SPatrick McHardy */
5812bc78049SPatrick McHardy if (ct->proto.dccp.last_dir == !dir &&
5822bc78049SPatrick McHardy ct->proto.dccp.last_pkt == DCCP_PKT_REQUEST &&
5832bc78049SPatrick McHardy type == DCCP_PKT_RESPONSE) {
5842bc78049SPatrick McHardy ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_CLIENT;
5852bc78049SPatrick McHardy ct->proto.dccp.role[dir] = CT_DCCP_ROLE_SERVER;
5862bc78049SPatrick McHardy ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh);
5872bc78049SPatrick McHardy new_state = CT_DCCP_RESPOND;
5882bc78049SPatrick McHardy break;
5892bc78049SPatrick McHardy }
5902bc78049SPatrick McHardy ct->proto.dccp.last_dir = dir;
5912bc78049SPatrick McHardy ct->proto.dccp.last_pkt = type;
5922bc78049SPatrick McHardy
593440f0d58SPatrick McHardy spin_unlock_bh(&ct->lock);
59462eec0d7SFlorian Westphal nf_ct_l4proto_log_invalid(skb, ct, state, "%s", "invalid packet");
5952bc78049SPatrick McHardy return NF_ACCEPT;
5962bc78049SPatrick McHardy case CT_DCCP_INVALID:
597440f0d58SPatrick McHardy spin_unlock_bh(&ct->lock);
59862eec0d7SFlorian Westphal nf_ct_l4proto_log_invalid(skb, ct, state, "%s", "invalid state transition");
5992bc78049SPatrick McHardy return -NF_ACCEPT;
6002bc78049SPatrick McHardy }
6012bc78049SPatrick McHardy
6022bc78049SPatrick McHardy ct->proto.dccp.last_dir = dir;
6032bc78049SPatrick McHardy ct->proto.dccp.last_pkt = type;
6042bc78049SPatrick McHardy ct->proto.dccp.state = new_state;
605440f0d58SPatrick McHardy spin_unlock_bh(&ct->lock);
6061546000fSCyrill Gorcunov
607b38b1f61SPablo Neira Ayuso if (new_state != old_state)
608b38b1f61SPablo Neira Ayuso nf_conntrack_event_cache(IPCT_PROTOINFO, ct);
609b38b1f61SPablo Neira Ayuso
610c779e849SFlorian Westphal timeouts = nf_ct_timeout_lookup(ct);
611c779e849SFlorian Westphal if (!timeouts)
612a95a7774SPablo Neira Ayuso timeouts = nf_dccp_pernet(nf_ct_net(ct))->dccp_timeout;
6132c8503f5SPablo Neira Ayuso nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]);
6142bc78049SPatrick McHardy
6152bc78049SPatrick McHardy return NF_ACCEPT;
6162bc78049SPatrick McHardy }
6172bc78049SPatrick McHardy
dccp_can_early_drop(const struct nf_conn * ct)618c6dd940bSFlorian Westphal static bool dccp_can_early_drop(const struct nf_conn *ct)
619c6dd940bSFlorian Westphal {
620c6dd940bSFlorian Westphal switch (ct->proto.dccp.state) {
621c6dd940bSFlorian Westphal case CT_DCCP_CLOSEREQ:
622c6dd940bSFlorian Westphal case CT_DCCP_CLOSING:
623c6dd940bSFlorian Westphal case CT_DCCP_TIMEWAIT:
624c6dd940bSFlorian Westphal return true;
625c6dd940bSFlorian Westphal default:
626c6dd940bSFlorian Westphal break;
627c6dd940bSFlorian Westphal }
628c6dd940bSFlorian Westphal
629c6dd940bSFlorian Westphal return false;
630c6dd940bSFlorian Westphal }
631c6dd940bSFlorian Westphal
632ea48cc83SFlorian Westphal #ifdef CONFIG_NF_CONNTRACK_PROCFS
dccp_print_conntrack(struct seq_file * s,struct nf_conn * ct)63337246a58SSteven Rostedt (Red Hat) static void dccp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
6342bc78049SPatrick McHardy {
63537246a58SSteven Rostedt (Red Hat) seq_printf(s, "%s ", dccp_state_names[ct->proto.dccp.state]);
6362bc78049SPatrick McHardy }
637ea48cc83SFlorian Westphal #endif
6382bc78049SPatrick McHardy
639c0cd1156SIgor Maravić #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
dccp_to_nlattr(struct sk_buff * skb,struct nlattr * nla,struct nf_conn * ct,bool destroy)6402bc78049SPatrick McHardy static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
64186d21fc7SFlorian Westphal struct nf_conn *ct, bool destroy)
6422bc78049SPatrick McHardy {
6432bc78049SPatrick McHardy struct nlattr *nest_parms;
6442bc78049SPatrick McHardy
645440f0d58SPatrick McHardy spin_lock_bh(&ct->lock);
646ae0be8deSMichal Kubecek nest_parms = nla_nest_start(skb, CTA_PROTOINFO_DCCP);
6472bc78049SPatrick McHardy if (!nest_parms)
6482bc78049SPatrick McHardy goto nla_put_failure;
64986d21fc7SFlorian Westphal if (nla_put_u8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state))
65086d21fc7SFlorian Westphal goto nla_put_failure;
65186d21fc7SFlorian Westphal
65286d21fc7SFlorian Westphal if (destroy)
65386d21fc7SFlorian Westphal goto skip_state;
65486d21fc7SFlorian Westphal
65586d21fc7SFlorian Westphal if (nla_put_u8(skb, CTA_PROTOINFO_DCCP_ROLE,
656516ee48fSDavid S. Miller ct->proto.dccp.role[IP_CT_DIR_ORIGINAL]) ||
657516ee48fSDavid S. Miller nla_put_be64(skb, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ,
658b46f6dedSNicolas Dichtel cpu_to_be64(ct->proto.dccp.handshake_seq),
659b46f6dedSNicolas Dichtel CTA_PROTOINFO_DCCP_PAD))
660516ee48fSDavid S. Miller goto nla_put_failure;
66186d21fc7SFlorian Westphal skip_state:
6622bc78049SPatrick McHardy nla_nest_end(skb, nest_parms);
663440f0d58SPatrick McHardy spin_unlock_bh(&ct->lock);
66486d21fc7SFlorian Westphal
6652bc78049SPatrick McHardy return 0;
6662bc78049SPatrick McHardy
6672bc78049SPatrick McHardy nla_put_failure:
668440f0d58SPatrick McHardy spin_unlock_bh(&ct->lock);
6692bc78049SPatrick McHardy return -1;
6702bc78049SPatrick McHardy }
6712bc78049SPatrick McHardy
6722bc78049SPatrick McHardy static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = {
6732bc78049SPatrick McHardy [CTA_PROTOINFO_DCCP_STATE] = { .type = NLA_U8 },
67471951b64SPablo Neira Ayuso [CTA_PROTOINFO_DCCP_ROLE] = { .type = NLA_U8 },
675a17c8598SPablo Neira Ayuso [CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ] = { .type = NLA_U64 },
676b46f6dedSNicolas Dichtel [CTA_PROTOINFO_DCCP_PAD] = { .type = NLA_UNSPEC },
6772bc78049SPatrick McHardy };
6782bc78049SPatrick McHardy
67939215846SFlorian Westphal #define DCCP_NLATTR_SIZE ( \
68039215846SFlorian Westphal NLA_ALIGN(NLA_HDRLEN + 1) + \
68139215846SFlorian Westphal NLA_ALIGN(NLA_HDRLEN + 1) + \
68239215846SFlorian Westphal NLA_ALIGN(NLA_HDRLEN + sizeof(u64)) + \
68339215846SFlorian Westphal NLA_ALIGN(NLA_HDRLEN + 0))
68439215846SFlorian Westphal
nlattr_to_dccp(struct nlattr * cda[],struct nf_conn * ct)6852bc78049SPatrick McHardy static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
6862bc78049SPatrick McHardy {
6872bc78049SPatrick McHardy struct nlattr *attr = cda[CTA_PROTOINFO_DCCP];
6882bc78049SPatrick McHardy struct nlattr *tb[CTA_PROTOINFO_DCCP_MAX + 1];
6892bc78049SPatrick McHardy int err;
6902bc78049SPatrick McHardy
6912bc78049SPatrick McHardy if (!attr)
6922bc78049SPatrick McHardy return 0;
6932bc78049SPatrick McHardy
6948cb08174SJohannes Berg err = nla_parse_nested_deprecated(tb, CTA_PROTOINFO_DCCP_MAX, attr,
695fceb6435SJohannes Berg dccp_nla_policy, NULL);
6962bc78049SPatrick McHardy if (err < 0)
6972bc78049SPatrick McHardy return err;
6982bc78049SPatrick McHardy
6992bc78049SPatrick McHardy if (!tb[CTA_PROTOINFO_DCCP_STATE] ||
70071951b64SPablo Neira Ayuso !tb[CTA_PROTOINFO_DCCP_ROLE] ||
70171951b64SPablo Neira Ayuso nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) > CT_DCCP_ROLE_MAX ||
70271951b64SPablo Neira Ayuso nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]) >= CT_DCCP_IGNORE) {
7032bc78049SPatrick McHardy return -EINVAL;
70471951b64SPablo Neira Ayuso }
7052bc78049SPatrick McHardy
706440f0d58SPatrick McHardy spin_lock_bh(&ct->lock);
7072bc78049SPatrick McHardy ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]);
70871951b64SPablo Neira Ayuso if (nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) == CT_DCCP_ROLE_CLIENT) {
70971951b64SPablo Neira Ayuso ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT;
71071951b64SPablo Neira Ayuso ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER;
71171951b64SPablo Neira Ayuso } else {
71271951b64SPablo Neira Ayuso ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_SERVER;
71371951b64SPablo Neira Ayuso ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_CLIENT;
71471951b64SPablo Neira Ayuso }
715a17c8598SPablo Neira Ayuso if (tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ]) {
716a17c8598SPablo Neira Ayuso ct->proto.dccp.handshake_seq =
717a17c8598SPablo Neira Ayuso be64_to_cpu(nla_get_be64(tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ]));
718a17c8598SPablo Neira Ayuso }
719440f0d58SPatrick McHardy spin_unlock_bh(&ct->lock);
7202bc78049SPatrick McHardy return 0;
7212bc78049SPatrick McHardy }
7222bc78049SPatrick McHardy #endif
7232bc78049SPatrick McHardy
724a874752aSPablo Neira Ayuso #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
72550978462SPablo Neira Ayuso
72650978462SPablo Neira Ayuso #include <linux/netfilter/nfnetlink.h>
72750978462SPablo Neira Ayuso #include <linux/netfilter/nfnetlink_cttimeout.h>
72850978462SPablo Neira Ayuso
dccp_timeout_nlattr_to_obj(struct nlattr * tb[],struct net * net,void * data)7298264deb8SGao feng static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[],
7308264deb8SGao feng struct net *net, void *data)
73150978462SPablo Neira Ayuso {
732a95a7774SPablo Neira Ayuso struct nf_dccp_net *dn = nf_dccp_pernet(net);
73350978462SPablo Neira Ayuso unsigned int *timeouts = data;
73450978462SPablo Neira Ayuso int i;
73550978462SPablo Neira Ayuso
7361d9a7acdSFlorian Westphal if (!timeouts)
7371d9a7acdSFlorian Westphal timeouts = dn->dccp_timeout;
7381d9a7acdSFlorian Westphal
73950978462SPablo Neira Ayuso /* set default DCCP timeouts. */
74050978462SPablo Neira Ayuso for (i=0; i<CT_DCCP_MAX; i++)
74150978462SPablo Neira Ayuso timeouts[i] = dn->dccp_timeout[i];
74250978462SPablo Neira Ayuso
74350978462SPablo Neira Ayuso /* there's a 1:1 mapping between attributes and protocol states. */
74450978462SPablo Neira Ayuso for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) {
74550978462SPablo Neira Ayuso if (tb[i]) {
74650978462SPablo Neira Ayuso timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ;
74750978462SPablo Neira Ayuso }
74850978462SPablo Neira Ayuso }
749ef39078dSFlorian Westphal
750ef39078dSFlorian Westphal timeouts[CTA_TIMEOUT_DCCP_UNSPEC] = timeouts[CTA_TIMEOUT_DCCP_REQUEST];
75150978462SPablo Neira Ayuso return 0;
75250978462SPablo Neira Ayuso }
75350978462SPablo Neira Ayuso
75450978462SPablo Neira Ayuso static int
dccp_timeout_obj_to_nlattr(struct sk_buff * skb,const void * data)75550978462SPablo Neira Ayuso dccp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
75650978462SPablo Neira Ayuso {
75750978462SPablo Neira Ayuso const unsigned int *timeouts = data;
75850978462SPablo Neira Ayuso int i;
75950978462SPablo Neira Ayuso
760516ee48fSDavid S. Miller for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) {
761516ee48fSDavid S. Miller if (nla_put_be32(skb, i, htonl(timeouts[i] / HZ)))
762516ee48fSDavid S. Miller goto nla_put_failure;
763516ee48fSDavid S. Miller }
76450978462SPablo Neira Ayuso return 0;
76550978462SPablo Neira Ayuso
76650978462SPablo Neira Ayuso nla_put_failure:
76750978462SPablo Neira Ayuso return -ENOSPC;
76850978462SPablo Neira Ayuso }
76950978462SPablo Neira Ayuso
77050978462SPablo Neira Ayuso static const struct nla_policy
77150978462SPablo Neira Ayuso dccp_timeout_nla_policy[CTA_TIMEOUT_DCCP_MAX+1] = {
77250978462SPablo Neira Ayuso [CTA_TIMEOUT_DCCP_REQUEST] = { .type = NLA_U32 },
77350978462SPablo Neira Ayuso [CTA_TIMEOUT_DCCP_RESPOND] = { .type = NLA_U32 },
77450978462SPablo Neira Ayuso [CTA_TIMEOUT_DCCP_PARTOPEN] = { .type = NLA_U32 },
77550978462SPablo Neira Ayuso [CTA_TIMEOUT_DCCP_OPEN] = { .type = NLA_U32 },
77650978462SPablo Neira Ayuso [CTA_TIMEOUT_DCCP_CLOSEREQ] = { .type = NLA_U32 },
77750978462SPablo Neira Ayuso [CTA_TIMEOUT_DCCP_CLOSING] = { .type = NLA_U32 },
77850978462SPablo Neira Ayuso [CTA_TIMEOUT_DCCP_TIMEWAIT] = { .type = NLA_U32 },
77950978462SPablo Neira Ayuso };
780a874752aSPablo Neira Ayuso #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
78150978462SPablo Neira Ayuso
nf_conntrack_dccp_init_net(struct net * net)7822a389de8SFlorian Westphal void nf_conntrack_dccp_init_net(struct net *net)
78354b8873fSGao feng {
784a95a7774SPablo Neira Ayuso struct nf_dccp_net *dn = nf_dccp_pernet(net);
78554b8873fSGao feng
78654b8873fSGao feng /* default values */
78754b8873fSGao feng dn->dccp_loose = 1;
78854b8873fSGao feng dn->dccp_timeout[CT_DCCP_REQUEST] = 2 * DCCP_MSL;
78954b8873fSGao feng dn->dccp_timeout[CT_DCCP_RESPOND] = 4 * DCCP_MSL;
79054b8873fSGao feng dn->dccp_timeout[CT_DCCP_PARTOPEN] = 4 * DCCP_MSL;
79154b8873fSGao feng dn->dccp_timeout[CT_DCCP_OPEN] = 12 * 3600 * HZ;
79254b8873fSGao feng dn->dccp_timeout[CT_DCCP_CLOSEREQ] = 64 * HZ;
79354b8873fSGao feng dn->dccp_timeout[CT_DCCP_CLOSING] = 64 * HZ;
79454b8873fSGao feng dn->dccp_timeout[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL;
795ef39078dSFlorian Westphal
796ef39078dSFlorian Westphal /* timeouts[0] is unused, make it same as SYN_SENT so
797ef39078dSFlorian Westphal * ->timeouts[0] contains 'new' timeout, like udp or icmp.
798ef39078dSFlorian Westphal */
799ef39078dSFlorian Westphal dn->dccp_timeout[CT_DCCP_NONE] = dn->dccp_timeout[CT_DCCP_REQUEST];
80054b8873fSGao feng }
80154b8873fSGao feng
802dd2934a9SFlorian Westphal const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp = {
8032bc78049SPatrick McHardy .l4proto = IPPROTO_DCCP,
804c6dd940bSFlorian Westphal .can_early_drop = dccp_can_early_drop,
805ea48cc83SFlorian Westphal #ifdef CONFIG_NF_CONNTRACK_PROCFS
8062bc78049SPatrick McHardy .print_conntrack = dccp_print_conntrack,
807ea48cc83SFlorian Westphal #endif
808c0cd1156SIgor Maravić #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
80939215846SFlorian Westphal .nlattr_size = DCCP_NLATTR_SIZE,
8102bc78049SPatrick McHardy .to_nlattr = dccp_to_nlattr,
8112bc78049SPatrick McHardy .from_nlattr = nlattr_to_dccp,
8122bc78049SPatrick McHardy .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
813a400c30eSHolger Eitzenberger .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
8142bc78049SPatrick McHardy .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
8152bc78049SPatrick McHardy .nla_policy = nf_ct_port_nla_policy,
8162bc78049SPatrick McHardy #endif
817a874752aSPablo Neira Ayuso #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
81850978462SPablo Neira Ayuso .ctnl_timeout = {
81950978462SPablo Neira Ayuso .nlattr_to_obj = dccp_timeout_nlattr_to_obj,
82050978462SPablo Neira Ayuso .obj_to_nlattr = dccp_timeout_obj_to_nlattr,
82150978462SPablo Neira Ayuso .nlattr_max = CTA_TIMEOUT_DCCP_MAX,
82250978462SPablo Neira Ayuso .obj_size = sizeof(unsigned int) * CT_DCCP_MAX,
82350978462SPablo Neira Ayuso .nla_policy = dccp_timeout_nla_policy,
82450978462SPablo Neira Ayuso },
825a874752aSPablo Neira Ayuso #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
8262bc78049SPatrick McHardy };
827