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