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