1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2008 5 * Swinburne University of Technology, Melbourne, Australia. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS "AS IS" AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * Alias_sctp forms part of the libalias kernel module to handle 31 * Network Address Translation (NAT) for the SCTP protocol. 32 * 33 * This software was developed by David A. Hayes and Jason But 34 * 35 * The design is outlined in CAIA technical report number 080618A 36 * (D. Hayes and J. But, "Alias_sctp Version 0.1: SCTP NAT implementation in IPFW") 37 * 38 * Development is part of the CAIA SONATA project, 39 * proposed by Jason But and Grenville Armitage: 40 * http://caia.swin.edu.au/urp/sonata/ 41 * 42 * 43 * This project has been made possible in part by a grant from 44 * the Cisco University Research Program Fund at Community 45 * Foundation Silicon Valley. 46 * 47 */ 48 /** @mainpage 49 * Alias_sctp is part of the SONATA (http://caia.swin.edu.au/urp/sonata) project 50 * to develop and release a BSD licensed implementation of a Network Address 51 * Translation (NAT) module that supports the Stream Control Transmission 52 * Protocol (SCTP). 53 * 54 * Traditional address and port number look ups are inadequate for SCTP's 55 * operation due to both processing requirements and issues with multi-homing. 56 * Alias_sctp integrates with FreeBSD's ipfw/libalias NAT system. 57 * 58 * Version 0.2 features include: 59 * - Support for global multi-homing 60 * - Support for ASCONF modification from Internet Draft 61 * (draft-stewart-behave-sctpnat-04, R. Stewart and M. Tuexen, "Stream control 62 * transmission protocol (SCTP) network address translation," Jul. 2008) to 63 * provide support for multi-homed privately addressed hosts 64 * - Support for forwarding of T-flagged packets 65 * - Generation and delivery of AbortM/ErrorM packets upon detection of NAT 66 * collisions 67 * - Per-port forwarding rules 68 * - Dynamically controllable logging and statistics 69 * - Dynamic management of timers 70 * - Dynamic control of hash-table size 71 */ 72 73 /* $FreeBSD$ */ 74 75 #ifdef _KERNEL 76 #include <machine/stdarg.h> 77 #include <sys/param.h> 78 #include <sys/systm.h> 79 #include <sys/kernel.h> 80 #include <sys/module.h> 81 #include <sys/syslog.h> 82 #include <netinet/libalias/alias_sctp.h> 83 #include <netinet/libalias/alias.h> 84 #include <netinet/libalias/alias_local.h> 85 #include <netinet/sctp_crc32.h> 86 #include <machine/in_cksum.h> 87 #else 88 #include "alias_sctp.h" 89 #include <arpa/inet.h> 90 #include "alias.h" 91 #include "alias_local.h" 92 #include <machine/in_cksum.h> 93 #include <sys/libkern.h> 94 #endif //#ifdef _KERNEL 95 96 /* ---------------------------------------------------------------------- 97 * FUNCTION PROTOTYPES 98 * ---------------------------------------------------------------------- 99 */ 100 /* Packet Parsing Functions */ 101 static int sctp_PktParser(struct libalias *la, int direction, struct ip *pip, 102 struct sctp_nat_msg *sm, struct sctp_nat_assoc **passoc); 103 static int GetAsconfVtags(struct libalias *la, struct sctp_nat_msg *sm, 104 uint32_t *l_vtag, uint32_t *g_vtag, int direction); 105 static int IsASCONFack(struct libalias *la, struct sctp_nat_msg *sm, int direction); 106 107 static void AddGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int direction); 108 static int Add_Global_Address_to_List(struct sctp_nat_assoc *assoc, struct sctp_GlobalAddress *G_addr); 109 static void RmGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int direction); 110 static int IsADDorDEL(struct libalias *la, struct sctp_nat_msg *sm, int direction); 111 112 /* State Machine Functions */ 113 static int ProcessSctpMsg(struct libalias *la, int direction, \ 114 struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc); 115 116 static int ID_process(struct libalias *la, int direction,\ 117 struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); 118 static int INi_process(struct libalias *la, int direction,\ 119 struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); 120 static int INa_process(struct libalias *la, int direction,\ 121 struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); 122 static int UP_process(struct libalias *la, int direction,\ 123 struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); 124 static int CL_process(struct libalias *la, int direction,\ 125 struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); 126 static void TxAbortErrorM(struct libalias *la, struct sctp_nat_msg *sm,\ 127 struct sctp_nat_assoc *assoc, int sndrply, int direction); 128 129 /* Hash Table Functions */ 130 static struct sctp_nat_assoc* 131 FindSctpLocal(struct libalias *la, struct in_addr l_addr, struct in_addr g_addr, uint32_t l_vtag, uint16_t l_port, uint16_t g_port); 132 static struct sctp_nat_assoc* 133 FindSctpGlobal(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uint16_t g_port, uint16_t l_port, int *partial_match); 134 static struct sctp_nat_assoc* 135 FindSctpGlobalClash(struct libalias *la, struct sctp_nat_assoc *Cassoc); 136 static struct sctp_nat_assoc* 137 FindSctpLocalT(struct libalias *la, struct in_addr g_addr, uint32_t l_vtag, uint16_t g_port, uint16_t l_port); 138 static struct sctp_nat_assoc* 139 FindSctpGlobalT(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uint16_t l_port, uint16_t g_port); 140 141 static int AddSctpAssocLocal(struct libalias *la, struct sctp_nat_assoc *assoc, struct in_addr g_addr); 142 static int AddSctpAssocGlobal(struct libalias *la, struct sctp_nat_assoc *assoc); 143 static void RmSctpAssoc(struct libalias *la, struct sctp_nat_assoc *assoc); 144 static void freeGlobalAddressList(struct sctp_nat_assoc *assoc); 145 146 /* Timer Queue Functions */ 147 static void sctp_AddTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc); 148 static void sctp_RmTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc); 149 static void sctp_ResetTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc, int newexp); 150 void sctp_CheckTimers(struct libalias *la); 151 152 153 /* Logging Functions */ 154 static void logsctperror(char* errormsg, uint32_t vtag, int error, int direction); 155 static void logsctpparse(int direction, struct sctp_nat_msg *sm); 156 static void logsctpassoc(struct sctp_nat_assoc *assoc, char *s); 157 static void logTimerQ(struct libalias *la); 158 static void logSctpGlobal(struct libalias *la); 159 static void logSctpLocal(struct libalias *la); 160 #ifdef _KERNEL 161 static void SctpAliasLog(const char *format, ...); 162 #endif 163 164 /** @defgroup external External code changes and modifications 165 * 166 * Some changes have been made to files external to alias_sctp.(c|h). These 167 * changes are primarily due to code needing to call static functions within 168 * those files or to perform extra functionality that can only be performed 169 * within these files. 170 */ 171 /** @ingroup external 172 * @brief Log current statistics for the libalias instance 173 * 174 * This function is defined in alias_db.c, since it calls static functions in 175 * this file 176 * 177 * Calls the higher level ShowAliasStats() in alias_db.c which logs all current 178 * statistics about the libalias instance - including SCTP statistics 179 * 180 * @param la Pointer to the libalias instance 181 */ 182 void SctpShowAliasStats(struct libalias *la); 183 184 #ifdef _KERNEL 185 186 static MALLOC_DEFINE(M_SCTPNAT, "sctpnat", "sctp nat dbs"); 187 /* Use kernel allocator. */ 188 #ifdef _SYS_MALLOC_H_ 189 #define sn_malloc(x) malloc(x, M_SCTPNAT, M_NOWAIT|M_ZERO) 190 #define sn_calloc(n,x) mallocarray((n), (x), M_SCTPNAT, M_NOWAIT|M_ZERO) 191 #define sn_free(x) free(x, M_SCTPNAT) 192 #endif// #ifdef _SYS_MALLOC_H_ 193 194 #else //#ifdef _KERNEL 195 #define sn_malloc(x) malloc(x) 196 #define sn_calloc(n, x) calloc(n, x) 197 #define sn_free(x) free(x) 198 199 #endif //#ifdef _KERNEL 200 201 /** @defgroup packet_parser SCTP Packet Parsing 202 * 203 * Macros to: 204 * - Return pointers to the first and next SCTP chunks within an SCTP Packet 205 * - Define possible return values of the packet parsing process 206 * - SCTP message types for storing in the sctp_nat_msg structure @{ 207 */ 208 209 #define SN_SCTP_FIRSTCHUNK(sctphead) (struct sctp_chunkhdr *)(((char *)sctphead) + sizeof(struct sctphdr)) 210 /**< Returns a pointer to the first chunk in an SCTP packet given a pointer to the SCTP header */ 211 212 #define SN_SCTP_NEXTCHUNK(chunkhead) (struct sctp_chunkhdr *)(((char *)chunkhead) + SCTP_SIZE32(ntohs(chunkhead->chunk_length))) 213 /**< Returns a pointer to the next chunk in an SCTP packet given a pointer to the current chunk */ 214 215 #define SN_SCTP_NEXTPARAM(param) (struct sctp_paramhdr *)(((char *)param) + SCTP_SIZE32(ntohs(param->param_length))) 216 /**< Returns a pointer to the next parameter in an SCTP packet given a pointer to the current parameter */ 217 218 #define SN_MIN_CHUNK_SIZE 4 /**< Smallest possible SCTP chunk size in bytes */ 219 #define SN_MIN_PARAM_SIZE 4 /**< Smallest possible SCTP param size in bytes */ 220 #define SN_VTAG_PARAM_SIZE 12 /**< Size of SCTP ASCONF vtag param in bytes */ 221 #define SN_ASCONFACK_PARAM_SIZE 8 /**< Size of SCTP ASCONF ACK param in bytes */ 222 223 /* Packet parsing return codes */ 224 #define SN_PARSE_OK 0 /**< Packet parsed for SCTP messages */ 225 #define SN_PARSE_ERROR_IPSHL 1 /**< Packet parsing error - IP and SCTP common header len */ 226 #define SN_PARSE_ERROR_AS_MALLOC 2 /**< Packet parsing error - assoc malloc */ 227 #define SN_PARSE_ERROR_CHHL 3 /**< Packet parsing error - Chunk header len */ 228 #define SN_PARSE_ERROR_DIR 4 /**< Packet parsing error - Direction */ 229 #define SN_PARSE_ERROR_VTAG 5 /**< Packet parsing error - Vtag */ 230 #define SN_PARSE_ERROR_CHUNK 6 /**< Packet parsing error - Chunk */ 231 #define SN_PARSE_ERROR_PORT 7 /**< Packet parsing error - Port=0 */ 232 #define SN_PARSE_ERROR_LOOKUP 8 /**< Packet parsing error - Lookup */ 233 #define SN_PARSE_ERROR_PARTIALLOOKUP 9 /**< Packet parsing error - partial lookup only found */ 234 #define SN_PARSE_ERROR_LOOKUP_ABORT 10 /**< Packet parsing error - Lookup - but abort packet */ 235 236 /* Alias_sctp performs its processing based on a number of key messages */ 237 #define SN_SCTP_ABORT 0x0000 /**< a packet containing an ABORT chunk */ 238 #define SN_SCTP_INIT 0x0001 /**< a packet containing an INIT chunk */ 239 #define SN_SCTP_INITACK 0x0002 /**< a packet containing an INIT-ACK chunk */ 240 #define SN_SCTP_SHUTCOMP 0x0010 /**< a packet containing a SHUTDOWN-COMPLETE chunk */ 241 #define SN_SCTP_SHUTACK 0x0020 /**< a packet containing a SHUTDOWN-ACK chunk */ 242 #define SN_SCTP_ASCONF 0x0100 /**< a packet containing an ASCONF chunk */ 243 #define SN_SCTP_ASCONFACK 0x0200 /**< a packet containing an ASCONF-ACK chunk */ 244 #define SN_SCTP_OTHER 0xFFFF /**< a packet containing a chunk that is not of interest */ 245 246 /** @} 247 * @defgroup state_machine SCTP NAT State Machine 248 * 249 * Defines the various states an association can be within the NAT @{ 250 */ 251 #define SN_ID 0x0000 /**< Idle state */ 252 #define SN_INi 0x0010 /**< Initialising, waiting for InitAck state */ 253 #define SN_INa 0x0020 /**< Initialising, waiting for AddIpAck state */ 254 #define SN_UP 0x0100 /**< Association in UP state */ 255 #define SN_CL 0x1000 /**< Closing state */ 256 #define SN_RM 0x2000 /**< Removing state */ 257 258 /** @} 259 * @defgroup Logging Logging Functionality 260 * 261 * Define various log levels and a macro to call specified log functions only if 262 * the current log level (sysctl_log_level) matches the specified level @{ 263 */ 264 #define SN_LOG_LOW 0 265 #define SN_LOG_EVENT 1 266 #define SN_LOG_INFO 2 267 #define SN_LOG_DETAIL 3 268 #define SN_LOG_DEBUG 4 269 #define SN_LOG_DEBUG_MAX 5 270 271 #define SN_LOG(level, action) if (sysctl_log_level >= level) { action; } /**< Perform log action ONLY if the current log level meets the specified log level */ 272 273 /** @} 274 * @defgroup Hash Hash Table Macros and Functions 275 * 276 * Defines minimum/maximum/default values for the hash table size @{ 277 */ 278 #define SN_MIN_HASH_SIZE 101 /**< Minimum hash table size (set to stop users choosing stupid values) */ 279 #define SN_MAX_HASH_SIZE 1000001 /**< Maximum hash table size (NB must be less than max int) */ 280 #define SN_DEFAULT_HASH_SIZE 2003 /**< A reasonable default size for the hash tables */ 281 282 #define SN_LOCAL_TBL 0x01 /**< assoc in local table */ 283 #define SN_GLOBAL_TBL 0x02 /**< assoc in global table */ 284 #define SN_BOTH_TBL 0x03 /**< assoc in both tables */ 285 #define SN_WAIT_TOLOCAL 0x10 /**< assoc waiting for TOLOCAL asconf ACK*/ 286 #define SN_WAIT_TOGLOBAL 0x20 /**< assoc waiting for TOLOCAL asconf ACK*/ 287 #define SN_NULL_TBL 0x00 /**< assoc in No table */ 288 #define SN_MAX_GLOBAL_ADDRESSES 100 /**< absolute maximum global address count*/ 289 290 #define SN_ADD_OK 0 /**< Association added to the table */ 291 #define SN_ADD_CLASH 1 /**< Clash when trying to add the assoc. info to the table */ 292 293 #define SN_TABLE_HASH(vtag, port, size) (((u_int) vtag + (u_int) port) % (u_int) size) /**< Calculate the hash table lookup position */ 294 295 /** @} 296 * @defgroup Timer Timer Queue Macros and Functions 297 * 298 * Timer macros set minimum/maximum timeout values and calculate timer expiry 299 * times for the provided libalias instance @{ 300 */ 301 #define SN_MIN_TIMER 1 302 #define SN_MAX_TIMER 600 303 #define SN_TIMER_QUEUE_SIZE SN_MAX_TIMER+2 304 305 #define SN_I_T(la) (la->timeStamp + sysctl_init_timer) /**< INIT State expiration time in seconds */ 306 #define SN_U_T(la) (la->timeStamp + sysctl_up_timer) /**< UP State expiration time in seconds */ 307 #define SN_C_T(la) (la->timeStamp + sysctl_shutdown_timer) /**< CL State expiration time in seconds */ 308 #define SN_X_T(la) (la->timeStamp + sysctl_holddown_timer) /**< Wait after a shutdown complete in seconds */ 309 310 /** @} 311 * @defgroup sysctl SysCtl Variable and callback function declarations 312 * 313 * Sysctl variables to modify NAT functionality in real-time along with associated functions 314 * to manage modifications to the sysctl variables @{ 315 */ 316 317 /* Callbacks */ 318 int sysctl_chg_loglevel(SYSCTL_HANDLER_ARGS); 319 int sysctl_chg_timer(SYSCTL_HANDLER_ARGS); 320 int sysctl_chg_hashtable_size(SYSCTL_HANDLER_ARGS); 321 int sysctl_chg_error_on_ootb(SYSCTL_HANDLER_ARGS); 322 int sysctl_chg_accept_global_ootb_addip(SYSCTL_HANDLER_ARGS); 323 int sysctl_chg_initialising_chunk_proc_limit(SYSCTL_HANDLER_ARGS); 324 int sysctl_chg_chunk_proc_limit(SYSCTL_HANDLER_ARGS); 325 int sysctl_chg_param_proc_limit(SYSCTL_HANDLER_ARGS); 326 int sysctl_chg_track_global_addresses(SYSCTL_HANDLER_ARGS); 327 328 /* Sysctl variables */ 329 /** @brief net.inet.ip.alias.sctp.log_level */ 330 static u_int sysctl_log_level = 0; /**< Stores the current level of logging */ 331 /** @brief net.inet.ip.alias.sctp.init_timer */ 332 static u_int sysctl_init_timer = 15; /**< Seconds to hold an association in the table waiting for an INIT-ACK or AddIP-ACK */ 333 /** @brief net.inet.ip.alias.sctp.up_timer */ 334 static u_int sysctl_up_timer = 300; /**< Seconds to hold an association in the table while no packets are transmitted */ 335 /** @brief net.inet.ip.alias.sctp.shutdown_timer */ 336 static u_int sysctl_shutdown_timer = 15; /**< Seconds to hold an association in the table waiting for a SHUTDOWN-COMPLETE */ 337 /** @brief net.inet.ip.alias.sctp.holddown_timer */ 338 static u_int sysctl_holddown_timer = 0; /**< Seconds to hold an association in the table after it has been shutdown (to allow for lost SHUTDOWN-COMPLETEs) */ 339 /** @brief net.inet.ip.alias.sctp.hashtable_size */ 340 static u_int sysctl_hashtable_size = SN_DEFAULT_HASH_SIZE; /**< Sets the hash table size for any NEW NAT instances (existing instances retain their existing Hash Table */ 341 /** @brief net.inet.ip.alias.sctp.error_on_ootb */ 342 static u_int sysctl_error_on_ootb = 1; /**< NAT response to receipt of OOTB packet 343 (0 - No response, 1 - NAT will send ErrorM only to local side, 344 2 - NAT will send local ErrorM and global ErrorM if there was a partial association match 345 3 - NAT will send ErrorM to both local and global) */ 346 /** @brief net.inet.ip.alias.sctp.accept_global_ootb_addip */ 347 static u_int sysctl_accept_global_ootb_addip = 0; /**<NAT responset to receipt of global OOTB AddIP (0 - No response, 1 - NAT will accept OOTB global AddIP messages for processing (Security risk)) */ 348 /** @brief net.inet.ip.alias.sctp.initialising_chunk_proc_limit */ 349 static u_int sysctl_initialising_chunk_proc_limit = 2; /**< A limit on the number of chunks that should be searched if there is no matching association (DoS prevention) */ 350 /** @brief net.inet.ip.alias.sctp.param_proc_limit */ 351 static u_int sysctl_chunk_proc_limit = 5; /**< A limit on the number of chunks that should be searched (DoS prevention) */ 352 /** @brief net.inet.ip.alias.sctp.param_proc_limit */ 353 static u_int sysctl_param_proc_limit = 25; /**< A limit on the number of parameters (in chunks) that should be searched (DoS prevention) */ 354 /** @brief net.inet.ip.alias.sctp.track_global_addresses */ 355 static u_int sysctl_track_global_addresses = 0; /**< Configures the global address tracking option within the NAT (0 - Global tracking is disabled, > 0 - enables tracking but limits the number of global IP addresses to this value) 356 If set to >=1 the NAT will track that many global IP addresses. This may reduce look up table conflicts, but increases processing */ 357 358 #define SN_NO_ERROR_ON_OOTB 0 /**< Send no errorM on out of the blue packets */ 359 #define SN_LOCAL_ERROR_ON_OOTB 1 /**< Send only local errorM on out of the blue packets */ 360 #define SN_LOCALandPARTIAL_ERROR_ON_OOTB 2 /**< Send local errorM and global errorM for out of the blue packets only if partial match found */ 361 #define SN_ERROR_ON_OOTB 3 /**< Send errorM on out of the blue packets */ 362 363 #ifdef SYSCTL_NODE 364 365 SYSCTL_DECL(_net_inet); 366 SYSCTL_DECL(_net_inet_ip); 367 SYSCTL_DECL(_net_inet_ip_alias); 368 369 static SYSCTL_NODE(_net_inet_ip_alias, OID_AUTO, sctp, CTLFLAG_RW, NULL, 370 "SCTP NAT"); 371 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, log_level, CTLTYPE_UINT | CTLFLAG_RW, 372 &sysctl_log_level, 0, sysctl_chg_loglevel, "IU", 373 "Level of detail (0 - default, 1 - event, 2 - info, 3 - detail, 4 - debug, 5 - max debug)"); 374 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, init_timer, CTLTYPE_UINT | CTLFLAG_RW, 375 &sysctl_init_timer, 0, sysctl_chg_timer, "IU", 376 "Timeout value (s) while waiting for (INIT-ACK|AddIP-ACK)"); 377 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, up_timer, CTLTYPE_UINT | CTLFLAG_RW, 378 &sysctl_up_timer, 0, sysctl_chg_timer, "IU", 379 "Timeout value (s) to keep an association up with no traffic"); 380 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, shutdown_timer, CTLTYPE_UINT | CTLFLAG_RW, 381 &sysctl_shutdown_timer, 0, sysctl_chg_timer, "IU", 382 "Timeout value (s) while waiting for SHUTDOWN-COMPLETE"); 383 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, holddown_timer, CTLTYPE_UINT | CTLFLAG_RW, 384 &sysctl_holddown_timer, 0, sysctl_chg_timer, "IU", 385 "Hold association in table for this many seconds after receiving a SHUTDOWN-COMPLETE"); 386 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, hashtable_size, CTLTYPE_UINT | CTLFLAG_RW, 387 &sysctl_hashtable_size, 0, sysctl_chg_hashtable_size, "IU", 388 "Size of hash tables used for NAT lookups (100 < prime_number > 1000001)"); 389 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, error_on_ootb, CTLTYPE_UINT | CTLFLAG_RW, 390 &sysctl_error_on_ootb, 0, sysctl_chg_error_on_ootb, "IU", 391 "ErrorM sent on receipt of ootb packet:\n\t0 - none,\n\t1 - to local only,\n\t2 - to local and global if a partial association match,\n\t3 - to local and global (DoS risk)"); 392 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, accept_global_ootb_addip, CTLTYPE_UINT | CTLFLAG_RW, 393 &sysctl_accept_global_ootb_addip, 0, sysctl_chg_accept_global_ootb_addip, "IU", 394 "NAT response to receipt of global OOTB AddIP:\n\t0 - No response,\n\t1 - NAT will accept OOTB global AddIP messages for processing (Security risk)"); 395 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, initialising_chunk_proc_limit, CTLTYPE_UINT | CTLFLAG_RW, 396 &sysctl_initialising_chunk_proc_limit, 0, sysctl_chg_initialising_chunk_proc_limit, "IU", 397 "Number of chunks that should be processed if there is no current association found:\n\t > 0 (A high value is a DoS risk)"); 398 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, chunk_proc_limit, CTLTYPE_UINT | CTLFLAG_RW, 399 &sysctl_chunk_proc_limit, 0, sysctl_chg_chunk_proc_limit, "IU", 400 "Number of chunks that should be processed to find key chunk:\n\t>= initialising_chunk_proc_limit (A high value is a DoS risk)"); 401 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, param_proc_limit, CTLTYPE_UINT | CTLFLAG_RW, 402 &sysctl_param_proc_limit, 0, sysctl_chg_param_proc_limit, "IU", 403 "Number of parameters (in a chunk) that should be processed to find key parameters:\n\t> 1 (A high value is a DoS risk)"); 404 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, track_global_addresses, CTLTYPE_UINT | CTLFLAG_RW, 405 &sysctl_track_global_addresses, 0, sysctl_chg_track_global_addresses, "IU", 406 "Configures the global address tracking option within the NAT:\n\t0 - Global tracking is disabled,\n\t> 0 - enables tracking but limits the number of global IP addresses to this value"); 407 408 #endif /* SYSCTL_NODE */ 409 410 /** @} 411 * @ingroup sysctl 412 * @brief sysctl callback for changing net.inet.ip.fw.sctp.log_level 413 * 414 * Updates the variable sysctl_log_level to the provided value and ensures 415 * it is in the valid range (SN_LOG_LOW -> SN_LOG_DEBUG) 416 */ 417 int sysctl_chg_loglevel(SYSCTL_HANDLER_ARGS) 418 { 419 u_int level = *(u_int *)arg1; 420 int error; 421 422 error = sysctl_handle_int(oidp, &level, 0, req); 423 if (error) return (error); 424 425 level = (level > SN_LOG_DEBUG_MAX) ? (SN_LOG_DEBUG_MAX) : (level); 426 level = (level < SN_LOG_LOW) ? (SN_LOG_LOW) : (level); 427 sysctl_log_level = level; 428 return (0); 429 } 430 431 /** @ingroup sysctl 432 * @brief sysctl callback for changing net.inet.ip.fw.sctp.(init_timer|up_timer|shutdown_timer) 433 * 434 * Updates the timer-based sysctl variables. The new values are sanity-checked 435 * to make sure that they are within the range SN_MIN_TIMER-SN_MAX_TIMER. The 436 * holddown timer is allowed to be 0 437 */ 438 int sysctl_chg_timer(SYSCTL_HANDLER_ARGS) 439 { 440 u_int timer = *(u_int *)arg1; 441 int error; 442 443 error = sysctl_handle_int(oidp, &timer, 0, req); 444 if (error) return (error); 445 446 timer = (timer > SN_MAX_TIMER) ? (SN_MAX_TIMER) : (timer); 447 448 if (((u_int *)arg1) != &sysctl_holddown_timer) { 449 timer = (timer < SN_MIN_TIMER) ? (SN_MIN_TIMER) : (timer); 450 } 451 452 *(u_int *)arg1 = timer; 453 454 return (0); 455 } 456 457 /** @ingroup sysctl 458 * @brief sysctl callback for changing net.inet.ip.alias.sctp.hashtable_size 459 * 460 * Updates the hashtable_size sysctl variable. The new value should be a prime 461 * number. We sanity check to ensure that the size is within the range 462 * SN_MIN_HASH_SIZE-SN_MAX_HASH_SIZE. We then check the provided number to see 463 * if it is prime. We approximate by checking that (2,3,5,7,11) are not factors, 464 * incrementing the user provided value until we find a suitable number. 465 */ 466 int sysctl_chg_hashtable_size(SYSCTL_HANDLER_ARGS) 467 { 468 u_int size = *(u_int *)arg1; 469 int error; 470 471 error = sysctl_handle_int(oidp, &size, 0, req); 472 if (error) return (error); 473 474 size = (size < SN_MIN_HASH_SIZE) ? (SN_MIN_HASH_SIZE) : ((size > SN_MAX_HASH_SIZE) ? (SN_MAX_HASH_SIZE) : (size)); 475 476 size |= 0x00000001; /* make odd */ 477 478 for (;(((size % 3) == 0) || ((size % 5) == 0) || ((size % 7) == 0) || ((size % 11) == 0)); size+=2); 479 sysctl_hashtable_size = size; 480 481 return (0); 482 } 483 484 /** @ingroup sysctl 485 * @brief sysctl callback for changing net.inet.ip.alias.sctp.error_on_ootb 486 * 487 * Updates the error_on_clash sysctl variable. 488 * If set to 0, no ErrorM will be sent if there is a look up table clash 489 * If set to 1, an ErrorM is sent only to the local side 490 * If set to 2, an ErrorM is sent to the local side and global side if there is 491 * a partial association match 492 * If set to 3, an ErrorM is sent to both local and global sides (DoS) risk. 493 */ 494 int sysctl_chg_error_on_ootb(SYSCTL_HANDLER_ARGS) 495 { 496 u_int flag = *(u_int *)arg1; 497 int error; 498 499 error = sysctl_handle_int(oidp, &flag, 0, req); 500 if (error) return (error); 501 502 sysctl_error_on_ootb = (flag > SN_ERROR_ON_OOTB) ? SN_ERROR_ON_OOTB: flag; 503 504 return (0); 505 } 506 507 /** @ingroup sysctl 508 * @brief sysctl callback for changing net.inet.ip.alias.sctp.accept_global_ootb_addip 509 * 510 * If set to 1 the NAT will accept ootb global addip messages for processing (Security risk) 511 * Default is 0, only responding to local ootb AddIP messages 512 */ 513 int sysctl_chg_accept_global_ootb_addip(SYSCTL_HANDLER_ARGS) 514 { 515 u_int flag = *(u_int *)arg1; 516 int error; 517 518 error = sysctl_handle_int(oidp, &flag, 0, req); 519 if (error) return (error); 520 521 sysctl_accept_global_ootb_addip = (flag == 1) ? 1: 0; 522 523 return (0); 524 } 525 526 /** @ingroup sysctl 527 * @brief sysctl callback for changing net.inet.ip.alias.sctp.initialising_chunk_proc_limit 528 * 529 * Updates the initialising_chunk_proc_limit sysctl variable. Number of chunks 530 * that should be processed if there is no current association found: > 0 (A 531 * high value is a DoS risk) 532 */ 533 int sysctl_chg_initialising_chunk_proc_limit(SYSCTL_HANDLER_ARGS) 534 { 535 u_int proclimit = *(u_int *)arg1; 536 int error; 537 538 error = sysctl_handle_int(oidp, &proclimit, 0, req); 539 if (error) return (error); 540 541 sysctl_initialising_chunk_proc_limit = (proclimit < 1) ? 1: proclimit; 542 sysctl_chunk_proc_limit = 543 (sysctl_chunk_proc_limit < sysctl_initialising_chunk_proc_limit) ? sysctl_initialising_chunk_proc_limit : sysctl_chunk_proc_limit; 544 545 return (0); 546 } 547 548 /** @ingroup sysctl 549 * @brief sysctl callback for changing net.inet.ip.alias.sctp.chunk_proc_limit 550 * 551 * Updates the chunk_proc_limit sysctl variable. 552 * Number of chunks that should be processed to find key chunk: 553 * >= initialising_chunk_proc_limit (A high value is a DoS risk) 554 */ 555 int sysctl_chg_chunk_proc_limit(SYSCTL_HANDLER_ARGS) 556 { 557 u_int proclimit = *(u_int *)arg1; 558 int error; 559 560 error = sysctl_handle_int(oidp, &proclimit, 0, req); 561 if (error) return (error); 562 563 sysctl_chunk_proc_limit = 564 (proclimit < sysctl_initialising_chunk_proc_limit) ? sysctl_initialising_chunk_proc_limit : proclimit; 565 566 return (0); 567 } 568 569 570 /** @ingroup sysctl 571 * @brief sysctl callback for changing net.inet.ip.alias.sctp.param_proc_limit 572 * 573 * Updates the param_proc_limit sysctl variable. 574 * Number of parameters that should be processed to find key parameters: 575 * > 1 (A high value is a DoS risk) 576 */ 577 int sysctl_chg_param_proc_limit(SYSCTL_HANDLER_ARGS) 578 { 579 u_int proclimit = *(u_int *)arg1; 580 int error; 581 582 error = sysctl_handle_int(oidp, &proclimit, 0, req); 583 if (error) return (error); 584 585 sysctl_param_proc_limit = 586 (proclimit < 2) ? 2 : proclimit; 587 588 return (0); 589 } 590 591 /** @ingroup sysctl 592 * @brief sysctl callback for changing net.inet.ip.alias.sctp.track_global_addresses 593 * 594 *Configures the global address tracking option within the NAT (0 - Global 595 *tracking is disabled, > 0 - enables tracking but limits the number of global 596 *IP addresses to this value) 597 */ 598 int sysctl_chg_track_global_addresses(SYSCTL_HANDLER_ARGS) 599 { 600 u_int num_to_track = *(u_int *)arg1; 601 int error; 602 603 error = sysctl_handle_int(oidp, &num_to_track, 0, req); 604 if (error) return (error); 605 606 sysctl_track_global_addresses = (num_to_track > SN_MAX_GLOBAL_ADDRESSES) ? SN_MAX_GLOBAL_ADDRESSES : num_to_track; 607 608 return (0); 609 } 610 611 612 /* ---------------------------------------------------------------------- 613 * CODE BEGINS HERE 614 * ---------------------------------------------------------------------- 615 */ 616 /** 617 * @brief Initialises the SCTP NAT Implementation 618 * 619 * Creates the look-up tables and the timer queue and initialises all state 620 * variables 621 * 622 * @param la Pointer to the relevant libalias instance 623 */ 624 void AliasSctpInit(struct libalias *la) 625 { 626 /* Initialise association tables*/ 627 int i; 628 la->sctpNatTableSize = sysctl_hashtable_size; 629 SN_LOG(SN_LOG_EVENT, 630 SctpAliasLog("Initialising SCTP NAT Instance (hash_table_size:%d)\n", la->sctpNatTableSize)); 631 la->sctpTableLocal = sn_calloc(la->sctpNatTableSize, sizeof(struct sctpNatTableL)); 632 la->sctpTableGlobal = sn_calloc(la->sctpNatTableSize, sizeof(struct sctpNatTableG)); 633 la->sctpNatTimer.TimerQ = sn_calloc(SN_TIMER_QUEUE_SIZE, sizeof(struct sctpTimerQ)); 634 /* Initialise hash table */ 635 for (i = 0; i < la->sctpNatTableSize; i++) { 636 LIST_INIT(&la->sctpTableLocal[i]); 637 LIST_INIT(&la->sctpTableGlobal[i]); 638 } 639 640 /* Initialise circular timer Q*/ 641 for (i = 0; i < SN_TIMER_QUEUE_SIZE; i++) 642 LIST_INIT(&la->sctpNatTimer.TimerQ[i]); 643 #ifdef _KERNEL 644 la->sctpNatTimer.loc_time=time_uptime; /* la->timeStamp is not set yet */ 645 #else 646 la->sctpNatTimer.loc_time=la->timeStamp; 647 #endif 648 la->sctpNatTimer.cur_loc = 0; 649 la->sctpLinkCount = 0; 650 } 651 652 /** 653 * @brief Cleans-up the SCTP NAT Implementation prior to unloading 654 * 655 * Removes all entries from the timer queue, freeing associations as it goes. 656 * We then free memory allocated to the look-up tables and the time queue 657 * 658 * NOTE: We do not need to traverse the look-up tables as each association 659 * will always have an entry in the timer queue, freeing this memory 660 * once will free all memory allocated to entries in the look-up tables 661 * 662 * @param la Pointer to the relevant libalias instance 663 */ 664 void AliasSctpTerm(struct libalias *la) 665 { 666 struct sctp_nat_assoc *assoc1, *assoc2; 667 int i; 668 669 LIBALIAS_LOCK_ASSERT(la); 670 SN_LOG(SN_LOG_EVENT, 671 SctpAliasLog("Removing SCTP NAT Instance\n")); 672 for (i = 0; i < SN_TIMER_QUEUE_SIZE; i++) { 673 assoc1 = LIST_FIRST(&la->sctpNatTimer.TimerQ[i]); 674 while (assoc1 != NULL) { 675 freeGlobalAddressList(assoc1); 676 assoc2 = LIST_NEXT(assoc1, timer_Q); 677 sn_free(assoc1); 678 assoc1 = assoc2; 679 } 680 } 681 682 sn_free(la->sctpTableLocal); 683 sn_free(la->sctpTableGlobal); 684 sn_free(la->sctpNatTimer.TimerQ); 685 } 686 687 /** 688 * @brief Handles SCTP packets passed from libalias 689 * 690 * This function needs to actually NAT/drop packets and possibly create and 691 * send AbortM or ErrorM packets in response. The process involves: 692 * - Validating the direction parameter passed by the caller 693 * - Checking and handling any expired timers for the NAT 694 * - Calling sctp_PktParser() to parse the packet 695 * - Call ProcessSctpMsg() to decide the appropriate outcome and to update 696 * the NAT tables 697 * - Based on the return code either: 698 * - NAT the packet 699 * - Construct and send an ErrorM|AbortM packet 700 * - Mark the association for removal from the tables 701 * - Potentially remove the association from all lookup tables 702 * - Return the appropriate result to libalias 703 * 704 * @param la Pointer to the relevant libalias instance 705 * @param pip Pointer to IP packet to process 706 * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 707 * 708 * @return PKT_ALIAS_OK | PKT_ALIAS_IGNORE | PKT_ALIAS_ERROR 709 */ 710 int 711 SctpAlias(struct libalias *la, struct ip *pip, int direction) 712 { 713 int rtnval; 714 struct sctp_nat_msg msg; 715 struct sctp_nat_assoc *assoc = NULL; 716 717 if ((direction != SN_TO_LOCAL) && (direction != SN_TO_GLOBAL)) { 718 SctpAliasLog("ERROR: Invalid direction\n"); 719 return (PKT_ALIAS_ERROR); 720 } 721 722 sctp_CheckTimers(la); /* Check timers */ 723 724 /* Parse the packet */ 725 rtnval = sctp_PktParser(la, direction, pip, &msg, &assoc); //using *char (change to mbuf when get code from paolo) 726 switch (rtnval) { 727 case SN_PARSE_OK: 728 break; 729 case SN_PARSE_ERROR_CHHL: 730 /* Not an error if there is a chunk length parsing error and this is a fragmented packet */ 731 if (ntohs(pip->ip_off) & IP_MF) { 732 rtnval = SN_PARSE_OK; 733 break; 734 } 735 SN_LOG(SN_LOG_EVENT, 736 logsctperror("SN_PARSE_ERROR", msg.sctp_hdr->v_tag, rtnval, direction)); 737 return (PKT_ALIAS_ERROR); 738 case SN_PARSE_ERROR_PARTIALLOOKUP: 739 if (sysctl_error_on_ootb > SN_LOCALandPARTIAL_ERROR_ON_OOTB) { 740 SN_LOG(SN_LOG_EVENT, 741 logsctperror("SN_PARSE_ERROR", msg.sctp_hdr->v_tag, rtnval, direction)); 742 return (PKT_ALIAS_ERROR); 743 } 744 case SN_PARSE_ERROR_LOOKUP: 745 if (sysctl_error_on_ootb == SN_ERROR_ON_OOTB || 746 (sysctl_error_on_ootb == SN_LOCALandPARTIAL_ERROR_ON_OOTB && direction == SN_TO_LOCAL) || 747 (sysctl_error_on_ootb == SN_LOCAL_ERROR_ON_OOTB && direction == SN_TO_GLOBAL)) { 748 TxAbortErrorM(la, &msg, assoc, SN_REFLECT_ERROR, direction); /*NB assoc=NULL */ 749 return (PKT_ALIAS_RESPOND); 750 } 751 default: 752 SN_LOG(SN_LOG_EVENT, 753 logsctperror("SN_PARSE_ERROR", msg.sctp_hdr->v_tag, rtnval, direction)); 754 return (PKT_ALIAS_ERROR); 755 } 756 757 SN_LOG(SN_LOG_DETAIL, 758 logsctpassoc(assoc, "*"); 759 logsctpparse(direction, &msg); 760 ); 761 762 /* Process the SCTP message */ 763 rtnval = ProcessSctpMsg(la, direction, &msg, assoc); 764 765 SN_LOG(SN_LOG_DEBUG_MAX, 766 logsctpassoc(assoc, "-"); 767 logSctpLocal(la); 768 logSctpGlobal(la); 769 ); 770 SN_LOG(SN_LOG_DEBUG, logTimerQ(la)); 771 772 switch (rtnval) { 773 case SN_NAT_PKT: 774 switch (direction) { 775 case SN_TO_LOCAL: 776 DifferentialChecksum(&(msg.ip_hdr->ip_sum), 777 &(assoc->l_addr), &(msg.ip_hdr->ip_dst), 2); 778 msg.ip_hdr->ip_dst = assoc->l_addr; /* change dst address to local address*/ 779 break; 780 case SN_TO_GLOBAL: 781 DifferentialChecksum(&(msg.ip_hdr->ip_sum), 782 &(assoc->a_addr), &(msg.ip_hdr->ip_src), 2); 783 msg.ip_hdr->ip_src = assoc->a_addr; /* change src to alias addr*/ 784 break; 785 default: 786 rtnval = SN_DROP_PKT; /* shouldn't get here, but if it does drop packet */ 787 SN_LOG(SN_LOG_LOW, logsctperror("ERROR: Invalid direction", msg.sctp_hdr->v_tag, rtnval, direction)); 788 break; 789 } 790 break; 791 case SN_DROP_PKT: 792 SN_LOG(SN_LOG_DETAIL, logsctperror("SN_DROP_PKT", msg.sctp_hdr->v_tag, rtnval, direction)); 793 break; 794 case SN_REPLY_ABORT: 795 case SN_REPLY_ERROR: 796 case SN_SEND_ABORT: 797 TxAbortErrorM(la, &msg, assoc, rtnval, direction); 798 break; 799 default: 800 // big error, remove association and go to idle and write log messages 801 SN_LOG(SN_LOG_LOW, logsctperror("SN_PROCESSING_ERROR", msg.sctp_hdr->v_tag, rtnval, direction)); 802 assoc->state=SN_RM;/* Mark for removal*/ 803 break; 804 } 805 806 /* Remove association if tagged for removal */ 807 if (assoc->state == SN_RM) { 808 if (assoc->TableRegister) { 809 sctp_RmTimeOut(la, assoc); 810 RmSctpAssoc(la, assoc); 811 } 812 LIBALIAS_LOCK_ASSERT(la); 813 freeGlobalAddressList(assoc); 814 sn_free(assoc); 815 } 816 switch (rtnval) { 817 case SN_NAT_PKT: 818 return (PKT_ALIAS_OK); 819 case SN_SEND_ABORT: 820 return (PKT_ALIAS_OK); 821 case SN_REPLY_ABORT: 822 case SN_REPLY_ERROR: 823 case SN_REFLECT_ERROR: 824 return (PKT_ALIAS_RESPOND); 825 case SN_DROP_PKT: 826 default: 827 return (PKT_ALIAS_ERROR); 828 } 829 } 830 831 /** 832 * @brief Send an AbortM or ErrorM 833 * 834 * We construct the new SCTP packet to send in place of the existing packet we 835 * have been asked to NAT. This function can only be called if the original 836 * packet was successfully parsed as a valid SCTP packet. 837 * 838 * An AbortM (without cause) packet is the smallest SCTP packet available and as 839 * such there is always space in the existing packet buffer to fit the AbortM 840 * packet. An ErrorM packet is 4 bytes longer than the (the error cause is not 841 * optional). An ErrorM is sent in response to an AddIP when the Vtag/address 842 * combination, if added, will produce a conflict in the association look up 843 * tables. It may also be used for an unexpected packet - a packet with no 844 * matching association in the NAT table and we are requesting an AddIP so we 845 * can add it. The smallest valid SCTP packet while the association is in an 846 * up-state is a Heartbeat packet, which is big enough to be transformed to an 847 * ErrorM. 848 * 849 * We create a temporary character array to store the packet as we are constructing 850 * it. We then populate the array with appropriate values based on: 851 * - Packet type (AbortM | ErrorM) 852 * - Initial packet direction (SN_TO_LOCAL | SN_TO_GLOBAL) 853 * - NAT response (Send packet | Reply packet) 854 * 855 * Once complete, we copy the contents of the temporary packet over the original 856 * SCTP packet we were asked to NAT 857 * 858 * @param la Pointer to the relevant libalias instance 859 * @param sm Pointer to sctp message information 860 * @param assoc Pointer to current association details 861 * @param sndrply SN_SEND_ABORT | SN_REPLY_ABORT | SN_REPLY_ERROR 862 * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 863 */ 864 static uint32_t 865 local_sctp_finalize_crc32(uint32_t crc32c) 866 { 867 /* This routine is duplicated from SCTP 868 * we need to do that since it MAY be that SCTP 869 * is NOT compiled into the kernel. The CRC32C routines 870 * however are always available in libkern. 871 */ 872 uint32_t result; 873 #if BYTE_ORDER == BIG_ENDIAN 874 uint8_t byte0, byte1, byte2, byte3; 875 876 #endif 877 /* Complement the result */ 878 result = ~crc32c; 879 #if BYTE_ORDER == BIG_ENDIAN 880 /* 881 * For BIG-ENDIAN.. aka Motorola byte order the result is in 882 * little-endian form. So we must manually swap the bytes. Then we 883 * can call htonl() which does nothing... 884 */ 885 byte0 = result & 0x000000ff; 886 byte1 = (result >> 8) & 0x000000ff; 887 byte2 = (result >> 16) & 0x000000ff; 888 byte3 = (result >> 24) & 0x000000ff; 889 crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); 890 #else 891 /* 892 * For INTEL platforms the result comes out in network order. No 893 * htonl is required or the swap above. So we optimize out both the 894 * htonl and the manual swap above. 895 */ 896 crc32c = result; 897 #endif 898 return (crc32c); 899 } 900 901 static void 902 TxAbortErrorM(struct libalias *la, struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int sndrply, int direction) 903 { 904 int sctp_size = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_error_cause); 905 int ip_size = sizeof(struct ip) + sctp_size; 906 int include_error_cause = 1; 907 char tmp_ip[ip_size]; 908 char addrbuf[INET_ADDRSTRLEN]; 909 910 if (ntohs(sm->ip_hdr->ip_len) < ip_size) { /* short packet, cannot send error cause */ 911 include_error_cause = 0; 912 ip_size = ip_size - sizeof(struct sctp_error_cause); 913 sctp_size = sctp_size - sizeof(struct sctp_error_cause); 914 } 915 /* Assign header pointers packet */ 916 struct ip* ip = (struct ip *) tmp_ip; 917 struct sctphdr* sctp_hdr = (struct sctphdr *) ((char *) ip + sizeof(*ip)); 918 struct sctp_chunkhdr* chunk_hdr = (struct sctp_chunkhdr *) ((char *) sctp_hdr + sizeof(*sctp_hdr)); 919 struct sctp_error_cause* error_cause = (struct sctp_error_cause *) ((char *) chunk_hdr + sizeof(*chunk_hdr)); 920 921 /* construct ip header */ 922 ip->ip_v = sm->ip_hdr->ip_v; 923 ip->ip_hl = 5; /* 5*32 bit words */ 924 ip->ip_tos = 0; 925 ip->ip_len = htons(ip_size); 926 ip->ip_id = sm->ip_hdr->ip_id; 927 ip->ip_off = 0; 928 ip->ip_ttl = 255; 929 ip->ip_p = IPPROTO_SCTP; 930 /* 931 The definitions below should be removed when they make it into the SCTP stack 932 */ 933 #define SCTP_MIDDLEBOX_FLAG 0x02 934 #define SCTP_NAT_TABLE_COLLISION 0x00b0 935 #define SCTP_MISSING_NAT 0x00b1 936 chunk_hdr->chunk_type = (sndrply & SN_TX_ABORT) ? SCTP_ABORT_ASSOCIATION : SCTP_OPERATION_ERROR; 937 chunk_hdr->chunk_flags = SCTP_MIDDLEBOX_FLAG; 938 if (include_error_cause) { 939 error_cause->code = htons((sndrply & SN_REFLECT_ERROR) ? SCTP_MISSING_NAT : SCTP_NAT_TABLE_COLLISION); 940 error_cause->length = htons(sizeof(struct sctp_error_cause)); 941 chunk_hdr->chunk_length = htons(sizeof(*chunk_hdr) + sizeof(struct sctp_error_cause)); 942 } else { 943 chunk_hdr->chunk_length = htons(sizeof(*chunk_hdr)); 944 } 945 946 /* set specific values */ 947 switch (sndrply) { 948 case SN_REFLECT_ERROR: 949 chunk_hdr->chunk_flags |= SCTP_HAD_NO_TCB; /* set Tbit */ 950 sctp_hdr->v_tag = sm->sctp_hdr->v_tag; 951 break; 952 case SN_REPLY_ERROR: 953 sctp_hdr->v_tag = (direction == SN_TO_LOCAL) ? assoc->g_vtag : assoc->l_vtag ; 954 break; 955 case SN_SEND_ABORT: 956 sctp_hdr->v_tag = sm->sctp_hdr->v_tag; 957 break; 958 case SN_REPLY_ABORT: 959 sctp_hdr->v_tag = sm->sctpchnk.Init->initiate_tag; 960 break; 961 } 962 963 /* Set send/reply values */ 964 if (sndrply == SN_SEND_ABORT) { /*pass through NAT */ 965 ip->ip_src = (direction == SN_TO_LOCAL) ? sm->ip_hdr->ip_src : assoc->a_addr; 966 ip->ip_dst = (direction == SN_TO_LOCAL) ? assoc->l_addr : sm->ip_hdr->ip_dst; 967 sctp_hdr->src_port = sm->sctp_hdr->src_port; 968 sctp_hdr->dest_port = sm->sctp_hdr->dest_port; 969 } else { /* reply and reflect */ 970 ip->ip_src = sm->ip_hdr->ip_dst; 971 ip->ip_dst = sm->ip_hdr->ip_src; 972 sctp_hdr->src_port = sm->sctp_hdr->dest_port; 973 sctp_hdr->dest_port = sm->sctp_hdr->src_port; 974 } 975 976 /* Calculate IP header checksum */ 977 ip->ip_sum = in_cksum_hdr(ip); 978 979 /* calculate SCTP header CRC32 */ 980 sctp_hdr->checksum = 0; 981 sctp_hdr->checksum = local_sctp_finalize_crc32(calculate_crc32c(0xffffffff, (unsigned char *) sctp_hdr, sctp_size)); 982 983 memcpy(sm->ip_hdr, ip, ip_size); 984 985 SN_LOG(SN_LOG_EVENT,SctpAliasLog("%s %s 0x%x (->%s:%u vtag=0x%x crc=0x%x)\n", 986 ((sndrply == SN_SEND_ABORT) ? "Sending" : "Replying"), 987 ((sndrply & SN_TX_ERROR) ? "ErrorM" : "AbortM"), 988 (include_error_cause ? ntohs(error_cause->code) : 0), 989 inet_ntoa_r(ip->ip_dst, INET_NTOA_BUF(addrbuf)), 990 ntohs(sctp_hdr->dest_port), 991 ntohl(sctp_hdr->v_tag), ntohl(sctp_hdr->checksum))); 992 } 993 994 /* ---------------------------------------------------------------------- 995 * PACKET PARSER CODE 996 * ---------------------------------------------------------------------- 997 */ 998 /** @addtogroup packet_parser 999 * 1000 * These functions parse the SCTP packet and fill a sctp_nat_msg structure 1001 * with the parsed contents. 1002 */ 1003 /** @ingroup packet_parser 1004 * @brief Parses SCTP packets for the key SCTP chunk that will be processed 1005 * 1006 * This module parses SCTP packets for the key SCTP chunk that will be processed 1007 * The module completes the sctp_nat_msg structure and either retrieves the 1008 * relevant (existing) stored association from the Hash Tables or creates a new 1009 * association entity with state SN_ID 1010 * 1011 * @param la Pointer to the relevant libalias instance 1012 * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1013 * @param pip 1014 * @param sm Pointer to sctp message information 1015 * @param passoc Pointer to the association this SCTP Message belongs to 1016 * 1017 * @return SN_PARSE_OK | SN_PARSE_ERROR_* 1018 */ 1019 static int 1020 sctp_PktParser(struct libalias *la, int direction, struct ip *pip, 1021 struct sctp_nat_msg *sm, struct sctp_nat_assoc **passoc) 1022 //sctp_PktParser(int direction, struct mbuf *ipak, int ip_hdr_len,struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc) 1023 { 1024 struct sctphdr *sctp_hdr; 1025 struct sctp_chunkhdr *chunk_hdr; 1026 struct sctp_paramhdr *param_hdr; 1027 struct in_addr ipv4addr; 1028 int bytes_left; /* bytes left in ip packet */ 1029 int chunk_length; 1030 int chunk_count; 1031 int partial_match = 0; 1032 // mbuf *mp; 1033 // int mlen; 1034 1035 // mlen = SCTP_HEADER_LEN(i_pak); 1036 // mp = SCTP_HEADER_TO_CHAIN(i_pak); /* does nothing in bsd since header and chain not separate */ 1037 1038 /* 1039 * Note, that if the VTag is zero, it must be an INIT 1040 * Also, I am only interested in the content of INIT and ADDIP chunks 1041 */ 1042 1043 // no mbuf stuff from Paolo yet so ... 1044 sm->ip_hdr = pip; 1045 /* remove ip header length from the bytes_left */ 1046 bytes_left = ntohs(pip->ip_len) - (pip->ip_hl << 2); 1047 1048 /* Check SCTP header length and move to first chunk */ 1049 if (bytes_left < sizeof(struct sctphdr)) { 1050 sm->sctp_hdr = NULL; 1051 return (SN_PARSE_ERROR_IPSHL); /* packet not long enough*/ 1052 } 1053 1054 sm->sctp_hdr = sctp_hdr = (struct sctphdr *) ip_next(pip); 1055 bytes_left -= sizeof(struct sctphdr); 1056 1057 /* Check for valid ports (zero valued ports would find partially initialised associations */ 1058 if (sctp_hdr->src_port == 0 || sctp_hdr->dest_port == 0) 1059 return (SN_PARSE_ERROR_PORT); 1060 1061 /* Check length of first chunk */ 1062 if (bytes_left < SN_MIN_CHUNK_SIZE) /* malformed chunk - could cause endless loop*/ 1063 return (SN_PARSE_ERROR_CHHL); /* packet not long enough for this chunk */ 1064 1065 /* First chunk */ 1066 chunk_hdr = SN_SCTP_FIRSTCHUNK(sctp_hdr); 1067 1068 chunk_length = SCTP_SIZE32(ntohs(chunk_hdr->chunk_length)); 1069 if ((chunk_length < SN_MIN_CHUNK_SIZE) || (chunk_length > bytes_left)) /* malformed chunk - could cause endless loop*/ 1070 return (SN_PARSE_ERROR_CHHL); 1071 1072 if ((chunk_hdr->chunk_flags & SCTP_HAD_NO_TCB) && 1073 ((chunk_hdr->chunk_type == SCTP_ABORT_ASSOCIATION) || 1074 (chunk_hdr->chunk_type == SCTP_SHUTDOWN_COMPLETE))) { 1075 /* T-Bit set */ 1076 if (direction == SN_TO_LOCAL) 1077 *passoc = FindSctpGlobalT(la, pip->ip_src, sctp_hdr->v_tag, sctp_hdr->dest_port, sctp_hdr->src_port); 1078 else 1079 *passoc = FindSctpLocalT(la, pip->ip_dst, sctp_hdr->v_tag, sctp_hdr->dest_port, sctp_hdr->src_port); 1080 } else { 1081 /* Proper v_tag settings */ 1082 if (direction == SN_TO_LOCAL) 1083 *passoc = FindSctpGlobal(la, pip->ip_src, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port, &partial_match); 1084 else 1085 *passoc = FindSctpLocal(la, pip->ip_src, pip->ip_dst, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port); 1086 } 1087 1088 chunk_count = 1; 1089 /* Real packet parsing occurs below */ 1090 sm->msg = SN_SCTP_OTHER;/* Initialise to largest value*/ 1091 sm->chunk_length = 0; /* only care about length for key chunks */ 1092 while (IS_SCTP_CONTROL(chunk_hdr)) { 1093 switch (chunk_hdr->chunk_type) { 1094 case SCTP_INITIATION: 1095 if (chunk_length < sizeof(struct sctp_init_chunk)) /* malformed chunk*/ 1096 return (SN_PARSE_ERROR_CHHL); 1097 sm->msg = SN_SCTP_INIT; 1098 sm->sctpchnk.Init = (struct sctp_init *) ((char *) chunk_hdr + sizeof(struct sctp_chunkhdr)); 1099 sm->chunk_length = chunk_length; 1100 /* if no existing association, create a new one */ 1101 if (*passoc == NULL) { 1102 if (sctp_hdr->v_tag == 0) { //Init requires vtag=0 1103 *passoc = (struct sctp_nat_assoc *) sn_malloc(sizeof(struct sctp_nat_assoc)); 1104 if (*passoc == NULL) {/* out of resources */ 1105 return (SN_PARSE_ERROR_AS_MALLOC); 1106 } 1107 /* Initialize association - sn_malloc initializes memory to zeros */ 1108 (*passoc)->state = SN_ID; 1109 LIST_INIT(&((*passoc)->Gaddr)); /* always initialise to avoid memory problems */ 1110 (*passoc)->TableRegister = SN_NULL_TBL; 1111 return (SN_PARSE_OK); 1112 } 1113 return (SN_PARSE_ERROR_VTAG); 1114 } 1115 return (SN_PARSE_ERROR_LOOKUP); 1116 case SCTP_INITIATION_ACK: 1117 if (chunk_length < sizeof(struct sctp_init_ack_chunk)) /* malformed chunk*/ 1118 return (SN_PARSE_ERROR_CHHL); 1119 sm->msg = SN_SCTP_INITACK; 1120 sm->sctpchnk.InitAck = (struct sctp_init_ack *) ((char *) chunk_hdr + sizeof(struct sctp_chunkhdr)); 1121 sm->chunk_length = chunk_length; 1122 return ((*passoc == NULL) ? (SN_PARSE_ERROR_LOOKUP) : (SN_PARSE_OK)); 1123 case SCTP_ABORT_ASSOCIATION: /* access only minimum sized chunk */ 1124 sm->msg = SN_SCTP_ABORT; 1125 sm->chunk_length = chunk_length; 1126 return ((*passoc == NULL) ? (SN_PARSE_ERROR_LOOKUP_ABORT) : (SN_PARSE_OK)); 1127 case SCTP_SHUTDOWN_ACK: 1128 if (chunk_length < sizeof(struct sctp_shutdown_ack_chunk)) /* malformed chunk*/ 1129 return (SN_PARSE_ERROR_CHHL); 1130 if (sm->msg > SN_SCTP_SHUTACK) { 1131 sm->msg = SN_SCTP_SHUTACK; 1132 sm->chunk_length = chunk_length; 1133 } 1134 break; 1135 case SCTP_SHUTDOWN_COMPLETE: /* minimum sized chunk */ 1136 if (sm->msg > SN_SCTP_SHUTCOMP) { 1137 sm->msg = SN_SCTP_SHUTCOMP; 1138 sm->chunk_length = chunk_length; 1139 } 1140 return ((*passoc == NULL) ? (SN_PARSE_ERROR_LOOKUP) : (SN_PARSE_OK)); 1141 case SCTP_ASCONF: 1142 if (sm->msg > SN_SCTP_ASCONF) { 1143 if (chunk_length < (sizeof(struct sctp_asconf_chunk) + sizeof(struct sctp_ipv4addr_param))) /* malformed chunk*/ 1144 return (SN_PARSE_ERROR_CHHL); 1145 //leave parameter searching to later, if required 1146 param_hdr = (struct sctp_paramhdr *) ((char *) chunk_hdr + sizeof(struct sctp_asconf_chunk)); /*compulsory IP parameter*/ 1147 if (ntohs(param_hdr->param_type) == SCTP_IPV4_ADDRESS) { 1148 if ((*passoc == NULL) && (direction == SN_TO_LOCAL)) { /* AddIP with no association */ 1149 /* try look up with the ASCONF packet's alternative address */ 1150 ipv4addr.s_addr = ((struct sctp_ipv4addr_param *) param_hdr)->addr; 1151 *passoc = FindSctpGlobal(la, ipv4addr, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port, &partial_match); 1152 } 1153 param_hdr = (struct sctp_paramhdr *) 1154 ((char *) param_hdr + sizeof(struct sctp_ipv4addr_param)); /*asconf's compulsory address parameter */ 1155 sm->chunk_length = chunk_length - sizeof(struct sctp_asconf_chunk) - sizeof(struct sctp_ipv4addr_param); /* rest of chunk */ 1156 } else { 1157 if (chunk_length < (sizeof(struct sctp_asconf_chunk) + sizeof(struct sctp_ipv6addr_param))) /* malformed chunk*/ 1158 return (SN_PARSE_ERROR_CHHL); 1159 param_hdr = (struct sctp_paramhdr *) 1160 ((char *) param_hdr + sizeof(struct sctp_ipv6addr_param)); /*asconf's compulsory address parameter */ 1161 sm->chunk_length = chunk_length - sizeof(struct sctp_asconf_chunk) - sizeof(struct sctp_ipv6addr_param); /* rest of chunk */ 1162 } 1163 sm->msg = SN_SCTP_ASCONF; 1164 sm->sctpchnk.Asconf = param_hdr; 1165 1166 if (*passoc == NULL) { /* AddIP with no association */ 1167 *passoc = (struct sctp_nat_assoc *) sn_malloc(sizeof(struct sctp_nat_assoc)); 1168 if (*passoc == NULL) {/* out of resources */ 1169 return (SN_PARSE_ERROR_AS_MALLOC); 1170 } 1171 /* Initialize association - sn_malloc initializes memory to zeros */ 1172 (*passoc)->state = SN_ID; 1173 LIST_INIT(&((*passoc)->Gaddr)); /* always initialise to avoid memory problems */ 1174 (*passoc)->TableRegister = SN_NULL_TBL; 1175 return (SN_PARSE_OK); 1176 } 1177 } 1178 break; 1179 case SCTP_ASCONF_ACK: 1180 if (sm->msg > SN_SCTP_ASCONFACK) { 1181 if (chunk_length < sizeof(struct sctp_asconf_ack_chunk)) /* malformed chunk*/ 1182 return (SN_PARSE_ERROR_CHHL); 1183 //leave parameter searching to later, if required 1184 param_hdr = (struct sctp_paramhdr *) ((char *) chunk_hdr 1185 + sizeof(struct sctp_asconf_ack_chunk)); 1186 sm->msg = SN_SCTP_ASCONFACK; 1187 sm->sctpchnk.Asconf = param_hdr; 1188 sm->chunk_length = chunk_length - sizeof(struct sctp_asconf_ack_chunk); 1189 } 1190 break; 1191 default: 1192 break; /* do nothing*/ 1193 } 1194 1195 /* if no association is found exit - we need to find an Init or AddIP within sysctl_initialising_chunk_proc_limit */ 1196 if ((*passoc == NULL) && (chunk_count >= sysctl_initialising_chunk_proc_limit)) 1197 return (SN_PARSE_ERROR_LOOKUP); 1198 1199 /* finished with this chunk, on to the next chunk*/ 1200 bytes_left-= chunk_length; 1201 1202 /* Is this the end of the packet ? */ 1203 if (bytes_left == 0) 1204 return (*passoc == NULL) ? (SN_PARSE_ERROR_LOOKUP) : (SN_PARSE_OK); 1205 1206 /* Are there enough bytes in packet to at least retrieve length of next chunk ? */ 1207 if (bytes_left < SN_MIN_CHUNK_SIZE) 1208 return (SN_PARSE_ERROR_CHHL); 1209 1210 chunk_hdr = SN_SCTP_NEXTCHUNK(chunk_hdr); 1211 1212 /* Is the chunk long enough to not cause endless look and are there enough bytes in packet to read the chunk ? */ 1213 chunk_length = SCTP_SIZE32(ntohs(chunk_hdr->chunk_length)); 1214 if ((chunk_length < SN_MIN_CHUNK_SIZE) || (chunk_length > bytes_left)) 1215 return (SN_PARSE_ERROR_CHHL); 1216 if (++chunk_count > sysctl_chunk_proc_limit) 1217 return (SN_PARSE_OK); /* limit for processing chunks, take what we get */ 1218 } 1219 1220 if (*passoc == NULL) 1221 return (partial_match) ? (SN_PARSE_ERROR_PARTIALLOOKUP) : (SN_PARSE_ERROR_LOOKUP); 1222 else 1223 return (SN_PARSE_OK); 1224 } 1225 1226 /** @ingroup packet_parser 1227 * @brief Extract Vtags from Asconf Chunk 1228 * 1229 * GetAsconfVtags scans an Asconf Chunk for the vtags parameter, and then 1230 * extracts the vtags. 1231 * 1232 * GetAsconfVtags is not called from within sctp_PktParser. It is called only 1233 * from within ID_process when an AddIP has been received. 1234 * 1235 * @param la Pointer to the relevant libalias instance 1236 * @param sm Pointer to sctp message information 1237 * @param l_vtag Pointer to the local vtag in the association this SCTP Message belongs to 1238 * @param g_vtag Pointer to the local vtag in the association this SCTP Message belongs to 1239 * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1240 * 1241 * @return 1 - success | 0 - fail 1242 */ 1243 static int 1244 GetAsconfVtags(struct libalias *la, struct sctp_nat_msg *sm, uint32_t *l_vtag, uint32_t *g_vtag, int direction) 1245 { 1246 /* To be removed when information is in the sctp headers */ 1247 #define SCTP_VTAG_PARAM 0xC007 1248 struct sctp_vtag_param { 1249 struct sctp_paramhdr ph;/* type=SCTP_VTAG_PARAM */ 1250 uint32_t local_vtag; 1251 uint32_t remote_vtag; 1252 } __attribute__((packed)); 1253 1254 struct sctp_vtag_param *vtag_param; 1255 struct sctp_paramhdr *param; 1256 int bytes_left; 1257 int param_size; 1258 int param_count; 1259 1260 param_count = 1; 1261 param = sm->sctpchnk.Asconf; 1262 param_size = SCTP_SIZE32(ntohs(param->param_length)); 1263 bytes_left = sm->chunk_length; 1264 /* step through Asconf parameters */ 1265 while((bytes_left >= param_size) && (bytes_left >= SN_VTAG_PARAM_SIZE)) { 1266 if (ntohs(param->param_type) == SCTP_VTAG_PARAM) { 1267 vtag_param = (struct sctp_vtag_param *) param; 1268 switch (direction) { 1269 /* The Internet draft is a little ambigious as to order of these vtags. 1270 We think it is this way around. If we are wrong, the order will need 1271 to be changed. */ 1272 case SN_TO_GLOBAL: 1273 *g_vtag = vtag_param->local_vtag; 1274 *l_vtag = vtag_param->remote_vtag; 1275 break; 1276 case SN_TO_LOCAL: 1277 *g_vtag = vtag_param->remote_vtag; 1278 *l_vtag = vtag_param->local_vtag; 1279 break; 1280 } 1281 return (1); /* found */ 1282 } 1283 1284 bytes_left -= param_size; 1285 if (bytes_left < SN_MIN_PARAM_SIZE) return (0); 1286 1287 param = SN_SCTP_NEXTPARAM(param); 1288 param_size = SCTP_SIZE32(ntohs(param->param_length)); 1289 if (++param_count > sysctl_param_proc_limit) { 1290 SN_LOG(SN_LOG_EVENT, 1291 logsctperror("Parameter parse limit exceeded (GetAsconfVtags)", 1292 sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); 1293 return (0); /* not found limit exceeded*/ 1294 } 1295 } 1296 return (0); /* not found */ 1297 } 1298 1299 /** @ingroup packet_parser 1300 * @brief AddGlobalIPAddresses from Init,InitAck,or AddIP packets 1301 * 1302 * AddGlobalIPAddresses scans an SCTP chunk (in sm) for Global IP addresses, and 1303 * adds them. 1304 * 1305 * @param sm Pointer to sctp message information 1306 * @param assoc Pointer to the association this SCTP Message belongs to 1307 * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1308 * 1309 */ 1310 static void 1311 AddGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int direction) 1312 { 1313 struct sctp_ipv4addr_param *ipv4_param; 1314 struct sctp_paramhdr *param = NULL; 1315 struct sctp_GlobalAddress *G_Addr; 1316 struct in_addr g_addr = {0}; 1317 int bytes_left = 0; 1318 int param_size; 1319 int param_count, addr_param_count = 0; 1320 1321 switch (direction) { 1322 case SN_TO_GLOBAL: /* does not contain global addresses */ 1323 g_addr = sm->ip_hdr->ip_dst; 1324 bytes_left = 0; /* force exit */ 1325 break; 1326 case SN_TO_LOCAL: 1327 g_addr = sm->ip_hdr->ip_src; 1328 param_count = 1; 1329 switch (sm->msg) { 1330 case SN_SCTP_INIT: 1331 bytes_left = sm->chunk_length - sizeof(struct sctp_init_chunk); 1332 param = (struct sctp_paramhdr *)((char *)sm->sctpchnk.Init + sizeof(struct sctp_init)); 1333 break; 1334 case SN_SCTP_INITACK: 1335 bytes_left = sm->chunk_length - sizeof(struct sctp_init_ack_chunk); 1336 param = (struct sctp_paramhdr *)((char *)sm->sctpchnk.InitAck + sizeof(struct sctp_init_ack)); 1337 break; 1338 case SN_SCTP_ASCONF: 1339 bytes_left = sm->chunk_length; 1340 param = sm->sctpchnk.Asconf; 1341 break; 1342 } 1343 } 1344 if (bytes_left >= SN_MIN_PARAM_SIZE) 1345 param_size = SCTP_SIZE32(ntohs(param->param_length)); 1346 else 1347 param_size = bytes_left+1; /* force skip loop */ 1348 1349 if ((assoc->state == SN_ID) && ((sm->msg == SN_SCTP_INIT) || (bytes_left < SN_MIN_PARAM_SIZE))) {/* add pkt address */ 1350 G_Addr = (struct sctp_GlobalAddress *) sn_malloc(sizeof(struct sctp_GlobalAddress)); 1351 if (G_Addr == NULL) {/* out of resources */ 1352 SN_LOG(SN_LOG_EVENT, 1353 logsctperror("AddGlobalIPAddress: No resources for adding global address - revert to no tracking", 1354 sm->sctp_hdr->v_tag, 0, direction)); 1355 assoc->num_Gaddr = 0; /* don't track any more for this assoc*/ 1356 sysctl_track_global_addresses=0; 1357 return; 1358 } 1359 G_Addr->g_addr = g_addr; 1360 if (!Add_Global_Address_to_List(assoc, G_Addr)) 1361 SN_LOG(SN_LOG_EVENT, 1362 logsctperror("AddGlobalIPAddress: Address already in list", 1363 sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); 1364 } 1365 1366 /* step through parameters */ 1367 while((bytes_left >= param_size) && (bytes_left >= sizeof(struct sctp_ipv4addr_param))) { 1368 if (assoc->num_Gaddr >= sysctl_track_global_addresses) { 1369 SN_LOG(SN_LOG_EVENT, 1370 logsctperror("AddGlobalIPAddress: Maximum Number of addresses reached", 1371 sm->sctp_hdr->v_tag, sysctl_track_global_addresses, direction)); 1372 return; 1373 } 1374 switch (ntohs(param->param_type)) { 1375 case SCTP_ADD_IP_ADDRESS: 1376 /* skip to address parameter - leave param_size so bytes left will be calculated properly*/ 1377 param = (struct sctp_paramhdr *) &((struct sctp_asconf_addrv4_param *) param)->addrp; 1378 /* FALLTHROUGH */ 1379 case SCTP_IPV4_ADDRESS: 1380 ipv4_param = (struct sctp_ipv4addr_param *) param; 1381 /* add addresses to association */ 1382 G_Addr = (struct sctp_GlobalAddress *) sn_malloc(sizeof(struct sctp_GlobalAddress)); 1383 if (G_Addr == NULL) {/* out of resources */ 1384 SN_LOG(SN_LOG_EVENT, 1385 logsctperror("AddGlobalIPAddress: No resources for adding global address - revert to no tracking", 1386 sm->sctp_hdr->v_tag, 0, direction)); 1387 assoc->num_Gaddr = 0; /* don't track any more for this assoc*/ 1388 sysctl_track_global_addresses=0; 1389 return; 1390 } 1391 /* add address */ 1392 addr_param_count++; 1393 if ((sm->msg == SN_SCTP_ASCONF) && (ipv4_param->addr == INADDR_ANY)) { /* use packet address */ 1394 G_Addr->g_addr = g_addr; 1395 if (!Add_Global_Address_to_List(assoc, G_Addr)) 1396 SN_LOG(SN_LOG_EVENT, 1397 logsctperror("AddGlobalIPAddress: Address already in list", 1398 sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); 1399 return; /*shouldn't be any other addresses if the zero address is given*/ 1400 } else { 1401 G_Addr->g_addr.s_addr = ipv4_param->addr; 1402 if (!Add_Global_Address_to_List(assoc, G_Addr)) 1403 SN_LOG(SN_LOG_EVENT, 1404 logsctperror("AddGlobalIPAddress: Address already in list", 1405 sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); 1406 } 1407 } 1408 1409 bytes_left -= param_size; 1410 if (bytes_left < SN_MIN_PARAM_SIZE) 1411 break; 1412 1413 param = SN_SCTP_NEXTPARAM(param); 1414 param_size = SCTP_SIZE32(ntohs(param->param_length)); 1415 if (++param_count > sysctl_param_proc_limit) { 1416 SN_LOG(SN_LOG_EVENT, 1417 logsctperror("Parameter parse limit exceeded (AddGlobalIPAddress)", 1418 sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); 1419 break; /* limit exceeded*/ 1420 } 1421 } 1422 if (addr_param_count == 0) { 1423 SN_LOG(SN_LOG_DETAIL, 1424 logsctperror("AddGlobalIPAddress: no address parameters to add", 1425 sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); 1426 } 1427 } 1428 1429 /** 1430 * @brief Add_Global_Address_to_List 1431 * 1432 * Adds a global IP address to an associations address list, if it is not 1433 * already there. The first address added us usually the packet's address, and 1434 * is most likely to be used, so it is added at the beginning. Subsequent 1435 * addresses are added after this one. 1436 * 1437 * @param assoc Pointer to the association this SCTP Message belongs to 1438 * @param G_addr Pointer to the global address to add 1439 * 1440 * @return 1 - success | 0 - fail 1441 */ 1442 static int Add_Global_Address_to_List(struct sctp_nat_assoc *assoc, struct sctp_GlobalAddress *G_addr) 1443 { 1444 struct sctp_GlobalAddress *iter_G_Addr = NULL, *first_G_Addr = NULL; 1445 first_G_Addr = LIST_FIRST(&(assoc->Gaddr)); 1446 if (first_G_Addr == NULL) { 1447 LIST_INSERT_HEAD(&(assoc->Gaddr), G_addr, list_Gaddr); /* add new address to beginning of list*/ 1448 } else { 1449 LIST_FOREACH(iter_G_Addr, &(assoc->Gaddr), list_Gaddr) { 1450 if (G_addr->g_addr.s_addr == iter_G_Addr->g_addr.s_addr) 1451 return (0); /* already exists, so don't add */ 1452 } 1453 LIST_INSERT_AFTER(first_G_Addr, G_addr, list_Gaddr); /* add address to end of list*/ 1454 } 1455 assoc->num_Gaddr++; 1456 return (1); /* success */ 1457 } 1458 1459 /** @ingroup packet_parser 1460 * @brief RmGlobalIPAddresses from DelIP packets 1461 * 1462 * RmGlobalIPAddresses scans an ASCONF chunk for DelIP parameters to remove the 1463 * given Global IP addresses from the association. It will not delete the 1464 * the address if it is a list of one address. 1465 * 1466 * 1467 * @param sm Pointer to sctp message information 1468 * @param assoc Pointer to the association this SCTP Message belongs to 1469 * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1470 * 1471 */ 1472 static void 1473 RmGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int direction) 1474 { 1475 struct sctp_asconf_addrv4_param *asconf_ipv4_param; 1476 struct sctp_paramhdr *param; 1477 struct sctp_GlobalAddress *G_Addr, *G_Addr_tmp; 1478 struct in_addr g_addr; 1479 int bytes_left; 1480 int param_size; 1481 int param_count; 1482 1483 if (direction == SN_TO_GLOBAL) 1484 g_addr = sm->ip_hdr->ip_dst; 1485 else 1486 g_addr = sm->ip_hdr->ip_src; 1487 1488 bytes_left = sm->chunk_length; 1489 param_count = 1; 1490 param = sm->sctpchnk.Asconf; 1491 if (bytes_left >= SN_MIN_PARAM_SIZE) { 1492 param_size = SCTP_SIZE32(ntohs(param->param_length)); 1493 } else { 1494 SN_LOG(SN_LOG_EVENT, 1495 logsctperror("RmGlobalIPAddress: truncated packet - cannot remove IP addresses", 1496 sm->sctp_hdr->v_tag, sysctl_track_global_addresses, direction)); 1497 return; 1498 } 1499 1500 /* step through Asconf parameters */ 1501 while((bytes_left >= param_size) && (bytes_left >= sizeof(struct sctp_ipv4addr_param))) { 1502 if (ntohs(param->param_type) == SCTP_DEL_IP_ADDRESS) { 1503 asconf_ipv4_param = (struct sctp_asconf_addrv4_param *) param; 1504 if (asconf_ipv4_param->addrp.addr == INADDR_ANY) { /* remove all bar pkt address */ 1505 LIST_FOREACH_SAFE(G_Addr, &(assoc->Gaddr), list_Gaddr, G_Addr_tmp) { 1506 if (G_Addr->g_addr.s_addr != sm->ip_hdr->ip_src.s_addr) { 1507 if (assoc->num_Gaddr > 1) { /* only delete if more than one */ 1508 LIST_REMOVE(G_Addr, list_Gaddr); 1509 sn_free(G_Addr); 1510 assoc->num_Gaddr--; 1511 } else { 1512 SN_LOG(SN_LOG_EVENT, 1513 logsctperror("RmGlobalIPAddress: Request to remove last IP address (didn't)", 1514 sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); 1515 } 1516 } 1517 } 1518 return; /*shouldn't be any other addresses if the zero address is given*/ 1519 } else { 1520 LIST_FOREACH_SAFE(G_Addr, &(assoc->Gaddr), list_Gaddr, G_Addr_tmp) { 1521 if (G_Addr->g_addr.s_addr == asconf_ipv4_param->addrp.addr) { 1522 if (assoc->num_Gaddr > 1) { /* only delete if more than one */ 1523 LIST_REMOVE(G_Addr, list_Gaddr); 1524 sn_free(G_Addr); 1525 assoc->num_Gaddr--; 1526 break; /* Since add only adds new addresses, there should be no double entries */ 1527 } else { 1528 SN_LOG(SN_LOG_EVENT, 1529 logsctperror("RmGlobalIPAddress: Request to remove last IP address (didn't)", 1530 sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); 1531 } 1532 } 1533 } 1534 } 1535 } 1536 bytes_left -= param_size; 1537 if (bytes_left == 0) return; 1538 else if (bytes_left < SN_MIN_PARAM_SIZE) { 1539 SN_LOG(SN_LOG_EVENT, 1540 logsctperror("RmGlobalIPAddress: truncated packet - may not have removed all IP addresses", 1541 sm->sctp_hdr->v_tag, sysctl_track_global_addresses, direction)); 1542 return; 1543 } 1544 1545 param = SN_SCTP_NEXTPARAM(param); 1546 param_size = SCTP_SIZE32(ntohs(param->param_length)); 1547 if (++param_count > sysctl_param_proc_limit) { 1548 SN_LOG(SN_LOG_EVENT, 1549 logsctperror("Parameter parse limit exceeded (RmGlobalIPAddress)", 1550 sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); 1551 return; /* limit exceeded*/ 1552 } 1553 } 1554 } 1555 1556 /** @ingroup packet_parser 1557 * @brief Check that ASCONF was successful 1558 * 1559 * Each ASCONF configuration parameter carries a correlation ID which should be 1560 * matched with an ASCONFack. This is difficult for a NAT, since every 1561 * association could potentially have a number of outstanding ASCONF 1562 * configuration parameters, which should only be activated on receipt of the 1563 * ACK. 1564 * 1565 * Currently we only look for an ACK when the NAT is setting up a new 1566 * association (ie AddIP for a connection that the NAT does not know about 1567 * because the original Init went through a public interface or another NAT) 1568 * Since there is currently no connection on this path, there should be no other 1569 * ASCONF configuration parameters outstanding, so we presume that if there is 1570 * an ACK that it is responding to the AddIP and activate the new association. 1571 * 1572 * @param la Pointer to the relevant libalias instance 1573 * @param sm Pointer to sctp message information 1574 * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1575 * 1576 * @return 1 - success | 0 - fail 1577 */ 1578 static int 1579 IsASCONFack(struct libalias *la, struct sctp_nat_msg *sm, int direction) 1580 { 1581 struct sctp_paramhdr *param; 1582 int bytes_left; 1583 int param_size; 1584 int param_count; 1585 1586 param_count = 1; 1587 param = sm->sctpchnk.Asconf; 1588 param_size = SCTP_SIZE32(ntohs(param->param_length)); 1589 if (param_size == 8) 1590 return (1); /*success - default acknowledgement of everything */ 1591 1592 bytes_left = sm->chunk_length; 1593 if (bytes_left < param_size) 1594 return (0); /* not found */ 1595 /* step through Asconf parameters */ 1596 while(bytes_left >= SN_ASCONFACK_PARAM_SIZE) { 1597 if (ntohs(param->param_type) == SCTP_SUCCESS_REPORT) 1598 return (1); /* success - but can't match correlation IDs - should only be one */ 1599 /* check others just in case */ 1600 bytes_left -= param_size; 1601 if (bytes_left >= SN_MIN_PARAM_SIZE) { 1602 param = SN_SCTP_NEXTPARAM(param); 1603 } else { 1604 return (0); 1605 } 1606 param_size = SCTP_SIZE32(ntohs(param->param_length)); 1607 if (bytes_left < param_size) return (0); 1608 1609 if (++param_count > sysctl_param_proc_limit) { 1610 SN_LOG(SN_LOG_EVENT, 1611 logsctperror("Parameter parse limit exceeded (IsASCONFack)", 1612 sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); 1613 return (0); /* not found limit exceeded*/ 1614 } 1615 } 1616 return (0); /* not success */ 1617 } 1618 1619 /** @ingroup packet_parser 1620 * @brief Check to see if ASCONF contains an Add IP or Del IP parameter 1621 * 1622 * IsADDorDEL scans an ASCONF packet to see if it contains an AddIP or DelIP 1623 * parameter 1624 * 1625 * @param la Pointer to the relevant libalias instance 1626 * @param sm Pointer to sctp message information 1627 * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1628 * 1629 * @return SCTP_ADD_IP_ADDRESS | SCTP_DEL_IP_ADDRESS | 0 - fail 1630 */ 1631 static int 1632 IsADDorDEL(struct libalias *la, struct sctp_nat_msg *sm, int direction) 1633 { 1634 struct sctp_paramhdr *param; 1635 int bytes_left; 1636 int param_size; 1637 int param_count; 1638 1639 param_count = 1; 1640 param = sm->sctpchnk.Asconf; 1641 param_size = SCTP_SIZE32(ntohs(param->param_length)); 1642 1643 bytes_left = sm->chunk_length; 1644 if (bytes_left < param_size) 1645 return (0); /* not found */ 1646 /* step through Asconf parameters */ 1647 while(bytes_left >= SN_ASCONFACK_PARAM_SIZE) { 1648 if (ntohs(param->param_type) == SCTP_ADD_IP_ADDRESS) 1649 return (SCTP_ADD_IP_ADDRESS); 1650 else if (ntohs(param->param_type) == SCTP_DEL_IP_ADDRESS) 1651 return (SCTP_DEL_IP_ADDRESS); 1652 /* check others just in case */ 1653 bytes_left -= param_size; 1654 if (bytes_left >= SN_MIN_PARAM_SIZE) { 1655 param = SN_SCTP_NEXTPARAM(param); 1656 } else { 1657 return (0); /*Neither found */ 1658 } 1659 param_size = SCTP_SIZE32(ntohs(param->param_length)); 1660 if (bytes_left < param_size) return (0); 1661 1662 if (++param_count > sysctl_param_proc_limit) { 1663 SN_LOG(SN_LOG_EVENT, 1664 logsctperror("Parameter parse limit exceeded IsADDorDEL)", 1665 sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); 1666 return (0); /* not found limit exceeded*/ 1667 } 1668 } 1669 return (0); /*Neither found */ 1670 } 1671 1672 /* ---------------------------------------------------------------------- 1673 * STATE MACHINE CODE 1674 * ---------------------------------------------------------------------- 1675 */ 1676 /** @addtogroup state_machine 1677 * 1678 * The SCTP NAT State Machine functions will: 1679 * - Process an already parsed packet 1680 * - Use the existing NAT Hash Tables 1681 * - Determine the next state for the association 1682 * - Update the NAT Hash Tables and Timer Queues 1683 * - Return the appropriate action to take with the packet 1684 */ 1685 /** @ingroup state_machine 1686 * @brief Process SCTP message 1687 * 1688 * This function is the base state machine. It calls the processing engine for 1689 * each state. 1690 * 1691 * @param la Pointer to the relevant libalias instance 1692 * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1693 * @param sm Pointer to sctp message information 1694 * @param assoc Pointer to the association this SCTP Message belongs to 1695 * 1696 * @return SN_DROP_PKT | SN_NAT_PKT | SN_REPLY_ABORT | SN_REPLY_ERROR | SN_PROCESSING_ERROR 1697 */ 1698 static int 1699 ProcessSctpMsg(struct libalias *la, int direction, struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc) 1700 { 1701 int rtnval; 1702 1703 switch (assoc->state) { 1704 case SN_ID: /* Idle */ 1705 rtnval = ID_process(la, direction, assoc, sm); 1706 if (rtnval != SN_NAT_PKT) { 1707 assoc->state = SN_RM;/* Mark for removal*/ 1708 } 1709 return (rtnval); 1710 case SN_INi: /* Initialising - Init */ 1711 return (INi_process(la, direction, assoc, sm)); 1712 case SN_INa: /* Initialising - AddIP */ 1713 return (INa_process(la, direction, assoc, sm)); 1714 case SN_UP: /* Association UP */ 1715 return (UP_process(la, direction, assoc, sm)); 1716 case SN_CL: /* Association Closing */ 1717 return (CL_process(la, direction, assoc, sm)); 1718 } 1719 return (SN_PROCESSING_ERROR); 1720 } 1721 1722 /** @ingroup state_machine 1723 * @brief Process SCTP message while in the Idle state 1724 * 1725 * This function looks for an Incoming INIT or AddIP message. 1726 * 1727 * All other SCTP messages are invalid when in SN_ID, and are dropped. 1728 * 1729 * @param la Pointer to the relevant libalias instance 1730 * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1731 * @param sm Pointer to sctp message information 1732 * @param assoc Pointer to the association this SCTP Message belongs to 1733 * 1734 * @return SN_NAT_PKT | SN_DROP_PKT | SN_REPLY_ABORT | SN_REPLY_ERROR 1735 */ 1736 static int 1737 ID_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm) 1738 { 1739 switch (sm->msg) { 1740 case SN_SCTP_ASCONF: /* a packet containing an ASCONF chunk with ADDIP */ 1741 if (!sysctl_accept_global_ootb_addip && (direction == SN_TO_LOCAL)) 1742 return (SN_DROP_PKT); 1743 /* if this Asconf packet does not contain the Vtag parameters it is of no use in Idle state */ 1744 if (!GetAsconfVtags(la, sm, &(assoc->l_vtag), &(assoc->g_vtag), direction)) 1745 return (SN_DROP_PKT); 1746 /* FALLTHROUGH */ 1747 case SN_SCTP_INIT: /* a packet containing an INIT chunk or an ASCONF AddIP */ 1748 if (sysctl_track_global_addresses) 1749 AddGlobalIPAddresses(sm, assoc, direction); 1750 switch (direction) { 1751 case SN_TO_GLOBAL: 1752 assoc->l_addr = sm->ip_hdr->ip_src; 1753 assoc->a_addr = FindAliasAddress(la, assoc->l_addr); 1754 assoc->l_port = sm->sctp_hdr->src_port; 1755 assoc->g_port = sm->sctp_hdr->dest_port; 1756 if (sm->msg == SN_SCTP_INIT) 1757 assoc->g_vtag = sm->sctpchnk.Init->initiate_tag; 1758 if (AddSctpAssocGlobal(la, assoc)) /* DB clash *///**** need to add dst address 1759 return ((sm->msg == SN_SCTP_INIT) ? SN_REPLY_ABORT : SN_REPLY_ERROR); 1760 if (sm->msg == SN_SCTP_ASCONF) { 1761 if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_dst)) /* DB clash */ 1762 return (SN_REPLY_ERROR); 1763 assoc->TableRegister |= SN_WAIT_TOLOCAL; /* wait for tolocal ack */ 1764 } 1765 break; 1766 case SN_TO_LOCAL: 1767 assoc->l_addr = FindSctpRedirectAddress(la, sm); 1768 assoc->a_addr = sm->ip_hdr->ip_dst; 1769 assoc->l_port = sm->sctp_hdr->dest_port; 1770 assoc->g_port = sm->sctp_hdr->src_port; 1771 if (sm->msg == SN_SCTP_INIT) 1772 assoc->l_vtag = sm->sctpchnk.Init->initiate_tag; 1773 if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_src)) /* DB clash */ 1774 return ((sm->msg == SN_SCTP_INIT) ? SN_REPLY_ABORT : SN_REPLY_ERROR); 1775 if (sm->msg == SN_SCTP_ASCONF) { 1776 if (AddSctpAssocGlobal(la, assoc)) /* DB clash */ //**** need to add src address 1777 return (SN_REPLY_ERROR); 1778 assoc->TableRegister |= SN_WAIT_TOGLOBAL; /* wait for toglobal ack */ 1779 } 1780 break; 1781 } 1782 assoc->state = (sm->msg == SN_SCTP_INIT) ? SN_INi : SN_INa; 1783 assoc->exp = SN_I_T(la); 1784 sctp_AddTimeOut(la,assoc); 1785 return (SN_NAT_PKT); 1786 default: /* Any other type of SCTP message is not valid in Idle */ 1787 return (SN_DROP_PKT); 1788 } 1789 return (SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ 1790 } 1791 1792 /** @ingroup state_machine 1793 * @brief Process SCTP message while waiting for an INIT-ACK message 1794 * 1795 * Only an INIT-ACK, resent INIT, or an ABORT SCTP packet are valid in this 1796 * state, all other packets are dropped. 1797 * 1798 * @param la Pointer to the relevant libalias instance 1799 * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1800 * @param sm Pointer to sctp message information 1801 * @param assoc Pointer to the association this SCTP Message belongs to 1802 * 1803 * @return SN_NAT_PKT | SN_DROP_PKT | SN_REPLY_ABORT 1804 */ 1805 static int 1806 INi_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm) 1807 { 1808 switch (sm->msg) { 1809 case SN_SCTP_INIT: /* a packet containing a retransmitted INIT chunk */ 1810 sctp_ResetTimeOut(la, assoc, SN_I_T(la)); 1811 return (SN_NAT_PKT); 1812 case SN_SCTP_INITACK: /* a packet containing an INIT-ACK chunk */ 1813 switch (direction) { 1814 case SN_TO_LOCAL: 1815 if (assoc->num_Gaddr) /*If tracking global addresses for this association */ 1816 AddGlobalIPAddresses(sm, assoc, direction); 1817 assoc->l_vtag = sm->sctpchnk.Init->initiate_tag; 1818 if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_src)) { /* DB clash */ 1819 assoc->state = SN_RM;/* Mark for removal*/ 1820 return (SN_SEND_ABORT); 1821 } 1822 break; 1823 case SN_TO_GLOBAL: 1824 assoc->l_addr = sm->ip_hdr->ip_src; // Only if not set in Init! * 1825 assoc->g_vtag = sm->sctpchnk.Init->initiate_tag; 1826 if (AddSctpAssocGlobal(la, assoc)) { /* DB clash */ 1827 assoc->state = SN_RM;/* Mark for removal*/ 1828 return (SN_SEND_ABORT); 1829 } 1830 break; 1831 } 1832 assoc->state = SN_UP;/* association established for NAT */ 1833 sctp_ResetTimeOut(la,assoc, SN_U_T(la)); 1834 return (SN_NAT_PKT); 1835 case SN_SCTP_ABORT: /* a packet containing an ABORT chunk */ 1836 assoc->state = SN_RM;/* Mark for removal*/ 1837 return (SN_NAT_PKT); 1838 default: 1839 return (SN_DROP_PKT); 1840 } 1841 return (SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ 1842 } 1843 1844 /** @ingroup state_machine 1845 * @brief Process SCTP message while waiting for an AddIp-ACK message 1846 * 1847 * Only an AddIP-ACK, resent AddIP, or an ABORT message are valid, all other 1848 * SCTP packets are dropped 1849 * 1850 * @param la Pointer to the relevant libalias instance 1851 * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1852 * @param sm Pointer to sctp message information 1853 * @param assoc Pointer to the association this SCTP Message belongs to 1854 * 1855 * @return SN_NAT_PKT | SN_DROP_PKT 1856 */ 1857 static int 1858 INa_process(struct libalias *la, int direction,struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm) 1859 { 1860 switch (sm->msg) { 1861 case SN_SCTP_ASCONF: /* a packet containing an ASCONF chunk*/ 1862 sctp_ResetTimeOut(la,assoc, SN_I_T(la)); 1863 return (SN_NAT_PKT); 1864 case SN_SCTP_ASCONFACK: /* a packet containing an ASCONF chunk with a ADDIP-ACK */ 1865 switch (direction) { 1866 case SN_TO_LOCAL: 1867 if (!(assoc->TableRegister & SN_WAIT_TOLOCAL)) /* wrong direction */ 1868 return (SN_DROP_PKT); 1869 break; 1870 case SN_TO_GLOBAL: 1871 if (!(assoc->TableRegister & SN_WAIT_TOGLOBAL)) /* wrong direction */ 1872 return (SN_DROP_PKT); 1873 } 1874 if (IsASCONFack(la,sm,direction)) { 1875 assoc->TableRegister &= SN_BOTH_TBL; /* remove wait flags */ 1876 assoc->state = SN_UP; /* association established for NAT */ 1877 sctp_ResetTimeOut(la,assoc, SN_U_T(la)); 1878 return (SN_NAT_PKT); 1879 } else { 1880 assoc->state = SN_RM;/* Mark for removal*/ 1881 return (SN_NAT_PKT); 1882 } 1883 case SN_SCTP_ABORT: /* a packet containing an ABORT chunk */ 1884 assoc->state = SN_RM;/* Mark for removal*/ 1885 return (SN_NAT_PKT); 1886 default: 1887 return (SN_DROP_PKT); 1888 } 1889 return (SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ 1890 } 1891 1892 /** @ingroup state_machine 1893 * @brief Process SCTP messages while association is UP redirecting packets 1894 * 1895 * While in the SN_UP state, all packets for the particular association 1896 * are passed. Only a SHUT-ACK or an ABORT will cause a change of state. 1897 * 1898 * @param la Pointer to the relevant libalias instance 1899 * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1900 * @param sm Pointer to sctp message information 1901 * @param assoc Pointer to the association this SCTP Message belongs to 1902 * 1903 * @return SN_NAT_PKT | SN_DROP_PKT 1904 */ 1905 static int 1906 UP_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm) 1907 { 1908 switch (sm->msg) { 1909 case SN_SCTP_SHUTACK: /* a packet containing a SHUTDOWN-ACK chunk */ 1910 assoc->state = SN_CL; 1911 sctp_ResetTimeOut(la,assoc, SN_C_T(la)); 1912 return (SN_NAT_PKT); 1913 case SN_SCTP_ABORT: /* a packet containing an ABORT chunk */ 1914 assoc->state = SN_RM;/* Mark for removal*/ 1915 return (SN_NAT_PKT); 1916 case SN_SCTP_ASCONF: /* a packet containing an ASCONF chunk*/ 1917 if ((direction == SN_TO_LOCAL) && assoc->num_Gaddr) /*If tracking global addresses for this association & from global side */ 1918 switch (IsADDorDEL(la,sm,direction)) { 1919 case SCTP_ADD_IP_ADDRESS: 1920 AddGlobalIPAddresses(sm, assoc, direction); 1921 break; 1922 case SCTP_DEL_IP_ADDRESS: 1923 RmGlobalIPAddresses(sm, assoc, direction); 1924 break; 1925 } /* fall through to default */ 1926 default: 1927 sctp_ResetTimeOut(la,assoc, SN_U_T(la)); 1928 return (SN_NAT_PKT); /* forward packet */ 1929 } 1930 return (SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ 1931 } 1932 1933 /** @ingroup state_machine 1934 * @brief Process SCTP message while association is in the process of closing 1935 * 1936 * This function waits for a SHUT-COMP to close the association. Depending on 1937 * the setting of sysctl_holddown_timer it may not remove the association 1938 * immediately, but leave it up until SN_X_T(la). Only SHUT-COMP, SHUT-ACK, and 1939 * ABORT packets are permitted in this state. All other packets are dropped. 1940 * 1941 * @param la Pointer to the relevant libalias instance 1942 * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1943 * @param sm Pointer to sctp message information 1944 * @param assoc Pointer to the association this SCTP Message belongs to 1945 * 1946 * @return SN_NAT_PKT | SN_DROP_PKT 1947 */ 1948 static int 1949 CL_process(struct libalias *la, int direction,struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm) 1950 { 1951 switch (sm->msg) { 1952 case SN_SCTP_SHUTCOMP: /* a packet containing a SHUTDOWN-COMPLETE chunk */ 1953 assoc->state = SN_CL; /* Stay in Close state until timeout */ 1954 if (sysctl_holddown_timer > 0) 1955 sctp_ResetTimeOut(la, assoc, SN_X_T(la));/* allow to stay open for Tbit packets*/ 1956 else 1957 assoc->state = SN_RM;/* Mark for removal*/ 1958 return (SN_NAT_PKT); 1959 case SN_SCTP_SHUTACK: /* a packet containing a SHUTDOWN-ACK chunk */ 1960 assoc->state = SN_CL; /* Stay in Close state until timeout */ 1961 sctp_ResetTimeOut(la, assoc, SN_C_T(la)); 1962 return (SN_NAT_PKT); 1963 case SN_SCTP_ABORT: /* a packet containing an ABORT chunk */ 1964 assoc->state = SN_RM;/* Mark for removal*/ 1965 return (SN_NAT_PKT); 1966 default: 1967 return (SN_DROP_PKT); 1968 } 1969 return (SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ 1970 } 1971 1972 /* ---------------------------------------------------------------------- 1973 * HASH TABLE CODE 1974 * ---------------------------------------------------------------------- 1975 */ 1976 /** @addtogroup Hash 1977 * 1978 * The Hash functions facilitate searching the NAT Hash Tables for associations 1979 * as well as adding/removing associations from the table(s). 1980 */ 1981 /** @ingroup Hash 1982 * @brief Find the SCTP association given the local address, port and vtag 1983 * 1984 * Searches the local look-up table for the association entry matching the 1985 * provided local <address:ports:vtag> tuple 1986 * 1987 * @param la Pointer to the relevant libalias instance 1988 * @param l_addr local address 1989 * @param g_addr global address 1990 * @param l_vtag local Vtag 1991 * @param l_port local Port 1992 * @param g_port global Port 1993 * 1994 * @return pointer to association or NULL 1995 */ 1996 static struct sctp_nat_assoc* 1997 FindSctpLocal(struct libalias *la, struct in_addr l_addr, struct in_addr g_addr, uint32_t l_vtag, uint16_t l_port, uint16_t g_port) 1998 { 1999 u_int i; 2000 struct sctp_nat_assoc *assoc = NULL; 2001 struct sctp_GlobalAddress *G_Addr = NULL; 2002 2003 if (l_vtag != 0) { /* an init packet, vtag==0 */ 2004 i = SN_TABLE_HASH(l_vtag, l_port, la->sctpNatTableSize); 2005 LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) { 2006 if ((assoc->l_vtag == l_vtag) && (assoc->l_port == l_port) && (assoc->g_port == g_port)\ 2007 && (assoc->l_addr.s_addr == l_addr.s_addr)) { 2008 if (assoc->num_Gaddr) { 2009 LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { 2010 if (G_Addr->g_addr.s_addr == g_addr.s_addr) 2011 return (assoc); 2012 } 2013 } else { 2014 return (assoc); 2015 } 2016 } 2017 } 2018 } 2019 return (NULL); 2020 } 2021 2022 /** @ingroup Hash 2023 * @brief Check for Global Clash 2024 * 2025 * Searches the global look-up table for the association entry matching the 2026 * provided global <(addresses):ports:vtag> tuple 2027 * 2028 * @param la Pointer to the relevant libalias instance 2029 * @param Cassoc association being checked for a clash 2030 * 2031 * @return pointer to association or NULL 2032 */ 2033 static struct sctp_nat_assoc* 2034 FindSctpGlobalClash(struct libalias *la, struct sctp_nat_assoc *Cassoc) 2035 { 2036 u_int i; 2037 struct sctp_nat_assoc *assoc = NULL; 2038 struct sctp_GlobalAddress *G_Addr = NULL; 2039 struct sctp_GlobalAddress *G_AddrC = NULL; 2040 2041 if (Cassoc->g_vtag != 0) { /* an init packet, vtag==0 */ 2042 i = SN_TABLE_HASH(Cassoc->g_vtag, Cassoc->g_port, la->sctpNatTableSize); 2043 LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) { 2044 if ((assoc->g_vtag == Cassoc->g_vtag) && (assoc->g_port == Cassoc->g_port) && (assoc->l_port == Cassoc->l_port)) { 2045 if (assoc->num_Gaddr) { 2046 LIST_FOREACH(G_AddrC, &(Cassoc->Gaddr), list_Gaddr) { 2047 LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { 2048 if (G_Addr->g_addr.s_addr == G_AddrC->g_addr.s_addr) 2049 return (assoc); 2050 } 2051 } 2052 } else { 2053 return (assoc); 2054 } 2055 } 2056 } 2057 } 2058 return (NULL); 2059 } 2060 2061 /** @ingroup Hash 2062 * @brief Find the SCTP association given the global port and vtag 2063 * 2064 * Searches the global look-up table for the association entry matching the 2065 * provided global <address:ports:vtag> tuple 2066 * 2067 * If all but the global address match it sets partial_match to 1 to indicate a 2068 * partial match. If the NAT is tracking global IP addresses for this 2069 * association, the NAT may respond with an ERRORM to request the missing 2070 * address to be added. 2071 * 2072 * @param la Pointer to the relevant libalias instance 2073 * @param g_addr global address 2074 * @param g_vtag global vtag 2075 * @param g_port global port 2076 * @param l_port local port 2077 * 2078 * @return pointer to association or NULL 2079 */ 2080 static struct sctp_nat_assoc* 2081 FindSctpGlobal(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uint16_t g_port, uint16_t l_port, int *partial_match) 2082 { 2083 u_int i; 2084 struct sctp_nat_assoc *assoc = NULL; 2085 struct sctp_GlobalAddress *G_Addr = NULL; 2086 2087 *partial_match = 0; 2088 if (g_vtag != 0) { /* an init packet, vtag==0 */ 2089 i = SN_TABLE_HASH(g_vtag, g_port, la->sctpNatTableSize); 2090 LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) { 2091 if ((assoc->g_vtag == g_vtag) && (assoc->g_port == g_port) && (assoc->l_port == l_port)) { 2092 *partial_match = 1; 2093 if (assoc->num_Gaddr) { 2094 LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { 2095 if (G_Addr->g_addr.s_addr == g_addr.s_addr) 2096 return (assoc); 2097 } 2098 } else { 2099 return (assoc); 2100 } 2101 } 2102 } 2103 } 2104 return (NULL); 2105 } 2106 2107 /** @ingroup Hash 2108 * @brief Find the SCTP association for a T-Flag message (given the global port and local vtag) 2109 * 2110 * Searches the local look-up table for a unique association entry matching the 2111 * provided global port and local vtag information 2112 * 2113 * @param la Pointer to the relevant libalias instance 2114 * @param g_addr global address 2115 * @param l_vtag local Vtag 2116 * @param g_port global Port 2117 * @param l_port local Port 2118 * 2119 * @return pointer to association or NULL 2120 */ 2121 static struct sctp_nat_assoc* 2122 FindSctpLocalT(struct libalias *la, struct in_addr g_addr, uint32_t l_vtag, uint16_t g_port, uint16_t l_port) 2123 { 2124 u_int i; 2125 struct sctp_nat_assoc *assoc = NULL, *lastmatch = NULL; 2126 struct sctp_GlobalAddress *G_Addr = NULL; 2127 int cnt = 0; 2128 2129 if (l_vtag != 0) { /* an init packet, vtag==0 */ 2130 i = SN_TABLE_HASH(l_vtag, g_port, la->sctpNatTableSize); 2131 LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) { 2132 if ((assoc->g_vtag == l_vtag) && (assoc->g_port == g_port) && (assoc->l_port == l_port)) { 2133 if (assoc->num_Gaddr) { 2134 LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { 2135 if (G_Addr->g_addr.s_addr == g_addr.s_addr) 2136 return (assoc); /* full match */ 2137 } 2138 } else { 2139 if (++cnt > 1) return (NULL); 2140 lastmatch = assoc; 2141 } 2142 } 2143 } 2144 } 2145 /* If there is more than one match we do not know which local address to send to */ 2146 return (cnt ? lastmatch : NULL); 2147 } 2148 2149 /** @ingroup Hash 2150 * @brief Find the SCTP association for a T-Flag message (given the local port and global vtag) 2151 * 2152 * Searches the global look-up table for a unique association entry matching the 2153 * provided local port and global vtag information 2154 * 2155 * @param la Pointer to the relevant libalias instance 2156 * @param g_addr global address 2157 * @param g_vtag global vtag 2158 * @param l_port local port 2159 * @param g_port global port 2160 * 2161 * @return pointer to association or NULL 2162 */ 2163 static struct sctp_nat_assoc* 2164 FindSctpGlobalT(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uint16_t l_port, uint16_t g_port) 2165 { 2166 u_int i; 2167 struct sctp_nat_assoc *assoc = NULL; 2168 struct sctp_GlobalAddress *G_Addr = NULL; 2169 2170 if (g_vtag != 0) { /* an init packet, vtag==0 */ 2171 i = SN_TABLE_HASH(g_vtag, l_port, la->sctpNatTableSize); 2172 LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) { 2173 if ((assoc->l_vtag == g_vtag) && (assoc->l_port == l_port) && (assoc->g_port == g_port)) { 2174 if (assoc->num_Gaddr) { 2175 LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { 2176 if (G_Addr->g_addr.s_addr == g_addr.s_addr) 2177 return (assoc); 2178 } 2179 } else { 2180 return (assoc); 2181 } 2182 } 2183 } 2184 } 2185 return (NULL); 2186 } 2187 2188 /** @ingroup Hash 2189 * @brief Add the sctp association information to the local look up table 2190 * 2191 * Searches the local look-up table for an existing association with the same 2192 * details. If a match exists and is ONLY in the local look-up table then this 2193 * is a repeated INIT packet, we need to remove this association from the 2194 * look-up table and add the new association 2195 * 2196 * The new association is added to the head of the list and state is updated 2197 * 2198 * @param la Pointer to the relevant libalias instance 2199 * @param assoc pointer to sctp association 2200 * @param g_addr global address 2201 * 2202 * @return SN_ADD_OK | SN_ADD_CLASH 2203 */ 2204 static int 2205 AddSctpAssocLocal(struct libalias *la, struct sctp_nat_assoc *assoc, struct in_addr g_addr) 2206 { 2207 struct sctp_nat_assoc *found; 2208 2209 LIBALIAS_LOCK_ASSERT(la); 2210 found = FindSctpLocal(la, assoc->l_addr, g_addr, assoc->l_vtag, assoc->l_port, assoc->g_port); 2211 /* 2212 * Note that if a different global address initiated this Init, 2213 * ie it wasn't resent as presumed: 2214 * - the local receiver if receiving it for the first time will establish 2215 * an association with the new global host 2216 * - if receiving an init from a different global address after sending a 2217 * lost initack it will send an initack to the new global host, the first 2218 * association attempt will then be blocked if retried. 2219 */ 2220 if (found != NULL) { 2221 if ((found->TableRegister == SN_LOCAL_TBL) && (found->g_port == assoc->g_port)) { /* resent message */ 2222 RmSctpAssoc(la, found); 2223 sctp_RmTimeOut(la, found); 2224 freeGlobalAddressList(found); 2225 sn_free(found); 2226 } else 2227 return (SN_ADD_CLASH); 2228 } 2229 2230 LIST_INSERT_HEAD(&la->sctpTableLocal[SN_TABLE_HASH(assoc->l_vtag, assoc->l_port, la->sctpNatTableSize)], 2231 assoc, list_L); 2232 assoc->TableRegister |= SN_LOCAL_TBL; 2233 la->sctpLinkCount++; //increment link count 2234 2235 if (assoc->TableRegister == SN_BOTH_TBL) { 2236 /* libalias log -- controlled by libalias */ 2237 if (la->packetAliasMode & PKT_ALIAS_LOG) 2238 SctpShowAliasStats(la); 2239 2240 SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "^")); 2241 } 2242 2243 return (SN_ADD_OK); 2244 } 2245 2246 /** @ingroup Hash 2247 * @brief Add the sctp association information to the global look up table 2248 * 2249 * Searches the global look-up table for an existing association with the same 2250 * details. If a match exists and is ONLY in the global look-up table then this 2251 * is a repeated INIT packet, we need to remove this association from the 2252 * look-up table and add the new association 2253 * 2254 * The new association is added to the head of the list and state is updated 2255 * 2256 * @param la Pointer to the relevant libalias instance 2257 * @param assoc pointer to sctp association 2258 * 2259 * @return SN_ADD_OK | SN_ADD_CLASH 2260 */ 2261 static int 2262 AddSctpAssocGlobal(struct libalias *la, struct sctp_nat_assoc *assoc) 2263 { 2264 struct sctp_nat_assoc *found; 2265 2266 LIBALIAS_LOCK_ASSERT(la); 2267 found = FindSctpGlobalClash(la, assoc); 2268 if (found != NULL) { 2269 if ((found->TableRegister == SN_GLOBAL_TBL) && \ 2270 (found->l_addr.s_addr == assoc->l_addr.s_addr) && (found->l_port == assoc->l_port)) { /* resent message */ 2271 RmSctpAssoc(la, found); 2272 sctp_RmTimeOut(la, found); 2273 freeGlobalAddressList(found); 2274 sn_free(found); 2275 } else 2276 return (SN_ADD_CLASH); 2277 } 2278 2279 LIST_INSERT_HEAD(&la->sctpTableGlobal[SN_TABLE_HASH(assoc->g_vtag, assoc->g_port, la->sctpNatTableSize)], 2280 assoc, list_G); 2281 assoc->TableRegister |= SN_GLOBAL_TBL; 2282 la->sctpLinkCount++; //increment link count 2283 2284 if (assoc->TableRegister == SN_BOTH_TBL) { 2285 /* libalias log -- controlled by libalias */ 2286 if (la->packetAliasMode & PKT_ALIAS_LOG) 2287 SctpShowAliasStats(la); 2288 2289 SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "^")); 2290 } 2291 2292 return (SN_ADD_OK); 2293 } 2294 2295 /** @ingroup Hash 2296 * @brief Remove the sctp association information from the look up table 2297 * 2298 * For each of the two (local/global) look-up tables, remove the association 2299 * from that table IF it has been registered in that table. 2300 * 2301 * NOTE: The calling code is responsible for freeing memory allocated to the 2302 * association structure itself 2303 * 2304 * NOTE: The association is NOT removed from the timer queue 2305 * 2306 * @param la Pointer to the relevant libalias instance 2307 * @param assoc pointer to sctp association 2308 */ 2309 static void 2310 RmSctpAssoc(struct libalias *la, struct sctp_nat_assoc *assoc) 2311 { 2312 // struct sctp_nat_assoc *found; 2313 if (assoc == NULL) { 2314 /* very bad, log and die*/ 2315 SN_LOG(SN_LOG_LOW, 2316 logsctperror("ERROR: alias_sctp:RmSctpAssoc(NULL)\n", 0, 0, SN_TO_NODIR)); 2317 return; 2318 } 2319 /* log if association is fully up and now closing */ 2320 if (assoc->TableRegister == SN_BOTH_TBL) { 2321 SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "$")); 2322 } 2323 LIBALIAS_LOCK_ASSERT(la); 2324 if (assoc->TableRegister & SN_LOCAL_TBL) { 2325 assoc->TableRegister ^= SN_LOCAL_TBL; 2326 la->sctpLinkCount--; //decrement link count 2327 LIST_REMOVE(assoc, list_L); 2328 } 2329 2330 if (assoc->TableRegister & SN_GLOBAL_TBL) { 2331 assoc->TableRegister ^= SN_GLOBAL_TBL; 2332 la->sctpLinkCount--; //decrement link count 2333 LIST_REMOVE(assoc, list_G); 2334 } 2335 // sn_free(assoc); //Don't remove now, remove if needed later 2336 /* libalias logging -- controlled by libalias log definition */ 2337 if (la->packetAliasMode & PKT_ALIAS_LOG) 2338 SctpShowAliasStats(la); 2339 } 2340 2341 /** 2342 * @ingroup Hash 2343 * @brief free the Global Address List memory 2344 * 2345 * freeGlobalAddressList deletes all global IP addresses in an associations 2346 * global IP address list. 2347 * 2348 * @param assoc 2349 */ 2350 static void freeGlobalAddressList(struct sctp_nat_assoc *assoc) 2351 { 2352 struct sctp_GlobalAddress *gaddr1=NULL,*gaddr2=NULL; 2353 /*free global address list*/ 2354 gaddr1 = LIST_FIRST(&(assoc->Gaddr)); 2355 while (gaddr1 != NULL) { 2356 gaddr2 = LIST_NEXT(gaddr1, list_Gaddr); 2357 sn_free(gaddr1); 2358 gaddr1 = gaddr2; 2359 } 2360 } 2361 /* ---------------------------------------------------------------------- 2362 * TIMER QUEUE CODE 2363 * ---------------------------------------------------------------------- 2364 */ 2365 /** @addtogroup Timer 2366 * 2367 * The timer queue management functions are designed to operate efficiently with 2368 * a minimum of interaction with the queues. 2369 * 2370 * Once a timeout is set in the queue it will not be altered in the queue unless 2371 * it has to be changed to a shorter time (usually only for aborts and closing). 2372 * On a queue timeout, the real expiry time is checked, and if not leq than the 2373 * timeout it is requeued (O(1)) at its later time. This is especially important 2374 * for normal packets sent during an association. When a timer expires, it is 2375 * updated to its new expiration time if necessary, or processed as a 2376 * timeout. This means that while in UP state, the timing queue is only altered 2377 * every U_T (every few minutes) for a particular association. 2378 */ 2379 /** @ingroup Timer 2380 * @brief Add an association timeout to the timer queue 2381 * 2382 * Determine the location in the queue to add the timeout and insert the 2383 * association into the list at that queue position 2384 * 2385 * @param la 2386 * @param assoc 2387 */ 2388 static void 2389 sctp_AddTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc) 2390 { 2391 int add_loc; 2392 LIBALIAS_LOCK_ASSERT(la); 2393 add_loc = assoc->exp - la->sctpNatTimer.loc_time + la->sctpNatTimer.cur_loc; 2394 if (add_loc >= SN_TIMER_QUEUE_SIZE) 2395 add_loc -= SN_TIMER_QUEUE_SIZE; 2396 LIST_INSERT_HEAD(&la->sctpNatTimer.TimerQ[add_loc], assoc, timer_Q); 2397 assoc->exp_loc = add_loc; 2398 } 2399 2400 /** @ingroup Timer 2401 * @brief Remove an association from timer queue 2402 * 2403 * This is an O(1) operation to remove the association pointer from its 2404 * current position in the timer queue 2405 * 2406 * @param la Pointer to the relevant libalias instance 2407 * @param assoc pointer to sctp association 2408 */ 2409 static void 2410 sctp_RmTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc) 2411 { 2412 LIBALIAS_LOCK_ASSERT(la); 2413 LIST_REMOVE(assoc, timer_Q);/* Note this is O(1) */ 2414 } 2415 2416 2417 /** @ingroup Timer 2418 * @brief Reset timer in timer queue 2419 * 2420 * Reset the actual timeout for the specified association. If it is earlier than 2421 * the existing timeout, then remove and re-install the association into the 2422 * queue 2423 * 2424 * @param la Pointer to the relevant libalias instance 2425 * @param assoc pointer to sctp association 2426 * @param newexp New expiration time 2427 */ 2428 static void 2429 sctp_ResetTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc, int newexp) 2430 { 2431 if (newexp < assoc->exp) { 2432 sctp_RmTimeOut(la, assoc); 2433 assoc->exp = newexp; 2434 sctp_AddTimeOut(la, assoc); 2435 } else { 2436 assoc->exp = newexp; 2437 } 2438 } 2439 2440 /** @ingroup Timer 2441 * @brief Check timer Q against current time 2442 * 2443 * Loop through each entry in the timer queue since the last time we processed 2444 * the timer queue until now (the current time). For each association in the 2445 * event list, we remove it from that position in the timer queue and check if 2446 * it has really expired. If so we: 2447 * - Log the timer expiry 2448 * - Remove the association from the NAT tables 2449 * - Release the memory used by the association 2450 * 2451 * If the timer hasn't really expired we place the association into its new 2452 * correct position in the timer queue. 2453 * 2454 * @param la Pointer to the relevant libalias instance 2455 */ 2456 void 2457 sctp_CheckTimers(struct libalias *la) 2458 { 2459 struct sctp_nat_assoc *assoc; 2460 2461 LIBALIAS_LOCK_ASSERT(la); 2462 while(la->timeStamp >= la->sctpNatTimer.loc_time) { 2463 while (!LIST_EMPTY(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc])) { 2464 assoc = LIST_FIRST(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc]); 2465 //SLIST_REMOVE_HEAD(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc], timer_Q); 2466 LIST_REMOVE(assoc, timer_Q); 2467 if (la->timeStamp >= assoc->exp) { /* state expired */ 2468 SN_LOG(((assoc->state == SN_CL) ? (SN_LOG_DEBUG) : (SN_LOG_INFO)), 2469 logsctperror("Timer Expired", assoc->g_vtag, assoc->state, SN_TO_NODIR)); 2470 RmSctpAssoc(la, assoc); 2471 freeGlobalAddressList(assoc); 2472 sn_free(assoc); 2473 } else {/* state not expired, reschedule timer*/ 2474 sctp_AddTimeOut(la, assoc); 2475 } 2476 } 2477 /* Goto next location in the timer queue*/ 2478 ++la->sctpNatTimer.loc_time; 2479 if (++la->sctpNatTimer.cur_loc >= SN_TIMER_QUEUE_SIZE) 2480 la->sctpNatTimer.cur_loc = 0; 2481 } 2482 } 2483 2484 /* ---------------------------------------------------------------------- 2485 * LOGGING CODE 2486 * ---------------------------------------------------------------------- 2487 */ 2488 /** @addtogroup Logging 2489 * 2490 * The logging functions provide logging of different items ranging from logging 2491 * a simple message, through logging an association details to logging the 2492 * current state of the NAT tables 2493 */ 2494 /** @ingroup Logging 2495 * @brief Log sctp nat errors 2496 * 2497 * @param errormsg Error message to be logged 2498 * @param vtag Current Vtag 2499 * @param error Error number 2500 * @param direction Direction of packet 2501 */ 2502 static void 2503 logsctperror(char* errormsg, uint32_t vtag, int error, int direction) 2504 { 2505 char dir; 2506 switch (direction) { 2507 case SN_TO_LOCAL: 2508 dir = 'L'; 2509 break; 2510 case SN_TO_GLOBAL: 2511 dir = 'G'; 2512 break; 2513 default: 2514 dir = '*'; 2515 break; 2516 } 2517 SctpAliasLog("->%c %s (vt=%u) %d\n", dir, errormsg, ntohl(vtag), error); 2518 } 2519 2520 /** @ingroup Logging 2521 * @brief Log what the parser parsed 2522 * 2523 * @param direction Direction of packet 2524 * @param sm Pointer to sctp message information 2525 */ 2526 static void 2527 logsctpparse(int direction, struct sctp_nat_msg *sm) 2528 { 2529 char *ploc, *pstate; 2530 switch (direction) { 2531 case SN_TO_LOCAL: 2532 ploc = "TO_LOCAL -"; 2533 break; 2534 case SN_TO_GLOBAL: 2535 ploc = "TO_GLOBAL -"; 2536 break; 2537 default: 2538 ploc = ""; 2539 } 2540 switch (sm->msg) { 2541 case SN_SCTP_INIT: 2542 pstate = "Init"; 2543 break; 2544 case SN_SCTP_INITACK: 2545 pstate = "InitAck"; 2546 break; 2547 case SN_SCTP_ABORT: 2548 pstate = "Abort"; 2549 break; 2550 case SN_SCTP_SHUTACK: 2551 pstate = "ShutAck"; 2552 break; 2553 case SN_SCTP_SHUTCOMP: 2554 pstate = "ShutComp"; 2555 break; 2556 case SN_SCTP_ASCONF: 2557 pstate = "Asconf"; 2558 break; 2559 case SN_SCTP_ASCONFACK: 2560 pstate = "AsconfAck"; 2561 break; 2562 case SN_SCTP_OTHER: 2563 pstate = "Other"; 2564 break; 2565 default: 2566 pstate = "***ERROR***"; 2567 break; 2568 } 2569 SctpAliasLog("Parsed: %s %s\n", ploc, pstate); 2570 } 2571 2572 /** @ingroup Logging 2573 * @brief Log an SCTP association's details 2574 * 2575 * @param assoc pointer to sctp association 2576 * @param s Character that indicates the state of processing for this packet 2577 */ 2578 static void logsctpassoc(struct sctp_nat_assoc *assoc, char* s) 2579 { 2580 struct sctp_GlobalAddress *G_Addr = NULL; 2581 char *sp; 2582 char addrbuf[INET_ADDRSTRLEN]; 2583 2584 switch (assoc->state) { 2585 case SN_ID: 2586 sp = "ID "; 2587 break; 2588 case SN_INi: 2589 sp = "INi "; 2590 break; 2591 case SN_INa: 2592 sp = "INa "; 2593 break; 2594 case SN_UP: 2595 sp = "UP "; 2596 break; 2597 case SN_CL: 2598 sp = "CL "; 2599 break; 2600 case SN_RM: 2601 sp = "RM "; 2602 break; 2603 default: 2604 sp = "***ERROR***"; 2605 break; 2606 } 2607 SctpAliasLog("%sAssoc: %s exp=%u la=%s lv=%u lp=%u gv=%u gp=%u tbl=%d\n", 2608 s, sp, assoc->exp, inet_ntoa_r(assoc->l_addr, addrbuf), 2609 ntohl(assoc->l_vtag), ntohs(assoc->l_port), 2610 ntohl(assoc->g_vtag), ntohs(assoc->g_port), 2611 assoc->TableRegister); 2612 /* list global addresses */ 2613 LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { 2614 SctpAliasLog("\t\tga=%s\n", 2615 inet_ntoa_r(G_Addr->g_addr, addrbuf)); 2616 } 2617 } 2618 2619 /** @ingroup Logging 2620 * @brief Output Global table to log 2621 * 2622 * @param la Pointer to the relevant libalias instance 2623 */ 2624 static void logSctpGlobal(struct libalias *la) 2625 { 2626 u_int i; 2627 struct sctp_nat_assoc *assoc = NULL; 2628 2629 SctpAliasLog("G->\n"); 2630 for (i=0; i < la->sctpNatTableSize; i++) { 2631 LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) { 2632 logsctpassoc(assoc, " "); 2633 } 2634 } 2635 } 2636 2637 /** @ingroup Logging 2638 * @brief Output Local table to log 2639 * 2640 * @param la Pointer to the relevant libalias instance 2641 */ 2642 static void logSctpLocal(struct libalias *la) 2643 { 2644 u_int i; 2645 struct sctp_nat_assoc *assoc = NULL; 2646 2647 SctpAliasLog("L->\n"); 2648 for (i=0; i < la->sctpNatTableSize; i++) { 2649 LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) { 2650 logsctpassoc(assoc, " "); 2651 } 2652 } 2653 } 2654 2655 /** @ingroup Logging 2656 * @brief Output timer queue to log 2657 * 2658 * @param la Pointer to the relevant libalias instance 2659 */ 2660 static void logTimerQ(struct libalias *la) 2661 { 2662 static char buf[50]; 2663 u_int i; 2664 struct sctp_nat_assoc *assoc = NULL; 2665 2666 SctpAliasLog("t->\n"); 2667 for (i=0; i < SN_TIMER_QUEUE_SIZE; i++) { 2668 LIST_FOREACH(assoc, &la->sctpNatTimer.TimerQ[i], timer_Q) { 2669 snprintf(buf, 50, " l=%u ",i); 2670 //SctpAliasLog(la->logDesc," l=%d ",i); 2671 logsctpassoc(assoc, buf); 2672 } 2673 } 2674 } 2675 2676 /** @ingroup Logging 2677 * @brief Sctp NAT logging function 2678 * 2679 * This function is based on a similar function in alias_db.c 2680 * 2681 * @param str/stream logging descriptor 2682 * @param format printf type string 2683 */ 2684 #ifdef _KERNEL 2685 static void 2686 SctpAliasLog(const char *format, ...) 2687 { 2688 char buffer[LIBALIAS_BUF_SIZE]; 2689 va_list ap; 2690 va_start(ap, format); 2691 vsnprintf(buffer, LIBALIAS_BUF_SIZE, format, ap); 2692 va_end(ap); 2693 log(LOG_SECURITY | LOG_INFO, 2694 "alias_sctp: %s", buffer); 2695 } 2696 #else 2697 static void 2698 SctpAliasLog(FILE *stream, const char *format, ...) 2699 { 2700 va_list ap; 2701 2702 va_start(ap, format); 2703 vfprintf(stream, format, ap); 2704 va_end(ap); 2705 fflush(stream); 2706 } 2707 #endif 2708