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