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