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