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 #include "fdproto-internal.h"
37 #include <time.h>
38 
39 /* This file contains helpers functions to be reused as callbacks in the struct dict_type_data structure.
40 There are three callbacks there:
41 
42  - type_encode    :
43  - type_interpret :
44  	  Those two callbacks allow to manipulate more natural structures of data in the code, and to
45 	map transparently these natural structures with the AVP-encoded format by calling the functions
46 	msg_avp_value_encode or msg_avp_value_interpret.
47  - type_dump :
48  	  This callback if provided gives a more human-readable debug information.
49 
50  */
51 
52 /****************************/
53 /*    Address  AVP  type    */
54 /****************************/
55 
56 /* The interpret and encode functions work with a "struct sockaddr_storage" pointer for mapping
57 the contents of the AVP */
58 
fd_dictfct_Address_encode(void * data,union avp_value * avp_value)59 int fd_dictfct_Address_encode(void * data, union avp_value * avp_value)
60 {
61 	sSS * ss = (sSS *) data;
62 	uint16_t AddressType = 0;
63 	size_t	size = 0;
64 	unsigned char * buf = NULL;
65 
66 	TRACE_ENTRY("%p %p", data, avp_value);
67 	CHECK_PARAMS( data && avp_value  );
68 
69 	switch (ss->ss_family) {
70 		case AF_INET:
71 			{
72 				/* We are encoding an IP address */
73 				sSA4 * sin = (sSA4 *)ss;
74 
75 				AddressType = 1;/* see http://www.iana.org/assignments/address-family-numbers/ */
76 				size = 6;	/* 2 for AddressType + 4 for data */
77 
78 				CHECK_MALLOC(  buf = malloc(size)  );
79 
80 				/* may not work because of alignment: *(uint32_t *)(buf+2) = htonl(sin->sin_addr.s_addr); */
81 				memcpy(buf + 2, &sin->sin_addr.s_addr, 4);
82 			}
83 			break;
84 
85 		case AF_INET6:
86 			{
87 				/* We are encoding an IPv6 address */
88 				sSA6 * sin6 = (sSA6 *)ss;
89 
90 				AddressType = 2;/* see http://www.iana.org/assignments/address-family-numbers/ */
91 				size = 18;	/* 2 for AddressType + 16 for data */
92 
93 				CHECK_MALLOC(  buf = malloc(size)  );
94 
95 				/* The order is already good here */
96 				memcpy(buf + 2, &sin6->sin6_addr.s6_addr, 16);
97 
98 			}
99 			break;
100 
101 		default:
102 			CHECK_PARAMS( AddressType = 0 );
103 	}
104 
105 	*(uint16_t *)buf = htons(AddressType);
106 
107 	avp_value->os.len = size;
108 	avp_value->os.data = buf;
109 
110 	return 0;
111 }
112 
fd_dictfct_Address_interpret(union avp_value * avp_value,void * interpreted)113 int fd_dictfct_Address_interpret(union avp_value * avp_value, void * interpreted)
114 {
115 	uint16_t AddressType = 0;
116 	unsigned char * buf;
117 
118 	TRACE_ENTRY("%p %p", avp_value, interpreted);
119 
120 	CHECK_PARAMS( avp_value && interpreted && (avp_value->os.len >= 2)  );
121 
122 	AddressType = ntohs(*(uint16_t *)avp_value->os.data);
123 	buf = &avp_value->os.data[2];
124 
125 	switch (AddressType) {
126 		case 1 /* IP */:
127 			{
128 				sSA4 * sin = (sSA4 *)interpreted;
129 
130 				CHECK_PARAMS(  avp_value->os.len == 6  );
131 
132 				sin->sin_family = AF_INET;
133 				/* sin->sin_addr.s_addr = ntohl( * (uint32_t *) buf); -- may not work because of bad alignment */
134 				memcpy(&sin->sin_addr.s_addr, buf, 4);
135 			}
136 			break;
137 
138 		case 2 /* IP6 */:
139 			{
140 				sSA6 * sin6 = (sSA6 *)interpreted;
141 
142 				CHECK_PARAMS(  avp_value->os.len == 18  );
143 
144 				sin6->sin6_family = AF_INET6;
145 				memcpy(&sin6->sin6_addr.s6_addr, buf, 16);
146 
147 			}
148 			break;
149 
150 		default:
151 			CHECK_PARAMS( AddressType = 0 );
152 	}
153 
154 	return 0;
155 }
156 
157 /* Dump the content of an Address AVP */
DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_Address_dump,union avp_value * avp_value)158 DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_Address_dump, union avp_value * avp_value)
159 {
160 	union {
161 		sSA	sa;
162 		sSS	ss;
163 		sSA4	sin;
164 		sSA6	sin6;
165 	} s;
166 	uint16_t fam;
167 
168 	FD_DUMP_HANDLE_OFFSET();
169 
170 	memset(&s, 0, sizeof(s));
171 
172 	/* The first two octets represent the address family, http://www.iana.org/assignments/address-family-numbers/ */
173 	if (avp_value->os.len < 2) {
174 		CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[invalid length: %zd]", avp_value->os.len), return NULL);
175 		return *buf;
176 	}
177 
178 	/* Following octets are the address in network byte order already */
179 	fam = avp_value->os.data[0] << 8 | avp_value->os.data[1];
180 	switch (fam) {
181 		case 1:
182 			/* IP */
183 			s.sa.sa_family = AF_INET;
184 			if ((avp_value->os.len != 6) && (avp_value->os.len != 8)) {
185 				CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[invalid IP length: %zd]", avp_value->os.len), return NULL);
186 				return *buf;
187 			}
188 			memcpy(&s.sin.sin_addr.s_addr, avp_value->os.data + 2, 4);
189 			if (avp_value->os.len == 8)
190 				memcpy(&s.sin.sin_port, avp_value->os.data + 6, 2);
191 			break;
192 		case 2:
193 			/* IP6 */
194 			s.sa.sa_family = AF_INET6;
195 			if ((avp_value->os.len != 18) && (avp_value->os.len != 20)) {
196 				CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[invalid IP6 length: %zd]", avp_value->os.len), return NULL);
197 				return *buf;
198 			}
199 			memcpy(&s.sin6.sin6_addr.s6_addr, avp_value->os.data + 2, 16);
200 			if (avp_value->os.len == 20)
201 				memcpy(&s.sin6.sin6_port, avp_value->os.data + 18, 2);
202 			break;
203 		case 8:
204 			/* E.164 */
205 			CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "%.*s", (int)(avp_value->os.len-2), avp_value->os.data+2), return NULL);
206 			return *buf;
207 		default:
208 			CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[unsupported family: 0x%hx]", fam), return NULL);
209 			return *buf;
210 	}
211 
212 	return fd_sa_dump(FD_DUMP_STD_PARAMS, &s.sa, NI_NUMERICHOST);
213 }
214 
215 
216 
217 /*******************************/
218 /*    UTF8String  AVP  type    */
219 /*******************************/
220 
221 /* Dump the AVP in a natural human-readable format. This dumps the complete length of the AVP, it is up to the caller to truncate if needed */
DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_UTF8String_dump,union avp_value * avp_value)222 DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_UTF8String_dump, union avp_value * avp_value)
223 {
224 	size_t l;
225 	FD_DUMP_HANDLE_OFFSET();
226 
227 	l = avp_value->os.len;
228 	/* Just in case the string ends in invalid UTF-8 chars, we shorten it */
229 	while ((l > 0) && (avp_value->os.data[l - 1] & 0x80)) {
230 		/* this byte is start or cont. of multibyte sequence, as we do not know the next byte we need to delete it. */
231 		l--;
232 		if (avp_value->os.data[l] & 0x40)
233 			break; /* This was a start byte, we can stop the loop */
234 	}
235 
236 	CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "\"%.*s\"", (int)l, (char *)avp_value->os.data), return NULL);
237 
238 	return *buf;
239 }
240 
241 
242 /*******************************/
243 /*    Time  AVP  type    */
244 /*******************************/
245 
246 /* The interpret and encode functions work with a "time_t" pointer for mapping
247 the contents of the AVP */
248 
249 /* Unix Epoch starts 1970-01-01, NTP 0 is at 1900-01-01 */
250 #define DIFF_EPOCH_TO_NTP ((365*(1970-1900) + 17ul) * 24 * 60 * 60)
251 
diameter_string_to_time_t(const char * str,size_t len,time_t * result)252 static int diameter_string_to_time_t(const char *str, size_t len, time_t *result) {
253     time_t time_stamp;
254     CHECK_PARAMS(len == 4);
255 
256     time_stamp = (((unsigned long)(str[0]&0xff))<<24) + ((str[1]&0xff)<<16) + ((str[2]&0xff)<<8) + ((str[3]&0xff));
257     time_stamp -= DIFF_EPOCH_TO_NTP;
258 #ifdef FIX__NEEDED_FOR_YEAR_2036_AND_LATER
259 /* NTP overflows in 2036; after that, values start at zero again */
260 #define NTP_OVERFLOW_CORRECTION (0x100000000ull)
261     /* XXX: debug and find correct conversion */
262     if (str[0] & 0x80 == 0x00) {
263         time_stamp += NTP_OVERFLOW_CORRECTION;
264     }
265 #endif
266     *result = time_stamp;
267     return 0;
268 }
269 
time_t_to_diameter_string(time_t time_stamp,char ** result)270 static int time_t_to_diameter_string(time_t time_stamp, char **result) {
271     uint64_t out = time_stamp;
272     char *conv;
273     /* XXX: 2036 fix */
274     out += DIFF_EPOCH_TO_NTP;
275     CHECK_PARAMS( (out >> 32) == 0);
276 
277     CHECK_MALLOC(conv=(char *)malloc(5));
278 
279     conv[0] = (out>>24) & 0xff;
280     conv[1] = (out>>16) & 0xff;
281     conv[2] = (out>> 8) & 0xff;
282     conv[3] =  out      & 0xff;
283     conv[4] = '\0';
284     *result = conv;
285     return 0;
286 }
287 
fd_dictfct_Time_encode(void * data,union avp_value * avp_value)288 int fd_dictfct_Time_encode(void * data, union avp_value * avp_value)
289 {
290 	char * buf = NULL;
291 	size_t len;
292 
293 	TRACE_ENTRY("%p %p", data, avp_value);
294 	CHECK_PARAMS( data && avp_value  );
295 
296 	CHECK_FCT( time_t_to_diameter_string( *((time_t *)data), &buf) );
297 	/* FIXME: return len from the function above? */ len = 4;
298 
299 	avp_value->os.len = len;
300 	avp_value->os.data = (uint8_t *)buf;
301 	return 0;
302 }
303 
fd_dictfct_Time_interpret(union avp_value * avp_value,void * interpreted)304 int fd_dictfct_Time_interpret(union avp_value * avp_value, void * interpreted)
305 {
306 	TRACE_ENTRY("%p %p", avp_value, interpreted);
307 
308 	CHECK_PARAMS( avp_value && interpreted );
309 
310 	return diameter_string_to_time_t((const char *)avp_value->os.data, avp_value->os.len, interpreted);
311 }
312 
_format_offs(long offset,char * buf)313 static void _format_offs (long offset, char *buf) {
314     int offs_hours, offs_minutes, sgn = 1;
315     if (offset < 0) {
316         offset = -offset;
317         sgn = 1;
318     }
319     offs_hours = (int)(offset/3600);
320     offs_minutes = (offset%3600)/60;
321 
322     char* s = buf;
323 
324     *(s++) = sgn == 1 ? '+' : '-';
325     *(s++) = (char)(offs_hours/10) + '0';
326     *(s++) = offs_hours%10 + '0';
327 
328     if (offs_minutes == 0) {
329         *(s++) = '\0';
330     } else {
331         *(s++) = (char)(offs_minutes/10) + '0';
332         *(s++) = offs_minutes%10 + '0';
333         *(s++) = '\0';
334     }
335 }
336 
DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_Time_dump,union avp_value * avp_value)337 DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_Time_dump, union avp_value * avp_value)
338 {
339 	time_t val;
340 	struct tm conv;
341 	char tz_buf[7];
342 
343 	FD_DUMP_HANDLE_OFFSET();
344 
345 	if (avp_value->os.len != 4) {
346 		CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[invalid length: %zd]", avp_value->os.len), return NULL);
347 		return *buf;
348 	}
349 
350 	if (diameter_string_to_time_t((char *)avp_value->os.data, avp_value->os.len, &val) != 0) {
351 		CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[time conversion error]"), return NULL);
352 		return *buf;
353 	}
354 
355 	CHECK_MALLOC_DO( localtime_r(&val, &conv), return NULL);
356 	_format_offs(conv.tm_gmtoff, tz_buf);
357 	CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "%d%02d%02dT%02d%02d%02d%s", conv.tm_year+1900, conv.tm_mon+1, conv.tm_mday, conv.tm_hour, conv.tm_min, conv.tm_sec, tz_buf), return NULL);
358 	return *buf;
359 }
360 
361 /* Check that a given AVP value contains all the characters from data in the same order */
362 static char error_message[80];
fd_dictfct_CharInOS_check(void * data,union avp_value * val,char ** error_msg)363 int fd_dictfct_CharInOS_check(void * data, union avp_value * val, char ** error_msg)
364 {
365 	char * inChar = data;
366 	char * inData = (char *)val->os.data;
367 	int i = 0;
368 	CHECK_PARAMS(data);
369 	while (*inChar != '\0') {
370 		while (i < val->os.len) {
371 			if (*inChar == inData[i++]) {
372 				inChar++;
373 				break;
374 			}
375 		}
376 		if (i >= val->os.len)
377 			break;
378 	}
379 	if (*inChar == '\0')
380 		return 0;
381 
382 	if (error_msg) {
383 		snprintf(error_message, sizeof(error_message), "Could not find '%c' in AVP", *inChar);
384 		*error_msg = error_message;
385 	}
386 	return EBADMSG;
387 }
388