1215153Slstewart/*- 2215153Slstewart * Copyright (c) 2008 3215153Slstewart * Swinburne University of Technology, Melbourne, Australia. 4215153Slstewart * 5186543Spiso * Redistribution and use in source and binary forms, with or without 6186543Spiso * modification, are permitted provided that the following conditions 7186543Spiso * are met: 8186543Spiso * 1. Redistributions of source code must retain the above copyright 9186543Spiso * notice, this list of conditions and the following disclaimer. 10186543Spiso * 2. Redistributions in binary form must reproduce the above copyright 11186543Spiso * notice, this list of conditions and the following disclaimer in the 12186543Spiso * documentation and/or other materials provided with the distribution. 13215153Slstewart * 14186543Spiso * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS "AS IS" AND 15186543Spiso * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16186543Spiso * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17186543Spiso * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18186543Spiso * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19186543Spiso * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20186543Spiso * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21186543Spiso * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22186543Spiso * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23186543Spiso * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24186543Spiso * SUCH DAMAGE. 25215153Slstewart */ 26215153Slstewart 27215153Slstewart/* 28188294Spiso * Alias_sctp forms part of the libalias kernel module to handle 29188294Spiso * Network Address Translation (NAT) for the SCTP protocol. 30188294Spiso * 31188294Spiso * This software was developed by David A. Hayes and Jason But 32188294Spiso * 33188294Spiso * The design is outlined in CAIA technical report number 080618A 34188294Spiso * (D. Hayes and J. But, "Alias_sctp Version 0.1: SCTP NAT implementation in IPFW") 35188294Spiso * 36188294Spiso * Development is part of the CAIA SONATA project, 37188294Spiso * proposed by Jason But and Grenville Armitage: 38188294Spiso * http://caia.swin.edu.au/urp/sonata/ 39188294Spiso * 40188294Spiso * 41188294Spiso * This project has been made possible in part by a grant from 42188294Spiso * the Cisco University Research Program Fund at Community 43188294Spiso * Foundation Silicon Valley. 44188294Spiso * 45186543Spiso */ 46186543Spiso/** @mainpage 47186543Spiso * Alias_sctp is part of the SONATA (http://caia.swin.edu.au/urp/sonata) project 48186543Spiso * to develop and release a BSD licensed implementation of a Network Address 49186543Spiso * Translation (NAT) module that supports the Stream Control Transmission 50186543Spiso * Protocol (SCTP). 51186543Spiso * 52186543Spiso * Traditional address and port number look ups are inadequate for SCTP's 53186543Spiso * operation due to both processing requirements and issues with multi-homing. 54186543Spiso * Alias_sctp integrates with FreeBSD's ipfw/libalias NAT system. 55186543Spiso * 56186543Spiso * Version 0.2 features include: 57186543Spiso * - Support for global multi-homing 58186543Spiso * - Support for ASCONF modification from Internet Draft 59186543Spiso * (draft-stewart-behave-sctpnat-04, R. Stewart and M. Tuexen, "Stream control 60186543Spiso * transmission protocol (SCTP) network address translation," Jul. 2008) to 61186543Spiso * provide support for multi-homed privately addressed hosts 62186543Spiso * - Support for forwarding of T-flagged packets 63186543Spiso * - Generation and delivery of AbortM/ErrorM packets upon detection of NAT 64186543Spiso * collisions 65186543Spiso * - Per-port forwarding rules 66186543Spiso * - Dynamically controllable logging and statistics 67186543Spiso * - Dynamic management of timers 68186543Spiso * - Dynamic control of hash-table size 69186543Spiso */ 70186543Spiso 71188294Spiso/* $FreeBSD: stable/10/sys/netinet/libalias/alias_sctp.c 332284 2018-04-08 16:29:24Z tuexen $ */ 72188294Spiso 73186543Spiso#ifdef _KERNEL 74186543Spiso#include <machine/stdarg.h> 75186543Spiso#include <sys/param.h> 76186543Spiso#include <sys/systm.h> 77186543Spiso#include <sys/kernel.h> 78186543Spiso#include <sys/module.h> 79186543Spiso#include <sys/syslog.h> 80186543Spiso#include <netinet/libalias/alias_sctp.h> 81186543Spiso#include <netinet/libalias/alias.h> 82186543Spiso#include <netinet/libalias/alias_local.h> 83186543Spiso#include <netinet/sctp_crc32.h> 84186543Spiso#include <machine/in_cksum.h> 85186543Spiso#else 86186543Spiso#include "alias_sctp.h" 87186543Spiso#include <arpa/inet.h> 88186543Spiso#include "alias.h" 89186543Spiso#include "alias_local.h" 90186543Spiso#include <machine/in_cksum.h> 91188605Srrs#include <sys/libkern.h> 92186543Spiso#endif //#ifdef _KERNEL 93186543Spiso 94186543Spiso/* ---------------------------------------------------------------------- 95186543Spiso * FUNCTION PROTOTYPES 96186543Spiso * ---------------------------------------------------------------------- 97186543Spiso */ 98186543Spiso/* Packet Parsing Functions */ 99186543Spisostatic int sctp_PktParser(struct libalias *la, int direction, struct ip *pip, 100188294Spiso struct sctp_nat_msg *sm, struct sctp_nat_assoc **passoc); 101186543Spisostatic int GetAsconfVtags(struct libalias *la, struct sctp_nat_msg *sm, 102188294Spiso uint32_t *l_vtag, uint32_t *g_vtag, int direction); 103186543Spisostatic int IsASCONFack(struct libalias *la, struct sctp_nat_msg *sm, int direction); 104186543Spiso 105186543Spisostatic void AddGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int direction); 106186543Spisostatic int Add_Global_Address_to_List(struct sctp_nat_assoc *assoc, struct sctp_GlobalAddress *G_addr); 107186543Spisostatic void RmGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int direction); 108186543Spisostatic int IsADDorDEL(struct libalias *la, struct sctp_nat_msg *sm, int direction); 109186543Spiso 110186543Spiso/* State Machine Functions */ 111186543Spisostatic int ProcessSctpMsg(struct libalias *la, int direction, \ 112188294Spiso struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc); 113186543Spiso 114186543Spisostatic int ID_process(struct libalias *la, int direction,\ 115188294Spiso struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); 116186543Spisostatic int INi_process(struct libalias *la, int direction,\ 117188294Spiso struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); 118186543Spisostatic int INa_process(struct libalias *la, int direction,\ 119188294Spiso struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); 120186543Spisostatic int UP_process(struct libalias *la, int direction,\ 121188294Spiso struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); 122186543Spisostatic int CL_process(struct libalias *la, int direction,\ 123188294Spiso struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm); 124186543Spisostatic void TxAbortErrorM(struct libalias *la, struct sctp_nat_msg *sm,\ 125188294Spiso struct sctp_nat_assoc *assoc, int sndrply, int direction); 126186543Spiso 127186543Spiso/* Hash Table Functions */ 128186543Spisostatic struct sctp_nat_assoc* 129186543SpisoFindSctpLocal(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); 130186543Spisostatic struct sctp_nat_assoc* 131186543SpisoFindSctpGlobal(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uint16_t g_port, uint16_t l_port, int *partial_match); 132186543Spisostatic struct sctp_nat_assoc* 133186543SpisoFindSctpGlobalClash(struct libalias *la, struct sctp_nat_assoc *Cassoc); 134186543Spisostatic struct sctp_nat_assoc* 135186543SpisoFindSctpLocalT(struct libalias *la, struct in_addr g_addr, uint32_t l_vtag, uint16_t g_port, uint16_t l_port); 136186543Spisostatic struct sctp_nat_assoc* 137186543SpisoFindSctpGlobalT(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uint16_t l_port, uint16_t g_port); 138186543Spiso 139186543Spisostatic int AddSctpAssocLocal(struct libalias *la, struct sctp_nat_assoc *assoc, struct in_addr g_addr); 140186543Spisostatic int AddSctpAssocGlobal(struct libalias *la, struct sctp_nat_assoc *assoc); 141186543Spisostatic void RmSctpAssoc(struct libalias *la, struct sctp_nat_assoc *assoc); 142186543Spisostatic void freeGlobalAddressList(struct sctp_nat_assoc *assoc); 143186543Spiso 144186543Spiso/* Timer Queue Functions */ 145186543Spisostatic void sctp_AddTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc); 146186543Spisostatic void sctp_RmTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc); 147186543Spisostatic void sctp_ResetTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc, int newexp); 148186543Spisovoid sctp_CheckTimers(struct libalias *la); 149186543Spiso 150186543Spiso 151186543Spiso/* Logging Functions */ 152186543Spisostatic void logsctperror(char* errormsg, uint32_t vtag, int error, int direction); 153186543Spisostatic void logsctpparse(int direction, struct sctp_nat_msg *sm); 154186543Spisostatic void logsctpassoc(struct sctp_nat_assoc *assoc, char *s); 155186543Spisostatic void logTimerQ(struct libalias *la); 156186543Spisostatic void logSctpGlobal(struct libalias *la); 157186543Spisostatic void logSctpLocal(struct libalias *la); 158186543Spiso#ifdef _KERNEL 159186543Spisostatic void SctpAliasLog(const char *format, ...); 160186543Spiso#endif 161186543Spiso 162186543Spiso/** @defgroup external External code changes and modifications 163186543Spiso * 164186543Spiso * Some changes have been made to files external to alias_sctp.(c|h). These 165186543Spiso * changes are primarily due to code needing to call static functions within 166186543Spiso * those files or to perform extra functionality that can only be performed 167186543Spiso * within these files. 168186543Spiso */ 169186543Spiso/** @ingroup external 170186543Spiso * @brief Log current statistics for the libalias instance 171186543Spiso * 172186543Spiso * This function is defined in alias_db.c, since it calls static functions in 173186543Spiso * this file 174186543Spiso * 175186543Spiso * Calls the higher level ShowAliasStats() in alias_db.c which logs all current 176186543Spiso * statistics about the libalias instance - including SCTP statistics 177186543Spiso * 178186543Spiso * @param la Pointer to the libalias instance 179186543Spiso */ 180186543Spisovoid SctpShowAliasStats(struct libalias *la); 181186543Spiso 182186543Spiso#ifdef _KERNEL 183186543Spiso 184227293Sedstatic MALLOC_DEFINE(M_SCTPNAT, "sctpnat", "sctp nat dbs"); 185186543Spiso/* Use kernel allocator. */ 186186543Spiso#ifdef _SYS_MALLOC_H_ 187186543Spiso#define sn_malloc(x) malloc(x, M_SCTPNAT, M_NOWAIT|M_ZERO) 188332282Stuexen#define sn_calloc(n,x) sn_malloc((x) * (n)) 189186543Spiso#define sn_free(x) free(x, M_SCTPNAT) 190186543Spiso#endif// #ifdef _SYS_MALLOC_H_ 191186543Spiso 192186543Spiso#else //#ifdef _KERNEL 193186543Spiso#define sn_malloc(x) malloc(x) 194186543Spiso#define sn_calloc(n, x) calloc(n, x) 195186543Spiso#define sn_free(x) free(x) 196186543Spiso 197186543Spiso#endif //#ifdef _KERNEL 198186543Spiso 199186543Spiso/** @defgroup packet_parser SCTP Packet Parsing 200186543Spiso * 201186543Spiso * Macros to: 202186543Spiso * - Return pointers to the first and next SCTP chunks within an SCTP Packet 203186543Spiso * - Define possible return values of the packet parsing process 204186543Spiso * - SCTP message types for storing in the sctp_nat_msg structure @{ 205186543Spiso */ 206186543Spiso 207186543Spiso#define SN_SCTP_FIRSTCHUNK(sctphead) (struct sctp_chunkhdr *)(((char *)sctphead) + sizeof(struct sctphdr)) 208186543Spiso/**< Returns a pointer to the first chunk in an SCTP packet given a pointer to the SCTP header */ 209186543Spiso 210186543Spiso#define SN_SCTP_NEXTCHUNK(chunkhead) (struct sctp_chunkhdr *)(((char *)chunkhead) + SCTP_SIZE32(ntohs(chunkhead->chunk_length))) 211186543Spiso/**< Returns a pointer to the next chunk in an SCTP packet given a pointer to the current chunk */ 212186543Spiso 213186543Spiso#define SN_SCTP_NEXTPARAM(param) (struct sctp_paramhdr *)(((char *)param) + SCTP_SIZE32(ntohs(param->param_length))) 214186543Spiso/**< Returns a pointer to the next parameter in an SCTP packet given a pointer to the current parameter */ 215186543Spiso 216186543Spiso#define SN_MIN_CHUNK_SIZE 4 /**< Smallest possible SCTP chunk size in bytes */ 217186543Spiso#define SN_MIN_PARAM_SIZE 4 /**< Smallest possible SCTP param size in bytes */ 218186543Spiso#define SN_VTAG_PARAM_SIZE 12 /**< Size of SCTP ASCONF vtag param in bytes */ 219186543Spiso#define SN_ASCONFACK_PARAM_SIZE 8 /**< Size of SCTP ASCONF ACK param in bytes */ 220186543Spiso 221186543Spiso/* Packet parsing return codes */ 222186543Spiso#define SN_PARSE_OK 0 /**< Packet parsed for SCTP messages */ 223186543Spiso#define SN_PARSE_ERROR_IPSHL 1 /**< Packet parsing error - IP and SCTP common header len */ 224186543Spiso#define SN_PARSE_ERROR_AS_MALLOC 2 /**< Packet parsing error - assoc malloc */ 225186543Spiso#define SN_PARSE_ERROR_CHHL 3 /**< Packet parsing error - Chunk header len */ 226186543Spiso#define SN_PARSE_ERROR_DIR 4 /**< Packet parsing error - Direction */ 227186543Spiso#define SN_PARSE_ERROR_VTAG 5 /**< Packet parsing error - Vtag */ 228186543Spiso#define SN_PARSE_ERROR_CHUNK 6 /**< Packet parsing error - Chunk */ 229186543Spiso#define SN_PARSE_ERROR_PORT 7 /**< Packet parsing error - Port=0 */ 230186543Spiso#define SN_PARSE_ERROR_LOOKUP 8 /**< Packet parsing error - Lookup */ 231186543Spiso#define SN_PARSE_ERROR_PARTIALLOOKUP 9 /**< Packet parsing error - partial lookup only found */ 232186543Spiso#define SN_PARSE_ERROR_LOOKUP_ABORT 10 /**< Packet parsing error - Lookup - but abort packet */ 233186543Spiso 234186543Spiso/* Alias_sctp performs its processing based on a number of key messages */ 235186543Spiso#define SN_SCTP_ABORT 0x0000 /**< a packet containing an ABORT chunk */ 236186543Spiso#define SN_SCTP_INIT 0x0001 /**< a packet containing an INIT chunk */ 237186543Spiso#define SN_SCTP_INITACK 0x0002 /**< a packet containing an INIT-ACK chunk */ 238186543Spiso#define SN_SCTP_SHUTCOMP 0x0010 /**< a packet containing a SHUTDOWN-COMPLETE chunk */ 239186543Spiso#define SN_SCTP_SHUTACK 0x0020 /**< a packet containing a SHUTDOWN-ACK chunk */ 240186543Spiso#define SN_SCTP_ASCONF 0x0100 /**< a packet containing an ASCONF chunk */ 241186543Spiso#define SN_SCTP_ASCONFACK 0x0200 /**< a packet containing an ASCONF-ACK chunk */ 242186543Spiso#define SN_SCTP_OTHER 0xFFFF /**< a packet containing a chunk that is not of interest */ 243186543Spiso 244186543Spiso/** @} 245186543Spiso * @defgroup state_machine SCTP NAT State Machine 246186543Spiso * 247186543Spiso * Defines the various states an association can be within the NAT @{ 248186543Spiso */ 249186543Spiso#define SN_ID 0x0000 /**< Idle state */ 250186543Spiso#define SN_INi 0x0010 /**< Initialising, waiting for InitAck state */ 251186543Spiso#define SN_INa 0x0020 /**< Initialising, waiting for AddIpAck state */ 252186543Spiso#define SN_UP 0x0100 /**< Association in UP state */ 253186543Spiso#define SN_CL 0x1000 /**< Closing state */ 254186543Spiso#define SN_RM 0x2000 /**< Removing state */ 255186543Spiso 256186543Spiso/** @} 257186543Spiso * @defgroup Logging Logging Functionality 258186543Spiso * 259186543Spiso * Define various log levels and a macro to call specified log functions only if 260186543Spiso * the current log level (sysctl_log_level) matches the specified level @{ 261186543Spiso */ 262186543Spiso#define SN_LOG_LOW 0 263186543Spiso#define SN_LOG_EVENT 1 264186543Spiso#define SN_LOG_INFO 2 265186543Spiso#define SN_LOG_DETAIL 3 266186543Spiso#define SN_LOG_DEBUG 4 267186543Spiso#define SN_LOG_DEBUG_MAX 5 268186543Spiso 269186543Spiso#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 */ 270186543Spiso 271186543Spiso/** @} 272186543Spiso * @defgroup Hash Hash Table Macros and Functions 273186543Spiso * 274186543Spiso * Defines minimum/maximum/default values for the hash table size @{ 275186543Spiso */ 276186543Spiso#define SN_MIN_HASH_SIZE 101 /**< Minimum hash table size (set to stop users choosing stupid values) */ 277186543Spiso#define SN_MAX_HASH_SIZE 1000001 /**< Maximum hash table size (NB must be less than max int) */ 278186543Spiso#define SN_DEFAULT_HASH_SIZE 2003 /**< A reasonable default size for the hash tables */ 279186543Spiso 280186543Spiso#define SN_LOCAL_TBL 0x01 /**< assoc in local table */ 281186543Spiso#define SN_GLOBAL_TBL 0x02 /**< assoc in global table */ 282186543Spiso#define SN_BOTH_TBL 0x03 /**< assoc in both tables */ 283186543Spiso#define SN_WAIT_TOLOCAL 0x10 /**< assoc waiting for TOLOCAL asconf ACK*/ 284186543Spiso#define SN_WAIT_TOGLOBAL 0x20 /**< assoc waiting for TOLOCAL asconf ACK*/ 285186543Spiso#define SN_NULL_TBL 0x00 /**< assoc in No table */ 286186543Spiso#define SN_MAX_GLOBAL_ADDRESSES 100 /**< absolute maximum global address count*/ 287186543Spiso 288186543Spiso#define SN_ADD_OK 0 /**< Association added to the table */ 289186543Spiso#define SN_ADD_CLASH 1 /**< Clash when trying to add the assoc. info to the table */ 290186543Spiso 291186543Spiso#define SN_TABLE_HASH(vtag, port, size) (((u_int) vtag + (u_int) port) % (u_int) size) /**< Calculate the hash table lookup position */ 292186543Spiso 293186543Spiso/** @} 294186543Spiso * @defgroup Timer Timer Queue Macros and Functions 295186543Spiso * 296186543Spiso * Timer macros set minimum/maximum timeout values and calculate timer expiry 297186543Spiso * times for the provided libalias instance @{ 298186543Spiso */ 299186543Spiso#define SN_MIN_TIMER 1 300186543Spiso#define SN_MAX_TIMER 600 301186543Spiso#define SN_TIMER_QUEUE_SIZE SN_MAX_TIMER+2 302186543Spiso 303186543Spiso#define SN_I_T(la) (la->timeStamp + sysctl_init_timer) /**< INIT State expiration time in seconds */ 304186543Spiso#define SN_U_T(la) (la->timeStamp + sysctl_up_timer) /**< UP State expiration time in seconds */ 305186543Spiso#define SN_C_T(la) (la->timeStamp + sysctl_shutdown_timer) /**< CL State expiration time in seconds */ 306186543Spiso#define SN_X_T(la) (la->timeStamp + sysctl_holddown_timer) /**< Wait after a shutdown complete in seconds */ 307186543Spiso 308186543Spiso/** @} 309186543Spiso * @defgroup sysctl SysCtl Variable and callback function declarations 310186543Spiso * 311186543Spiso * Sysctl variables to modify NAT functionality in real-time along with associated functions 312186543Spiso * to manage modifications to the sysctl variables @{ 313186543Spiso */ 314186543Spiso 315186543Spiso/* Callbacks */ 316186543Spisoint sysctl_chg_loglevel(SYSCTL_HANDLER_ARGS); 317186543Spisoint sysctl_chg_timer(SYSCTL_HANDLER_ARGS); 318186543Spisoint sysctl_chg_hashtable_size(SYSCTL_HANDLER_ARGS); 319186543Spisoint sysctl_chg_error_on_ootb(SYSCTL_HANDLER_ARGS); 320186543Spisoint sysctl_chg_accept_global_ootb_addip(SYSCTL_HANDLER_ARGS); 321186543Spisoint sysctl_chg_initialising_chunk_proc_limit(SYSCTL_HANDLER_ARGS); 322186543Spisoint sysctl_chg_chunk_proc_limit(SYSCTL_HANDLER_ARGS); 323186543Spisoint sysctl_chg_param_proc_limit(SYSCTL_HANDLER_ARGS); 324186543Spisoint sysctl_chg_track_global_addresses(SYSCTL_HANDLER_ARGS); 325186543Spiso 326186543Spiso/* Sysctl variables */ 327186543Spiso/** @brief net.inet.ip.alias.sctp.log_level */ 328186543Spisostatic u_int sysctl_log_level = 0; /**< Stores the current level of logging */ 329186543Spiso/** @brief net.inet.ip.alias.sctp.init_timer */ 330186543Spisostatic u_int sysctl_init_timer = 15; /**< Seconds to hold an association in the table waiting for an INIT-ACK or AddIP-ACK */ 331186543Spiso/** @brief net.inet.ip.alias.sctp.up_timer */ 332186543Spisostatic u_int sysctl_up_timer = 300; /**< Seconds to hold an association in the table while no packets are transmitted */ 333186543Spiso/** @brief net.inet.ip.alias.sctp.shutdown_timer */ 334186543Spisostatic u_int sysctl_shutdown_timer = 15; /**< Seconds to hold an association in the table waiting for a SHUTDOWN-COMPLETE */ 335186543Spiso/** @brief net.inet.ip.alias.sctp.holddown_timer */ 336186543Spisostatic 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) */ 337186543Spiso/** @brief net.inet.ip.alias.sctp.hashtable_size */ 338186543Spisostatic 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 */ 339186543Spiso/** @brief net.inet.ip.alias.sctp.error_on_ootb */ 340186543Spisostatic u_int sysctl_error_on_ootb = 1; /**< NAT response to receipt of OOTB packet 341188294Spiso (0 - No response, 1 - NAT will send ErrorM only to local side, 342188294Spiso 2 - NAT will send local ErrorM and global ErrorM if there was a partial association match 343188294Spiso 3 - NAT will send ErrorM to both local and global) */ 344186543Spiso/** @brief net.inet.ip.alias.sctp.accept_global_ootb_addip */ 345186543Spisostatic 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)) */ 346186543Spiso/** @brief net.inet.ip.alias.sctp.initialising_chunk_proc_limit */ 347186543Spisostatic 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) */ 348186543Spiso/** @brief net.inet.ip.alias.sctp.param_proc_limit */ 349186543Spisostatic u_int sysctl_chunk_proc_limit = 5; /**< A limit on the number of chunks that should be searched (DoS prevention) */ 350186543Spiso/** @brief net.inet.ip.alias.sctp.param_proc_limit */ 351186543Spisostatic u_int sysctl_param_proc_limit = 25; /**< A limit on the number of parameters (in chunks) that should be searched (DoS prevention) */ 352186543Spiso/** @brief net.inet.ip.alias.sctp.track_global_addresses */ 353186543Spisostatic 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) 354188294Spiso If set to >=1 the NAT will track that many global IP addresses. This may reduce look up table conflicts, but increases processing */ 355186543Spiso 356186543Spiso#define SN_NO_ERROR_ON_OOTB 0 /**< Send no errorM on out of the blue packets */ 357186543Spiso#define SN_LOCAL_ERROR_ON_OOTB 1 /**< Send only local errorM on out of the blue packets */ 358186543Spiso#define SN_LOCALandPARTIAL_ERROR_ON_OOTB 2 /**< Send local errorM and global errorM for out of the blue packets only if partial match found */ 359186543Spiso#define SN_ERROR_ON_OOTB 3 /**< Send errorM on out of the blue packets */ 360186543Spiso 361186543Spiso#ifdef SYSCTL_NODE 362186543Spiso 363186543SpisoSYSCTL_DECL(_net_inet); 364186543SpisoSYSCTL_DECL(_net_inet_ip); 365186543SpisoSYSCTL_DECL(_net_inet_ip_alias); 366186543Spiso 367227309Sedstatic SYSCTL_NODE(_net_inet_ip_alias, OID_AUTO, sctp, CTLFLAG_RW, NULL, 368227309Sed "SCTP NAT"); 369186543SpisoSYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, log_level, CTLTYPE_UINT | CTLFLAG_RW, 370188294Spiso &sysctl_log_level, 0, sysctl_chg_loglevel, "IU", 371188294Spiso "Level of detail (0 - default, 1 - event, 2 - info, 3 - detail, 4 - debug, 5 - max debug)"); 372186543SpisoSYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, init_timer, CTLTYPE_UINT | CTLFLAG_RW, 373188294Spiso &sysctl_init_timer, 0, sysctl_chg_timer, "IU", 374188294Spiso "Timeout value (s) while waiting for (INIT-ACK|AddIP-ACK)"); 375186543SpisoSYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, up_timer, CTLTYPE_UINT | CTLFLAG_RW, 376188294Spiso &sysctl_up_timer, 0, sysctl_chg_timer, "IU", 377188294Spiso "Timeout value (s) to keep an association up with no traffic"); 378186543SpisoSYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, shutdown_timer, CTLTYPE_UINT | CTLFLAG_RW, 379188294Spiso &sysctl_shutdown_timer, 0, sysctl_chg_timer, "IU", 380188294Spiso "Timeout value (s) while waiting for SHUTDOWN-COMPLETE"); 381186543SpisoSYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, holddown_timer, CTLTYPE_UINT | CTLFLAG_RW, 382188294Spiso &sysctl_holddown_timer, 0, sysctl_chg_timer, "IU", 383188294Spiso "Hold association in table for this many seconds after receiving a SHUTDOWN-COMPLETE"); 384186543SpisoSYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, hashtable_size, CTLTYPE_UINT | CTLFLAG_RW, 385188294Spiso &sysctl_hashtable_size, 0, sysctl_chg_hashtable_size, "IU", 386188294Spiso "Size of hash tables used for NAT lookups (100 < prime_number > 1000001)"); 387186543SpisoSYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, error_on_ootb, CTLTYPE_UINT | CTLFLAG_RW, 388188294Spiso &sysctl_error_on_ootb, 0, sysctl_chg_error_on_ootb, "IU", 389188294Spiso "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)"); 390186543SpisoSYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, accept_global_ootb_addip, CTLTYPE_UINT | CTLFLAG_RW, 391188294Spiso &sysctl_accept_global_ootb_addip, 0, sysctl_chg_accept_global_ootb_addip, "IU", 392188294Spiso "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)"); 393186543SpisoSYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, initialising_chunk_proc_limit, CTLTYPE_UINT | CTLFLAG_RW, 394188294Spiso &sysctl_initialising_chunk_proc_limit, 0, sysctl_chg_initialising_chunk_proc_limit, "IU", 395188294Spiso "Number of chunks that should be processed if there is no current association found:\n\t > 0 (A high value is a DoS risk)"); 396186543SpisoSYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, chunk_proc_limit, CTLTYPE_UINT | CTLFLAG_RW, 397188294Spiso &sysctl_chunk_proc_limit, 0, sysctl_chg_chunk_proc_limit, "IU", 398188294Spiso "Number of chunks that should be processed to find key chunk:\n\t>= initialising_chunk_proc_limit (A high value is a DoS risk)"); 399186543SpisoSYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, param_proc_limit, CTLTYPE_UINT | CTLFLAG_RW, 400188294Spiso &sysctl_param_proc_limit, 0, sysctl_chg_param_proc_limit, "IU", 401188294Spiso "Number of parameters (in a chunk) that should be processed to find key parameters:\n\t> 1 (A high value is a DoS risk)"); 402186543SpisoSYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, track_global_addresses, CTLTYPE_UINT | CTLFLAG_RW, 403188294Spiso &sysctl_track_global_addresses, 0, sysctl_chg_track_global_addresses, "IU", 404188294Spiso "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"); 405186543Spiso 406186543Spiso#endif /* SYSCTL_NODE */ 407186543Spiso 408186543Spiso/** @} 409186543Spiso * @ingroup sysctl 410186543Spiso * @brief sysctl callback for changing net.inet.ip.fw.sctp.log_level 411186543Spiso * 412186543Spiso * Updates the variable sysctl_log_level to the provided value and ensures 413186543Spiso * it is in the valid range (SN_LOG_LOW -> SN_LOG_DEBUG) 414186543Spiso */ 415186543Spisoint sysctl_chg_loglevel(SYSCTL_HANDLER_ARGS) 416186543Spiso{ 417188294Spiso u_int level = *(u_int *)arg1; 418188294Spiso int error; 419186543Spiso 420188294Spiso error = sysctl_handle_int(oidp, &level, 0, req); 421188294Spiso if (error) return (error); 422186543Spiso 423332284Stuexen level = (level > SN_LOG_DEBUG_MAX)?(SN_LOG_DEBUG_MAX):(level); 424332284Stuexen level = (level < SN_LOG_LOW)?(SN_LOG_LOW):(level); 425332284Stuexen sysctl_log_level = level; 426188294Spiso return (0); 427186543Spiso} 428186543Spiso 429186543Spiso/** @ingroup sysctl 430186543Spiso * @brief sysctl callback for changing net.inet.ip.fw.sctp.(init_timer|up_timer|shutdown_timer) 431186543Spiso * 432186543Spiso * Updates the timer-based sysctl variables. The new values are sanity-checked 433186543Spiso * to make sure that they are within the range SN_MIN_TIMER-SN_MAX_TIMER. The 434186543Spiso * holddown timer is allowed to be 0 435186543Spiso */ 436186543Spisoint sysctl_chg_timer(SYSCTL_HANDLER_ARGS) 437186543Spiso{ 438188294Spiso u_int timer = *(u_int *)arg1; 439188294Spiso int error; 440186543Spiso 441188294Spiso error = sysctl_handle_int(oidp, &timer, 0, req); 442188294Spiso if (error) return (error); 443186543Spiso 444188294Spiso timer = (timer > SN_MAX_TIMER)?(SN_MAX_TIMER):(timer); 445186543Spiso 446188294Spiso if (((u_int *)arg1) != &sysctl_holddown_timer) 447188294Spiso { 448188294Spiso timer = (timer < SN_MIN_TIMER)?(SN_MIN_TIMER):(timer); 449188294Spiso } 450186543Spiso 451188294Spiso *(u_int *)arg1 = timer; 452186543Spiso 453188294Spiso return (0); 454186543Spiso} 455186543Spiso 456186543Spiso/** @ingroup sysctl 457186543Spiso * @brief sysctl callback for changing net.inet.ip.alias.sctp.hashtable_size 458186543Spiso * 459186543Spiso * Updates the hashtable_size sysctl variable. The new value should be a prime 460186543Spiso * number. We sanity check to ensure that the size is within the range 461186543Spiso * SN_MIN_HASH_SIZE-SN_MAX_HASH_SIZE. We then check the provided number to see 462186543Spiso * if it is prime. We approximate by checking that (2,3,5,7,11) are not factors, 463186543Spiso * incrementing the user provided value until we find a suitable number. 464186543Spiso */ 465186543Spisoint sysctl_chg_hashtable_size(SYSCTL_HANDLER_ARGS) 466186543Spiso{ 467188294Spiso u_int size = *(u_int *)arg1; 468188294Spiso int error; 469186543Spiso 470188294Spiso error = sysctl_handle_int(oidp, &size, 0, req); 471188294Spiso if (error) return (error); 472186543Spiso 473188294Spiso size = (size < SN_MIN_HASH_SIZE)?(SN_MIN_HASH_SIZE):((size > SN_MAX_HASH_SIZE)?(SN_MAX_HASH_SIZE):(size)); 474186543Spiso 475188294Spiso size |= 0x00000001; /* make odd */ 476186543Spiso 477188294Spiso for(;(((size % 3) == 0) || ((size % 5) == 0) || ((size % 7) == 0) || ((size % 11) == 0)); size+=2); 478188294Spiso sysctl_hashtable_size = size; 479186543Spiso 480188294Spiso return (0); 481186543Spiso} 482186543Spiso 483186543Spiso/** @ingroup sysctl 484186543Spiso * @brief sysctl callback for changing net.inet.ip.alias.sctp.error_on_ootb 485186543Spiso * 486186543Spiso * Updates the error_on_clash sysctl variable. 487186543Spiso * If set to 0, no ErrorM will be sent if there is a look up table clash 488186543Spiso * If set to 1, an ErrorM is sent only to the local side 489186543Spiso * If set to 2, an ErrorM is sent to the local side and global side if there is 490186543Spiso * a partial association match 491186543Spiso * If set to 3, an ErrorM is sent to both local and global sides (DoS) risk. 492186543Spiso */ 493186543Spisoint sysctl_chg_error_on_ootb(SYSCTL_HANDLER_ARGS) 494186543Spiso{ 495188294Spiso u_int flag = *(u_int *)arg1; 496188294Spiso int error; 497186543Spiso 498188294Spiso error = sysctl_handle_int(oidp, &flag, 0, req); 499188294Spiso if (error) return (error); 500186543Spiso 501188294Spiso sysctl_error_on_ootb = (flag > SN_ERROR_ON_OOTB) ? SN_ERROR_ON_OOTB: flag; 502186543Spiso 503188294Spiso return (0); 504186543Spiso} 505186543Spiso 506186543Spiso/** @ingroup sysctl 507186543Spiso * @brief sysctl callback for changing net.inet.ip.alias.sctp.accept_global_ootb_addip 508186543Spiso * 509186543Spiso * If set to 1 the NAT will accept ootb global addip messages for processing (Security risk) 510186543Spiso * Default is 0, only responding to local ootb AddIP messages 511186543Spiso */ 512186543Spisoint sysctl_chg_accept_global_ootb_addip(SYSCTL_HANDLER_ARGS) 513186543Spiso{ 514188294Spiso u_int flag = *(u_int *)arg1; 515188294Spiso int error; 516186543Spiso 517188294Spiso error = sysctl_handle_int(oidp, &flag, 0, req); 518188294Spiso if (error) return (error); 519186543Spiso 520188294Spiso sysctl_accept_global_ootb_addip = (flag == 1) ? 1: 0; 521186543Spiso 522188294Spiso return (0); 523186543Spiso} 524186543Spiso 525186543Spiso/** @ingroup sysctl 526186543Spiso * @brief sysctl callback for changing net.inet.ip.alias.sctp.initialising_chunk_proc_limit 527186543Spiso * 528186543Spiso * Updates the initialising_chunk_proc_limit sysctl variable. Number of chunks 529186543Spiso * that should be processed if there is no current association found: > 0 (A 530186543Spiso * high value is a DoS risk) 531186543Spiso */ 532186543Spisoint sysctl_chg_initialising_chunk_proc_limit(SYSCTL_HANDLER_ARGS) 533186543Spiso{ 534188294Spiso u_int proclimit = *(u_int *)arg1; 535188294Spiso int error; 536186543Spiso 537188294Spiso error = sysctl_handle_int(oidp, &proclimit, 0, req); 538188294Spiso if (error) return (error); 539186543Spiso 540188294Spiso sysctl_initialising_chunk_proc_limit = (proclimit < 1) ? 1: proclimit; 541188294Spiso sysctl_chunk_proc_limit = 542188294Spiso (sysctl_chunk_proc_limit < sysctl_initialising_chunk_proc_limit) ? sysctl_initialising_chunk_proc_limit : sysctl_chunk_proc_limit; 543186543Spiso 544188294Spiso return (0); 545186543Spiso} 546186543Spiso 547186543Spiso/** @ingroup sysctl 548186543Spiso * @brief sysctl callback for changing net.inet.ip.alias.sctp.chunk_proc_limit 549186543Spiso * 550186543Spiso * Updates the chunk_proc_limit sysctl variable. 551186543Spiso * Number of chunks that should be processed to find key chunk: 552186543Spiso * >= initialising_chunk_proc_limit (A high value is a DoS risk) 553186543Spiso */ 554186543Spisoint sysctl_chg_chunk_proc_limit(SYSCTL_HANDLER_ARGS) 555186543Spiso{ 556188294Spiso u_int proclimit = *(u_int *)arg1; 557188294Spiso int error; 558186543Spiso 559188294Spiso error = sysctl_handle_int(oidp, &proclimit, 0, req); 560188294Spiso if (error) return (error); 561186543Spiso 562188294Spiso sysctl_chunk_proc_limit = 563188294Spiso (proclimit < sysctl_initialising_chunk_proc_limit) ? sysctl_initialising_chunk_proc_limit : proclimit; 564186543Spiso 565188294Spiso return (0); 566186543Spiso} 567186543Spiso 568186543Spiso 569186543Spiso/** @ingroup sysctl 570186543Spiso * @brief sysctl callback for changing net.inet.ip.alias.sctp.param_proc_limit 571186543Spiso * 572186543Spiso * Updates the param_proc_limit sysctl variable. 573186543Spiso * Number of parameters that should be processed to find key parameters: 574186543Spiso * > 1 (A high value is a DoS risk) 575186543Spiso */ 576186543Spisoint sysctl_chg_param_proc_limit(SYSCTL_HANDLER_ARGS) 577186543Spiso{ 578188294Spiso u_int proclimit = *(u_int *)arg1; 579188294Spiso int error; 580186543Spiso 581188294Spiso error = sysctl_handle_int(oidp, &proclimit, 0, req); 582188294Spiso if (error) return (error); 583186543Spiso 584188294Spiso sysctl_param_proc_limit = 585188294Spiso (proclimit < 2) ? 2 : proclimit; 586186543Spiso 587188294Spiso return (0); 588186543Spiso} 589186543Spiso 590186543Spiso/** @ingroup sysctl 591186543Spiso * @brief sysctl callback for changing net.inet.ip.alias.sctp.track_global_addresses 592186543Spiso * 593186543Spiso *Configures the global address tracking option within the NAT (0 - Global 594186543Spiso *tracking is disabled, > 0 - enables tracking but limits the number of global 595186543Spiso *IP addresses to this value) 596186543Spiso */ 597186543Spisoint sysctl_chg_track_global_addresses(SYSCTL_HANDLER_ARGS) 598186543Spiso{ 599188294Spiso u_int num_to_track = *(u_int *)arg1; 600188294Spiso int error; 601186543Spiso 602188294Spiso error = sysctl_handle_int(oidp, &num_to_track, 0, req); 603188294Spiso if (error) return (error); 604186543Spiso 605188294Spiso sysctl_track_global_addresses = (num_to_track > SN_MAX_GLOBAL_ADDRESSES) ? SN_MAX_GLOBAL_ADDRESSES : num_to_track; 606186543Spiso 607188294Spiso return (0); 608186543Spiso} 609186543Spiso 610186543Spiso 611186543Spiso/* ---------------------------------------------------------------------- 612186543Spiso * CODE BEGINS HERE 613186543Spiso * ---------------------------------------------------------------------- 614186543Spiso */ 615186543Spiso/** 616186543Spiso * @brief Initialises the SCTP NAT Implementation 617186543Spiso * 618186543Spiso * Creates the look-up tables and the timer queue and initialises all state 619186543Spiso * variables 620186543Spiso * 621186543Spiso * @param la Pointer to the relevant libalias instance 622186543Spiso */ 623186543Spisovoid AliasSctpInit(struct libalias *la) 624186543Spiso{ 625188294Spiso /* Initialise association tables*/ 626188294Spiso int i; 627188294Spiso la->sctpNatTableSize = sysctl_hashtable_size; 628188294Spiso SN_LOG(SN_LOG_EVENT, 629188294Spiso SctpAliasLog("Initialising SCTP NAT Instance (hash_table_size:%d)\n", la->sctpNatTableSize)); 630188294Spiso la->sctpTableLocal = sn_calloc(la->sctpNatTableSize, sizeof(struct sctpNatTableL)); 631188294Spiso la->sctpTableGlobal = sn_calloc(la->sctpNatTableSize, sizeof(struct sctpNatTableG)); 632188294Spiso la->sctpNatTimer.TimerQ = sn_calloc(SN_TIMER_QUEUE_SIZE, sizeof(struct sctpTimerQ)); 633188294Spiso /* Initialise hash table */ 634188294Spiso for (i = 0; i < la->sctpNatTableSize; i++) { 635188294Spiso LIST_INIT(&la->sctpTableLocal[i]); 636188294Spiso LIST_INIT(&la->sctpTableGlobal[i]); 637188294Spiso } 638186543Spiso 639188294Spiso /* Initialise circular timer Q*/ 640188294Spiso for (i = 0; i < SN_TIMER_QUEUE_SIZE; i++) 641188294Spiso LIST_INIT(&la->sctpNatTimer.TimerQ[i]); 642186543Spiso#ifdef _KERNEL 643188294Spiso la->sctpNatTimer.loc_time=time_uptime; /* la->timeStamp is not set yet */ 644186543Spiso#else 645188294Spiso la->sctpNatTimer.loc_time=la->timeStamp; 646186543Spiso#endif 647188294Spiso la->sctpNatTimer.cur_loc = 0; 648188294Spiso la->sctpLinkCount = 0; 649186543Spiso} 650186543Spiso 651186543Spiso/** 652186543Spiso * @brief Cleans-up the SCTP NAT Implementation prior to unloading 653186543Spiso * 654186543Spiso * Removes all entries from the timer queue, freeing associations as it goes. 655186543Spiso * We then free memory allocated to the look-up tables and the time queue 656186543Spiso * 657186543Spiso * NOTE: We do not need to traverse the look-up tables as each association 658186543Spiso * will always have an entry in the timer queue, freeing this memory 659186543Spiso * once will free all memory allocated to entries in the look-up tables 660186543Spiso * 661186543Spiso * @param la Pointer to the relevant libalias instance 662186543Spiso */ 663186543Spisovoid AliasSctpTerm(struct libalias *la) 664186543Spiso{ 665188294Spiso struct sctp_nat_assoc *assoc1, *assoc2; 666188294Spiso int i; 667186543Spiso 668188294Spiso LIBALIAS_LOCK_ASSERT(la); 669188294Spiso SN_LOG(SN_LOG_EVENT, 670188294Spiso SctpAliasLog("Removing SCTP NAT Instance\n")); 671188294Spiso for (i = 0; i < SN_TIMER_QUEUE_SIZE; i++) { 672188294Spiso assoc1 = LIST_FIRST(&la->sctpNatTimer.TimerQ[i]); 673188294Spiso while (assoc1 != NULL) { 674188294Spiso freeGlobalAddressList(assoc1); 675188294Spiso assoc2 = LIST_NEXT(assoc1, timer_Q); 676188294Spiso sn_free(assoc1); 677188294Spiso assoc1 = assoc2; 678188294Spiso } 679188294Spiso } 680186543Spiso 681188294Spiso sn_free(la->sctpTableLocal); 682188294Spiso sn_free(la->sctpTableGlobal); 683188294Spiso sn_free(la->sctpNatTimer.TimerQ); 684186543Spiso} 685186543Spiso 686186543Spiso/** 687186543Spiso * @brief Handles SCTP packets passed from libalias 688186543Spiso * 689186543Spiso * This function needs to actually NAT/drop packets and possibly create and 690186543Spiso * send AbortM or ErrorM packets in response. The process involves: 691186543Spiso * - Validating the direction parameter passed by the caller 692186543Spiso * - Checking and handling any expired timers for the NAT 693186543Spiso * - Calling sctp_PktParser() to parse the packet 694186543Spiso * - Call ProcessSctpMsg() to decide the appropriate outcome and to update 695186543Spiso * the NAT tables 696186543Spiso * - Based on the return code either: 697186543Spiso * - NAT the packet 698186543Spiso * - Construct and send an ErrorM|AbortM packet 699186543Spiso * - Mark the association for removal from the tables 700186543Spiso * - Potentially remove the association from all lookup tables 701186543Spiso * - Return the appropriate result to libalias 702186543Spiso * 703186543Spiso * @param la Pointer to the relevant libalias instance 704186543Spiso * @param pip Pointer to IP packet to process 705186543Spiso * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 706186543Spiso * 707186543Spiso * @return PKT_ALIAS_OK | PKT_ALIAS_IGNORE | PKT_ALIAS_ERROR 708186543Spiso */ 709186543Spisoint 710186543SpisoSctpAlias(struct libalias *la, struct ip *pip, int direction) 711186543Spiso{ 712188294Spiso int rtnval; 713188294Spiso struct sctp_nat_msg msg; 714188294Spiso struct sctp_nat_assoc *assoc = NULL; 715186543Spiso 716188294Spiso if ((direction != SN_TO_LOCAL) && (direction != SN_TO_GLOBAL)) { 717188294Spiso SctpAliasLog("ERROR: Invalid direction\n"); 718188294Spiso return(PKT_ALIAS_ERROR); 719188294Spiso } 720186543Spiso 721188294Spiso sctp_CheckTimers(la); /* Check timers */ 722186543Spiso 723188294Spiso /* Parse the packet */ 724188294Spiso rtnval = sctp_PktParser(la, direction, pip, &msg, &assoc); //using *char (change to mbuf when get code from paolo) 725188294Spiso switch (rtnval) { 726188294Spiso case SN_PARSE_OK: 727188294Spiso break; 728188294Spiso case SN_PARSE_ERROR_CHHL: 729188294Spiso /* Not an error if there is a chunk length parsing error and this is a fragmented packet */ 730188294Spiso if (ntohs(pip->ip_off) & IP_MF) { 731188294Spiso rtnval = SN_PARSE_OK; 732188294Spiso break; 733188294Spiso } 734188294Spiso SN_LOG(SN_LOG_EVENT, 735188294Spiso logsctperror("SN_PARSE_ERROR", msg.sctp_hdr->v_tag, rtnval, direction)); 736188294Spiso return(PKT_ALIAS_ERROR); 737188294Spiso case SN_PARSE_ERROR_PARTIALLOOKUP: 738188294Spiso if (sysctl_error_on_ootb > SN_LOCALandPARTIAL_ERROR_ON_OOTB) { 739188294Spiso SN_LOG(SN_LOG_EVENT, 740188294Spiso logsctperror("SN_PARSE_ERROR", msg.sctp_hdr->v_tag, rtnval, direction)); 741188294Spiso return(PKT_ALIAS_ERROR); 742188294Spiso } 743188294Spiso case SN_PARSE_ERROR_LOOKUP: 744188294Spiso if (sysctl_error_on_ootb == SN_ERROR_ON_OOTB || 745188294Spiso (sysctl_error_on_ootb == SN_LOCALandPARTIAL_ERROR_ON_OOTB && direction == SN_TO_LOCAL) || 746188294Spiso (sysctl_error_on_ootb == SN_LOCAL_ERROR_ON_OOTB && direction == SN_TO_GLOBAL)) { 747188294Spiso TxAbortErrorM(la, &msg, assoc, SN_REFLECT_ERROR, direction); /*NB assoc=NULL */ 748188294Spiso return(PKT_ALIAS_RESPOND); 749188294Spiso } 750188294Spiso default: 751188294Spiso SN_LOG(SN_LOG_EVENT, 752188294Spiso logsctperror("SN_PARSE_ERROR", msg.sctp_hdr->v_tag, rtnval, direction)); 753188294Spiso return(PKT_ALIAS_ERROR); 754188294Spiso } 755186543Spiso 756188294Spiso SN_LOG(SN_LOG_DETAIL, 757188294Spiso logsctpassoc(assoc, "*"); 758188294Spiso logsctpparse(direction, &msg); 759188294Spiso ); 760186543Spiso 761188294Spiso /* Process the SCTP message */ 762188294Spiso rtnval = ProcessSctpMsg(la, direction, &msg, assoc); 763186543Spiso 764188294Spiso SN_LOG(SN_LOG_DEBUG_MAX, 765188294Spiso logsctpassoc(assoc, "-"); 766188294Spiso logSctpLocal(la); 767188294Spiso logSctpGlobal(la); 768188294Spiso ); 769188294Spiso SN_LOG(SN_LOG_DEBUG, logTimerQ(la)); 770186543Spiso 771188294Spiso switch(rtnval){ 772188294Spiso case SN_NAT_PKT: 773188294Spiso switch(direction) { 774188294Spiso case SN_TO_LOCAL: 775188294Spiso DifferentialChecksum(&(msg.ip_hdr->ip_sum), 776188294Spiso &(assoc->l_addr), &(msg.ip_hdr->ip_dst), 2); 777188294Spiso msg.ip_hdr->ip_dst = assoc->l_addr; /* change dst address to local address*/ 778188294Spiso break; 779188294Spiso case SN_TO_GLOBAL: 780188294Spiso DifferentialChecksum(&(msg.ip_hdr->ip_sum), 781188294Spiso &(assoc->a_addr), &(msg.ip_hdr->ip_src), 2); 782188294Spiso msg.ip_hdr->ip_src = assoc->a_addr; /* change src to alias addr*/ 783188294Spiso break; 784188294Spiso default: 785188294Spiso rtnval = SN_DROP_PKT; /* shouldn't get here, but if it does drop packet */ 786188294Spiso SN_LOG(SN_LOG_LOW, logsctperror("ERROR: Invalid direction", msg.sctp_hdr->v_tag, rtnval, direction)); 787188294Spiso break; 788188294Spiso } 789188294Spiso break; 790188294Spiso case SN_DROP_PKT: 791188294Spiso SN_LOG(SN_LOG_DETAIL, logsctperror("SN_DROP_PKT", msg.sctp_hdr->v_tag, rtnval, direction)); 792188294Spiso break; 793188294Spiso case SN_REPLY_ABORT: 794188294Spiso case SN_REPLY_ERROR: 795188294Spiso case SN_SEND_ABORT: 796188294Spiso TxAbortErrorM(la, &msg, assoc, rtnval, direction); 797188294Spiso break; 798188294Spiso default: 799188294Spiso // big error, remove association and go to idle and write log messages 800188294Spiso SN_LOG(SN_LOG_LOW, logsctperror("SN_PROCESSING_ERROR", msg.sctp_hdr->v_tag, rtnval, direction)); 801188294Spiso assoc->state=SN_RM;/* Mark for removal*/ 802188294Spiso break; 803188294Spiso } 804186543Spiso 805188294Spiso /* Remove association if tagged for removal */ 806188294Spiso if (assoc->state == SN_RM) { 807188294Spiso if (assoc->TableRegister) { 808188294Spiso sctp_RmTimeOut(la, assoc); 809188294Spiso RmSctpAssoc(la, assoc); 810188294Spiso } 811188294Spiso LIBALIAS_LOCK_ASSERT(la); 812188294Spiso freeGlobalAddressList(assoc); 813188294Spiso sn_free(assoc); 814188294Spiso } 815188294Spiso switch(rtnval) { 816188294Spiso case SN_NAT_PKT: 817188294Spiso return(PKT_ALIAS_OK); 818188294Spiso case SN_SEND_ABORT: 819188294Spiso return(PKT_ALIAS_OK); 820188294Spiso case SN_REPLY_ABORT: 821188294Spiso case SN_REPLY_ERROR: 822188294Spiso case SN_REFLECT_ERROR: 823188294Spiso return(PKT_ALIAS_RESPOND); 824188294Spiso case SN_DROP_PKT: 825188294Spiso default: 826188294Spiso return(PKT_ALIAS_ERROR); 827188294Spiso } 828186543Spiso} 829186543Spiso 830186543Spiso/** 831186543Spiso * @brief Send an AbortM or ErrorM 832186543Spiso * 833186543Spiso * We construct the new SCTP packet to send in place of the existing packet we 834186543Spiso * have been asked to NAT. This function can only be called if the original 835186543Spiso * packet was successfully parsed as a valid SCTP packet. 836186543Spiso * 837186543Spiso * An AbortM (without cause) packet is the smallest SCTP packet available and as 838186543Spiso * such there is always space in the existing packet buffer to fit the AbortM 839186543Spiso * packet. An ErrorM packet is 4 bytes longer than the (the error cause is not 840186543Spiso * optional). An ErrorM is sent in response to an AddIP when the Vtag/address 841186543Spiso * combination, if added, will produce a conflict in the association look up 842186543Spiso * tables. It may also be used for an unexpected packet - a packet with no 843186543Spiso * matching association in the NAT table and we are requesting an AddIP so we 844186543Spiso * can add it. The smallest valid SCTP packet while the association is in an 845186543Spiso * up-state is a Heartbeat packet, which is big enough to be transformed to an 846186543Spiso * ErrorM. 847186543Spiso * 848186543Spiso * We create a temporary character array to store the packet as we are constructing 849186543Spiso * it. We then populate the array with appropriate values based on: 850186543Spiso * - Packet type (AbortM | ErrorM) 851186543Spiso * - Initial packet direction (SN_TO_LOCAL | SN_TO_GLOBAL) 852186543Spiso * - NAT response (Send packet | Reply packet) 853186543Spiso * 854186543Spiso * Once complete, we copy the contents of the temporary packet over the original 855186543Spiso * SCTP packet we were asked to NAT 856186543Spiso * 857186543Spiso * @param la Pointer to the relevant libalias instance 858186543Spiso * @param sm Pointer to sctp message information 859186543Spiso * @param assoc Pointer to current association details 860186543Spiso * @param sndrply SN_SEND_ABORT | SN_REPLY_ABORT | SN_REPLY_ERROR 861186543Spiso * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 862186543Spiso */ 863188605Srrsstatic uint32_t 864188605Srrslocal_sctp_finalize_crc32(uint32_t crc32c) 865188605Srrs{ 866188605Srrs /* This routine is duplicated from SCTP 867188605Srrs * we need to do that since it MAY be that SCTP 868188605Srrs * is NOT compiled into the kernel. The CRC32C routines 869188605Srrs * however are always available in libkern. 870188605Srrs */ 871188605Srrs uint32_t result; 872188605Srrs#if BYTE_ORDER == BIG_ENDIAN 873188605Srrs uint8_t byte0, byte1, byte2, byte3; 874188605Srrs 875188605Srrs#endif 876188605Srrs /* Complement the result */ 877188605Srrs result = ~crc32c; 878188605Srrs#if BYTE_ORDER == BIG_ENDIAN 879188605Srrs /* 880188605Srrs * For BIG-ENDIAN.. aka Motorola byte order the result is in 881188605Srrs * little-endian form. So we must manually swap the bytes. Then we 882188605Srrs * can call htonl() which does nothing... 883188605Srrs */ 884188605Srrs byte0 = result & 0x000000ff; 885188605Srrs byte1 = (result >> 8) & 0x000000ff; 886188605Srrs byte2 = (result >> 16) & 0x000000ff; 887188605Srrs byte3 = (result >> 24) & 0x000000ff; 888188605Srrs crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); 889188605Srrs#else 890188605Srrs /* 891188605Srrs * For INTEL platforms the result comes out in network order. No 892188605Srrs * htonl is required or the swap above. So we optimize out both the 893188605Srrs * htonl and the manual swap above. 894188605Srrs */ 895188605Srrs crc32c = result; 896188605Srrs#endif 897188605Srrs return (crc32c); 898188605Srrs} 899188605Srrs 900186543Spisostatic void 901186543SpisoTxAbortErrorM(struct libalias *la, struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int sndrply, int direction) 902186543Spiso{ 903188294Spiso int sctp_size = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_error_cause); 904188294Spiso int ip_size = sizeof(struct ip) + sctp_size; 905188294Spiso int include_error_cause = 1; 906188294Spiso char tmp_ip[ip_size]; 907186543Spiso 908188294Spiso if (ntohs(sm->ip_hdr->ip_len) < ip_size) { /* short packet, cannot send error cause */ 909188294Spiso include_error_cause = 0; 910188294Spiso ip_size = ip_size - sizeof(struct sctp_error_cause); 911188294Spiso sctp_size = sctp_size - sizeof(struct sctp_error_cause); 912188294Spiso } 913188294Spiso /* Assign header pointers packet */ 914188294Spiso struct ip* ip = (struct ip *) tmp_ip; 915188294Spiso struct sctphdr* sctp_hdr = (struct sctphdr *) ((char *) ip + sizeof(*ip)); 916188294Spiso struct sctp_chunkhdr* chunk_hdr = (struct sctp_chunkhdr *) ((char *) sctp_hdr + sizeof(*sctp_hdr)); 917188294Spiso struct sctp_error_cause* error_cause = (struct sctp_error_cause *) ((char *) chunk_hdr + sizeof(*chunk_hdr)); 918186543Spiso 919188294Spiso /* construct ip header */ 920188294Spiso ip->ip_v = sm->ip_hdr->ip_v; 921188294Spiso ip->ip_hl = 5; /* 5*32 bit words */ 922188294Spiso ip->ip_tos = 0; 923188294Spiso ip->ip_len = htons(ip_size); 924188294Spiso ip->ip_id = sm->ip_hdr->ip_id; 925188294Spiso ip->ip_off = 0; 926188294Spiso ip->ip_ttl = 255; 927188294Spiso ip->ip_p = IPPROTO_SCTP; 928188294Spiso /* 929188294Spiso The definitions below should be removed when they make it into the SCTP stack 930188294Spiso */ 931186543Spiso#define SCTP_MIDDLEBOX_FLAG 0x02 932186543Spiso#define SCTP_NAT_TABLE_COLLISION 0x00b0 933186543Spiso#define SCTP_MISSING_NAT 0x00b1 934188294Spiso chunk_hdr->chunk_type = (sndrply & SN_TX_ABORT) ? SCTP_ABORT_ASSOCIATION : SCTP_OPERATION_ERROR; 935188294Spiso chunk_hdr->chunk_flags = SCTP_MIDDLEBOX_FLAG; 936188294Spiso if (include_error_cause) { 937188294Spiso error_cause->code = htons((sndrply & SN_REFLECT_ERROR) ? SCTP_MISSING_NAT : SCTP_NAT_TABLE_COLLISION); 938188294Spiso error_cause->length = htons(sizeof(struct sctp_error_cause)); 939188294Spiso chunk_hdr->chunk_length = htons(sizeof(*chunk_hdr) + sizeof(struct sctp_error_cause)); 940188294Spiso } else { 941188294Spiso chunk_hdr->chunk_length = htons(sizeof(*chunk_hdr)); 942188294Spiso } 943186543Spiso 944188294Spiso /* set specific values */ 945188294Spiso switch(sndrply) { 946188294Spiso case SN_REFLECT_ERROR: 947188294Spiso chunk_hdr->chunk_flags |= SCTP_HAD_NO_TCB; /* set Tbit */ 948188294Spiso sctp_hdr->v_tag = sm->sctp_hdr->v_tag; 949188294Spiso break; 950188294Spiso case SN_REPLY_ERROR: 951188294Spiso sctp_hdr->v_tag = (direction == SN_TO_LOCAL) ? assoc->g_vtag : assoc->l_vtag ; 952188294Spiso break; 953188294Spiso case SN_SEND_ABORT: 954188294Spiso sctp_hdr->v_tag = sm->sctp_hdr->v_tag; 955188294Spiso break; 956188294Spiso case SN_REPLY_ABORT: 957188294Spiso sctp_hdr->v_tag = sm->sctpchnk.Init->initiate_tag; 958188294Spiso break; 959188294Spiso } 960186543Spiso 961188294Spiso /* Set send/reply values */ 962188294Spiso if (sndrply == SN_SEND_ABORT) { /*pass through NAT */ 963188294Spiso ip->ip_src = (direction == SN_TO_LOCAL) ? sm->ip_hdr->ip_src : assoc->a_addr; 964188294Spiso ip->ip_dst = (direction == SN_TO_LOCAL) ? assoc->l_addr : sm->ip_hdr->ip_dst; 965188294Spiso sctp_hdr->src_port = sm->sctp_hdr->src_port; 966188294Spiso sctp_hdr->dest_port = sm->sctp_hdr->dest_port; 967188294Spiso } else { /* reply and reflect */ 968188294Spiso ip->ip_src = sm->ip_hdr->ip_dst; 969188294Spiso ip->ip_dst = sm->ip_hdr->ip_src; 970188294Spiso sctp_hdr->src_port = sm->sctp_hdr->dest_port; 971188294Spiso sctp_hdr->dest_port = sm->sctp_hdr->src_port; 972188294Spiso } 973186543Spiso 974188294Spiso /* Calculate IP header checksum */ 975188294Spiso ip->ip_sum = in_cksum_hdr(ip); 976186543Spiso 977188294Spiso /* calculate SCTP header CRC32 */ 978188294Spiso sctp_hdr->checksum = 0; 979188605Srrs sctp_hdr->checksum = local_sctp_finalize_crc32(calculate_crc32c(0xffffffff, (unsigned char *) sctp_hdr, sctp_size)); 980186543Spiso 981188294Spiso memcpy(sm->ip_hdr, ip, ip_size); 982186543Spiso 983188294Spiso SN_LOG(SN_LOG_EVENT,SctpAliasLog("%s %s 0x%x (->%s:%u vtag=0x%x crc=0x%x)\n", 984188294Spiso ((sndrply == SN_SEND_ABORT) ? "Sending" : "Replying"), 985188294Spiso ((sndrply & SN_TX_ERROR) ? "ErrorM" : "AbortM"), 986188294Spiso (include_error_cause ? ntohs(error_cause->code) : 0), 987188294Spiso inet_ntoa(ip->ip_dst),ntohs(sctp_hdr->dest_port), 988188294Spiso ntohl(sctp_hdr->v_tag), ntohl(sctp_hdr->checksum))); 989186543Spiso} 990186543Spiso 991186543Spiso/* ---------------------------------------------------------------------- 992186543Spiso * PACKET PARSER CODE 993186543Spiso * ---------------------------------------------------------------------- 994186543Spiso */ 995186543Spiso/** @addtogroup packet_parser 996186543Spiso * 997186543Spiso * These functions parse the SCTP packet and fill a sctp_nat_msg structure 998186543Spiso * with the parsed contents. 999186543Spiso */ 1000186543Spiso/** @ingroup packet_parser 1001186543Spiso * @brief Parses SCTP packets for the key SCTP chunk that will be processed 1002186543Spiso * 1003186543Spiso * This module parses SCTP packets for the key SCTP chunk that will be processed 1004186543Spiso * The module completes the sctp_nat_msg structure and either retrieves the 1005186543Spiso * relevant (existing) stored association from the Hash Tables or creates a new 1006186543Spiso * association entity with state SN_ID 1007186543Spiso * 1008186543Spiso * @param la Pointer to the relevant libalias instance 1009186543Spiso * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1010186543Spiso * @param pip 1011186543Spiso * @param sm Pointer to sctp message information 1012186543Spiso * @param passoc Pointer to the association this SCTP Message belongs to 1013186543Spiso * 1014186543Spiso * @return SN_PARSE_OK | SN_PARSE_ERROR_* 1015186543Spiso */ 1016186543Spisostatic int 1017186543Spisosctp_PktParser(struct libalias *la, int direction, struct ip *pip, 1018188294Spiso struct sctp_nat_msg *sm, struct sctp_nat_assoc **passoc) 1019186543Spiso//sctp_PktParser(int direction, struct mbuf *ipak, int ip_hdr_len,struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc) 1020186543Spiso{ 1021188294Spiso struct sctphdr *sctp_hdr; 1022188294Spiso struct sctp_chunkhdr *chunk_hdr; 1023188294Spiso struct sctp_paramhdr *param_hdr; 1024188294Spiso struct in_addr ipv4addr; 1025188294Spiso int bytes_left; /* bytes left in ip packet */ 1026188294Spiso int chunk_length; 1027188294Spiso int chunk_count; 1028188294Spiso int partial_match = 0; 1029188294Spiso // mbuf *mp; 1030188294Spiso // int mlen; 1031186543Spiso 1032188294Spiso // mlen = SCTP_HEADER_LEN(i_pak); 1033188294Spiso // mp = SCTP_HEADER_TO_CHAIN(i_pak); /* does nothing in bsd since header and chain not separate */ 1034186543Spiso 1035188294Spiso /* 1036188294Spiso * Note, that if the VTag is zero, it must be an INIT 1037188294Spiso * Also, I am only interested in the content of INIT and ADDIP chunks 1038188294Spiso */ 1039186543Spiso 1040188294Spiso // no mbuf stuff from Paolo yet so ... 1041188294Spiso sm->ip_hdr = pip; 1042188294Spiso /* remove ip header length from the bytes_left */ 1043188294Spiso bytes_left = ntohs(pip->ip_len) - (pip->ip_hl << 2); 1044186543Spiso 1045188294Spiso /* Check SCTP header length and move to first chunk */ 1046188294Spiso if (bytes_left < sizeof(struct sctphdr)) { 1047188294Spiso sm->sctp_hdr = NULL; 1048188294Spiso return(SN_PARSE_ERROR_IPSHL); /* packet not long enough*/ 1049188294Spiso } 1050186543Spiso 1051188294Spiso sm->sctp_hdr = sctp_hdr = (struct sctphdr *) ip_next(pip); 1052188294Spiso bytes_left -= sizeof(struct sctphdr); 1053186543Spiso 1054188294Spiso /* Check for valid ports (zero valued ports would find partially initialised associations */ 1055188294Spiso if (sctp_hdr->src_port == 0 || sctp_hdr->dest_port == 0) 1056188294Spiso return(SN_PARSE_ERROR_PORT); 1057186543Spiso 1058188294Spiso /* Check length of first chunk */ 1059188294Spiso if (bytes_left < SN_MIN_CHUNK_SIZE) /* malformed chunk - could cause endless loop*/ 1060188294Spiso return(SN_PARSE_ERROR_CHHL); /* packet not long enough for this chunk */ 1061186543Spiso 1062188294Spiso /* First chunk */ 1063188294Spiso chunk_hdr = SN_SCTP_FIRSTCHUNK(sctp_hdr); 1064186543Spiso 1065188294Spiso chunk_length = SCTP_SIZE32(ntohs(chunk_hdr->chunk_length)); 1066188294Spiso if ((chunk_length < SN_MIN_CHUNK_SIZE) || (chunk_length > bytes_left)) /* malformed chunk - could cause endless loop*/ 1067188294Spiso return(SN_PARSE_ERROR_CHHL); 1068186543Spiso 1069188294Spiso if ((chunk_hdr->chunk_flags & SCTP_HAD_NO_TCB) && 1070188294Spiso ((chunk_hdr->chunk_type == SCTP_ABORT_ASSOCIATION) || 1071188294Spiso (chunk_hdr->chunk_type == SCTP_SHUTDOWN_COMPLETE))) { 1072188294Spiso /* T-Bit set */ 1073188294Spiso if (direction == SN_TO_LOCAL) 1074188294Spiso *passoc = FindSctpGlobalT(la, pip->ip_src, sctp_hdr->v_tag, sctp_hdr->dest_port, sctp_hdr->src_port); 1075188294Spiso else 1076188294Spiso *passoc = FindSctpLocalT(la, pip->ip_dst, sctp_hdr->v_tag, sctp_hdr->dest_port, sctp_hdr->src_port); 1077186543Spiso } else { 1078188294Spiso /* Proper v_tag settings */ 1079188294Spiso if (direction == SN_TO_LOCAL) 1080188294Spiso *passoc = FindSctpGlobal(la, pip->ip_src, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port, &partial_match); 1081188294Spiso else 1082188294Spiso *passoc = FindSctpLocal(la, pip->ip_src, pip->ip_dst, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port); 1083186543Spiso } 1084188294Spiso 1085188294Spiso chunk_count = 1; 1086188294Spiso /* Real packet parsing occurs below */ 1087188294Spiso sm->msg = SN_SCTP_OTHER;/* Initialise to largest value*/ 1088188294Spiso sm->chunk_length = 0; /* only care about length for key chunks */ 1089188294Spiso while (IS_SCTP_CONTROL(chunk_hdr)) { 1090188294Spiso switch(chunk_hdr->chunk_type) { 1091188294Spiso case SCTP_INITIATION: 1092188294Spiso if (chunk_length < sizeof(struct sctp_init_chunk)) /* malformed chunk*/ 1093188294Spiso return(SN_PARSE_ERROR_CHHL); 1094188294Spiso sm->msg = SN_SCTP_INIT; 1095188294Spiso sm->sctpchnk.Init = (struct sctp_init *) ((char *) chunk_hdr + sizeof(struct sctp_chunkhdr)); 1096188294Spiso sm->chunk_length = chunk_length; 1097188294Spiso /* if no existing association, create a new one */ 1098188294Spiso if (*passoc == NULL) { 1099188294Spiso if (sctp_hdr->v_tag == 0){ //Init requires vtag=0 1100188294Spiso *passoc = (struct sctp_nat_assoc *) sn_malloc(sizeof(struct sctp_nat_assoc)); 1101188294Spiso if (*passoc == NULL) {/* out of resources */ 1102188294Spiso return(SN_PARSE_ERROR_AS_MALLOC); 1103188294Spiso } 1104188294Spiso /* Initialise association - malloc initialises memory to zeros */ 1105188294Spiso (*passoc)->state = SN_ID; 1106188294Spiso LIST_INIT(&((*passoc)->Gaddr)); /* always initialise to avoid memory problems */ 1107188294Spiso (*passoc)->TableRegister = SN_NULL_TBL; 1108188294Spiso return(SN_PARSE_OK); 1109188294Spiso } 1110188294Spiso return(SN_PARSE_ERROR_VTAG); 1111188294Spiso } 1112188294Spiso return(SN_PARSE_ERROR_LOOKUP); 1113188294Spiso case SCTP_INITIATION_ACK: 1114188294Spiso if (chunk_length < sizeof(struct sctp_init_ack_chunk)) /* malformed chunk*/ 1115188294Spiso return(SN_PARSE_ERROR_CHHL); 1116188294Spiso sm->msg = SN_SCTP_INITACK; 1117188294Spiso sm->sctpchnk.InitAck = (struct sctp_init_ack *) ((char *) chunk_hdr + sizeof(struct sctp_chunkhdr)); 1118188294Spiso sm->chunk_length = chunk_length; 1119188294Spiso return ((*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP):(SN_PARSE_OK)); 1120188294Spiso case SCTP_ABORT_ASSOCIATION: /* access only minimum sized chunk */ 1121188294Spiso sm->msg = SN_SCTP_ABORT; 1122188294Spiso sm->chunk_length = chunk_length; 1123188294Spiso return ((*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP_ABORT):(SN_PARSE_OK)); 1124188294Spiso case SCTP_SHUTDOWN_ACK: 1125188294Spiso if (chunk_length < sizeof(struct sctp_shutdown_ack_chunk)) /* malformed chunk*/ 1126188294Spiso return(SN_PARSE_ERROR_CHHL); 1127188294Spiso if (sm->msg > SN_SCTP_SHUTACK) { 1128188294Spiso sm->msg = SN_SCTP_SHUTACK; 1129188294Spiso sm->chunk_length = chunk_length; 1130188294Spiso } 1131188294Spiso break; 1132188294Spiso case SCTP_SHUTDOWN_COMPLETE: /* minimum sized chunk */ 1133188294Spiso if (sm->msg > SN_SCTP_SHUTCOMP) { 1134188294Spiso sm->msg = SN_SCTP_SHUTCOMP; 1135188294Spiso sm->chunk_length = chunk_length; 1136188294Spiso } 1137188294Spiso return ((*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP):(SN_PARSE_OK)); 1138188294Spiso case SCTP_ASCONF: 1139188294Spiso if (sm->msg > SN_SCTP_ASCONF) { 1140188294Spiso if (chunk_length < (sizeof(struct sctp_asconf_chunk) + sizeof(struct sctp_ipv4addr_param))) /* malformed chunk*/ 1141188294Spiso return(SN_PARSE_ERROR_CHHL); 1142188294Spiso //leave parameter searching to later, if required 1143188294Spiso param_hdr = (struct sctp_paramhdr *) ((char *) chunk_hdr + sizeof(struct sctp_asconf_chunk)); /*compulsory IP parameter*/ 1144188294Spiso if (ntohs(param_hdr->param_type) == SCTP_IPV4_ADDRESS) { 1145188294Spiso if ((*passoc == NULL) && (direction == SN_TO_LOCAL)) { /* AddIP with no association */ 1146188294Spiso /* try look up with the ASCONF packet's alternative address */ 1147188294Spiso ipv4addr.s_addr = ((struct sctp_ipv4addr_param *) param_hdr)->addr; 1148188294Spiso *passoc = FindSctpGlobal(la, ipv4addr, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port, &partial_match); 1149188294Spiso } 1150188294Spiso param_hdr = (struct sctp_paramhdr *) 1151188294Spiso ((char *) param_hdr + sizeof(struct sctp_ipv4addr_param)); /*asconf's compulsory address parameter */ 1152188294Spiso sm->chunk_length = chunk_length - sizeof(struct sctp_asconf_chunk) - sizeof(struct sctp_ipv4addr_param); /* rest of chunk */ 1153188294Spiso } else { 1154188294Spiso if (chunk_length < (sizeof(struct sctp_asconf_chunk) + sizeof(struct sctp_ipv6addr_param))) /* malformed chunk*/ 1155188294Spiso return(SN_PARSE_ERROR_CHHL); 1156188294Spiso param_hdr = (struct sctp_paramhdr *) 1157188294Spiso ((char *) param_hdr + sizeof(struct sctp_ipv6addr_param)); /*asconf's compulsory address parameter */ 1158188294Spiso sm->chunk_length = chunk_length - sizeof(struct sctp_asconf_chunk) - sizeof(struct sctp_ipv6addr_param); /* rest of chunk */ 1159188294Spiso } 1160188294Spiso sm->msg = SN_SCTP_ASCONF; 1161188294Spiso sm->sctpchnk.Asconf = param_hdr; 1162186543Spiso 1163188294Spiso if (*passoc == NULL) { /* AddIP with no association */ 1164188294Spiso *passoc = (struct sctp_nat_assoc *) sn_malloc(sizeof(struct sctp_nat_assoc)); 1165188294Spiso if (*passoc == NULL) {/* out of resources */ 1166188294Spiso return(SN_PARSE_ERROR_AS_MALLOC); 1167188294Spiso } 1168188294Spiso /* Initialise association - malloc initialises memory to zeros */ 1169188294Spiso (*passoc)->state = SN_ID; 1170188294Spiso LIST_INIT(&((*passoc)->Gaddr)); /* always initialise to avoid memory problems */ 1171188294Spiso (*passoc)->TableRegister = SN_NULL_TBL; 1172188294Spiso return(SN_PARSE_OK); 1173188294Spiso } 1174188294Spiso } 1175188294Spiso break; 1176188294Spiso case SCTP_ASCONF_ACK: 1177188294Spiso if (sm->msg > SN_SCTP_ASCONFACK) { 1178188294Spiso if (chunk_length < sizeof(struct sctp_asconf_ack_chunk)) /* malformed chunk*/ 1179188294Spiso return(SN_PARSE_ERROR_CHHL); 1180188294Spiso //leave parameter searching to later, if required 1181188294Spiso param_hdr = (struct sctp_paramhdr *) ((char *) chunk_hdr 1182188294Spiso + sizeof(struct sctp_asconf_ack_chunk)); 1183188294Spiso sm->msg = SN_SCTP_ASCONFACK; 1184188294Spiso sm->sctpchnk.Asconf = param_hdr; 1185188294Spiso sm->chunk_length = chunk_length - sizeof(struct sctp_asconf_ack_chunk); 1186188294Spiso } 1187188294Spiso break; 1188188294Spiso default: 1189188294Spiso break; /* do nothing*/ 1190188294Spiso } 1191186543Spiso 1192188294Spiso /* if no association is found exit - we need to find an Init or AddIP within sysctl_initialising_chunk_proc_limit */ 1193188294Spiso if ((*passoc == NULL) && (chunk_count >= sysctl_initialising_chunk_proc_limit)) 1194188294Spiso return(SN_PARSE_ERROR_LOOKUP); 1195186543Spiso 1196188294Spiso /* finished with this chunk, on to the next chunk*/ 1197188294Spiso bytes_left-= chunk_length; 1198186543Spiso 1199188294Spiso /* Is this the end of the packet ? */ 1200188294Spiso if (bytes_left == 0) 1201188294Spiso return (*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP):(SN_PARSE_OK); 1202186543Spiso 1203188294Spiso /* Are there enough bytes in packet to at least retrieve length of next chunk ? */ 1204188294Spiso if (bytes_left < SN_MIN_CHUNK_SIZE) 1205188294Spiso return(SN_PARSE_ERROR_CHHL); 1206186543Spiso 1207188294Spiso chunk_hdr = SN_SCTP_NEXTCHUNK(chunk_hdr); 1208186543Spiso 1209188294Spiso /* Is the chunk long enough to not cause endless look and are there enough bytes in packet to read the chunk ? */ 1210188294Spiso chunk_length = SCTP_SIZE32(ntohs(chunk_hdr->chunk_length)); 1211188294Spiso if ((chunk_length < SN_MIN_CHUNK_SIZE) || (chunk_length > bytes_left)) 1212188294Spiso return(SN_PARSE_ERROR_CHHL); 1213188294Spiso if(++chunk_count > sysctl_chunk_proc_limit) 1214188294Spiso return(SN_PARSE_OK); /* limit for processing chunks, take what we get */ 1215188294Spiso } 1216186543Spiso 1217188294Spiso if (*passoc == NULL) 1218188294Spiso return (partial_match)?(SN_PARSE_ERROR_PARTIALLOOKUP):(SN_PARSE_ERROR_LOOKUP); 1219188294Spiso else 1220188294Spiso return(SN_PARSE_OK); 1221186543Spiso} 1222186543Spiso 1223186543Spiso/** @ingroup packet_parser 1224186543Spiso * @brief Extract Vtags from Asconf Chunk 1225186543Spiso * 1226186543Spiso * GetAsconfVtags scans an Asconf Chunk for the vtags parameter, and then 1227186543Spiso * extracts the vtags. 1228186543Spiso * 1229186543Spiso * GetAsconfVtags is not called from within sctp_PktParser. It is called only 1230186543Spiso * from within ID_process when an AddIP has been received. 1231186543Spiso * 1232186543Spiso * @param la Pointer to the relevant libalias instance 1233186543Spiso * @param sm Pointer to sctp message information 1234186543Spiso * @param l_vtag Pointer to the local vtag in the association this SCTP Message belongs to 1235186543Spiso * @param g_vtag Pointer to the local vtag in the association this SCTP Message belongs to 1236186543Spiso * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1237186543Spiso * 1238186543Spiso * @return 1 - success | 0 - fail 1239186543Spiso */ 1240186543Spisostatic int 1241186543SpisoGetAsconfVtags(struct libalias *la, struct sctp_nat_msg *sm, uint32_t *l_vtag, uint32_t *g_vtag, int direction) 1242186543Spiso{ 1243188294Spiso /* To be removed when information is in the sctp headers */ 1244186543Spiso#define SCTP_VTAG_PARAM 0xC007 1245188294Spiso struct sctp_vtag_param { 1246188294Spiso struct sctp_paramhdr ph;/* type=SCTP_VTAG_PARAM */ 1247188294Spiso uint32_t local_vtag; 1248188294Spiso uint32_t remote_vtag; 1249188294Spiso } __attribute__((packed)); 1250186543Spiso 1251188294Spiso struct sctp_vtag_param *vtag_param; 1252188294Spiso struct sctp_paramhdr *param; 1253188294Spiso int bytes_left; 1254188294Spiso int param_size; 1255188294Spiso int param_count; 1256186543Spiso 1257188294Spiso param_count = 1; 1258188294Spiso param = sm->sctpchnk.Asconf; 1259188294Spiso param_size = SCTP_SIZE32(ntohs(param->param_length)); 1260188294Spiso bytes_left = sm->chunk_length; 1261188294Spiso /* step through Asconf parameters */ 1262188294Spiso while((bytes_left >= param_size) && (bytes_left >= SN_VTAG_PARAM_SIZE)) { 1263188294Spiso if (ntohs(param->param_type) == SCTP_VTAG_PARAM) { 1264188294Spiso vtag_param = (struct sctp_vtag_param *) param; 1265188294Spiso switch(direction) { 1266188294Spiso /* The Internet draft is a little ambigious as to order of these vtags. 1267188294Spiso We think it is this way around. If we are wrong, the order will need 1268188294Spiso to be changed. */ 1269188294Spiso case SN_TO_GLOBAL: 1270188294Spiso *g_vtag = vtag_param->local_vtag; 1271188294Spiso *l_vtag = vtag_param->remote_vtag; 1272188294Spiso break; 1273188294Spiso case SN_TO_LOCAL: 1274188294Spiso *g_vtag = vtag_param->remote_vtag; 1275188294Spiso *l_vtag = vtag_param->local_vtag; 1276188294Spiso break; 1277188294Spiso } 1278188294Spiso return(1); /* found */ 1279188294Spiso } 1280186543Spiso 1281188294Spiso bytes_left -= param_size; 1282188294Spiso if (bytes_left < SN_MIN_PARAM_SIZE) return(0); 1283186543Spiso 1284188294Spiso param = SN_SCTP_NEXTPARAM(param); 1285188294Spiso param_size = SCTP_SIZE32(ntohs(param->param_length)); 1286188294Spiso if (++param_count > sysctl_param_proc_limit) { 1287188294Spiso SN_LOG(SN_LOG_EVENT, 1288188294Spiso logsctperror("Parameter parse limit exceeded (GetAsconfVtags)", 1289188294Spiso sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); 1290188294Spiso return(0); /* not found limit exceeded*/ 1291188294Spiso } 1292188294Spiso } 1293188294Spiso return(0); /* not found */ 1294186543Spiso} 1295186543Spiso 1296186543Spiso/** @ingroup packet_parser 1297186543Spiso * @brief AddGlobalIPAddresses from Init,InitAck,or AddIP packets 1298186543Spiso * 1299186543Spiso * AddGlobalIPAddresses scans an SCTP chunk (in sm) for Global IP addresses, and 1300186543Spiso * adds them. 1301186543Spiso * 1302186543Spiso * @param sm Pointer to sctp message information 1303186543Spiso * @param assoc Pointer to the association this SCTP Message belongs to 1304186543Spiso * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1305186543Spiso * 1306186543Spiso */ 1307186543Spisostatic void 1308186543SpisoAddGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int direction) 1309186543Spiso{ 1310188294Spiso struct sctp_ipv4addr_param *ipv4_param; 1311188294Spiso struct sctp_paramhdr *param = NULL; 1312188294Spiso struct sctp_GlobalAddress *G_Addr; 1313188294Spiso struct in_addr g_addr = {0}; 1314188294Spiso int bytes_left = 0; 1315188294Spiso int param_size; 1316188294Spiso int param_count, addr_param_count = 0; 1317186543Spiso 1318188294Spiso switch(direction) { 1319188294Spiso case SN_TO_GLOBAL: /* does not contain global addresses */ 1320188294Spiso g_addr = sm->ip_hdr->ip_dst; 1321188294Spiso bytes_left = 0; /* force exit */ 1322188294Spiso break; 1323188294Spiso case SN_TO_LOCAL: 1324188294Spiso g_addr = sm->ip_hdr->ip_src; 1325188294Spiso param_count = 1; 1326188294Spiso switch(sm->msg) { 1327188294Spiso case SN_SCTP_INIT: 1328188294Spiso bytes_left = sm->chunk_length - sizeof(struct sctp_init_chunk); 1329188294Spiso param = (struct sctp_paramhdr *)((char *)sm->sctpchnk.Init + sizeof(struct sctp_init)); 1330188294Spiso break; 1331188294Spiso case SN_SCTP_INITACK: 1332188294Spiso bytes_left = sm->chunk_length - sizeof(struct sctp_init_ack_chunk); 1333188294Spiso param = (struct sctp_paramhdr *)((char *)sm->sctpchnk.InitAck + sizeof(struct sctp_init_ack)); 1334188294Spiso break; 1335188294Spiso case SN_SCTP_ASCONF: 1336188294Spiso bytes_left = sm->chunk_length; 1337188294Spiso param = sm->sctpchnk.Asconf; 1338188294Spiso break; 1339188294Spiso } 1340188294Spiso } 1341188294Spiso if (bytes_left >= SN_MIN_PARAM_SIZE) 1342188294Spiso param_size = SCTP_SIZE32(ntohs(param->param_length)); 1343188294Spiso else 1344188294Spiso param_size = bytes_left+1; /* force skip loop */ 1345186543Spiso 1346188294Spiso if ((assoc->state == SN_ID) && ((sm->msg == SN_SCTP_INIT) || (bytes_left < SN_MIN_PARAM_SIZE))) {/* add pkt address */ 1347188294Spiso G_Addr = (struct sctp_GlobalAddress *) sn_malloc(sizeof(struct sctp_GlobalAddress)); 1348188294Spiso if (G_Addr == NULL) {/* out of resources */ 1349188294Spiso SN_LOG(SN_LOG_EVENT, 1350188294Spiso logsctperror("AddGlobalIPAddress: No resources for adding global address - revert to no tracking", 1351188294Spiso sm->sctp_hdr->v_tag, 0, direction)); 1352188294Spiso assoc->num_Gaddr = 0; /* don't track any more for this assoc*/ 1353188294Spiso sysctl_track_global_addresses=0; 1354188294Spiso return; 1355188294Spiso } 1356188294Spiso G_Addr->g_addr = g_addr; 1357188294Spiso if (!Add_Global_Address_to_List(assoc, G_Addr)) 1358188294Spiso SN_LOG(SN_LOG_EVENT, 1359188294Spiso logsctperror("AddGlobalIPAddress: Address already in list", 1360188294Spiso sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); 1361188294Spiso } 1362186543Spiso 1363188294Spiso /* step through parameters */ 1364188294Spiso while((bytes_left >= param_size) && (bytes_left >= sizeof(struct sctp_ipv4addr_param))) { 1365188294Spiso if (assoc->num_Gaddr >= sysctl_track_global_addresses) { 1366188294Spiso SN_LOG(SN_LOG_EVENT, 1367188294Spiso logsctperror("AddGlobalIPAddress: Maximum Number of addresses reached", 1368188294Spiso sm->sctp_hdr->v_tag, sysctl_track_global_addresses, direction)); 1369188294Spiso return; 1370188294Spiso } 1371188294Spiso switch(ntohs(param->param_type)) { 1372188294Spiso case SCTP_ADD_IP_ADDRESS: 1373188294Spiso /* skip to address parameter - leave param_size so bytes left will be calculated properly*/ 1374188294Spiso param = (struct sctp_paramhdr *) &((struct sctp_asconf_addrv4_param *) param)->addrp; 1375188294Spiso case SCTP_IPV4_ADDRESS: 1376188294Spiso ipv4_param = (struct sctp_ipv4addr_param *) param; 1377188294Spiso /* add addresses to association */ 1378188294Spiso G_Addr = (struct sctp_GlobalAddress *) sn_malloc(sizeof(struct sctp_GlobalAddress)); 1379188294Spiso if (G_Addr == NULL) {/* out of resources */ 1380188294Spiso SN_LOG(SN_LOG_EVENT, 1381188294Spiso logsctperror("AddGlobalIPAddress: No resources for adding global address - revert to no tracking", 1382188294Spiso sm->sctp_hdr->v_tag, 0, direction)); 1383188294Spiso assoc->num_Gaddr = 0; /* don't track any more for this assoc*/ 1384188294Spiso sysctl_track_global_addresses=0; 1385188294Spiso return; 1386188294Spiso } 1387188294Spiso /* add address */ 1388188294Spiso addr_param_count++; 1389188294Spiso if ((sm->msg == SN_SCTP_ASCONF) && (ipv4_param->addr == INADDR_ANY)) { /* use packet address */ 1390188294Spiso G_Addr->g_addr = g_addr; 1391188294Spiso if (!Add_Global_Address_to_List(assoc, G_Addr)) 1392188294Spiso SN_LOG(SN_LOG_EVENT, 1393188294Spiso logsctperror("AddGlobalIPAddress: Address already in list", 1394188294Spiso sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); 1395188294Spiso return; /*shouldn't be any other addresses if the zero address is given*/ 1396188294Spiso } else { 1397188294Spiso G_Addr->g_addr.s_addr = ipv4_param->addr; 1398188294Spiso if (!Add_Global_Address_to_List(assoc, G_Addr)) 1399188294Spiso SN_LOG(SN_LOG_EVENT, 1400188294Spiso logsctperror("AddGlobalIPAddress: Address already in list", 1401188294Spiso sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); 1402188294Spiso } 1403188294Spiso } 1404186543Spiso 1405188294Spiso bytes_left -= param_size; 1406188294Spiso if (bytes_left < SN_MIN_PARAM_SIZE) 1407188294Spiso break; 1408186543Spiso 1409188294Spiso param = SN_SCTP_NEXTPARAM(param); 1410188294Spiso param_size = SCTP_SIZE32(ntohs(param->param_length)); 1411188294Spiso if (++param_count > sysctl_param_proc_limit) { 1412188294Spiso SN_LOG(SN_LOG_EVENT, 1413188294Spiso logsctperror("Parameter parse limit exceeded (AddGlobalIPAddress)", 1414188294Spiso sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); 1415188294Spiso break; /* limit exceeded*/ 1416188294Spiso } 1417188294Spiso } 1418188294Spiso if (addr_param_count == 0) { 1419188294Spiso SN_LOG(SN_LOG_DETAIL, 1420188294Spiso logsctperror("AddGlobalIPAddress: no address parameters to add", 1421186543Spiso sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); 1422188294Spiso } 1423186543Spiso} 1424186543Spiso 1425186543Spiso/** 1426186543Spiso * @brief Add_Global_Address_to_List 1427186543Spiso * 1428186543Spiso * Adds a global IP address to an associations address list, if it is not 1429186543Spiso * already there. The first address added us usually the packet's address, and 1430186543Spiso * is most likely to be used, so it is added at the beginning. Subsequent 1431186543Spiso * addresses are added after this one. 1432186543Spiso * 1433186543Spiso * @param assoc Pointer to the association this SCTP Message belongs to 1434186543Spiso * @param G_addr Pointer to the global address to add 1435186543Spiso * 1436186543Spiso * @return 1 - success | 0 - fail 1437186543Spiso */ 1438186543Spisostatic int Add_Global_Address_to_List(struct sctp_nat_assoc *assoc, struct sctp_GlobalAddress *G_addr) 1439186543Spiso{ 1440188294Spiso struct sctp_GlobalAddress *iter_G_Addr = NULL, *first_G_Addr = NULL; 1441188294Spiso first_G_Addr = LIST_FIRST(&(assoc->Gaddr)); 1442188294Spiso if (first_G_Addr == NULL) { 1443188294Spiso LIST_INSERT_HEAD(&(assoc->Gaddr), G_addr, list_Gaddr); /* add new address to beginning of list*/ 1444188294Spiso } else { 1445188294Spiso LIST_FOREACH(iter_G_Addr, &(assoc->Gaddr), list_Gaddr) { 1446188294Spiso if (G_addr->g_addr.s_addr == iter_G_Addr->g_addr.s_addr) 1447188294Spiso return(0); /* already exists, so don't add */ 1448188294Spiso } 1449188294Spiso LIST_INSERT_AFTER(first_G_Addr, G_addr, list_Gaddr); /* add address to end of list*/ 1450188294Spiso } 1451188294Spiso assoc->num_Gaddr++; 1452188294Spiso return(1); /* success */ 1453186543Spiso} 1454186543Spiso 1455186543Spiso/** @ingroup packet_parser 1456186543Spiso * @brief RmGlobalIPAddresses from DelIP packets 1457186543Spiso * 1458186543Spiso * RmGlobalIPAddresses scans an ASCONF chunk for DelIP parameters to remove the 1459186543Spiso * given Global IP addresses from the association. It will not delete the 1460186543Spiso * the address if it is a list of one address. 1461186543Spiso * 1462186543Spiso * 1463186543Spiso * @param sm Pointer to sctp message information 1464186543Spiso * @param assoc Pointer to the association this SCTP Message belongs to 1465186543Spiso * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1466186543Spiso * 1467186543Spiso */ 1468186543Spisostatic void 1469186543SpisoRmGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int direction) 1470186543Spiso{ 1471188294Spiso struct sctp_asconf_addrv4_param *asconf_ipv4_param; 1472188294Spiso struct sctp_paramhdr *param; 1473188294Spiso struct sctp_GlobalAddress *G_Addr, *G_Addr_tmp; 1474188294Spiso struct in_addr g_addr; 1475188294Spiso int bytes_left; 1476188294Spiso int param_size; 1477188294Spiso int param_count; 1478186543Spiso 1479188294Spiso if(direction == SN_TO_GLOBAL) 1480188294Spiso g_addr = sm->ip_hdr->ip_dst; 1481188294Spiso else 1482188294Spiso g_addr = sm->ip_hdr->ip_src; 1483186543Spiso 1484188294Spiso bytes_left = sm->chunk_length; 1485188294Spiso param_count = 1; 1486188294Spiso param = sm->sctpchnk.Asconf; 1487188294Spiso if (bytes_left >= SN_MIN_PARAM_SIZE) { 1488188294Spiso param_size = SCTP_SIZE32(ntohs(param->param_length)); 1489188294Spiso } else { 1490188294Spiso SN_LOG(SN_LOG_EVENT, 1491188294Spiso logsctperror("RmGlobalIPAddress: truncated packet - cannot remove IP addresses", 1492186543Spiso sm->sctp_hdr->v_tag, sysctl_track_global_addresses, direction)); 1493188294Spiso return; 1494188294Spiso } 1495186543Spiso 1496188294Spiso /* step through Asconf parameters */ 1497188294Spiso while((bytes_left >= param_size) && (bytes_left >= sizeof(struct sctp_ipv4addr_param))) { 1498188294Spiso if (ntohs(param->param_type) == SCTP_DEL_IP_ADDRESS) { 1499188294Spiso asconf_ipv4_param = (struct sctp_asconf_addrv4_param *) param; 1500188294Spiso if (asconf_ipv4_param->addrp.addr == INADDR_ANY) { /* remove all bar pkt address */ 1501188294Spiso LIST_FOREACH_SAFE(G_Addr, &(assoc->Gaddr), list_Gaddr, G_Addr_tmp) { 1502188294Spiso if(G_Addr->g_addr.s_addr != sm->ip_hdr->ip_src.s_addr) { 1503188294Spiso if (assoc->num_Gaddr > 1) { /* only delete if more than one */ 1504188294Spiso LIST_REMOVE(G_Addr, list_Gaddr); 1505188294Spiso sn_free(G_Addr); 1506188294Spiso assoc->num_Gaddr--; 1507188294Spiso } else { 1508188294Spiso SN_LOG(SN_LOG_EVENT, 1509188294Spiso logsctperror("RmGlobalIPAddress: Request to remove last IP address (didn't)", 1510188294Spiso sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); 1511188294Spiso } 1512188294Spiso } 1513188294Spiso } 1514188294Spiso return; /*shouldn't be any other addresses if the zero address is given*/ 1515188294Spiso } else { 1516188294Spiso LIST_FOREACH_SAFE(G_Addr, &(assoc->Gaddr), list_Gaddr, G_Addr_tmp) { 1517188294Spiso if(G_Addr->g_addr.s_addr == asconf_ipv4_param->addrp.addr) { 1518188294Spiso if (assoc->num_Gaddr > 1) { /* only delete if more than one */ 1519188294Spiso LIST_REMOVE(G_Addr, list_Gaddr); 1520188294Spiso sn_free(G_Addr); 1521188294Spiso assoc->num_Gaddr--; 1522188294Spiso break; /* Since add only adds new addresses, there should be no double entries */ 1523188294Spiso } else { 1524188294Spiso SN_LOG(SN_LOG_EVENT, 1525188294Spiso logsctperror("RmGlobalIPAddress: Request to remove last IP address (didn't)", 1526188294Spiso sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction)); 1527188294Spiso } 1528188294Spiso } 1529188294Spiso } 1530188294Spiso } 1531188294Spiso } 1532188294Spiso bytes_left -= param_size; 1533188294Spiso if (bytes_left == 0) return; 1534188294Spiso else if (bytes_left < SN_MIN_PARAM_SIZE) { 1535188294Spiso SN_LOG(SN_LOG_EVENT, 1536188294Spiso logsctperror("RmGlobalIPAddress: truncated packet - may not have removed all IP addresses", 1537188294Spiso sm->sctp_hdr->v_tag, sysctl_track_global_addresses, direction)); 1538188294Spiso return; 1539188294Spiso } 1540188294Spiso 1541188294Spiso param = SN_SCTP_NEXTPARAM(param); 1542188294Spiso param_size = SCTP_SIZE32(ntohs(param->param_length)); 1543188294Spiso if (++param_count > sysctl_param_proc_limit) { 1544188294Spiso SN_LOG(SN_LOG_EVENT, 1545188294Spiso logsctperror("Parameter parse limit exceeded (RmGlobalIPAddress)", 1546188294Spiso sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); 1547188294Spiso return; /* limit exceeded*/ 1548188294Spiso } 1549186543Spiso } 1550186543Spiso} 1551186543Spiso 1552186543Spiso/** @ingroup packet_parser 1553186543Spiso * @brief Check that ASCONF was successful 1554186543Spiso * 1555186543Spiso * Each ASCONF configuration parameter carries a correlation ID which should be 1556186543Spiso * matched with an ASCONFack. This is difficult for a NAT, since every 1557186543Spiso * association could potentially have a number of outstanding ASCONF 1558186543Spiso * configuration parameters, which should only be activated on receipt of the 1559186543Spiso * ACK. 1560186543Spiso * 1561186543Spiso * Currently we only look for an ACK when the NAT is setting up a new 1562186543Spiso * association (ie AddIP for a connection that the NAT does not know about 1563186543Spiso * because the original Init went through a public interface or another NAT) 1564186543Spiso * Since there is currently no connection on this path, there should be no other 1565186543Spiso * ASCONF configuration parameters outstanding, so we presume that if there is 1566186543Spiso * an ACK that it is responding to the AddIP and activate the new association. 1567186543Spiso * 1568186543Spiso * @param la Pointer to the relevant libalias instance 1569186543Spiso * @param sm Pointer to sctp message information 1570186543Spiso * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1571186543Spiso * 1572186543Spiso * @return 1 - success | 0 - fail 1573186543Spiso */ 1574186543Spisostatic int 1575186543SpisoIsASCONFack(struct libalias *la, struct sctp_nat_msg *sm, int direction) 1576186543Spiso{ 1577188294Spiso struct sctp_paramhdr *param; 1578188294Spiso int bytes_left; 1579188294Spiso int param_size; 1580188294Spiso int param_count; 1581186543Spiso 1582188294Spiso param_count = 1; 1583188294Spiso param = sm->sctpchnk.Asconf; 1584188294Spiso param_size = SCTP_SIZE32(ntohs(param->param_length)); 1585188294Spiso if (param_size == 8) 1586188294Spiso return(1); /*success - default acknowledgement of everything */ 1587186543Spiso 1588188294Spiso bytes_left = sm->chunk_length; 1589188294Spiso if (bytes_left < param_size) 1590188294Spiso return(0); /* not found */ 1591188294Spiso /* step through Asconf parameters */ 1592188294Spiso while(bytes_left >= SN_ASCONFACK_PARAM_SIZE) { 1593188294Spiso if (ntohs(param->param_type) == SCTP_SUCCESS_REPORT) 1594188294Spiso return(1); /* success - but can't match correlation IDs - should only be one */ 1595188294Spiso /* check others just in case */ 1596188294Spiso bytes_left -= param_size; 1597188294Spiso if (bytes_left >= SN_MIN_PARAM_SIZE) { 1598188294Spiso param = SN_SCTP_NEXTPARAM(param); 1599188294Spiso } else { 1600188294Spiso return(0); 1601188294Spiso } 1602188294Spiso param_size = SCTP_SIZE32(ntohs(param->param_length)); 1603188294Spiso if (bytes_left < param_size) return(0); 1604186543Spiso 1605188294Spiso if (++param_count > sysctl_param_proc_limit) { 1606188294Spiso SN_LOG(SN_LOG_EVENT, 1607188294Spiso logsctperror("Parameter parse limit exceeded (IsASCONFack)", 1608188294Spiso sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); 1609188294Spiso return(0); /* not found limit exceeded*/ 1610188294Spiso } 1611188294Spiso } 1612188294Spiso return(0); /* not success */ 1613186543Spiso} 1614186543Spiso 1615186543Spiso/** @ingroup packet_parser 1616186543Spiso * @brief Check to see if ASCONF contains an Add IP or Del IP parameter 1617186543Spiso * 1618186543Spiso * IsADDorDEL scans an ASCONF packet to see if it contains an AddIP or DelIP 1619186543Spiso * parameter 1620186543Spiso * 1621186543Spiso * @param la Pointer to the relevant libalias instance 1622186543Spiso * @param sm Pointer to sctp message information 1623186543Spiso * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1624186543Spiso * 1625186543Spiso * @return SCTP_ADD_IP_ADDRESS | SCTP_DEL_IP_ADDRESS | 0 - fail 1626186543Spiso */ 1627186543Spisostatic int 1628186543SpisoIsADDorDEL(struct libalias *la, struct sctp_nat_msg *sm, int direction) 1629186543Spiso{ 1630188294Spiso struct sctp_paramhdr *param; 1631188294Spiso int bytes_left; 1632188294Spiso int param_size; 1633188294Spiso int param_count; 1634186543Spiso 1635188294Spiso param_count = 1; 1636188294Spiso param = sm->sctpchnk.Asconf; 1637188294Spiso param_size = SCTP_SIZE32(ntohs(param->param_length)); 1638186543Spiso 1639188294Spiso bytes_left = sm->chunk_length; 1640188294Spiso if (bytes_left < param_size) 1641188294Spiso return(0); /* not found */ 1642188294Spiso /* step through Asconf parameters */ 1643188294Spiso while(bytes_left >= SN_ASCONFACK_PARAM_SIZE) { 1644188294Spiso if (ntohs(param->param_type) == SCTP_ADD_IP_ADDRESS) 1645188294Spiso return(SCTP_ADD_IP_ADDRESS); 1646188294Spiso else if (ntohs(param->param_type) == SCTP_DEL_IP_ADDRESS) 1647188294Spiso return(SCTP_DEL_IP_ADDRESS); 1648188294Spiso /* check others just in case */ 1649188294Spiso bytes_left -= param_size; 1650188294Spiso if (bytes_left >= SN_MIN_PARAM_SIZE) { 1651188294Spiso param = SN_SCTP_NEXTPARAM(param); 1652188294Spiso } else { 1653188294Spiso return(0); /*Neither found */ 1654188294Spiso } 1655188294Spiso param_size = SCTP_SIZE32(ntohs(param->param_length)); 1656188294Spiso if (bytes_left < param_size) return(0); 1657186543Spiso 1658188294Spiso if (++param_count > sysctl_param_proc_limit) { 1659188294Spiso SN_LOG(SN_LOG_EVENT, 1660188294Spiso logsctperror("Parameter parse limit exceeded IsADDorDEL)", 1661188294Spiso sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction)); 1662188294Spiso return(0); /* not found limit exceeded*/ 1663188294Spiso } 1664188294Spiso } 1665188294Spiso return(0); /*Neither found */ 1666186543Spiso} 1667186543Spiso 1668186543Spiso/* ---------------------------------------------------------------------- 1669186543Spiso * STATE MACHINE CODE 1670186543Spiso * ---------------------------------------------------------------------- 1671186543Spiso */ 1672186543Spiso/** @addtogroup state_machine 1673186543Spiso * 1674186543Spiso * The SCTP NAT State Machine functions will: 1675186543Spiso * - Process an already parsed packet 1676186543Spiso * - Use the existing NAT Hash Tables 1677186543Spiso * - Determine the next state for the association 1678186543Spiso * - Update the NAT Hash Tables and Timer Queues 1679186543Spiso * - Return the appropriate action to take with the packet 1680186543Spiso */ 1681186543Spiso/** @ingroup state_machine 1682186543Spiso * @brief Process SCTP message 1683186543Spiso * 1684186543Spiso * This function is the base state machine. It calls the processing engine for 1685186543Spiso * each state. 1686186543Spiso * 1687186543Spiso * @param la Pointer to the relevant libalias instance 1688186543Spiso * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1689186543Spiso * @param sm Pointer to sctp message information 1690186543Spiso * @param assoc Pointer to the association this SCTP Message belongs to 1691186543Spiso * 1692186543Spiso * @return SN_DROP_PKT | SN_NAT_PKT | SN_REPLY_ABORT | SN_REPLY_ERROR | SN_PROCESSING_ERROR 1693186543Spiso */ 1694186543Spisostatic int 1695186543SpisoProcessSctpMsg(struct libalias *la, int direction, struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc) 1696186543Spiso{ 1697188294Spiso int rtnval; 1698186543Spiso 1699188294Spiso switch (assoc->state) { 1700188294Spiso case SN_ID: /* Idle */ 1701188294Spiso rtnval = ID_process(la, direction, assoc, sm); 1702188294Spiso if (rtnval != SN_NAT_PKT) { 1703188294Spiso assoc->state = SN_RM;/* Mark for removal*/ 1704188294Spiso } 1705188294Spiso return(rtnval); 1706188294Spiso case SN_INi: /* Initialising - Init */ 1707188294Spiso return(INi_process(la, direction, assoc, sm)); 1708188294Spiso case SN_INa: /* Initialising - AddIP */ 1709188294Spiso return(INa_process(la, direction, assoc, sm)); 1710188294Spiso case SN_UP: /* Association UP */ 1711188294Spiso return(UP_process(la, direction, assoc, sm)); 1712188294Spiso case SN_CL: /* Association Closing */ 1713188294Spiso return(CL_process(la, direction, assoc, sm)); 1714188294Spiso } 1715188294Spiso return(SN_PROCESSING_ERROR); 1716186543Spiso} 1717186543Spiso 1718186543Spiso/** @ingroup state_machine 1719186543Spiso * @brief Process SCTP message while in the Idle state 1720186543Spiso * 1721186543Spiso * This function looks for an Incoming INIT or AddIP message. 1722186543Spiso * 1723186543Spiso * All other SCTP messages are invalid when in SN_ID, and are dropped. 1724186543Spiso * 1725186543Spiso * @param la Pointer to the relevant libalias instance 1726186543Spiso * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1727186543Spiso * @param sm Pointer to sctp message information 1728186543Spiso * @param assoc Pointer to the association this SCTP Message belongs to 1729186543Spiso * 1730186543Spiso * @return SN_NAT_PKT | SN_DROP_PKT | SN_REPLY_ABORT | SN_REPLY_ERROR 1731186543Spiso */ 1732186543Spisostatic int 1733186543SpisoID_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm) 1734186543Spiso{ 1735188294Spiso switch(sm->msg) { 1736188294Spiso case SN_SCTP_ASCONF: /* a packet containing an ASCONF chunk with ADDIP */ 1737188294Spiso if (!sysctl_accept_global_ootb_addip && (direction == SN_TO_LOCAL)) 1738188294Spiso return(SN_DROP_PKT); 1739188294Spiso /* if this Asconf packet does not contain the Vtag parameters it is of no use in Idle state */ 1740188294Spiso if (!GetAsconfVtags(la, sm, &(assoc->l_vtag), &(assoc->g_vtag), direction)) 1741188294Spiso return(SN_DROP_PKT); 1742188294Spiso case SN_SCTP_INIT: /* a packet containing an INIT chunk or an ASCONF AddIP */ 1743188294Spiso if (sysctl_track_global_addresses) 1744188294Spiso AddGlobalIPAddresses(sm, assoc, direction); 1745188294Spiso switch(direction){ 1746188294Spiso case SN_TO_GLOBAL: 1747188294Spiso assoc->l_addr = sm->ip_hdr->ip_src; 1748188294Spiso assoc->a_addr = FindAliasAddress(la, assoc->l_addr); 1749188294Spiso assoc->l_port = sm->sctp_hdr->src_port; 1750188294Spiso assoc->g_port = sm->sctp_hdr->dest_port; 1751188294Spiso if(sm->msg == SN_SCTP_INIT) 1752188294Spiso assoc->g_vtag = sm->sctpchnk.Init->initiate_tag; 1753188294Spiso if (AddSctpAssocGlobal(la, assoc)) /* DB clash *///**** need to add dst address 1754188294Spiso return((sm->msg == SN_SCTP_INIT) ? SN_REPLY_ABORT : SN_REPLY_ERROR); 1755188294Spiso if(sm->msg == SN_SCTP_ASCONF) { 1756188294Spiso if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_dst)) /* DB clash */ 1757188294Spiso return(SN_REPLY_ERROR); 1758188294Spiso assoc->TableRegister |= SN_WAIT_TOLOCAL; /* wait for tolocal ack */ 1759188294Spiso } 1760188294Spiso break; 1761188294Spiso case SN_TO_LOCAL: 1762188294Spiso assoc->l_addr = FindSctpRedirectAddress(la, sm); 1763188294Spiso assoc->a_addr = sm->ip_hdr->ip_dst; 1764188294Spiso assoc->l_port = sm->sctp_hdr->dest_port; 1765188294Spiso assoc->g_port = sm->sctp_hdr->src_port; 1766188294Spiso if(sm->msg == SN_SCTP_INIT) 1767188294Spiso assoc->l_vtag = sm->sctpchnk.Init->initiate_tag; 1768188294Spiso if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_src)) /* DB clash */ 1769188294Spiso return((sm->msg == SN_SCTP_INIT) ? SN_REPLY_ABORT : SN_REPLY_ERROR); 1770188294Spiso if(sm->msg == SN_SCTP_ASCONF) { 1771188294Spiso if (AddSctpAssocGlobal(la, assoc)) /* DB clash */ //**** need to add src address 1772188294Spiso return(SN_REPLY_ERROR); 1773188294Spiso assoc->TableRegister |= SN_WAIT_TOGLOBAL; /* wait for toglobal ack */ 1774188294Spiso } 1775188294Spiso break; 1776188294Spiso } 1777188294Spiso assoc->state = (sm->msg == SN_SCTP_INIT) ? SN_INi : SN_INa; 1778188294Spiso assoc->exp = SN_I_T(la); 1779188294Spiso sctp_AddTimeOut(la,assoc); 1780188294Spiso return(SN_NAT_PKT); 1781188294Spiso default: /* Any other type of SCTP message is not valid in Idle */ 1782188294Spiso return(SN_DROP_PKT); 1783188294Spiso } 1784188294Spisoreturn(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ 1785186543Spiso} 1786186543Spiso 1787186543Spiso/** @ingroup state_machine 1788186543Spiso * @brief Process SCTP message while waiting for an INIT-ACK message 1789186543Spiso * 1790186543Spiso * Only an INIT-ACK, resent INIT, or an ABORT SCTP packet are valid in this 1791186543Spiso * state, all other packets are dropped. 1792186543Spiso * 1793186543Spiso * @param la Pointer to the relevant libalias instance 1794186543Spiso * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1795186543Spiso * @param sm Pointer to sctp message information 1796186543Spiso * @param assoc Pointer to the association this SCTP Message belongs to 1797186543Spiso * 1798186543Spiso * @return SN_NAT_PKT | SN_DROP_PKT | SN_REPLY_ABORT 1799186543Spiso */ 1800186543Spisostatic int 1801186543SpisoINi_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm) 1802186543Spiso{ 1803188294Spiso switch(sm->msg) { 1804188294Spiso case SN_SCTP_INIT: /* a packet containing a retransmitted INIT chunk */ 1805188294Spiso sctp_ResetTimeOut(la, assoc, SN_I_T(la)); 1806188294Spiso return(SN_NAT_PKT); 1807188294Spiso case SN_SCTP_INITACK: /* a packet containing an INIT-ACK chunk */ 1808188294Spiso switch(direction){ 1809188294Spiso case SN_TO_LOCAL: 1810188294Spiso if (assoc->num_Gaddr) /*If tracking global addresses for this association */ 1811188294Spiso AddGlobalIPAddresses(sm, assoc, direction); 1812188294Spiso assoc->l_vtag = sm->sctpchnk.Init->initiate_tag; 1813188294Spiso if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_src)) { /* DB clash */ 1814188294Spiso assoc->state = SN_RM;/* Mark for removal*/ 1815188294Spiso return(SN_SEND_ABORT); 1816188294Spiso } 1817188294Spiso break; 1818188294Spiso case SN_TO_GLOBAL: 1819188294Spiso assoc->l_addr = sm->ip_hdr->ip_src; // Only if not set in Init! * 1820188294Spiso assoc->g_vtag = sm->sctpchnk.Init->initiate_tag; 1821188294Spiso if (AddSctpAssocGlobal(la, assoc)) { /* DB clash */ 1822188294Spiso assoc->state = SN_RM;/* Mark for removal*/ 1823188294Spiso return(SN_SEND_ABORT); 1824188294Spiso } 1825188294Spiso break; 1826188294Spiso } 1827188294Spiso assoc->state = SN_UP;/* association established for NAT */ 1828188294Spiso sctp_ResetTimeOut(la,assoc, SN_U_T(la)); 1829188294Spiso return(SN_NAT_PKT); 1830188294Spiso case SN_SCTP_ABORT: /* a packet containing an ABORT chunk */ 1831188294Spiso assoc->state = SN_RM;/* Mark for removal*/ 1832188294Spiso return(SN_NAT_PKT); 1833188294Spiso default: 1834188294Spiso return(SN_DROP_PKT); 1835188294Spiso } 1836188294Spiso return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ 1837186543Spiso} 1838186543Spiso 1839186543Spiso/** @ingroup state_machine 1840186543Spiso * @brief Process SCTP message while waiting for an AddIp-ACK message 1841186543Spiso * 1842186543Spiso * Only an AddIP-ACK, resent AddIP, or an ABORT message are valid, all other 1843186543Spiso * SCTP packets are dropped 1844186543Spiso * 1845186543Spiso * @param la Pointer to the relevant libalias instance 1846186543Spiso * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1847186543Spiso * @param sm Pointer to sctp message information 1848186543Spiso * @param assoc Pointer to the association this SCTP Message belongs to 1849186543Spiso * 1850186543Spiso * @return SN_NAT_PKT | SN_DROP_PKT 1851186543Spiso */ 1852186543Spisostatic int 1853186543SpisoINa_process(struct libalias *la, int direction,struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm) 1854186543Spiso{ 1855188294Spiso switch(sm->msg) { 1856188294Spiso case SN_SCTP_ASCONF: /* a packet containing an ASCONF chunk*/ 1857188294Spiso sctp_ResetTimeOut(la,assoc, SN_I_T(la)); 1858188294Spiso return(SN_NAT_PKT); 1859188294Spiso case SN_SCTP_ASCONFACK: /* a packet containing an ASCONF chunk with a ADDIP-ACK */ 1860188294Spiso switch(direction){ 1861188294Spiso case SN_TO_LOCAL: 1862188294Spiso if (!(assoc->TableRegister & SN_WAIT_TOLOCAL)) /* wrong direction */ 1863188294Spiso return(SN_DROP_PKT); 1864188294Spiso break; 1865188294Spiso case SN_TO_GLOBAL: 1866188294Spiso if (!(assoc->TableRegister & SN_WAIT_TOGLOBAL)) /* wrong direction */ 1867188294Spiso return(SN_DROP_PKT); 1868188294Spiso } 1869188294Spiso if (IsASCONFack(la,sm,direction)) { 1870188294Spiso assoc->TableRegister &= SN_BOTH_TBL; /* remove wait flags */ 1871188294Spiso assoc->state = SN_UP; /* association established for NAT */ 1872188294Spiso sctp_ResetTimeOut(la,assoc, SN_U_T(la)); 1873188294Spiso return(SN_NAT_PKT); 1874188294Spiso } else { 1875188294Spiso assoc->state = SN_RM;/* Mark for removal*/ 1876188294Spiso return(SN_NAT_PKT); 1877188294Spiso } 1878188294Spiso case SN_SCTP_ABORT: /* a packet containing an ABORT chunk */ 1879188294Spiso assoc->state = SN_RM;/* Mark for removal*/ 1880188294Spiso return(SN_NAT_PKT); 1881188294Spiso default: 1882188294Spiso return(SN_DROP_PKT); 1883188294Spiso } 1884188294Spiso return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ 1885186543Spiso} 1886186543Spiso 1887186543Spiso/** @ingroup state_machine 1888186543Spiso * @brief Process SCTP messages while association is UP redirecting packets 1889186543Spiso * 1890186543Spiso * While in the SN_UP state, all packets for the particular association 1891186543Spiso * are passed. Only a SHUT-ACK or an ABORT will cause a change of state. 1892186543Spiso * 1893186543Spiso * @param la Pointer to the relevant libalias instance 1894186543Spiso * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1895186543Spiso * @param sm Pointer to sctp message information 1896186543Spiso * @param assoc Pointer to the association this SCTP Message belongs to 1897186543Spiso * 1898186543Spiso * @return SN_NAT_PKT | SN_DROP_PKT 1899186543Spiso */ 1900186543Spisostatic int 1901186543SpisoUP_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm) 1902186543Spiso{ 1903188294Spiso switch(sm->msg) { 1904188294Spiso case SN_SCTP_SHUTACK: /* a packet containing a SHUTDOWN-ACK chunk */ 1905188294Spiso assoc->state = SN_CL; 1906188294Spiso sctp_ResetTimeOut(la,assoc, SN_C_T(la)); 1907188294Spiso return(SN_NAT_PKT); 1908188294Spiso case SN_SCTP_ABORT: /* a packet containing an ABORT chunk */ 1909188294Spiso assoc->state = SN_RM;/* Mark for removal*/ 1910188294Spiso return(SN_NAT_PKT); 1911188294Spiso case SN_SCTP_ASCONF: /* a packet containing an ASCONF chunk*/ 1912188294Spiso if ((direction == SN_TO_LOCAL) && assoc->num_Gaddr) /*If tracking global addresses for this association & from global side */ 1913188294Spiso switch(IsADDorDEL(la,sm,direction)) { 1914188294Spiso case SCTP_ADD_IP_ADDRESS: 1915188294Spiso AddGlobalIPAddresses(sm, assoc, direction); 1916188294Spiso break; 1917188294Spiso case SCTP_DEL_IP_ADDRESS: 1918188294Spiso RmGlobalIPAddresses(sm, assoc, direction); 1919188294Spiso break; 1920188294Spiso } /* fall through to default */ 1921188294Spiso default: 1922188294Spiso sctp_ResetTimeOut(la,assoc, SN_U_T(la)); 1923188294Spiso return(SN_NAT_PKT); /* forward packet */ 1924188294Spiso } 1925188294Spiso return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ 1926186543Spiso} 1927186543Spiso 1928186543Spiso/** @ingroup state_machine 1929186543Spiso * @brief Process SCTP message while association is in the process of closing 1930186543Spiso * 1931186543Spiso * This function waits for a SHUT-COMP to close the association. Depending on 1932218909Sbrucec * the setting of sysctl_holddown_timer it may not remove the association 1933186543Spiso * immediately, but leave it up until SN_X_T(la). Only SHUT-COMP, SHUT-ACK, and 1934186543Spiso * ABORT packets are permitted in this state. All other packets are dropped. 1935186543Spiso * 1936186543Spiso * @param la Pointer to the relevant libalias instance 1937186543Spiso * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 1938186543Spiso * @param sm Pointer to sctp message information 1939186543Spiso * @param assoc Pointer to the association this SCTP Message belongs to 1940186543Spiso * 1941186543Spiso * @return SN_NAT_PKT | SN_DROP_PKT 1942186543Spiso */ 1943186543Spisostatic int 1944186543SpisoCL_process(struct libalias *la, int direction,struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm) 1945186543Spiso{ 1946188294Spiso switch(sm->msg) { 1947188294Spiso case SN_SCTP_SHUTCOMP: /* a packet containing a SHUTDOWN-COMPLETE chunk */ 1948188294Spiso assoc->state = SN_CL; /* Stay in Close state until timeout */ 1949188294Spiso if (sysctl_holddown_timer > 0) 1950188294Spiso sctp_ResetTimeOut(la, assoc, SN_X_T(la));/* allow to stay open for Tbit packets*/ 1951188294Spiso else 1952188294Spiso assoc->state = SN_RM;/* Mark for removal*/ 1953188294Spiso return(SN_NAT_PKT); 1954188294Spiso case SN_SCTP_SHUTACK: /* a packet containing a SHUTDOWN-ACK chunk */ 1955188294Spiso assoc->state = SN_CL; /* Stay in Close state until timeout */ 1956188294Spiso sctp_ResetTimeOut(la, assoc, SN_C_T(la)); 1957188294Spiso return(SN_NAT_PKT); 1958188294Spiso case SN_SCTP_ABORT: /* a packet containing an ABORT chunk */ 1959188294Spiso assoc->state = SN_RM;/* Mark for removal*/ 1960188294Spiso return(SN_NAT_PKT); 1961188294Spiso default: 1962188294Spiso return(SN_DROP_PKT); 1963188294Spiso } 1964188294Spiso return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */ 1965186543Spiso} 1966186543Spiso 1967186543Spiso/* ---------------------------------------------------------------------- 1968186543Spiso * HASH TABLE CODE 1969186543Spiso * ---------------------------------------------------------------------- 1970186543Spiso */ 1971186543Spiso/** @addtogroup Hash 1972186543Spiso * 1973186543Spiso * The Hash functions facilitate searching the NAT Hash Tables for associations 1974186543Spiso * as well as adding/removing associations from the table(s). 1975186543Spiso */ 1976186543Spiso/** @ingroup Hash 1977186543Spiso * @brief Find the SCTP association given the local address, port and vtag 1978186543Spiso * 1979186543Spiso * Searches the local look-up table for the association entry matching the 1980186543Spiso * provided local <address:ports:vtag> tuple 1981186543Spiso * 1982186543Spiso * @param la Pointer to the relevant libalias instance 1983186543Spiso * @param l_addr local address 1984186543Spiso * @param g_addr global address 1985186543Spiso * @param l_vtag local Vtag 1986186543Spiso * @param l_port local Port 1987186543Spiso * @param g_port global Port 1988186543Spiso * 1989186543Spiso * @return pointer to association or NULL 1990186543Spiso */ 1991186543Spisostatic struct sctp_nat_assoc* 1992186543SpisoFindSctpLocal(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) 1993186543Spiso{ 1994188294Spiso u_int i; 1995188294Spiso struct sctp_nat_assoc *assoc = NULL; 1996188294Spiso struct sctp_GlobalAddress *G_Addr = NULL; 1997186543Spiso 1998188294Spiso if (l_vtag != 0) { /* an init packet, vtag==0 */ 1999188294Spiso i = SN_TABLE_HASH(l_vtag, l_port, la->sctpNatTableSize); 2000188294Spiso LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) { 2001188294Spiso if ((assoc->l_vtag == l_vtag) && (assoc->l_port == l_port) && (assoc->g_port == g_port)\ 2002188294Spiso && (assoc->l_addr.s_addr == l_addr.s_addr)) { 2003188294Spiso if (assoc->num_Gaddr) { 2004188294Spiso LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { 2005188294Spiso if(G_Addr->g_addr.s_addr == g_addr.s_addr) 2006188294Spiso return(assoc); 2007188294Spiso } 2008188294Spiso } else { 2009188294Spiso return(assoc); 2010188294Spiso } 2011188294Spiso } 2012188294Spiso } 2013186543Spiso } 2014188294Spiso return(NULL); 2015186543Spiso} 2016186543Spiso 2017186543Spiso/** @ingroup Hash 2018186543Spiso * @brief Check for Global Clash 2019186543Spiso * 2020186543Spiso * Searches the global look-up table for the association entry matching the 2021186543Spiso * provided global <(addresses):ports:vtag> tuple 2022186543Spiso * 2023186543Spiso * @param la Pointer to the relevant libalias instance 2024186543Spiso * @param Cassoc association being checked for a clash 2025186543Spiso * 2026186543Spiso * @return pointer to association or NULL 2027186543Spiso */ 2028186543Spisostatic struct sctp_nat_assoc* 2029186543SpisoFindSctpGlobalClash(struct libalias *la, struct sctp_nat_assoc *Cassoc) 2030186543Spiso{ 2031188294Spiso u_int i; 2032188294Spiso struct sctp_nat_assoc *assoc = NULL; 2033188294Spiso struct sctp_GlobalAddress *G_Addr = NULL; 2034188294Spiso struct sctp_GlobalAddress *G_AddrC = NULL; 2035186543Spiso 2036188294Spiso if (Cassoc->g_vtag != 0) { /* an init packet, vtag==0 */ 2037188294Spiso i = SN_TABLE_HASH(Cassoc->g_vtag, Cassoc->g_port, la->sctpNatTableSize); 2038188294Spiso LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) { 2039188294Spiso if ((assoc->g_vtag == Cassoc->g_vtag) && (assoc->g_port == Cassoc->g_port) && (assoc->l_port == Cassoc->l_port)) { 2040188294Spiso if (assoc->num_Gaddr) { 2041188294Spiso LIST_FOREACH(G_AddrC, &(Cassoc->Gaddr), list_Gaddr) { 2042188294Spiso LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { 2043188294Spiso if(G_Addr->g_addr.s_addr == G_AddrC->g_addr.s_addr) 2044188294Spiso return(assoc); 2045188294Spiso } 2046188294Spiso } 2047188294Spiso } else { 2048188294Spiso return(assoc); 2049188294Spiso } 2050188294Spiso } 2051188294Spiso } 2052186543Spiso } 2053188294Spiso return(NULL); 2054186543Spiso} 2055186543Spiso 2056186543Spiso/** @ingroup Hash 2057186543Spiso * @brief Find the SCTP association given the global port and vtag 2058186543Spiso * 2059186543Spiso * Searches the global look-up table for the association entry matching the 2060186543Spiso * provided global <address:ports:vtag> tuple 2061186543Spiso * 2062186543Spiso * If all but the global address match it sets partial_match to 1 to indicate a 2063186543Spiso * partial match. If the NAT is tracking global IP addresses for this 2064186543Spiso * association, the NAT may respond with an ERRORM to request the missing 2065186543Spiso * address to be added. 2066186543Spiso * 2067186543Spiso * @param la Pointer to the relevant libalias instance 2068186543Spiso * @param g_addr global address 2069186543Spiso * @param g_vtag global vtag 2070186543Spiso * @param g_port global port 2071186543Spiso * @param l_port local port 2072186543Spiso * 2073186543Spiso * @return pointer to association or NULL 2074186543Spiso */ 2075186543Spisostatic struct sctp_nat_assoc* 2076186543SpisoFindSctpGlobal(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uint16_t g_port, uint16_t l_port, int *partial_match) 2077186543Spiso{ 2078188294Spiso u_int i; 2079188294Spiso struct sctp_nat_assoc *assoc = NULL; 2080188294Spiso struct sctp_GlobalAddress *G_Addr = NULL; 2081186543Spiso 2082188294Spiso *partial_match = 0; 2083188294Spiso if (g_vtag != 0) { /* an init packet, vtag==0 */ 2084188294Spiso i = SN_TABLE_HASH(g_vtag, g_port, la->sctpNatTableSize); 2085188294Spiso LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) { 2086188294Spiso if ((assoc->g_vtag == g_vtag) && (assoc->g_port == g_port) && (assoc->l_port == l_port)) { 2087188294Spiso *partial_match = 1; 2088188294Spiso if (assoc->num_Gaddr) { 2089188294Spiso LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { 2090188294Spiso if(G_Addr->g_addr.s_addr == g_addr.s_addr) 2091188294Spiso return(assoc); 2092188294Spiso } 2093188294Spiso } else { 2094188294Spiso return(assoc); 2095188294Spiso } 2096188294Spiso } 2097188294Spiso } 2098186543Spiso } 2099188294Spiso return(NULL); 2100186543Spiso} 2101186543Spiso 2102186543Spiso/** @ingroup Hash 2103186543Spiso * @brief Find the SCTP association for a T-Flag message (given the global port and local vtag) 2104186543Spiso * 2105186543Spiso * Searches the local look-up table for a unique association entry matching the 2106186543Spiso * provided global port and local vtag information 2107186543Spiso * 2108186543Spiso * @param la Pointer to the relevant libalias instance 2109186543Spiso * @param g_addr global address 2110186543Spiso * @param l_vtag local Vtag 2111186543Spiso * @param g_port global Port 2112186543Spiso * @param l_port local Port 2113186543Spiso * 2114186543Spiso * @return pointer to association or NULL 2115186543Spiso */ 2116186543Spisostatic struct sctp_nat_assoc* 2117332283StuexenFindSctpLocalT(struct libalias *la, struct in_addr g_addr, uint32_t l_vtag, uint16_t g_port, uint16_t l_port) 2118186543Spiso{ 2119188294Spiso u_int i; 2120188294Spiso struct sctp_nat_assoc *assoc = NULL, *lastmatch = NULL; 2121188294Spiso struct sctp_GlobalAddress *G_Addr = NULL; 2122188294Spiso int cnt = 0; 2123332283Stuexen 2124188294Spiso if (l_vtag != 0) { /* an init packet, vtag==0 */ 2125188294Spiso i = SN_TABLE_HASH(l_vtag, g_port, la->sctpNatTableSize); 2126188294Spiso LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) { 2127188294Spiso if ((assoc->g_vtag == l_vtag) && (assoc->g_port == g_port) && (assoc->l_port == l_port)) { 2128188294Spiso if (assoc->num_Gaddr) { 2129188294Spiso LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { 2130332283Stuexen if (G_Addr->g_addr.s_addr == g_addr.s_addr) 2131332283Stuexen return (assoc); /* full match */ 2132188294Spiso } 2133188294Spiso } else { 2134332283Stuexen if (++cnt > 1) return (NULL); 2135188294Spiso lastmatch = assoc; 2136188294Spiso } 2137188294Spiso } 2138188294Spiso } 2139186543Spiso } 2140188294Spiso /* If there is more than one match we do not know which local address to send to */ 2141332283Stuexen return (cnt ? lastmatch : NULL); 2142186543Spiso} 2143186543Spiso 2144186543Spiso/** @ingroup Hash 2145186543Spiso * @brief Find the SCTP association for a T-Flag message (given the local port and global vtag) 2146186543Spiso * 2147186543Spiso * Searches the global look-up table for a unique association entry matching the 2148186543Spiso * provided local port and global vtag information 2149186543Spiso * 2150186543Spiso * @param la Pointer to the relevant libalias instance 2151186543Spiso * @param g_addr global address 2152186543Spiso * @param g_vtag global vtag 2153186543Spiso * @param l_port local port 2154186543Spiso * @param g_port global port 2155186543Spiso * 2156186543Spiso * @return pointer to association or NULL 2157186543Spiso */ 2158186543Spisostatic struct sctp_nat_assoc* 2159186543SpisoFindSctpGlobalT(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uint16_t l_port, uint16_t g_port) 2160186543Spiso{ 2161188294Spiso u_int i; 2162188294Spiso struct sctp_nat_assoc *assoc = NULL; 2163188294Spiso struct sctp_GlobalAddress *G_Addr = NULL; 2164186543Spiso 2165188294Spiso if (g_vtag != 0) { /* an init packet, vtag==0 */ 2166188294Spiso i = SN_TABLE_HASH(g_vtag, l_port, la->sctpNatTableSize); 2167188294Spiso LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) { 2168188294Spiso if ((assoc->l_vtag == g_vtag) && (assoc->l_port == l_port) && (assoc->g_port == g_port)) { 2169188294Spiso if (assoc->num_Gaddr) { 2170188294Spiso LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { 2171188294Spiso if(G_Addr->g_addr.s_addr == g_addr.s_addr) 2172188294Spiso return(assoc); 2173188294Spiso } 2174188294Spiso } else { 2175188294Spiso return(assoc); 2176188294Spiso } 2177188294Spiso } 2178188294Spiso } 2179186543Spiso } 2180188294Spiso return(NULL); 2181186543Spiso} 2182186543Spiso 2183186543Spiso/** @ingroup Hash 2184186543Spiso * @brief Add the sctp association information to the local look up table 2185186543Spiso * 2186186543Spiso * Searches the local look-up table for an existing association with the same 2187186543Spiso * details. If a match exists and is ONLY in the local look-up table then this 2188186543Spiso * is a repeated INIT packet, we need to remove this association from the 2189186543Spiso * look-up table and add the new association 2190186543Spiso * 2191186543Spiso * The new association is added to the head of the list and state is updated 2192186543Spiso * 2193186543Spiso * @param la Pointer to the relevant libalias instance 2194186543Spiso * @param assoc pointer to sctp association 2195186543Spiso * @param g_addr global address 2196186543Spiso * 2197186543Spiso * @return SN_ADD_OK | SN_ADD_CLASH 2198186543Spiso */ 2199186543Spisostatic int 2200186543SpisoAddSctpAssocLocal(struct libalias *la, struct sctp_nat_assoc *assoc, struct in_addr g_addr) 2201186543Spiso{ 2202188294Spiso struct sctp_nat_assoc *found; 2203186543Spiso 2204188294Spiso LIBALIAS_LOCK_ASSERT(la); 2205188294Spiso found = FindSctpLocal(la, assoc->l_addr, g_addr, assoc->l_vtag, assoc->l_port, assoc->g_port); 2206188294Spiso /* 2207188294Spiso * Note that if a different global address initiated this Init, 2208188294Spiso * ie it wasn't resent as presumed: 2209188294Spiso * - the local receiver if receiving it for the first time will establish 2210188294Spiso * an association with the new global host 2211188294Spiso * - if receiving an init from a different global address after sending a 2212188294Spiso * lost initack it will send an initack to the new global host, the first 2213188294Spiso * association attempt will then be blocked if retried. 2214188294Spiso */ 2215188294Spiso if (found != NULL) { 2216188294Spiso if ((found->TableRegister == SN_LOCAL_TBL) && (found->g_port == assoc->g_port)) { /* resent message */ 2217188294Spiso RmSctpAssoc(la, found); 2218188294Spiso sctp_RmTimeOut(la, found); 2219188294Spiso freeGlobalAddressList(found); 2220188294Spiso sn_free(found); 2221188294Spiso } else 2222188294Spiso return(SN_ADD_CLASH); 2223188294Spiso } 2224186543Spiso 2225188294Spiso LIST_INSERT_HEAD(&la->sctpTableLocal[SN_TABLE_HASH(assoc->l_vtag, assoc->l_port, la->sctpNatTableSize)], 2226188294Spiso assoc, list_L); 2227188294Spiso assoc->TableRegister |= SN_LOCAL_TBL; 2228188294Spiso la->sctpLinkCount++; //increment link count 2229186543Spiso 2230188294Spiso if (assoc->TableRegister == SN_BOTH_TBL) { 2231188294Spiso /* libalias log -- controlled by libalias */ 2232188294Spiso if (la->packetAliasMode & PKT_ALIAS_LOG) 2233188294Spiso SctpShowAliasStats(la); 2234186543Spiso 2235188294Spiso SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "^")); 2236188294Spiso } 2237186543Spiso 2238188294Spiso return(SN_ADD_OK); 2239186543Spiso} 2240186543Spiso 2241186543Spiso/** @ingroup Hash 2242186543Spiso * @brief Add the sctp association information to the global look up table 2243186543Spiso * 2244186543Spiso * Searches the global look-up table for an existing association with the same 2245186543Spiso * details. If a match exists and is ONLY in the global look-up table then this 2246186543Spiso * is a repeated INIT packet, we need to remove this association from the 2247186543Spiso * look-up table and add the new association 2248186543Spiso * 2249186543Spiso * The new association is added to the head of the list and state is updated 2250186543Spiso * 2251186543Spiso * @param la Pointer to the relevant libalias instance 2252186543Spiso * @param assoc pointer to sctp association 2253186543Spiso * 2254186543Spiso * @return SN_ADD_OK | SN_ADD_CLASH 2255186543Spiso */ 2256186543Spisostatic int 2257186543SpisoAddSctpAssocGlobal(struct libalias *la, struct sctp_nat_assoc *assoc) 2258186543Spiso{ 2259188294Spiso struct sctp_nat_assoc *found; 2260186543Spiso 2261188294Spiso LIBALIAS_LOCK_ASSERT(la); 2262188294Spiso found = FindSctpGlobalClash(la, assoc); 2263188294Spiso if (found != NULL) { 2264188294Spiso if ((found->TableRegister == SN_GLOBAL_TBL) && \ 2265188294Spiso (found->l_addr.s_addr == assoc->l_addr.s_addr) && (found->l_port == assoc->l_port)) { /* resent message */ 2266188294Spiso RmSctpAssoc(la, found); 2267188294Spiso sctp_RmTimeOut(la, found); 2268188294Spiso freeGlobalAddressList(found); 2269188294Spiso sn_free(found); 2270188294Spiso } else 2271188294Spiso return(SN_ADD_CLASH); 2272188294Spiso } 2273186543Spiso 2274188294Spiso LIST_INSERT_HEAD(&la->sctpTableGlobal[SN_TABLE_HASH(assoc->g_vtag, assoc->g_port, la->sctpNatTableSize)], 2275188294Spiso assoc, list_G); 2276188294Spiso assoc->TableRegister |= SN_GLOBAL_TBL; 2277188294Spiso la->sctpLinkCount++; //increment link count 2278186543Spiso 2279188294Spiso if (assoc->TableRegister == SN_BOTH_TBL) { 2280188294Spiso /* libalias log -- controlled by libalias */ 2281188294Spiso if (la->packetAliasMode & PKT_ALIAS_LOG) 2282188294Spiso SctpShowAliasStats(la); 2283186543Spiso 2284188294Spiso SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "^")); 2285188294Spiso } 2286186543Spiso 2287188294Spiso return(SN_ADD_OK); 2288186543Spiso} 2289186543Spiso 2290186543Spiso/** @ingroup Hash 2291186543Spiso * @brief Remove the sctp association information from the look up table 2292186543Spiso * 2293186543Spiso * For each of the two (local/global) look-up tables, remove the association 2294186543Spiso * from that table IF it has been registered in that table. 2295186543Spiso * 2296186543Spiso * NOTE: The calling code is responsible for freeing memory allocated to the 2297186543Spiso * association structure itself 2298186543Spiso * 2299186543Spiso * NOTE: The association is NOT removed from the timer queue 2300186543Spiso * 2301186543Spiso * @param la Pointer to the relevant libalias instance 2302186543Spiso * @param assoc pointer to sctp association 2303186543Spiso */ 2304186543Spisostatic void 2305186543SpisoRmSctpAssoc(struct libalias *la, struct sctp_nat_assoc *assoc) 2306186543Spiso{ 2307188294Spiso // struct sctp_nat_assoc *found; 2308188294Spiso if (assoc == NULL) { 2309188294Spiso /* very bad, log and die*/ 2310188294Spiso SN_LOG(SN_LOG_LOW, 2311188294Spiso logsctperror("ERROR: alias_sctp:RmSctpAssoc(NULL)\n", 0, 0, SN_TO_NODIR)); 2312188294Spiso return; 2313188294Spiso } 2314188294Spiso /* log if association is fully up and now closing */ 2315188294Spiso if (assoc->TableRegister == SN_BOTH_TBL) { 2316188294Spiso SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "$")); 2317188294Spiso } 2318188294Spiso LIBALIAS_LOCK_ASSERT(la); 2319188294Spiso if (assoc->TableRegister & SN_LOCAL_TBL) { 2320188294Spiso assoc->TableRegister ^= SN_LOCAL_TBL; 2321188294Spiso la->sctpLinkCount--; //decrement link count 2322188294Spiso LIST_REMOVE(assoc, list_L); 2323188294Spiso } 2324186543Spiso 2325188294Spiso if (assoc->TableRegister & SN_GLOBAL_TBL) { 2326188294Spiso assoc->TableRegister ^= SN_GLOBAL_TBL; 2327188294Spiso la->sctpLinkCount--; //decrement link count 2328188294Spiso LIST_REMOVE(assoc, list_G); 2329188294Spiso } 2330188294Spiso // sn_free(assoc); //Don't remove now, remove if needed later 2331188294Spiso /* libalias logging -- controlled by libalias log definition */ 2332188294Spiso if (la->packetAliasMode & PKT_ALIAS_LOG) 2333188294Spiso SctpShowAliasStats(la); 2334186543Spiso} 2335186543Spiso 2336186543Spiso/** 2337186543Spiso * @ingroup Hash 2338186543Spiso * @brief free the Global Address List memory 2339186543Spiso * 2340186543Spiso * freeGlobalAddressList deletes all global IP addresses in an associations 2341186543Spiso * global IP address list. 2342186543Spiso * 2343186543Spiso * @param assoc 2344186543Spiso */ 2345186543Spisostatic void freeGlobalAddressList(struct sctp_nat_assoc *assoc) 2346186543Spiso{ 2347188294Spiso struct sctp_GlobalAddress *gaddr1=NULL,*gaddr2=NULL; 2348188294Spiso /*free global address list*/ 2349188294Spiso gaddr1 = LIST_FIRST(&(assoc->Gaddr)); 2350188294Spiso while (gaddr1 != NULL) { 2351188294Spiso gaddr2 = LIST_NEXT(gaddr1, list_Gaddr); 2352188294Spiso sn_free(gaddr1); 2353188294Spiso gaddr1 = gaddr2; 2354188294Spiso } 2355186543Spiso} 2356186543Spiso/* ---------------------------------------------------------------------- 2357186543Spiso * TIMER QUEUE CODE 2358186543Spiso * ---------------------------------------------------------------------- 2359186543Spiso */ 2360186543Spiso/** @addtogroup Timer 2361186543Spiso * 2362186543Spiso * The timer queue management functions are designed to operate efficiently with 2363186543Spiso * a minimum of interaction with the queues. 2364186543Spiso * 2365186543Spiso * Once a timeout is set in the queue it will not be altered in the queue unless 2366186543Spiso * it has to be changed to a shorter time (usually only for aborts and closing). 2367186543Spiso * On a queue timeout, the real expiry time is checked, and if not leq than the 2368186543Spiso * timeout it is requeued (O(1)) at its later time. This is especially important 2369186543Spiso * for normal packets sent during an association. When a timer expires, it is 2370186543Spiso * updated to its new expiration time if necessary, or processed as a 2371186543Spiso * timeout. This means that while in UP state, the timing queue is only altered 2372186543Spiso * every U_T (every few minutes) for a particular association. 2373186543Spiso */ 2374186543Spiso/** @ingroup Timer 2375186543Spiso * @brief Add an association timeout to the timer queue 2376186543Spiso * 2377186543Spiso * Determine the location in the queue to add the timeout and insert the 2378186543Spiso * association into the list at that queue position 2379186543Spiso * 2380186543Spiso * @param la 2381186543Spiso * @param assoc 2382186543Spiso */ 2383186543Spisostatic void 2384186543Spisosctp_AddTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc) 2385186543Spiso{ 2386188294Spiso int add_loc; 2387188294Spiso LIBALIAS_LOCK_ASSERT(la); 2388188294Spiso add_loc = assoc->exp - la->sctpNatTimer.loc_time + la->sctpNatTimer.cur_loc; 2389188294Spiso if (add_loc >= SN_TIMER_QUEUE_SIZE) 2390188294Spiso add_loc -= SN_TIMER_QUEUE_SIZE; 2391188294Spiso LIST_INSERT_HEAD(&la->sctpNatTimer.TimerQ[add_loc], assoc, timer_Q); 2392188294Spiso assoc->exp_loc = add_loc; 2393186543Spiso} 2394186543Spiso 2395186543Spiso/** @ingroup Timer 2396186543Spiso * @brief Remove an association from timer queue 2397186543Spiso * 2398186543Spiso * This is an O(1) operation to remove the association pointer from its 2399186543Spiso * current position in the timer queue 2400186543Spiso * 2401186543Spiso * @param la Pointer to the relevant libalias instance 2402186543Spiso * @param assoc pointer to sctp association 2403186543Spiso */ 2404186543Spisostatic void 2405186543Spisosctp_RmTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc) 2406186543Spiso{ 2407188294Spiso LIBALIAS_LOCK_ASSERT(la); 2408188294Spiso LIST_REMOVE(assoc, timer_Q);/* Note this is O(1) */ 2409186543Spiso} 2410186543Spiso 2411186543Spiso 2412186543Spiso/** @ingroup Timer 2413186543Spiso * @brief Reset timer in timer queue 2414186543Spiso * 2415186543Spiso * Reset the actual timeout for the specified association. If it is earlier than 2416186543Spiso * the existing timeout, then remove and re-install the association into the 2417186543Spiso * queue 2418186543Spiso * 2419186543Spiso * @param la Pointer to the relevant libalias instance 2420186543Spiso * @param assoc pointer to sctp association 2421186543Spiso * @param newexp New expiration time 2422186543Spiso */ 2423186543Spisostatic void 2424186543Spisosctp_ResetTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc, int newexp) 2425186543Spiso{ 2426188294Spiso if (newexp < assoc->exp) { 2427188294Spiso sctp_RmTimeOut(la, assoc); 2428188294Spiso assoc->exp = newexp; 2429188294Spiso sctp_AddTimeOut(la, assoc); 2430188294Spiso } else { 2431188294Spiso assoc->exp = newexp; 2432188294Spiso } 2433186543Spiso} 2434186543Spiso 2435186543Spiso/** @ingroup Timer 2436186543Spiso * @brief Check timer Q against current time 2437186543Spiso * 2438186543Spiso * Loop through each entry in the timer queue since the last time we processed 2439186543Spiso * the timer queue until now (the current time). For each association in the 2440186543Spiso * event list, we remove it from that position in the timer queue and check if 2441186543Spiso * it has really expired. If so we: 2442186543Spiso * - Log the timer expiry 2443186543Spiso * - Remove the association from the NAT tables 2444186543Spiso * - Release the memory used by the association 2445186543Spiso * 2446186543Spiso * If the timer hasn't really expired we place the association into its new 2447186543Spiso * correct position in the timer queue. 2448186543Spiso * 2449186543Spiso * @param la Pointer to the relevant libalias instance 2450186543Spiso */ 2451186543Spisovoid 2452186543Spisosctp_CheckTimers(struct libalias *la) 2453186543Spiso{ 2454188294Spiso struct sctp_nat_assoc *assoc; 2455186543Spiso 2456188294Spiso LIBALIAS_LOCK_ASSERT(la); 2457188294Spiso while(la->timeStamp >= la->sctpNatTimer.loc_time) { 2458188294Spiso while (!LIST_EMPTY(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc])) { 2459188294Spiso assoc = LIST_FIRST(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc]); 2460188294Spiso //SLIST_REMOVE_HEAD(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc], timer_Q); 2461188294Spiso LIST_REMOVE(assoc, timer_Q); 2462188294Spiso if (la->timeStamp >= assoc->exp) { /* state expired */ 2463188294Spiso SN_LOG(((assoc->state == SN_CL)?(SN_LOG_DEBUG):(SN_LOG_INFO)), 2464188294Spiso logsctperror("Timer Expired", assoc->g_vtag, assoc->state, SN_TO_NODIR)); 2465188294Spiso RmSctpAssoc(la, assoc); 2466188294Spiso freeGlobalAddressList(assoc); 2467188294Spiso sn_free(assoc); 2468188294Spiso } else {/* state not expired, reschedule timer*/ 2469188294Spiso sctp_AddTimeOut(la, assoc); 2470188294Spiso } 2471188294Spiso } 2472188294Spiso /* Goto next location in the timer queue*/ 2473188294Spiso ++la->sctpNatTimer.loc_time; 2474188294Spiso if (++la->sctpNatTimer.cur_loc >= SN_TIMER_QUEUE_SIZE) 2475188294Spiso la->sctpNatTimer.cur_loc = 0; 2476188294Spiso } 2477186543Spiso} 2478186543Spiso 2479186543Spiso/* ---------------------------------------------------------------------- 2480186543Spiso * LOGGING CODE 2481186543Spiso * ---------------------------------------------------------------------- 2482186543Spiso */ 2483186543Spiso/** @addtogroup Logging 2484186543Spiso * 2485186543Spiso * The logging functions provide logging of different items ranging from logging 2486186543Spiso * a simple message, through logging an association details to logging the 2487186543Spiso * current state of the NAT tables 2488186543Spiso */ 2489186543Spiso/** @ingroup Logging 2490186543Spiso * @brief Log sctp nat errors 2491186543Spiso * 2492186543Spiso * @param errormsg Error message to be logged 2493186543Spiso * @param vtag Current Vtag 2494186543Spiso * @param error Error number 2495186543Spiso * @param direction Direction of packet 2496186543Spiso */ 2497186543Spisostatic void 2498186543Spisologsctperror(char* errormsg, uint32_t vtag, int error, int direction) 2499186543Spiso{ 2500188294Spiso char dir; 2501188294Spiso switch(direction) { 2502188294Spiso case SN_TO_LOCAL: 2503188294Spiso dir = 'L'; 2504188294Spiso break; 2505188294Spiso case SN_TO_GLOBAL: 2506188294Spiso dir = 'G'; 2507188294Spiso break; 2508188294Spiso default: 2509188294Spiso dir = '*'; 2510188294Spiso break; 2511188294Spiso } 2512188294Spiso SctpAliasLog("->%c %s (vt=%u) %d\n", dir, errormsg, ntohl(vtag), error); 2513186543Spiso} 2514186543Spiso 2515186543Spiso/** @ingroup Logging 2516186543Spiso * @brief Log what the parser parsed 2517186543Spiso * 2518186543Spiso * @param direction Direction of packet 2519186543Spiso * @param sm Pointer to sctp message information 2520186543Spiso */ 2521186543Spisostatic void 2522186543Spisologsctpparse(int direction, struct sctp_nat_msg *sm) 2523186543Spiso{ 2524188294Spiso char *ploc, *pstate; 2525188294Spiso switch(direction) { 2526188294Spiso case SN_TO_LOCAL: 2527188294Spiso ploc = "TO_LOCAL -"; 2528188294Spiso break; 2529188294Spiso case SN_TO_GLOBAL: 2530188294Spiso ploc = "TO_GLOBAL -"; 2531188294Spiso break; 2532188294Spiso default: 2533188294Spiso ploc = ""; 2534188294Spiso } 2535188294Spiso switch(sm->msg) { 2536188294Spiso case SN_SCTP_INIT: 2537188294Spiso pstate = "Init"; 2538188294Spiso break; 2539188294Spiso case SN_SCTP_INITACK: 2540188294Spiso pstate = "InitAck"; 2541188294Spiso break; 2542188294Spiso case SN_SCTP_ABORT: 2543188294Spiso pstate = "Abort"; 2544188294Spiso break; 2545188294Spiso case SN_SCTP_SHUTACK: 2546188294Spiso pstate = "ShutAck"; 2547188294Spiso break; 2548188294Spiso case SN_SCTP_SHUTCOMP: 2549188294Spiso pstate = "ShutComp"; 2550188294Spiso break; 2551188294Spiso case SN_SCTP_ASCONF: 2552188294Spiso pstate = "Asconf"; 2553188294Spiso break; 2554188294Spiso case SN_SCTP_ASCONFACK: 2555188294Spiso pstate = "AsconfAck"; 2556188294Spiso break; 2557188294Spiso case SN_SCTP_OTHER: 2558188294Spiso pstate = "Other"; 2559188294Spiso break; 2560188294Spiso default: 2561188294Spiso pstate = "***ERROR***"; 2562188294Spiso break; 2563188294Spiso } 2564188294Spiso SctpAliasLog("Parsed: %s %s\n", ploc, pstate); 2565186543Spiso} 2566186543Spiso 2567186543Spiso/** @ingroup Logging 2568186543Spiso * @brief Log an SCTP association's details 2569186543Spiso * 2570186543Spiso * @param assoc pointer to sctp association 2571186543Spiso * @param s Character that indicates the state of processing for this packet 2572186543Spiso */ 2573186543Spisostatic void logsctpassoc(struct sctp_nat_assoc *assoc, char* s) 2574186543Spiso{ 2575188294Spiso struct sctp_GlobalAddress *G_Addr = NULL; 2576188294Spiso char *sp; 2577188294Spiso switch(assoc->state) { 2578188294Spiso case SN_ID: 2579188294Spiso sp = "ID "; 2580188294Spiso break; 2581188294Spiso case SN_INi: 2582188294Spiso sp = "INi "; 2583188294Spiso break; 2584188294Spiso case SN_INa: 2585188294Spiso sp = "INa "; 2586188294Spiso break; 2587188294Spiso case SN_UP: 2588188294Spiso sp = "UP "; 2589188294Spiso break; 2590188294Spiso case SN_CL: 2591188294Spiso sp = "CL "; 2592188294Spiso break; 2593188294Spiso case SN_RM: 2594188294Spiso sp = "RM "; 2595188294Spiso break; 2596188294Spiso default: 2597188294Spiso sp = "***ERROR***"; 2598188294Spiso break; 2599188294Spiso } 2600188294Spiso SctpAliasLog("%sAssoc: %s exp=%u la=%s lv=%u lp=%u gv=%u gp=%u tbl=%d\n", 2601188294Spiso s, sp, assoc->exp, inet_ntoa(assoc->l_addr), ntohl(assoc->l_vtag), 2602188294Spiso ntohs(assoc->l_port), ntohl(assoc->g_vtag), ntohs(assoc->g_port), 2603188294Spiso assoc->TableRegister); 2604188294Spiso /* list global addresses */ 2605188294Spiso LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) { 2606188294Spiso SctpAliasLog("\t\tga=%s\n",inet_ntoa(G_Addr->g_addr)); 2607188294Spiso } 2608186543Spiso} 2609186543Spiso 2610186543Spiso/** @ingroup Logging 2611186543Spiso * @brief Output Global table to log 2612186543Spiso * 2613186543Spiso * @param la Pointer to the relevant libalias instance 2614186543Spiso */ 2615186543Spisostatic void logSctpGlobal(struct libalias *la) 2616186543Spiso{ 2617188294Spiso u_int i; 2618188294Spiso struct sctp_nat_assoc *assoc = NULL; 2619186543Spiso 2620188294Spiso SctpAliasLog("G->\n"); 2621188294Spiso for (i=0; i < la->sctpNatTableSize; i++) { 2622188294Spiso LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) { 2623188294Spiso logsctpassoc(assoc, " "); 2624188294Spiso } 2625188294Spiso } 2626186543Spiso} 2627186543Spiso 2628186543Spiso/** @ingroup Logging 2629186543Spiso * @brief Output Local table to log 2630186543Spiso * 2631186543Spiso * @param la Pointer to the relevant libalias instance 2632186543Spiso */ 2633186543Spisostatic void logSctpLocal(struct libalias *la) 2634186543Spiso{ 2635188294Spiso u_int i; 2636188294Spiso struct sctp_nat_assoc *assoc = NULL; 2637186543Spiso 2638188294Spiso SctpAliasLog("L->\n"); 2639188294Spiso for (i=0; i < la->sctpNatTableSize; i++) { 2640188294Spiso LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) { 2641188294Spiso logsctpassoc(assoc, " "); 2642188294Spiso } 2643188294Spiso } 2644186543Spiso} 2645186543Spiso 2646186543Spiso/** @ingroup Logging 2647186543Spiso * @brief Output timer queue to log 2648186543Spiso * 2649186543Spiso * @param la Pointer to the relevant libalias instance 2650186543Spiso */ 2651186543Spisostatic void logTimerQ(struct libalias *la) 2652186543Spiso{ 2653188294Spiso static char buf[50]; 2654188294Spiso u_int i; 2655188294Spiso struct sctp_nat_assoc *assoc = NULL; 2656186543Spiso 2657188294Spiso SctpAliasLog("t->\n"); 2658188294Spiso for (i=0; i < SN_TIMER_QUEUE_SIZE; i++) { 2659188294Spiso LIST_FOREACH(assoc, &la->sctpNatTimer.TimerQ[i], timer_Q) { 2660188294Spiso snprintf(buf, 50, " l=%u ",i); 2661188294Spiso //SctpAliasLog(la->logDesc," l=%d ",i); 2662188294Spiso logsctpassoc(assoc, buf); 2663188294Spiso } 2664188294Spiso } 2665186543Spiso} 2666186543Spiso 2667186543Spiso/** @ingroup Logging 2668186543Spiso * @brief Sctp NAT logging function 2669186543Spiso * 2670186543Spiso * This function is based on a similar function in alias_db.c 2671186543Spiso * 2672186543Spiso * @param str/stream logging descriptor 2673186543Spiso * @param format printf type string 2674186543Spiso */ 2675186543Spiso#ifdef _KERNEL 2676186543Spisostatic void 2677186543SpisoSctpAliasLog(const char *format, ...) 2678186543Spiso{ 2679188294Spiso char buffer[LIBALIAS_BUF_SIZE]; 2680188294Spiso va_list ap; 2681188294Spiso va_start(ap, format); 2682188294Spiso vsnprintf(buffer, LIBALIAS_BUF_SIZE, format, ap); 2683188294Spiso va_end(ap); 2684188294Spiso log(LOG_SECURITY | LOG_INFO, 2685188294Spiso "alias_sctp: %s", buffer); 2686186543Spiso} 2687186543Spiso#else 2688186543Spisostatic void 2689186543SpisoSctpAliasLog(FILE *stream, const char *format, ...) 2690186543Spiso{ 2691188294Spiso va_list ap; 2692186543Spiso 2693188294Spiso va_start(ap, format); 2694188294Spiso vfprintf(stream, format, ap); 2695188294Spiso va_end(ap); 2696188294Spiso fflush(stream); 2697186543Spiso} 2698186543Spiso#endif 2699