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