12bc78049SPatrick McHardy /* 22bc78049SPatrick McHardy * DCCP connection tracking protocol helper 32bc78049SPatrick McHardy * 42bc78049SPatrick McHardy * Copyright (c) 2005, 2006, 2008 Patrick McHardy <kaber@trash.net> 52bc78049SPatrick McHardy * 62bc78049SPatrick McHardy * This program is free software; you can redistribute it and/or modify 72bc78049SPatrick McHardy * it under the terms of the GNU General Public License version 2 as 82bc78049SPatrick McHardy * published by the Free Software Foundation. 92bc78049SPatrick McHardy * 102bc78049SPatrick McHardy */ 112bc78049SPatrick McHardy #include <linux/kernel.h> 122bc78049SPatrick McHardy #include <linux/module.h> 132bc78049SPatrick McHardy #include <linux/init.h> 142bc78049SPatrick McHardy #include <linux/sysctl.h> 152bc78049SPatrick McHardy #include <linux/spinlock.h> 162bc78049SPatrick McHardy #include <linux/skbuff.h> 172bc78049SPatrick McHardy #include <linux/dccp.h> 185a0e3ad6STejun Heo #include <linux/slab.h> 192bc78049SPatrick McHardy 201546000fSCyrill Gorcunov #include <net/net_namespace.h> 211546000fSCyrill Gorcunov #include <net/netns/generic.h> 221546000fSCyrill Gorcunov 232bc78049SPatrick McHardy #include <linux/netfilter/nfnetlink_conntrack.h> 242bc78049SPatrick McHardy #include <net/netfilter/nf_conntrack.h> 252bc78049SPatrick McHardy #include <net/netfilter/nf_conntrack_l4proto.h> 26b38b1f61SPablo Neira Ayuso #include <net/netfilter/nf_conntrack_ecache.h> 272bc78049SPatrick McHardy #include <net/netfilter/nf_log.h> 282bc78049SPatrick McHardy 292bc78049SPatrick McHardy /* Timeouts are based on values from RFC4340: 302bc78049SPatrick McHardy * 312bc78049SPatrick McHardy * - REQUEST: 322bc78049SPatrick McHardy * 332bc78049SPatrick McHardy * 8.1.2. Client Request 342bc78049SPatrick McHardy * 352bc78049SPatrick McHardy * A client MAY give up on its DCCP-Requests after some time 362bc78049SPatrick McHardy * (3 minutes, for example). 372bc78049SPatrick McHardy * 382bc78049SPatrick McHardy * - RESPOND: 392bc78049SPatrick McHardy * 402bc78049SPatrick McHardy * 8.1.3. Server Response 412bc78049SPatrick McHardy * 422bc78049SPatrick McHardy * It MAY also leave the RESPOND state for CLOSED after a timeout of 432bc78049SPatrick McHardy * not less than 4MSL (8 minutes); 442bc78049SPatrick McHardy * 452bc78049SPatrick McHardy * - PARTOPEN: 462bc78049SPatrick McHardy * 472bc78049SPatrick McHardy * 8.1.5. Handshake Completion 482bc78049SPatrick McHardy * 492bc78049SPatrick McHardy * If the client remains in PARTOPEN for more than 4MSL (8 minutes), 502bc78049SPatrick McHardy * it SHOULD reset the connection with Reset Code 2, "Aborted". 512bc78049SPatrick McHardy * 522bc78049SPatrick McHardy * - OPEN: 532bc78049SPatrick McHardy * 542bc78049SPatrick McHardy * The DCCP timestamp overflows after 11.9 hours. If the connection 552bc78049SPatrick McHardy * stays idle this long the sequence number won't be recognized 562bc78049SPatrick McHardy * as valid anymore. 572bc78049SPatrick McHardy * 582bc78049SPatrick McHardy * - CLOSEREQ/CLOSING: 592bc78049SPatrick McHardy * 602bc78049SPatrick McHardy * 8.3. Termination 612bc78049SPatrick McHardy * 622bc78049SPatrick McHardy * The retransmission timer should initially be set to go off in two 632bc78049SPatrick McHardy * round-trip times and should back off to not less than once every 642bc78049SPatrick McHardy * 64 seconds ... 652bc78049SPatrick McHardy * 662bc78049SPatrick McHardy * - TIMEWAIT: 672bc78049SPatrick McHardy * 682bc78049SPatrick McHardy * 4.3. States 692bc78049SPatrick McHardy * 702bc78049SPatrick McHardy * A server or client socket remains in this state for 2MSL (4 minutes) 712bc78049SPatrick McHardy * after the connection has been town down, ... 722bc78049SPatrick McHardy */ 732bc78049SPatrick McHardy 742bc78049SPatrick McHardy #define DCCP_MSL (2 * 60 * HZ) 752bc78049SPatrick McHardy 762bc78049SPatrick McHardy static const char * const dccp_state_names[] = { 772bc78049SPatrick McHardy [CT_DCCP_NONE] = "NONE", 782bc78049SPatrick McHardy [CT_DCCP_REQUEST] = "REQUEST", 792bc78049SPatrick McHardy [CT_DCCP_RESPOND] = "RESPOND", 802bc78049SPatrick McHardy [CT_DCCP_PARTOPEN] = "PARTOPEN", 812bc78049SPatrick McHardy [CT_DCCP_OPEN] = "OPEN", 822bc78049SPatrick McHardy [CT_DCCP_CLOSEREQ] = "CLOSEREQ", 832bc78049SPatrick McHardy [CT_DCCP_CLOSING] = "CLOSING", 842bc78049SPatrick McHardy [CT_DCCP_TIMEWAIT] = "TIMEWAIT", 852bc78049SPatrick McHardy [CT_DCCP_IGNORE] = "IGNORE", 862bc78049SPatrick McHardy [CT_DCCP_INVALID] = "INVALID", 872bc78049SPatrick McHardy }; 882bc78049SPatrick McHardy 892bc78049SPatrick McHardy #define sNO CT_DCCP_NONE 902bc78049SPatrick McHardy #define sRQ CT_DCCP_REQUEST 912bc78049SPatrick McHardy #define sRS CT_DCCP_RESPOND 922bc78049SPatrick McHardy #define sPO CT_DCCP_PARTOPEN 932bc78049SPatrick McHardy #define sOP CT_DCCP_OPEN 942bc78049SPatrick McHardy #define sCR CT_DCCP_CLOSEREQ 952bc78049SPatrick McHardy #define sCG CT_DCCP_CLOSING 962bc78049SPatrick McHardy #define sTW CT_DCCP_TIMEWAIT 972bc78049SPatrick McHardy #define sIG CT_DCCP_IGNORE 982bc78049SPatrick McHardy #define sIV CT_DCCP_INVALID 992bc78049SPatrick McHardy 1002bc78049SPatrick McHardy /* 10125985edcSLucas De Marchi * DCCP state transition table 1022bc78049SPatrick McHardy * 1032bc78049SPatrick McHardy * The assumption is the same as for TCP tracking: 1042bc78049SPatrick McHardy * 1052bc78049SPatrick McHardy * We are the man in the middle. All the packets go through us but might 1062bc78049SPatrick McHardy * get lost in transit to the destination. It is assumed that the destination 1072bc78049SPatrick McHardy * can't receive segments we haven't seen. 1082bc78049SPatrick McHardy * 1092bc78049SPatrick McHardy * The following states exist: 1102bc78049SPatrick McHardy * 1112bc78049SPatrick McHardy * NONE: Initial state, expecting Request 1122bc78049SPatrick McHardy * REQUEST: Request seen, waiting for Response from server 1132bc78049SPatrick McHardy * RESPOND: Response from server seen, waiting for Ack from client 1142bc78049SPatrick McHardy * PARTOPEN: Ack after Response seen, waiting for packet other than Response, 1152bc78049SPatrick McHardy * Reset or Sync from server 1162bc78049SPatrick McHardy * OPEN: Packet other than Response, Reset or Sync seen 1172bc78049SPatrick McHardy * CLOSEREQ: CloseReq from server seen, expecting Close from client 1182bc78049SPatrick McHardy * CLOSING: Close seen, expecting Reset 1192bc78049SPatrick McHardy * TIMEWAIT: Reset seen 1202bc78049SPatrick McHardy * IGNORE: Not determinable whether packet is valid 1212bc78049SPatrick McHardy * 1222bc78049SPatrick McHardy * Some states exist only on one side of the connection: REQUEST, RESPOND, 1232bc78049SPatrick McHardy * PARTOPEN, CLOSEREQ. For the other side these states are equivalent to 1242bc78049SPatrick McHardy * the one it was in before. 1252bc78049SPatrick McHardy * 1262bc78049SPatrick McHardy * Packets are marked as ignored (sIG) if we don't know if they're valid 1272bc78049SPatrick McHardy * (for example a reincarnation of a connection we didn't notice is dead 1282bc78049SPatrick McHardy * already) and the server may send back a connection closing Reset or a 1292bc78049SPatrick McHardy * Response. They're also used for Sync/SyncAck packets, which we don't 1302bc78049SPatrick McHardy * care about. 1312bc78049SPatrick McHardy */ 1322bc78049SPatrick McHardy static const u_int8_t 1332bc78049SPatrick McHardy dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = { 1342bc78049SPatrick McHardy [CT_DCCP_ROLE_CLIENT] = { 1352bc78049SPatrick McHardy [DCCP_PKT_REQUEST] = { 1362bc78049SPatrick McHardy /* 1372bc78049SPatrick McHardy * sNO -> sRQ Regular Request 1382bc78049SPatrick McHardy * sRQ -> sRQ Retransmitted Request or reincarnation 1392bc78049SPatrick McHardy * sRS -> sRS Retransmitted Request (apparently Response 1402bc78049SPatrick McHardy * got lost after we saw it) or reincarnation 1412bc78049SPatrick McHardy * sPO -> sIG Ignore, conntrack might be out of sync 1422bc78049SPatrick McHardy * sOP -> sIG Ignore, conntrack might be out of sync 1432bc78049SPatrick McHardy * sCR -> sIG Ignore, conntrack might be out of sync 1442bc78049SPatrick McHardy * sCG -> sIG Ignore, conntrack might be out of sync 1452bc78049SPatrick McHardy * sTW -> sRQ Reincarnation 1462bc78049SPatrick McHardy * 1472bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO. sOP, sCR, sCG, sTW, */ 1482bc78049SPatrick McHardy sRQ, sRQ, sRS, sIG, sIG, sIG, sIG, sRQ, 1492bc78049SPatrick McHardy }, 1502bc78049SPatrick McHardy [DCCP_PKT_RESPONSE] = { 1512bc78049SPatrick McHardy /* 1522bc78049SPatrick McHardy * sNO -> sIV Invalid 1532bc78049SPatrick McHardy * sRQ -> sIG Ignore, might be response to ignored Request 1542bc78049SPatrick McHardy * sRS -> sIG Ignore, might be response to ignored Request 1552bc78049SPatrick McHardy * sPO -> sIG Ignore, might be response to ignored Request 1562bc78049SPatrick McHardy * sOP -> sIG Ignore, might be response to ignored Request 1572bc78049SPatrick McHardy * sCR -> sIG Ignore, might be response to ignored Request 1582bc78049SPatrick McHardy * sCG -> sIG Ignore, might be response to ignored Request 1592bc78049SPatrick McHardy * sTW -> sIV Invalid, reincarnation in reverse direction 1602bc78049SPatrick McHardy * goes through sRQ 1612bc78049SPatrick McHardy * 1622bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 1632bc78049SPatrick McHardy sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIV, 1642bc78049SPatrick McHardy }, 1652bc78049SPatrick McHardy [DCCP_PKT_ACK] = { 1662bc78049SPatrick McHardy /* 1672bc78049SPatrick McHardy * sNO -> sIV No connection 1682bc78049SPatrick McHardy * sRQ -> sIV No connection 1692bc78049SPatrick McHardy * sRS -> sPO Ack for Response, move to PARTOPEN (8.1.5.) 1702bc78049SPatrick McHardy * sPO -> sPO Retransmitted Ack for Response, remain in PARTOPEN 1712bc78049SPatrick McHardy * sOP -> sOP Regular ACK, remain in OPEN 1722bc78049SPatrick McHardy * sCR -> sCR Ack in CLOSEREQ MAY be processed (8.3.) 1732bc78049SPatrick McHardy * sCG -> sCG Ack in CLOSING MAY be processed (8.3.) 1742bc78049SPatrick McHardy * sTW -> sIV 1752bc78049SPatrick McHardy * 1762bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 1772bc78049SPatrick McHardy sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV 1782bc78049SPatrick McHardy }, 1792bc78049SPatrick McHardy [DCCP_PKT_DATA] = { 1802bc78049SPatrick McHardy /* 1812bc78049SPatrick McHardy * sNO -> sIV No connection 1822bc78049SPatrick McHardy * sRQ -> sIV No connection 1832bc78049SPatrick McHardy * sRS -> sIV No connection 1842bc78049SPatrick McHardy * sPO -> sIV MUST use DataAck in PARTOPEN state (8.1.5.) 1852bc78049SPatrick McHardy * sOP -> sOP Regular Data packet 1862bc78049SPatrick McHardy * sCR -> sCR Data in CLOSEREQ MAY be processed (8.3.) 1872bc78049SPatrick McHardy * sCG -> sCG Data in CLOSING MAY be processed (8.3.) 1882bc78049SPatrick McHardy * sTW -> sIV 1892bc78049SPatrick McHardy * 1902bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 1912bc78049SPatrick McHardy sIV, sIV, sIV, sIV, sOP, sCR, sCG, sIV, 1922bc78049SPatrick McHardy }, 1932bc78049SPatrick McHardy [DCCP_PKT_DATAACK] = { 1942bc78049SPatrick McHardy /* 1952bc78049SPatrick McHardy * sNO -> sIV No connection 1962bc78049SPatrick McHardy * sRQ -> sIV No connection 1972bc78049SPatrick McHardy * sRS -> sPO Ack for Response, move to PARTOPEN (8.1.5.) 1982bc78049SPatrick McHardy * sPO -> sPO Remain in PARTOPEN state 1992bc78049SPatrick McHardy * sOP -> sOP Regular DataAck packet in OPEN state 2002bc78049SPatrick McHardy * sCR -> sCR DataAck in CLOSEREQ MAY be processed (8.3.) 2012bc78049SPatrick McHardy * sCG -> sCG DataAck in CLOSING MAY be processed (8.3.) 2022bc78049SPatrick McHardy * sTW -> sIV 2032bc78049SPatrick McHardy * 2042bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 2052bc78049SPatrick McHardy sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV 2062bc78049SPatrick McHardy }, 2072bc78049SPatrick McHardy [DCCP_PKT_CLOSEREQ] = { 2082bc78049SPatrick McHardy /* 2092bc78049SPatrick McHardy * CLOSEREQ may only be sent by the server. 2102bc78049SPatrick McHardy * 2112bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 2122bc78049SPatrick McHardy sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV 2132bc78049SPatrick McHardy }, 2142bc78049SPatrick McHardy [DCCP_PKT_CLOSE] = { 2152bc78049SPatrick McHardy /* 2162bc78049SPatrick McHardy * sNO -> sIV No connection 2172bc78049SPatrick McHardy * sRQ -> sIV No connection 2182bc78049SPatrick McHardy * sRS -> sIV No connection 2192bc78049SPatrick McHardy * sPO -> sCG Client-initiated close 2202bc78049SPatrick McHardy * sOP -> sCG Client-initiated close 2212bc78049SPatrick McHardy * sCR -> sCG Close in response to CloseReq (8.3.) 2222bc78049SPatrick McHardy * sCG -> sCG Retransmit 2232bc78049SPatrick McHardy * sTW -> sIV Late retransmit, already in TIME_WAIT 2242bc78049SPatrick McHardy * 2252bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 2262bc78049SPatrick McHardy sIV, sIV, sIV, sCG, sCG, sCG, sIV, sIV 2272bc78049SPatrick McHardy }, 2282bc78049SPatrick McHardy [DCCP_PKT_RESET] = { 2292bc78049SPatrick McHardy /* 2302bc78049SPatrick McHardy * sNO -> sIV No connection 2312bc78049SPatrick McHardy * sRQ -> sTW Sync received or timeout, SHOULD send Reset (8.1.1.) 2322bc78049SPatrick McHardy * sRS -> sTW Response received without Request 2332bc78049SPatrick McHardy * sPO -> sTW Timeout, SHOULD send Reset (8.1.5.) 2342bc78049SPatrick McHardy * sOP -> sTW Connection reset 2352bc78049SPatrick McHardy * sCR -> sTW Connection reset 2362bc78049SPatrick McHardy * sCG -> sTW Connection reset 2372bc78049SPatrick McHardy * sTW -> sIG Ignore (don't refresh timer) 2382bc78049SPatrick McHardy * 2392bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 2402bc78049SPatrick McHardy sIV, sTW, sTW, sTW, sTW, sTW, sTW, sIG 2412bc78049SPatrick McHardy }, 2422bc78049SPatrick McHardy [DCCP_PKT_SYNC] = { 2432bc78049SPatrick McHardy /* 2442bc78049SPatrick McHardy * We currently ignore Sync packets 2452bc78049SPatrick McHardy * 2462bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 2472bc78049SPatrick McHardy sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, 2482bc78049SPatrick McHardy }, 2492bc78049SPatrick McHardy [DCCP_PKT_SYNCACK] = { 2502bc78049SPatrick McHardy /* 2512bc78049SPatrick McHardy * We currently ignore SyncAck packets 2522bc78049SPatrick McHardy * 2532bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 2542bc78049SPatrick McHardy sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, 2552bc78049SPatrick McHardy }, 2562bc78049SPatrick McHardy }, 2572bc78049SPatrick McHardy [CT_DCCP_ROLE_SERVER] = { 2582bc78049SPatrick McHardy [DCCP_PKT_REQUEST] = { 2592bc78049SPatrick McHardy /* 2602bc78049SPatrick McHardy * sNO -> sIV Invalid 2612bc78049SPatrick McHardy * sRQ -> sIG Ignore, conntrack might be out of sync 2622bc78049SPatrick McHardy * sRS -> sIG Ignore, conntrack might be out of sync 2632bc78049SPatrick McHardy * sPO -> sIG Ignore, conntrack might be out of sync 2642bc78049SPatrick McHardy * sOP -> sIG Ignore, conntrack might be out of sync 2652bc78049SPatrick McHardy * sCR -> sIG Ignore, conntrack might be out of sync 2662bc78049SPatrick McHardy * sCG -> sIG Ignore, conntrack might be out of sync 2672bc78049SPatrick McHardy * sTW -> sRQ Reincarnation, must reverse roles 2682bc78049SPatrick McHardy * 2692bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 2702bc78049SPatrick McHardy sIV, sIG, sIG, sIG, sIG, sIG, sIG, sRQ 2712bc78049SPatrick McHardy }, 2722bc78049SPatrick McHardy [DCCP_PKT_RESPONSE] = { 2732bc78049SPatrick McHardy /* 2742bc78049SPatrick McHardy * sNO -> sIV Response without Request 2752bc78049SPatrick McHardy * sRQ -> sRS Response to clients Request 2762bc78049SPatrick McHardy * sRS -> sRS Retransmitted Response (8.1.3. SHOULD NOT) 2772bc78049SPatrick McHardy * sPO -> sIG Response to an ignored Request or late retransmit 2782bc78049SPatrick McHardy * sOP -> sIG Ignore, might be response to ignored Request 2792bc78049SPatrick McHardy * sCR -> sIG Ignore, might be response to ignored Request 2802bc78049SPatrick McHardy * sCG -> sIG Ignore, might be response to ignored Request 2812bc78049SPatrick McHardy * sTW -> sIV Invalid, Request from client in sTW moves to sRQ 2822bc78049SPatrick McHardy * 2832bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 2842bc78049SPatrick McHardy sIV, sRS, sRS, sIG, sIG, sIG, sIG, sIV 2852bc78049SPatrick McHardy }, 2862bc78049SPatrick McHardy [DCCP_PKT_ACK] = { 2872bc78049SPatrick McHardy /* 2882bc78049SPatrick McHardy * sNO -> sIV No connection 2892bc78049SPatrick McHardy * sRQ -> sIV No connection 2902bc78049SPatrick McHardy * sRS -> sIV No connection 2912bc78049SPatrick McHardy * sPO -> sOP Enter OPEN state (8.1.5.) 2922bc78049SPatrick McHardy * sOP -> sOP Regular Ack in OPEN state 2932bc78049SPatrick McHardy * sCR -> sIV Waiting for Close from client 2942bc78049SPatrick McHardy * sCG -> sCG Ack in CLOSING MAY be processed (8.3.) 2952bc78049SPatrick McHardy * sTW -> sIV 2962bc78049SPatrick McHardy * 2972bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 2982bc78049SPatrick McHardy sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV 2992bc78049SPatrick McHardy }, 3002bc78049SPatrick McHardy [DCCP_PKT_DATA] = { 3012bc78049SPatrick McHardy /* 3022bc78049SPatrick McHardy * sNO -> sIV No connection 3032bc78049SPatrick McHardy * sRQ -> sIV No connection 3042bc78049SPatrick McHardy * sRS -> sIV No connection 3052bc78049SPatrick McHardy * sPO -> sOP Enter OPEN state (8.1.5.) 3062bc78049SPatrick McHardy * sOP -> sOP Regular Data packet in OPEN state 3072bc78049SPatrick McHardy * sCR -> sIV Waiting for Close from client 3082bc78049SPatrick McHardy * sCG -> sCG Data in CLOSING MAY be processed (8.3.) 3092bc78049SPatrick McHardy * sTW -> sIV 3102bc78049SPatrick McHardy * 3112bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 3122bc78049SPatrick McHardy sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV 3132bc78049SPatrick McHardy }, 3142bc78049SPatrick McHardy [DCCP_PKT_DATAACK] = { 3152bc78049SPatrick McHardy /* 3162bc78049SPatrick McHardy * sNO -> sIV No connection 3172bc78049SPatrick McHardy * sRQ -> sIV No connection 3182bc78049SPatrick McHardy * sRS -> sIV No connection 3192bc78049SPatrick McHardy * sPO -> sOP Enter OPEN state (8.1.5.) 3202bc78049SPatrick McHardy * sOP -> sOP Regular DataAck in OPEN state 3212bc78049SPatrick McHardy * sCR -> sIV Waiting for Close from client 3222bc78049SPatrick McHardy * sCG -> sCG Data in CLOSING MAY be processed (8.3.) 3232bc78049SPatrick McHardy * sTW -> sIV 3242bc78049SPatrick McHardy * 3252bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 3262bc78049SPatrick McHardy sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV 3272bc78049SPatrick McHardy }, 3282bc78049SPatrick McHardy [DCCP_PKT_CLOSEREQ] = { 3292bc78049SPatrick McHardy /* 3302bc78049SPatrick McHardy * sNO -> sIV No connection 3312bc78049SPatrick McHardy * sRQ -> sIV No connection 3322bc78049SPatrick McHardy * sRS -> sIV No connection 3332bc78049SPatrick McHardy * sPO -> sOP -> sCR Move directly to CLOSEREQ (8.1.5.) 3342bc78049SPatrick McHardy * sOP -> sCR CloseReq in OPEN state 3352bc78049SPatrick McHardy * sCR -> sCR Retransmit 3362bc78049SPatrick McHardy * sCG -> sCR Simultaneous close, client sends another Close 3372bc78049SPatrick McHardy * sTW -> sIV Already closed 3382bc78049SPatrick McHardy * 3392bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 3402bc78049SPatrick McHardy sIV, sIV, sIV, sCR, sCR, sCR, sCR, sIV 3412bc78049SPatrick McHardy }, 3422bc78049SPatrick McHardy [DCCP_PKT_CLOSE] = { 3432bc78049SPatrick McHardy /* 3442bc78049SPatrick McHardy * sNO -> sIV No connection 3452bc78049SPatrick McHardy * sRQ -> sIV No connection 3462bc78049SPatrick McHardy * sRS -> sIV No connection 3472bc78049SPatrick McHardy * sPO -> sOP -> sCG Move direcly to CLOSING 3482bc78049SPatrick McHardy * sOP -> sCG Move to CLOSING 3492bc78049SPatrick McHardy * sCR -> sIV Close after CloseReq is invalid 3502bc78049SPatrick McHardy * sCG -> sCG Retransmit 3512bc78049SPatrick McHardy * sTW -> sIV Already closed 3522bc78049SPatrick McHardy * 3532bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 3542bc78049SPatrick McHardy sIV, sIV, sIV, sCG, sCG, sIV, sCG, sIV 3552bc78049SPatrick McHardy }, 3562bc78049SPatrick McHardy [DCCP_PKT_RESET] = { 3572bc78049SPatrick McHardy /* 3582bc78049SPatrick McHardy * sNO -> sIV No connection 3592bc78049SPatrick McHardy * sRQ -> sTW Reset in response to Request 3602bc78049SPatrick McHardy * sRS -> sTW Timeout, SHOULD send Reset (8.1.3.) 3612bc78049SPatrick McHardy * sPO -> sTW Timeout, SHOULD send Reset (8.1.3.) 3622bc78049SPatrick McHardy * sOP -> sTW 3632bc78049SPatrick McHardy * sCR -> sTW 3642bc78049SPatrick McHardy * sCG -> sTW 3652bc78049SPatrick McHardy * sTW -> sIG Ignore (don't refresh timer) 3662bc78049SPatrick McHardy * 3672bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW, sTW */ 3682bc78049SPatrick McHardy sIV, sTW, sTW, sTW, sTW, sTW, sTW, sTW, sIG 3692bc78049SPatrick McHardy }, 3702bc78049SPatrick McHardy [DCCP_PKT_SYNC] = { 3712bc78049SPatrick McHardy /* 3722bc78049SPatrick McHardy * We currently ignore Sync packets 3732bc78049SPatrick McHardy * 3742bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 3752bc78049SPatrick McHardy sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, 3762bc78049SPatrick McHardy }, 3772bc78049SPatrick McHardy [DCCP_PKT_SYNCACK] = { 3782bc78049SPatrick McHardy /* 3792bc78049SPatrick McHardy * We currently ignore SyncAck packets 3802bc78049SPatrick McHardy * 3812bc78049SPatrick McHardy * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ 3822bc78049SPatrick McHardy sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, 3832bc78049SPatrick McHardy }, 3842bc78049SPatrick McHardy }, 3852bc78049SPatrick McHardy }; 3862bc78049SPatrick McHardy 3871546000fSCyrill Gorcunov /* this module per-net specifics */ 388f99189b1SEric Dumazet static int dccp_net_id __read_mostly; 3891546000fSCyrill Gorcunov struct dccp_net { 39054b8873fSGao feng struct nf_proto_net pn; 3911546000fSCyrill Gorcunov int dccp_loose; 3921546000fSCyrill Gorcunov unsigned int dccp_timeout[CT_DCCP_MAX + 1]; 3931546000fSCyrill Gorcunov }; 3941546000fSCyrill Gorcunov 3951546000fSCyrill Gorcunov static inline struct dccp_net *dccp_pernet(struct net *net) 3961546000fSCyrill Gorcunov { 3971546000fSCyrill Gorcunov return net_generic(net, dccp_net_id); 3981546000fSCyrill Gorcunov } 3991546000fSCyrill Gorcunov 40009f263cdSJan Engelhardt static bool dccp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, 4012bc78049SPatrick McHardy struct nf_conntrack_tuple *tuple) 4022bc78049SPatrick McHardy { 4032bc78049SPatrick McHardy struct dccp_hdr _hdr, *dh; 4042bc78049SPatrick McHardy 4052bc78049SPatrick McHardy dh = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); 4062bc78049SPatrick McHardy if (dh == NULL) 40709f263cdSJan Engelhardt return false; 4082bc78049SPatrick McHardy 4092bc78049SPatrick McHardy tuple->src.u.dccp.port = dh->dccph_sport; 4102bc78049SPatrick McHardy tuple->dst.u.dccp.port = dh->dccph_dport; 41109f263cdSJan Engelhardt return true; 4122bc78049SPatrick McHardy } 4132bc78049SPatrick McHardy 41409f263cdSJan Engelhardt static bool dccp_invert_tuple(struct nf_conntrack_tuple *inv, 4152bc78049SPatrick McHardy const struct nf_conntrack_tuple *tuple) 4162bc78049SPatrick McHardy { 4172bc78049SPatrick McHardy inv->src.u.dccp.port = tuple->dst.u.dccp.port; 4182bc78049SPatrick McHardy inv->dst.u.dccp.port = tuple->src.u.dccp.port; 41909f263cdSJan Engelhardt return true; 4202bc78049SPatrick McHardy } 4212bc78049SPatrick McHardy 42209f263cdSJan Engelhardt static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb, 4232c8503f5SPablo Neira Ayuso unsigned int dataoff, unsigned int *timeouts) 4242bc78049SPatrick McHardy { 425c2a2c7e0SAlexey Dobriyan struct net *net = nf_ct_net(ct); 4261546000fSCyrill Gorcunov struct dccp_net *dn; 4272bc78049SPatrick McHardy struct dccp_hdr _dh, *dh; 4282bc78049SPatrick McHardy const char *msg; 4292bc78049SPatrick McHardy u_int8_t state; 4302bc78049SPatrick McHardy 4312bc78049SPatrick McHardy dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); 4322bc78049SPatrick McHardy BUG_ON(dh == NULL); 4332bc78049SPatrick McHardy 4342bc78049SPatrick McHardy state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE]; 4352bc78049SPatrick McHardy switch (state) { 4362bc78049SPatrick McHardy default: 4371546000fSCyrill Gorcunov dn = dccp_pernet(net); 4381546000fSCyrill Gorcunov if (dn->dccp_loose == 0) { 4392bc78049SPatrick McHardy msg = "nf_ct_dccp: not picking up existing connection "; 4402bc78049SPatrick McHardy goto out_invalid; 4412bc78049SPatrick McHardy } 4422bc78049SPatrick McHardy case CT_DCCP_REQUEST: 4432bc78049SPatrick McHardy break; 4442bc78049SPatrick McHardy case CT_DCCP_INVALID: 4452bc78049SPatrick McHardy msg = "nf_ct_dccp: invalid state transition "; 4462bc78049SPatrick McHardy goto out_invalid; 4472bc78049SPatrick McHardy } 4482bc78049SPatrick McHardy 4492bc78049SPatrick McHardy ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT; 4502bc78049SPatrick McHardy ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER; 4512bc78049SPatrick McHardy ct->proto.dccp.state = CT_DCCP_NONE; 452e5fc9e7aSChangli Gao ct->proto.dccp.last_pkt = DCCP_PKT_REQUEST; 453e5fc9e7aSChangli Gao ct->proto.dccp.last_dir = IP_CT_DIR_ORIGINAL; 454e5fc9e7aSChangli Gao ct->proto.dccp.handshake_seq = 0; 45509f263cdSJan Engelhardt return true; 4562bc78049SPatrick McHardy 4572bc78049SPatrick McHardy out_invalid: 458c2a2c7e0SAlexey Dobriyan if (LOG_INVALID(net, IPPROTO_DCCP)) 45930e0c6a6SGao feng nf_log_packet(net, nf_ct_l3num(ct), 0, skb, NULL, NULL, 46030e0c6a6SGao feng NULL, msg); 46109f263cdSJan Engelhardt return false; 4622bc78049SPatrick McHardy } 4632bc78049SPatrick McHardy 4642bc78049SPatrick McHardy static u64 dccp_ack_seq(const struct dccp_hdr *dh) 4652bc78049SPatrick McHardy { 4662bc78049SPatrick McHardy const struct dccp_hdr_ack_bits *dhack; 4672bc78049SPatrick McHardy 4682bc78049SPatrick McHardy dhack = (void *)dh + __dccp_basic_hdr_len(dh); 4692bc78049SPatrick McHardy return ((u64)ntohs(dhack->dccph_ack_nr_high) << 32) + 4702bc78049SPatrick McHardy ntohl(dhack->dccph_ack_nr_low); 4712bc78049SPatrick McHardy } 4722bc78049SPatrick McHardy 4732c8503f5SPablo Neira Ayuso static unsigned int *dccp_get_timeouts(struct net *net) 4742c8503f5SPablo Neira Ayuso { 4752c8503f5SPablo Neira Ayuso return dccp_pernet(net)->dccp_timeout; 4762c8503f5SPablo Neira Ayuso } 4772c8503f5SPablo Neira Ayuso 4782bc78049SPatrick McHardy static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, 4792bc78049SPatrick McHardy unsigned int dataoff, enum ip_conntrack_info ctinfo, 4802c8503f5SPablo Neira Ayuso u_int8_t pf, unsigned int hooknum, 4812c8503f5SPablo Neira Ayuso unsigned int *timeouts) 4822bc78049SPatrick McHardy { 483c2a2c7e0SAlexey Dobriyan struct net *net = nf_ct_net(ct); 4842bc78049SPatrick McHardy enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 4852bc78049SPatrick McHardy struct dccp_hdr _dh, *dh; 4862bc78049SPatrick McHardy u_int8_t type, old_state, new_state; 4872bc78049SPatrick McHardy enum ct_dccp_roles role; 4882bc78049SPatrick McHardy 4892bc78049SPatrick McHardy dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); 4902bc78049SPatrick McHardy BUG_ON(dh == NULL); 4912bc78049SPatrick McHardy type = dh->dccph_type; 4922bc78049SPatrick McHardy 4932bc78049SPatrick McHardy if (type == DCCP_PKT_RESET && 4942bc78049SPatrick McHardy !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { 4952bc78049SPatrick McHardy /* Tear down connection immediately if only reply is a RESET */ 496718d4ad9SFabian Hugelshofer nf_ct_kill_acct(ct, ctinfo, skb); 4972bc78049SPatrick McHardy return NF_ACCEPT; 4982bc78049SPatrick McHardy } 4992bc78049SPatrick McHardy 500440f0d58SPatrick McHardy spin_lock_bh(&ct->lock); 5012bc78049SPatrick McHardy 5022bc78049SPatrick McHardy role = ct->proto.dccp.role[dir]; 5032bc78049SPatrick McHardy old_state = ct->proto.dccp.state; 5042bc78049SPatrick McHardy new_state = dccp_state_table[role][type][old_state]; 5052bc78049SPatrick McHardy 5062bc78049SPatrick McHardy switch (new_state) { 5072bc78049SPatrick McHardy case CT_DCCP_REQUEST: 5082bc78049SPatrick McHardy if (old_state == CT_DCCP_TIMEWAIT && 5092bc78049SPatrick McHardy role == CT_DCCP_ROLE_SERVER) { 5102bc78049SPatrick McHardy /* Reincarnation in the reverse direction: reopen and 5112bc78049SPatrick McHardy * reverse client/server roles. */ 5122bc78049SPatrick McHardy ct->proto.dccp.role[dir] = CT_DCCP_ROLE_CLIENT; 5132bc78049SPatrick McHardy ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_SERVER; 5142bc78049SPatrick McHardy } 5152bc78049SPatrick McHardy break; 5162bc78049SPatrick McHardy case CT_DCCP_RESPOND: 5172bc78049SPatrick McHardy if (old_state == CT_DCCP_REQUEST) 5182bc78049SPatrick McHardy ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh); 5192bc78049SPatrick McHardy break; 5202bc78049SPatrick McHardy case CT_DCCP_PARTOPEN: 5212bc78049SPatrick McHardy if (old_state == CT_DCCP_RESPOND && 5222bc78049SPatrick McHardy type == DCCP_PKT_ACK && 5232bc78049SPatrick McHardy dccp_ack_seq(dh) == ct->proto.dccp.handshake_seq) 5242bc78049SPatrick McHardy set_bit(IPS_ASSURED_BIT, &ct->status); 5252bc78049SPatrick McHardy break; 5262bc78049SPatrick McHardy case CT_DCCP_IGNORE: 5272bc78049SPatrick McHardy /* 5282bc78049SPatrick McHardy * Connection tracking might be out of sync, so we ignore 5292bc78049SPatrick McHardy * packets that might establish a new connection and resync 5302bc78049SPatrick McHardy * if the server responds with a valid Response. 5312bc78049SPatrick McHardy */ 5322bc78049SPatrick McHardy if (ct->proto.dccp.last_dir == !dir && 5332bc78049SPatrick McHardy ct->proto.dccp.last_pkt == DCCP_PKT_REQUEST && 5342bc78049SPatrick McHardy type == DCCP_PKT_RESPONSE) { 5352bc78049SPatrick McHardy ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_CLIENT; 5362bc78049SPatrick McHardy ct->proto.dccp.role[dir] = CT_DCCP_ROLE_SERVER; 5372bc78049SPatrick McHardy ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh); 5382bc78049SPatrick McHardy new_state = CT_DCCP_RESPOND; 5392bc78049SPatrick McHardy break; 5402bc78049SPatrick McHardy } 5412bc78049SPatrick McHardy ct->proto.dccp.last_dir = dir; 5422bc78049SPatrick McHardy ct->proto.dccp.last_pkt = type; 5432bc78049SPatrick McHardy 544440f0d58SPatrick McHardy spin_unlock_bh(&ct->lock); 545c2a2c7e0SAlexey Dobriyan if (LOG_INVALID(net, IPPROTO_DCCP)) 54630e0c6a6SGao feng nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, 5472bc78049SPatrick McHardy "nf_ct_dccp: invalid packet ignored "); 5482bc78049SPatrick McHardy return NF_ACCEPT; 5492bc78049SPatrick McHardy case CT_DCCP_INVALID: 550440f0d58SPatrick McHardy spin_unlock_bh(&ct->lock); 551c2a2c7e0SAlexey Dobriyan if (LOG_INVALID(net, IPPROTO_DCCP)) 55230e0c6a6SGao feng nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, 5532bc78049SPatrick McHardy "nf_ct_dccp: invalid state transition "); 5542bc78049SPatrick McHardy return -NF_ACCEPT; 5552bc78049SPatrick McHardy } 5562bc78049SPatrick McHardy 5572bc78049SPatrick McHardy ct->proto.dccp.last_dir = dir; 5582bc78049SPatrick McHardy ct->proto.dccp.last_pkt = type; 5592bc78049SPatrick McHardy ct->proto.dccp.state = new_state; 560440f0d58SPatrick McHardy spin_unlock_bh(&ct->lock); 5611546000fSCyrill Gorcunov 562b38b1f61SPablo Neira Ayuso if (new_state != old_state) 563b38b1f61SPablo Neira Ayuso nf_conntrack_event_cache(IPCT_PROTOINFO, ct); 564b38b1f61SPablo Neira Ayuso 5652c8503f5SPablo Neira Ayuso nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]); 5662bc78049SPatrick McHardy 5672bc78049SPatrick McHardy return NF_ACCEPT; 5682bc78049SPatrick McHardy } 5692bc78049SPatrick McHardy 5708fea97ecSPatrick McHardy static int dccp_error(struct net *net, struct nf_conn *tmpl, 5718fea97ecSPatrick McHardy struct sk_buff *skb, unsigned int dataoff, 5728fea97ecSPatrick McHardy enum ip_conntrack_info *ctinfo, 57374c51a14SAlexey Dobriyan u_int8_t pf, unsigned int hooknum) 5742bc78049SPatrick McHardy { 5752bc78049SPatrick McHardy struct dccp_hdr _dh, *dh; 5762bc78049SPatrick McHardy unsigned int dccp_len = skb->len - dataoff; 5772bc78049SPatrick McHardy unsigned int cscov; 5782bc78049SPatrick McHardy const char *msg; 5792bc78049SPatrick McHardy 5802bc78049SPatrick McHardy dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); 5812bc78049SPatrick McHardy if (dh == NULL) { 5822bc78049SPatrick McHardy msg = "nf_ct_dccp: short packet "; 5832bc78049SPatrick McHardy goto out_invalid; 5842bc78049SPatrick McHardy } 5852bc78049SPatrick McHardy 5862bc78049SPatrick McHardy if (dh->dccph_doff * 4 < sizeof(struct dccp_hdr) || 5872bc78049SPatrick McHardy dh->dccph_doff * 4 > dccp_len) { 5882bc78049SPatrick McHardy msg = "nf_ct_dccp: truncated/malformed packet "; 5892bc78049SPatrick McHardy goto out_invalid; 5902bc78049SPatrick McHardy } 5912bc78049SPatrick McHardy 5922bc78049SPatrick McHardy cscov = dccp_len; 5932bc78049SPatrick McHardy if (dh->dccph_cscov) { 5942bc78049SPatrick McHardy cscov = (dh->dccph_cscov - 1) * 4; 5952bc78049SPatrick McHardy if (cscov > dccp_len) { 5962bc78049SPatrick McHardy msg = "nf_ct_dccp: bad checksum coverage "; 5972bc78049SPatrick McHardy goto out_invalid; 5982bc78049SPatrick McHardy } 5992bc78049SPatrick McHardy } 6002bc78049SPatrick McHardy 601c04d0552SAlexey Dobriyan if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && 6022bc78049SPatrick McHardy nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_DCCP, 6032bc78049SPatrick McHardy pf)) { 6042bc78049SPatrick McHardy msg = "nf_ct_dccp: bad checksum "; 6052bc78049SPatrick McHardy goto out_invalid; 6062bc78049SPatrick McHardy } 6072bc78049SPatrick McHardy 6082bc78049SPatrick McHardy if (dh->dccph_type >= DCCP_PKT_INVALID) { 6092bc78049SPatrick McHardy msg = "nf_ct_dccp: reserved packet type "; 6102bc78049SPatrick McHardy goto out_invalid; 6112bc78049SPatrick McHardy } 6122bc78049SPatrick McHardy 6132bc78049SPatrick McHardy return NF_ACCEPT; 6142bc78049SPatrick McHardy 6152bc78049SPatrick McHardy out_invalid: 616c2a2c7e0SAlexey Dobriyan if (LOG_INVALID(net, IPPROTO_DCCP)) 61730e0c6a6SGao feng nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, msg); 6182bc78049SPatrick McHardy return -NF_ACCEPT; 6192bc78049SPatrick McHardy } 6202bc78049SPatrick McHardy 6212bc78049SPatrick McHardy static int dccp_print_tuple(struct seq_file *s, 6222bc78049SPatrick McHardy const struct nf_conntrack_tuple *tuple) 6232bc78049SPatrick McHardy { 6242bc78049SPatrick McHardy return seq_printf(s, "sport=%hu dport=%hu ", 6252bc78049SPatrick McHardy ntohs(tuple->src.u.dccp.port), 6262bc78049SPatrick McHardy ntohs(tuple->dst.u.dccp.port)); 6272bc78049SPatrick McHardy } 6282bc78049SPatrick McHardy 629440f0d58SPatrick McHardy static int dccp_print_conntrack(struct seq_file *s, struct nf_conn *ct) 6302bc78049SPatrick McHardy { 6312bc78049SPatrick McHardy return seq_printf(s, "%s ", dccp_state_names[ct->proto.dccp.state]); 6322bc78049SPatrick McHardy } 6332bc78049SPatrick McHardy 634c0cd1156SIgor Maravić #if IS_ENABLED(CONFIG_NF_CT_NETLINK) 6352bc78049SPatrick McHardy static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, 636440f0d58SPatrick McHardy struct nf_conn *ct) 6372bc78049SPatrick McHardy { 6382bc78049SPatrick McHardy struct nlattr *nest_parms; 6392bc78049SPatrick McHardy 640440f0d58SPatrick McHardy spin_lock_bh(&ct->lock); 6412bc78049SPatrick McHardy nest_parms = nla_nest_start(skb, CTA_PROTOINFO_DCCP | NLA_F_NESTED); 6422bc78049SPatrick McHardy if (!nest_parms) 6432bc78049SPatrick McHardy goto nla_put_failure; 644516ee48fSDavid S. Miller if (nla_put_u8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state) || 645516ee48fSDavid S. Miller nla_put_u8(skb, CTA_PROTOINFO_DCCP_ROLE, 646516ee48fSDavid S. Miller ct->proto.dccp.role[IP_CT_DIR_ORIGINAL]) || 647516ee48fSDavid S. Miller nla_put_be64(skb, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ, 648516ee48fSDavid S. Miller cpu_to_be64(ct->proto.dccp.handshake_seq))) 649516ee48fSDavid S. Miller goto nla_put_failure; 6502bc78049SPatrick McHardy nla_nest_end(skb, nest_parms); 651440f0d58SPatrick McHardy spin_unlock_bh(&ct->lock); 6522bc78049SPatrick McHardy return 0; 6532bc78049SPatrick McHardy 6542bc78049SPatrick McHardy nla_put_failure: 655440f0d58SPatrick McHardy spin_unlock_bh(&ct->lock); 6562bc78049SPatrick McHardy return -1; 6572bc78049SPatrick McHardy } 6582bc78049SPatrick McHardy 6592bc78049SPatrick McHardy static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = { 6602bc78049SPatrick McHardy [CTA_PROTOINFO_DCCP_STATE] = { .type = NLA_U8 }, 66171951b64SPablo Neira Ayuso [CTA_PROTOINFO_DCCP_ROLE] = { .type = NLA_U8 }, 662a17c8598SPablo Neira Ayuso [CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ] = { .type = NLA_U64 }, 6632bc78049SPatrick McHardy }; 6642bc78049SPatrick McHardy 6652bc78049SPatrick McHardy static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) 6662bc78049SPatrick McHardy { 6672bc78049SPatrick McHardy struct nlattr *attr = cda[CTA_PROTOINFO_DCCP]; 6682bc78049SPatrick McHardy struct nlattr *tb[CTA_PROTOINFO_DCCP_MAX + 1]; 6692bc78049SPatrick McHardy int err; 6702bc78049SPatrick McHardy 6712bc78049SPatrick McHardy if (!attr) 6722bc78049SPatrick McHardy return 0; 6732bc78049SPatrick McHardy 6742bc78049SPatrick McHardy err = nla_parse_nested(tb, CTA_PROTOINFO_DCCP_MAX, attr, 6752bc78049SPatrick McHardy dccp_nla_policy); 6762bc78049SPatrick McHardy if (err < 0) 6772bc78049SPatrick McHardy return err; 6782bc78049SPatrick McHardy 6792bc78049SPatrick McHardy if (!tb[CTA_PROTOINFO_DCCP_STATE] || 68071951b64SPablo Neira Ayuso !tb[CTA_PROTOINFO_DCCP_ROLE] || 68171951b64SPablo Neira Ayuso nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) > CT_DCCP_ROLE_MAX || 68271951b64SPablo Neira Ayuso nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]) >= CT_DCCP_IGNORE) { 6832bc78049SPatrick McHardy return -EINVAL; 68471951b64SPablo Neira Ayuso } 6852bc78049SPatrick McHardy 686440f0d58SPatrick McHardy spin_lock_bh(&ct->lock); 6872bc78049SPatrick McHardy ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]); 68871951b64SPablo Neira Ayuso if (nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) == CT_DCCP_ROLE_CLIENT) { 68971951b64SPablo Neira Ayuso ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT; 69071951b64SPablo Neira Ayuso ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER; 69171951b64SPablo Neira Ayuso } else { 69271951b64SPablo Neira Ayuso ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_SERVER; 69371951b64SPablo Neira Ayuso ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_CLIENT; 69471951b64SPablo Neira Ayuso } 695a17c8598SPablo Neira Ayuso if (tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ]) { 696a17c8598SPablo Neira Ayuso ct->proto.dccp.handshake_seq = 697a17c8598SPablo Neira Ayuso be64_to_cpu(nla_get_be64(tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ])); 698a17c8598SPablo Neira Ayuso } 699440f0d58SPatrick McHardy spin_unlock_bh(&ct->lock); 7002bc78049SPatrick McHardy return 0; 7012bc78049SPatrick McHardy } 702a400c30eSHolger Eitzenberger 703a400c30eSHolger Eitzenberger static int dccp_nlattr_size(void) 704a400c30eSHolger Eitzenberger { 705a400c30eSHolger Eitzenberger return nla_total_size(0) /* CTA_PROTOINFO_DCCP */ 706a400c30eSHolger Eitzenberger + nla_policy_len(dccp_nla_policy, CTA_PROTOINFO_DCCP_MAX + 1); 707a400c30eSHolger Eitzenberger } 70850978462SPablo Neira Ayuso 7092bc78049SPatrick McHardy #endif 7102bc78049SPatrick McHardy 71150978462SPablo Neira Ayuso #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) 71250978462SPablo Neira Ayuso 71350978462SPablo Neira Ayuso #include <linux/netfilter/nfnetlink.h> 71450978462SPablo Neira Ayuso #include <linux/netfilter/nfnetlink_cttimeout.h> 71550978462SPablo Neira Ayuso 7168264deb8SGao feng static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[], 7178264deb8SGao feng struct net *net, void *data) 71850978462SPablo Neira Ayuso { 7198264deb8SGao feng struct dccp_net *dn = dccp_pernet(net); 72050978462SPablo Neira Ayuso unsigned int *timeouts = data; 72150978462SPablo Neira Ayuso int i; 72250978462SPablo Neira Ayuso 72350978462SPablo Neira Ayuso /* set default DCCP timeouts. */ 72450978462SPablo Neira Ayuso for (i=0; i<CT_DCCP_MAX; i++) 72550978462SPablo Neira Ayuso timeouts[i] = dn->dccp_timeout[i]; 72650978462SPablo Neira Ayuso 72750978462SPablo Neira Ayuso /* there's a 1:1 mapping between attributes and protocol states. */ 72850978462SPablo Neira Ayuso for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) { 72950978462SPablo Neira Ayuso if (tb[i]) { 73050978462SPablo Neira Ayuso timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ; 73150978462SPablo Neira Ayuso } 73250978462SPablo Neira Ayuso } 73350978462SPablo Neira Ayuso return 0; 73450978462SPablo Neira Ayuso } 73550978462SPablo Neira Ayuso 73650978462SPablo Neira Ayuso static int 73750978462SPablo Neira Ayuso dccp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) 73850978462SPablo Neira Ayuso { 73950978462SPablo Neira Ayuso const unsigned int *timeouts = data; 74050978462SPablo Neira Ayuso int i; 74150978462SPablo Neira Ayuso 742516ee48fSDavid S. Miller for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) { 743516ee48fSDavid S. Miller if (nla_put_be32(skb, i, htonl(timeouts[i] / HZ))) 744516ee48fSDavid S. Miller goto nla_put_failure; 745516ee48fSDavid S. Miller } 74650978462SPablo Neira Ayuso return 0; 74750978462SPablo Neira Ayuso 74850978462SPablo Neira Ayuso nla_put_failure: 74950978462SPablo Neira Ayuso return -ENOSPC; 75050978462SPablo Neira Ayuso } 75150978462SPablo Neira Ayuso 75250978462SPablo Neira Ayuso static const struct nla_policy 75350978462SPablo Neira Ayuso dccp_timeout_nla_policy[CTA_TIMEOUT_DCCP_MAX+1] = { 75450978462SPablo Neira Ayuso [CTA_TIMEOUT_DCCP_REQUEST] = { .type = NLA_U32 }, 75550978462SPablo Neira Ayuso [CTA_TIMEOUT_DCCP_RESPOND] = { .type = NLA_U32 }, 75650978462SPablo Neira Ayuso [CTA_TIMEOUT_DCCP_PARTOPEN] = { .type = NLA_U32 }, 75750978462SPablo Neira Ayuso [CTA_TIMEOUT_DCCP_OPEN] = { .type = NLA_U32 }, 75850978462SPablo Neira Ayuso [CTA_TIMEOUT_DCCP_CLOSEREQ] = { .type = NLA_U32 }, 75950978462SPablo Neira Ayuso [CTA_TIMEOUT_DCCP_CLOSING] = { .type = NLA_U32 }, 76050978462SPablo Neira Ayuso [CTA_TIMEOUT_DCCP_TIMEWAIT] = { .type = NLA_U32 }, 76150978462SPablo Neira Ayuso }; 76250978462SPablo Neira Ayuso #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ 76350978462SPablo Neira Ayuso 7642bc78049SPatrick McHardy #ifdef CONFIG_SYSCTL 7651546000fSCyrill Gorcunov /* template, data assigned later */ 7661546000fSCyrill Gorcunov static struct ctl_table dccp_sysctl_table[] = { 7672bc78049SPatrick McHardy { 7682bc78049SPatrick McHardy .procname = "nf_conntrack_dccp_timeout_request", 7692bc78049SPatrick McHardy .maxlen = sizeof(unsigned int), 7702bc78049SPatrick McHardy .mode = 0644, 7712bc78049SPatrick McHardy .proc_handler = proc_dointvec_jiffies, 7722bc78049SPatrick McHardy }, 7732bc78049SPatrick McHardy { 7742bc78049SPatrick McHardy .procname = "nf_conntrack_dccp_timeout_respond", 7752bc78049SPatrick McHardy .maxlen = sizeof(unsigned int), 7762bc78049SPatrick McHardy .mode = 0644, 7772bc78049SPatrick McHardy .proc_handler = proc_dointvec_jiffies, 7782bc78049SPatrick McHardy }, 7792bc78049SPatrick McHardy { 7802bc78049SPatrick McHardy .procname = "nf_conntrack_dccp_timeout_partopen", 7812bc78049SPatrick McHardy .maxlen = sizeof(unsigned int), 7822bc78049SPatrick McHardy .mode = 0644, 7832bc78049SPatrick McHardy .proc_handler = proc_dointvec_jiffies, 7842bc78049SPatrick McHardy }, 7852bc78049SPatrick McHardy { 7862bc78049SPatrick McHardy .procname = "nf_conntrack_dccp_timeout_open", 7872bc78049SPatrick McHardy .maxlen = sizeof(unsigned int), 7882bc78049SPatrick McHardy .mode = 0644, 7892bc78049SPatrick McHardy .proc_handler = proc_dointvec_jiffies, 7902bc78049SPatrick McHardy }, 7912bc78049SPatrick McHardy { 7922bc78049SPatrick McHardy .procname = "nf_conntrack_dccp_timeout_closereq", 7932bc78049SPatrick McHardy .maxlen = sizeof(unsigned int), 7942bc78049SPatrick McHardy .mode = 0644, 7952bc78049SPatrick McHardy .proc_handler = proc_dointvec_jiffies, 7962bc78049SPatrick McHardy }, 7972bc78049SPatrick McHardy { 7982bc78049SPatrick McHardy .procname = "nf_conntrack_dccp_timeout_closing", 7992bc78049SPatrick McHardy .maxlen = sizeof(unsigned int), 8002bc78049SPatrick McHardy .mode = 0644, 8012bc78049SPatrick McHardy .proc_handler = proc_dointvec_jiffies, 8022bc78049SPatrick McHardy }, 8032bc78049SPatrick McHardy { 8042bc78049SPatrick McHardy .procname = "nf_conntrack_dccp_timeout_timewait", 8052bc78049SPatrick McHardy .maxlen = sizeof(unsigned int), 8062bc78049SPatrick McHardy .mode = 0644, 8072bc78049SPatrick McHardy .proc_handler = proc_dointvec_jiffies, 8082bc78049SPatrick McHardy }, 8092bc78049SPatrick McHardy { 8102bc78049SPatrick McHardy .procname = "nf_conntrack_dccp_loose", 8111546000fSCyrill Gorcunov .maxlen = sizeof(int), 8122bc78049SPatrick McHardy .mode = 0644, 8132bc78049SPatrick McHardy .proc_handler = proc_dointvec, 8142bc78049SPatrick McHardy }, 815f8572d8fSEric W. Biederman { } 8162bc78049SPatrick McHardy }; 8172bc78049SPatrick McHardy #endif /* CONFIG_SYSCTL */ 8182bc78049SPatrick McHardy 819464dc801SEric W. Biederman static int dccp_kmemdup_sysctl_table(struct net *net, struct nf_proto_net *pn, 82054b8873fSGao feng struct dccp_net *dn) 82184c39451SGao feng { 82254b8873fSGao feng #ifdef CONFIG_SYSCTL 82354b8873fSGao feng if (pn->ctl_table) 82454b8873fSGao feng return 0; 82584c39451SGao feng 82684c39451SGao feng pn->ctl_table = kmemdup(dccp_sysctl_table, 82784c39451SGao feng sizeof(dccp_sysctl_table), 82884c39451SGao feng GFP_KERNEL); 82984c39451SGao feng if (!pn->ctl_table) 83084c39451SGao feng return -ENOMEM; 83184c39451SGao feng 83284c39451SGao feng pn->ctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST]; 83384c39451SGao feng pn->ctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND]; 83484c39451SGao feng pn->ctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN]; 83584c39451SGao feng pn->ctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN]; 83684c39451SGao feng pn->ctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ]; 83784c39451SGao feng pn->ctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING]; 83884c39451SGao feng pn->ctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT]; 83984c39451SGao feng pn->ctl_table[7].data = &dn->dccp_loose; 840464dc801SEric W. Biederman 841464dc801SEric W. Biederman /* Don't export sysctls to unprivileged users */ 842464dc801SEric W. Biederman if (net->user_ns != &init_user_ns) 843464dc801SEric W. Biederman pn->ctl_table[0].procname = NULL; 84484c39451SGao feng #endif 84584c39451SGao feng return 0; 84684c39451SGao feng } 84784c39451SGao feng 84854b8873fSGao feng static int dccp_init_net(struct net *net, u_int16_t proto) 84954b8873fSGao feng { 85054b8873fSGao feng struct dccp_net *dn = dccp_pernet(net); 85154b8873fSGao feng struct nf_proto_net *pn = &dn->pn; 85254b8873fSGao feng 85354b8873fSGao feng if (!pn->users) { 85454b8873fSGao feng /* default values */ 85554b8873fSGao feng dn->dccp_loose = 1; 85654b8873fSGao feng dn->dccp_timeout[CT_DCCP_REQUEST] = 2 * DCCP_MSL; 85754b8873fSGao feng dn->dccp_timeout[CT_DCCP_RESPOND] = 4 * DCCP_MSL; 85854b8873fSGao feng dn->dccp_timeout[CT_DCCP_PARTOPEN] = 4 * DCCP_MSL; 85954b8873fSGao feng dn->dccp_timeout[CT_DCCP_OPEN] = 12 * 3600 * HZ; 86054b8873fSGao feng dn->dccp_timeout[CT_DCCP_CLOSEREQ] = 64 * HZ; 86154b8873fSGao feng dn->dccp_timeout[CT_DCCP_CLOSING] = 64 * HZ; 86254b8873fSGao feng dn->dccp_timeout[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL; 86354b8873fSGao feng } 86454b8873fSGao feng 865464dc801SEric W. Biederman return dccp_kmemdup_sysctl_table(net, pn, dn); 86654b8873fSGao feng } 86754b8873fSGao feng 8682bc78049SPatrick McHardy static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = { 8692bc78049SPatrick McHardy .l3proto = AF_INET, 8702bc78049SPatrick McHardy .l4proto = IPPROTO_DCCP, 8712bc78049SPatrick McHardy .name = "dccp", 8722bc78049SPatrick McHardy .pkt_to_tuple = dccp_pkt_to_tuple, 8732bc78049SPatrick McHardy .invert_tuple = dccp_invert_tuple, 8742bc78049SPatrick McHardy .new = dccp_new, 8752bc78049SPatrick McHardy .packet = dccp_packet, 8762c8503f5SPablo Neira Ayuso .get_timeouts = dccp_get_timeouts, 8772bc78049SPatrick McHardy .error = dccp_error, 8782bc78049SPatrick McHardy .print_tuple = dccp_print_tuple, 8792bc78049SPatrick McHardy .print_conntrack = dccp_print_conntrack, 880c0cd1156SIgor Maravić #if IS_ENABLED(CONFIG_NF_CT_NETLINK) 8812bc78049SPatrick McHardy .to_nlattr = dccp_to_nlattr, 882a400c30eSHolger Eitzenberger .nlattr_size = dccp_nlattr_size, 8832bc78049SPatrick McHardy .from_nlattr = nlattr_to_dccp, 8842bc78049SPatrick McHardy .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, 885a400c30eSHolger Eitzenberger .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, 8862bc78049SPatrick McHardy .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, 8872bc78049SPatrick McHardy .nla_policy = nf_ct_port_nla_policy, 8882bc78049SPatrick McHardy #endif 88950978462SPablo Neira Ayuso #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) 89050978462SPablo Neira Ayuso .ctnl_timeout = { 89150978462SPablo Neira Ayuso .nlattr_to_obj = dccp_timeout_nlattr_to_obj, 89250978462SPablo Neira Ayuso .obj_to_nlattr = dccp_timeout_obj_to_nlattr, 89350978462SPablo Neira Ayuso .nlattr_max = CTA_TIMEOUT_DCCP_MAX, 89450978462SPablo Neira Ayuso .obj_size = sizeof(unsigned int) * CT_DCCP_MAX, 89550978462SPablo Neira Ayuso .nla_policy = dccp_timeout_nla_policy, 89650978462SPablo Neira Ayuso }, 89750978462SPablo Neira Ayuso #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ 89884c39451SGao feng .net_id = &dccp_net_id, 89984c39451SGao feng .init_net = dccp_init_net, 9002bc78049SPatrick McHardy }; 9012bc78049SPatrick McHardy 9022bc78049SPatrick McHardy static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { 9032bc78049SPatrick McHardy .l3proto = AF_INET6, 9042bc78049SPatrick McHardy .l4proto = IPPROTO_DCCP, 9052bc78049SPatrick McHardy .name = "dccp", 9062bc78049SPatrick McHardy .pkt_to_tuple = dccp_pkt_to_tuple, 9072bc78049SPatrick McHardy .invert_tuple = dccp_invert_tuple, 9082bc78049SPatrick McHardy .new = dccp_new, 9092bc78049SPatrick McHardy .packet = dccp_packet, 9102c8503f5SPablo Neira Ayuso .get_timeouts = dccp_get_timeouts, 9112bc78049SPatrick McHardy .error = dccp_error, 9122bc78049SPatrick McHardy .print_tuple = dccp_print_tuple, 9132bc78049SPatrick McHardy .print_conntrack = dccp_print_conntrack, 914c0cd1156SIgor Maravić #if IS_ENABLED(CONFIG_NF_CT_NETLINK) 9152bc78049SPatrick McHardy .to_nlattr = dccp_to_nlattr, 9165ff48294SPatrick McHardy .nlattr_size = dccp_nlattr_size, 9172bc78049SPatrick McHardy .from_nlattr = nlattr_to_dccp, 9182bc78049SPatrick McHardy .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, 919a400c30eSHolger Eitzenberger .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, 9202bc78049SPatrick McHardy .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, 9212bc78049SPatrick McHardy .nla_policy = nf_ct_port_nla_policy, 9222bc78049SPatrick McHardy #endif 92350978462SPablo Neira Ayuso #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) 92450978462SPablo Neira Ayuso .ctnl_timeout = { 92550978462SPablo Neira Ayuso .nlattr_to_obj = dccp_timeout_nlattr_to_obj, 92650978462SPablo Neira Ayuso .obj_to_nlattr = dccp_timeout_obj_to_nlattr, 92750978462SPablo Neira Ayuso .nlattr_max = CTA_TIMEOUT_DCCP_MAX, 92850978462SPablo Neira Ayuso .obj_size = sizeof(unsigned int) * CT_DCCP_MAX, 92950978462SPablo Neira Ayuso .nla_policy = dccp_timeout_nla_policy, 93050978462SPablo Neira Ayuso }, 93150978462SPablo Neira Ayuso #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ 93284c39451SGao feng .net_id = &dccp_net_id, 93384c39451SGao feng .init_net = dccp_init_net, 9341546000fSCyrill Gorcunov }; 9351546000fSCyrill Gorcunov 9361546000fSCyrill Gorcunov static __net_init int dccp_net_init(struct net *net) 9371546000fSCyrill Gorcunov { 93884c39451SGao feng int ret = 0; 939c296bb4dSGao feng ret = nf_ct_l4proto_pernet_register(net, &dccp_proto4); 94084c39451SGao feng if (ret < 0) { 941c296bb4dSGao feng pr_err("nf_conntrack_dccp4: pernet registration failed.\n"); 94284c39451SGao feng goto out; 9431546000fSCyrill Gorcunov } 944c296bb4dSGao feng ret = nf_ct_l4proto_pernet_register(net, &dccp_proto6); 94584c39451SGao feng if (ret < 0) { 946c296bb4dSGao feng pr_err("nf_conntrack_dccp6: pernet registration failed.\n"); 94784c39451SGao feng goto cleanup_dccp4; 94884c39451SGao feng } 9491546000fSCyrill Gorcunov return 0; 95084c39451SGao feng cleanup_dccp4: 951c296bb4dSGao feng nf_ct_l4proto_pernet_unregister(net, &dccp_proto4); 95284c39451SGao feng out: 95384c39451SGao feng return ret; 9541546000fSCyrill Gorcunov } 9551546000fSCyrill Gorcunov 9561546000fSCyrill Gorcunov static __net_exit void dccp_net_exit(struct net *net) 9571546000fSCyrill Gorcunov { 958c296bb4dSGao feng nf_ct_l4proto_pernet_unregister(net, &dccp_proto6); 959c296bb4dSGao feng nf_ct_l4proto_pernet_unregister(net, &dccp_proto4); 9601546000fSCyrill Gorcunov } 9611546000fSCyrill Gorcunov 9621546000fSCyrill Gorcunov static struct pernet_operations dccp_net_ops = { 9631546000fSCyrill Gorcunov .init = dccp_net_init, 9641546000fSCyrill Gorcunov .exit = dccp_net_exit, 96532b51f92SEric W. Biederman .id = &dccp_net_id, 96632b51f92SEric W. Biederman .size = sizeof(struct dccp_net), 9672bc78049SPatrick McHardy }; 9682bc78049SPatrick McHardy 9692bc78049SPatrick McHardy static int __init nf_conntrack_proto_dccp_init(void) 9702bc78049SPatrick McHardy { 971c296bb4dSGao feng int ret; 972c296bb4dSGao feng 9730d98da5dSGao feng ret = register_pernet_subsys(&dccp_net_ops); 9740d98da5dSGao feng if (ret < 0) 9750d98da5dSGao feng goto out_pernet; 9760d98da5dSGao feng 977c296bb4dSGao feng ret = nf_ct_l4proto_register(&dccp_proto4); 978c296bb4dSGao feng if (ret < 0) 979c296bb4dSGao feng goto out_dccp4; 980c296bb4dSGao feng 981c296bb4dSGao feng ret = nf_ct_l4proto_register(&dccp_proto6); 982c296bb4dSGao feng if (ret < 0) 983c296bb4dSGao feng goto out_dccp6; 984c296bb4dSGao feng 985c296bb4dSGao feng return 0; 986c296bb4dSGao feng out_dccp6: 987c296bb4dSGao feng nf_ct_l4proto_unregister(&dccp_proto4); 988c296bb4dSGao feng out_dccp4: 9890d98da5dSGao feng unregister_pernet_subsys(&dccp_net_ops); 9900d98da5dSGao feng out_pernet: 991c296bb4dSGao feng return ret; 9922bc78049SPatrick McHardy } 9932bc78049SPatrick McHardy 9942bc78049SPatrick McHardy static void __exit nf_conntrack_proto_dccp_fini(void) 9952bc78049SPatrick McHardy { 996c296bb4dSGao feng nf_ct_l4proto_unregister(&dccp_proto6); 997c296bb4dSGao feng nf_ct_l4proto_unregister(&dccp_proto4); 99832b51f92SEric W. Biederman unregister_pernet_subsys(&dccp_net_ops); 9992bc78049SPatrick McHardy } 10002bc78049SPatrick McHardy 10012bc78049SPatrick McHardy module_init(nf_conntrack_proto_dccp_init); 10022bc78049SPatrick McHardy module_exit(nf_conntrack_proto_dccp_fini); 10032bc78049SPatrick McHardy 10042bc78049SPatrick McHardy MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 10052bc78049SPatrick McHardy MODULE_DESCRIPTION("DCCP connection tracking protocol helper"); 10062bc78049SPatrick McHardy MODULE_LICENSE("GPL"); 1007