1 /*********************************************************************************************************
2 * Software License Agreement (BSD License)                                                               *
3 * Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
4 *													 *
5 * Copyright (c) 2020, WIDE Project and NICT								 *
6 * All rights reserved.											 *
7 * 													 *
8 * Redistribution and use of this software in source and binary forms, with or without modification, are  *
9 * permitted provided that the following conditions are met:						 *
10 * 													 *
11 * * Redistributions of source code must retain the above 						 *
12 *   copyright notice, this list of conditions and the 							 *
13 *   following disclaimer.										 *
14 *    													 *
15 * * Redistributions in binary form must reproduce the above 						 *
16 *   copyright notice, this list of conditions and the 							 *
17 *   following disclaimer in the documentation and/or other						 *
18 *   materials provided with the distribution.								 *
19 * 													 *
20 * * Neither the name of the WIDE Project or NICT nor the 						 *
21 *   names of its contributors may be used to endorse or 						 *
22 *   promote products derived from this software without 						 *
23 *   specific prior written permission of WIDE Project and 						 *
24 *   NICT.												 *
25 * 													 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
34 *********************************************************************************************************/
35 
36 /* This file contains the definitions for internal use in the freeDiameter core library */
37 
38 #ifndef _FDCORE_INTERNAL_H
39 #define _FDCORE_INTERNAL_H
40 
41 #include <freeDiameter/freeDiameter-host.h>
42 #include <freeDiameter/libfdcore.h>
43 
44 #ifdef DISABLE_SCTP
45 #undef IPPROTO_SCTP
46 #define IPPROTO_SCTP	(2 = 4) /* some compilation error to spot the references */
47 #endif /* DISABLE_SCTP */
48 
49 #ifndef HAVE_AI_ADDRCONFIG
50 #define AI_ADDRCONFIG 0 /* ignore this flag at the moment */
51 #endif /* HAVE_AI_ADDRCONFIG */
52 
53 /* Timeout for establishing a connection */
54 #ifndef CNX_TIMEOUT
55 #define  CNX_TIMEOUT	10	/* in seconds */
56 #endif /* CNX_TIMEOUT */
57 
58 /* Timeout for receiving a CER after incoming connection is established */
59 #ifndef INCNX_TIMEOUT
60 #define  INCNX_TIMEOUT	 20	/* in seconds */
61 #endif /* INCNX_TIMEOUT */
62 
63 /* Timeout for receiving a CEA after CER is sent */
64 #ifndef CEA_TIMEOUT
65 #define  CEA_TIMEOUT	10	/* in seconds */
66 #endif /* CEA_TIMEOUT */
67 
68 /* The timeout value to wait for answer to a DPR */
69 #ifndef DPR_TIMEOUT
70 #define DPR_TIMEOUT 	15	/* in seconds */
71 #endif /* DPR_TIMEOUT */
72 
73 /* Delay where the connection is maintained opened to allow exchanging remaining pending answers after DPR/DPA */
74 #ifndef GRACE_TIMEOUT
75 #define GRACE_TIMEOUT   1	/* in seconds */
76 #endif /* GRACE_TIMEOUT */
77 
78 /* The Vendor-Id to advertise in CER/CEA */
79 #ifndef MY_VENDOR_ID
80 #define MY_VENDOR_ID	0 	/* Reserved value to tell it must be ignored */
81 #endif /* MY_VENDOR_ID */
82 
83 
84 
85 /* Configuration */
86 int fd_conf_init();
87 int fd_conf_deinit();
88 int fd_conf_parse();
89 int fddparse(struct fd_config * conf); /* yacc generated */
90 int fd_conf_stream_to_gnutls_datum(FILE * pemfile, gnutls_datum_t *out);
91 
92 
93 /* Extensions */
94 int fd_ext_add( char * filename, char * conffile );
95 int fd_ext_load();
96 int fd_ext_term(void);
97 
98 /* Messages */
99 int fd_msg_init(void);
100 extern struct dict_object * fd_dict_avp_OSI; /* Origin-State-Id */
101 extern struct dict_object * fd_dict_cmd_CER; /* Capabilities-Exchange-Request */
102 extern struct dict_object * fd_dict_cmd_DWR; /* Device-Watchdog-Request */
103 extern struct dict_object * fd_dict_avp_DC;  /* Disconnect-Cause */
104 extern struct dict_object * fd_dict_cmd_DPR; /* Disconnect-Peer-Request */
105 
106 /* Global message queues */
107 extern struct fifo * fd_g_incoming; /* all messages received from other peers, except local messages (CER, ...) */
108 extern struct fifo * fd_g_outgoing; /* messages to be sent to other peers on the network following routing procedure */
109 extern struct fifo * fd_g_local; /* messages to be handled to local extensions */
110 /* Message queues */
111 int fd_queues_init(void);
112 int fd_queues_init_after_conf(void);
113 int fd_queues_fini(struct fifo ** queue);
114 
115 /* Trigged events */
116 int fd_event_trig_call_cb(int trigger_val);
117 int fd_event_trig_fini(void);
118 
119 /* Create all the dictionary objects defined in the Diameter base RFC. */
120 int fd_dict_base_protocol(struct dictionary * dict);
121 
122 /* Routing */
123 int fd_rtdisp_init(void);
124 int fd_rtdisp_cleanstop(void);
125 int fd_rtdisp_fini(void);
126 int fd_rtdisp_cleanup(void);
127 
128 /* Sentinel for the sent requests list */
129 struct sr_list {
130 	struct fd_list 	srs; /* requests ordered by hop-by-hop id */
131 	struct fd_list  exp; /* requests that have a timeout set, ordered by timeout */
132 	long            cnt; /* number of requests in the srs list */
133 	long		cnt_lost; /* number of requests that have not been answered in time.
134 				     It is decremented when an unexpected answer is received, so this may not be accurate. */
135 	pthread_mutex_t	mtx; /* mutex to protect these lists */
136 	pthread_cond_t  cnd; /* cond var used by the thread that handles timeouts */
137 	pthread_t       thr; /* the thread that handles timeouts (expirecb called in separate forked threads) */
138 };
139 
140 /* Peers */
141 struct fd_peer { /* The "real" definition of the peer structure */
142 
143 	/* The public data */
144 	struct peer_hdr	 p_hdr;
145 
146 	/* Eye catcher, EYEC_PEER */
147 	int		 p_eyec;
148 	#define EYEC_PEER	0x373C9336
149 
150 	/* Origin of this peer object, for debug */
151 	char		*p_dbgorig;
152 
153 	/* State of the peer, and its lock */
154 	enum peer_state	 p_state;
155 	pthread_mutex_t  p_state_mtx;
156 
157 	/* Chaining in peers sublists */
158 	struct fd_list	 p_actives;	/* list of peers in the STATE_OPEN state -- used by routing */
159 	struct fd_list	 p_expiry; 	/* list of expiring peers, ordered by their timeout value */
160 	struct timespec	 p_exp_timer;	/* Timestamp where the peer will expire; updated each time activity is seen on the peer (except DW) */
161 
162 	/* Some flags influencing the peer state machine */
163 	struct {
164 		unsigned pf_responder	: 1;	/* The peer has been created to handle incoming connection */
165 		unsigned pf_delete	: 1;	/* Destroy the peer when the connection is terminated */
166 		unsigned pf_localterm	: 1;	/* If the latest DPR/DPA was initiated from this side */
167 
168 		unsigned pf_dw_pending 	: 1;	/* A DWR message was sent and not answered yet */
169 
170 		unsigned pf_cnx_pb	: 1;	/* The peer was disconnected because of watchdogs; must exchange 3 watchdogs before putting back to normal */
171 		unsigned pf_reopen_cnt	: 2;	/* remaining DW to be exchanged after re-established connection */
172 
173 	}		 p_flags;
174 
175 	/* The events queue, peer state machine thread, timer for states timeouts */
176 	struct fifo	*p_events;	/* The mutex of this FIFO list protects also the state and timer information */
177 	pthread_t	 p_psm;
178 	struct timespec	 p_psm_timer;
179 
180 	/* Outgoing message queue, and thread managing sending the messages */
181 	struct fifo	*p_tosend;
182 	pthread_t	 p_outthr;
183 
184 	/* The next hop-by-hop id value for the link, only read & modified by p_outthr */
185 	uint32_t	 p_hbh;
186 
187 	/* Sent requests (for fallback), list of struct sentreq ordered by hbh */
188 	struct sr_list	 p_sr;
189 	struct fifo	*p_tofailover;
190 
191 	/* Pending received requests not yet answered (count only) */
192 	long		 p_reqin_count; /* We use p_state_mtx to protect this value */
193 
194 	/* Data for transitional states before the peer is in OPEN state */
195 	struct {
196 		struct cnxctx * p_receiver;	/* Only used in case of election */
197 		struct msg    * p_cer;		/* Only used in case of election */
198 
199 		pthread_t	p_ini_thr;	/* Initiator thread for establishing a connection */
200 		struct fd_list  p_connparams;	/* The list of connection attempts, see p_cnx.c */
201 	};
202 
203 	/* connection context: socket and related information */
204 	struct cnxctx	*p_cnxctx;
205 
206 	/* Callback for peer validation after the handshake */
207 	int		(*p_cb2)(struct peer_info *);
208 
209 	/* Callback on initial connection success / failure after the peer was added */
210 	void 		(*p_cb)(struct peer_info *, void *);
211 	void 		*p_cb_data;
212 
213 };
214 #define CHECK_PEER( _p ) \
215 	(((_p) != NULL) && (((struct fd_peer *)(_p))->p_eyec == EYEC_PEER))
216 
217 #define fd_peer_getstate(peer)  fd_peer_get_state((struct peer_hdr *)(peer))
218 
219 
220 /* Events codespace for struct fd_peer->p_events */
221 enum {
222 	/* request to terminate this peer : disconnect, requeue all messages */
223 	FDEVP_TERMINATE = 1500
224 
225 	/* A connection object has received a message. (data contains the buffer + padding + struct fd_msg_pmdl) */
226 	,FDEVP_CNX_MSG_RECV
227 
228 	/* A connection object has encountered an error (disconnected). */
229 	,FDEVP_CNX_ERROR
230 
231 	/* Endpoints of a connection have been changed (multihomed SCTP). */
232 	,FDEVP_CNX_EP_CHANGE
233 
234 	/* The connection is being shutdown (SCTP notification). */
235 	,FDEVP_CNX_SHUTDOWN
236 
237 	/* A new connection (with a CER) has been received */
238 	,FDEVP_CNX_INCOMING
239 
240 	/* A new connection has been established to the remote peer (event data is the cnxctx object) */
241 	,FDEVP_CNX_ESTABLISHED
242 
243 	/* A connection attempt (initiator side) has failed */
244 	,FDEVP_CNX_FAILED
245 
246 	/* The PSM state is expired */
247 	,FDEVP_PSM_TIMEOUT
248 
249 };
250 #define CHECK_PEVENT( _e ) \
251 	(((int)(_e) >= FDEVP_TERMINATE) && ((int)(_e) <= FDEVP_PSM_TIMEOUT))
252 /* The following macro is actually called in p_psm.c -- another solution would be to declare it static inline */
253 #define DECLARE_PEV_STR()				\
254 const char * fd_pev_str(int event)			\
255 {							\
256 	switch (event) {				\
257 		case_str(FDEVP_TERMINATE);		\
258 		case_str(FDEVP_CNX_MSG_RECV);		\
259 		case_str(FDEVP_CNX_ERROR);		\
260 		case_str(FDEVP_CNX_EP_CHANGE);		\
261 		case_str(FDEVP_CNX_INCOMING);		\
262 		case_str(FDEVP_CNX_ESTABLISHED);	\
263 		case_str(FDEVP_CNX_FAILED);		\
264 		case_str(FDEVP_PSM_TIMEOUT);		\
265 	}						\
266 	TRACE_DEBUG(FULL, "Unknown event : %d", event);	\
267 	return "Unknown event";				\
268 }
269 const char * fd_pev_str(int event);
270 
271 /* The data structure for FDEVP_CNX_INCOMING event */
272 struct cnx_incoming {
273 	struct msg	* cer;		/* the CER message received on this connection */
274 	struct cnxctx	* cnx;		/* The connection context */
275 	int  		  validate;	/* The peer is new, it must be validated (by an extension) or error CEA to be sent */
276 };
277 
278 /* Functions */
279 int  fd_peer_fini();
280 int  fd_peer_alloc(struct fd_peer ** ptr);
281 int  fd_peer_free(struct fd_peer ** ptr);
282 int fd_peer_handle_newCER( struct msg ** cer, struct cnxctx ** cnx );
283 /* fd_peer_add declared in freeDiameter.h */
284 int fd_peer_validate( struct fd_peer * peer );
285 void fd_peer_failover_msg(struct fd_peer * peer);
286 
287 /* Peer expiry */
288 int fd_p_expi_init(void);
289 int fd_p_expi_fini(void);
290 int fd_p_expi_update(struct fd_peer * peer );
291 
292 /* Peer state machine */
293 int  fd_psm_start();
294 int  fd_psm_begin(struct fd_peer * peer );
295 int  fd_psm_terminate(struct fd_peer * peer, char * reason );
296 void fd_psm_abord(struct fd_peer * peer );
297 void fd_psm_next_timeout(struct fd_peer * peer, int add_random, int delay);
298 int fd_psm_change_state(struct fd_peer * peer, int new_state);
299 void fd_psm_cleanup(struct fd_peer * peer, int terminate);
300 
301 /* Peer out */
302 int fd_out_send(struct msg ** msg, struct cnxctx * cnx, struct fd_peer * peer, int update_reqin_cnt);
303 int fd_out_start(struct fd_peer * peer);
304 int fd_out_stop(struct fd_peer * peer);
305 
306 /* Initiating connections */
307 int fd_p_cnx_init(struct fd_peer * peer);
308 void fd_p_cnx_abort(struct fd_peer * peer, int cleanup_all);
309 
310 /* Peer sent requests cache */
311 int fd_p_sr_store(struct sr_list * srlist, struct msg **req, uint32_t *hbhloc, uint32_t hbh_restore);
312 int fd_p_sr_fetch(struct sr_list * srlist, uint32_t hbh, struct msg **req);
313 int fd_p_sr_start(struct sr_list * srlist);
314 int fd_p_sr_stop(struct sr_list * srlist);
315 void fd_p_sr_failover(struct sr_list * srlist);
316 
317 /* Local Link messages (CER/CEA, DWR/DWA, DPR/DPA) */
318 int fd_p_ce_msgrcv(struct msg ** msg, int req, struct fd_peer * peer);
319 int fd_p_ce_handle_newCER(struct msg ** msg, struct fd_peer * peer, struct cnxctx ** cnx, int valid);
320 int fd_p_ce_handle_newcnx(struct fd_peer * peer, struct cnxctx * initiator);
321 int fd_p_ce_process_receiver(struct fd_peer * peer);
322 void fd_p_ce_clear_cnx(struct fd_peer * peer, struct cnxctx ** cnx_kept);
323 int fd_p_dw_handle(struct msg ** msg, int req, struct fd_peer * peer);
324 int fd_p_dw_timeout(struct fd_peer * peer);
325 int fd_p_dw_reopen(struct fd_peer * peer);
326 int fd_p_dp_handle(struct msg ** msg, int req, struct fd_peer * peer);
327 int fd_p_dp_initiate(struct fd_peer * peer, char * reason);
328 int fd_p_dp_newdelay(struct fd_peer * peer);
329 
330 /* Active peers -- routing process should only ever take the read lock, the write lock is managed by PSMs */
331 extern struct fd_list fd_g_activ_peers;
332 extern pthread_rwlock_t fd_g_activ_peers_rw; /* protect the list */
333 
334 
335 /* Server sockets */
336 int  fd_servers_start();
337 int  fd_servers_stop();
338 
339 /* Connection contexts -- there are also definitions in cnxctx.h for the relevant files */
340 struct cnxctx * fd_cnx_serv_tcp(uint16_t port, int family, struct fd_endpoint * ep);
341 struct cnxctx * fd_cnx_serv_sctp(uint16_t port, struct fd_list * ep_list);
342 int             fd_cnx_serv_listen(struct cnxctx * conn);
343 struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv);
344 struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa, socklen_t addrlen);
345 struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list, struct fd_list * src_list);
346 int             fd_cnx_start_clear(struct cnxctx * conn, int loop);
347 void		fd_cnx_sethostname(struct cnxctx * conn, DiamId_t hn);
348 int		fd_cnx_proto_info(struct cnxctx * conn, char * buf, size_t len);
349 #define ALGO_HANDSHAKE_DEFAULT	0 /* TLS for TCP, DTLS for SCTP */
350 #define ALGO_HANDSHAKE_3436	1 /* For TLS for SCTP also */
351 int             fd_cnx_handshake(struct cnxctx * conn, int mode, int algo, char * priority, void * alt_creds);
352 char *          fd_cnx_getid(struct cnxctx * conn);
353 int		fd_cnx_getproto(struct cnxctx * conn);
354 int		fd_cnx_getTLS(struct cnxctx * conn);
355 int		fd_cnx_is_unordered_delivery_supported(struct cnxctx * conn);
356 int		fd_cnx_unordered_delivery(struct cnxctx * conn, int is_allowed);
357 int             fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size);
358 int 		fd_cnx_get_local_eps(struct fd_list * list);
359 int             fd_cnx_getremoteeps(struct cnxctx * conn, struct fd_list * eps);
360 char *          fd_cnx_getremoteid(struct cnxctx * conn);
361 int             fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len);
362 int             fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo); /* send FDEVP_CNX_MSG_RECV event to the fifo list */
363 int             fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len);
364 void            fd_cnx_destroy(struct cnxctx * conn);
365 #ifdef GNUTLS_VERSION_300
366 int             fd_tls_verify_credentials_2(gnutls_session_t session);
367 #endif /* GNUTLS_VERSION_300 */
368 
369 /* Internal calls of the hook mechanism */
370 void   fd_hook_call(enum fd_hook_type type, struct msg * msg, struct fd_peer * peer, void * other, struct fd_msg_pmdl * pmdl);
371 void   fd_hook_associate(struct msg * msg, struct fd_msg_pmdl * pmdl);
372 int    fd_hooks_init(void);
373 size_t fd_msg_pmdl_sizewithoverhead(size_t datalen);
374 struct fd_msg_pmdl * fd_msg_pmdl_get_inbuf(uint8_t * buf, size_t datalen);
375 
376 #endif /* _FDCORE_INTERNAL_H */
377