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