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