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