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