1/*
2 * Copyright (C) NEC Europe Ltd., 2003
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <stdlib.h>
31#include <string.h>
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <arpa/inet.h>
35
36#include "relay6_database.h"
37
38void
39init_relay(void)
40{
41	nr_of_uni_addr = 0;
42	multicast_off = 0;
43	nr_of_devices = 0;
44	max_count = 0;
45
46	cifaces_list.next = &cifaces_list;
47
48	sifaces_list.next = &sifaces_list;
49
50	server_list.next = &server_list;
51
52	IPv6_address_list.next = &IPv6_address_list;
53
54	IPv6_uniaddr_list.next = &IPv6_uniaddr_list;
55
56	interface_list.prev = &interface_list;
57	interface_list.next = &interface_list;
58
59	msg_parser_list.prev = &msg_parser_list;
60	msg_parser_list.next = &msg_parser_list;
61}
62
63int
64check_interface_semafor(int index)
65{
66	struct interface *device = NULL;
67	struct cifaces *iface;
68
69	device = get_interface(index);
70	if (device == NULL) {
71		printf("FATAL ERROR IN CheckInterfaceSemafor()\n");
72		exit(1);
73	}
74
75	if (cifaces_list.next == &cifaces_list)
76		return 1;
77
78	for (iface = cifaces_list.next; iface != &cifaces_list;
79	     iface = iface->next) {
80		if (strcmp(device->ifname, iface->ciface) == 0)
81			return 1;
82	}
83
84	return 0;
85}
86
87struct interface *get_interface(int if_index)
88{
89	struct interface *deviface;
90
91	for (deviface = interface_list.next; deviface != &interface_list;
92	     deviface = deviface->next) {
93		if (deviface->devindex == if_index)
94			return deviface;
95	}
96
97	return NULL;
98}
99
100struct interface *get_interface_s(char *s)
101{
102	struct interface *deviface;
103
104	for (deviface = interface_list.next; deviface != &interface_list;
105	     deviface = deviface->next) {
106		if (strcmp(s, deviface->ifname)== 0)
107			return deviface;
108	}
109
110	return NULL;
111}
112
113struct msg_parser *get_send_messages_out(void)
114{
115	struct msg_parser *msg;
116
117	for (msg = msg_parser_list.next; msg != &msg_parser_list; msg = msg->next) {
118		if (msg->sent == 0)
119			return msg;
120	}
121
122	return NULL;
123}
124
125
126void delete_messages(void)
127{
128	struct msg_parser *msg;
129
130	for (msg = msg_parser_list.next; msg != &msg_parser_list; msg = msg->next) {
131		if (msg->sent == 1) {
132			msg->prev->next = msg->next;
133			msg->next->prev = msg->prev;
134			msg->next = NULL;
135			msg->prev = NULL;
136			free(msg->buffer);
137			free(msg);
138			msg = msg_parser_list.next;
139		}
140	}
141}
142
143
144int
145process_RELAY_FORW(struct msg_parser *msg)
146{
147	uint8_t *head = (uint8_t *) malloc(HEAD_SIZE*sizeof(uint8_t));
148	uint8_t *newbuff = (uint8_t *) malloc(MAX_DHCP_MSG_LENGTH*sizeof(uint8_t));
149	uint8_t *pointer;
150	struct interface *device = NULL;
151	struct sockaddr_in6 sap;
152	int check = 0;
153	uint16_t *p16, *optl;
154	uint32_t *p32;
155	int len, hop;
156
157	if ((head == NULL) || (newbuff == NULL)) {
158		printf("ProcessRELAYFORW--> ERROR, NO MORE MEMRY AVAILABLE  \n");
159		exit(1);
160	}
161
162	memset(head, 0, HEAD_SIZE);
163
164	pointer = head;
165
166
167	if (msg->isRF == 1) { /* got message from a relay agent to be relayed */
168		(*pointer) = RELAY_FORW;
169		pointer += 1;
170		(*pointer) = msg->hop_count + 1; /* increased hop-count */
171		msg->hc_pointer = pointer;
172
173		if (max_count == 1) {
174			(*pointer) = MAXHOPCOUNT;
175			hop = (int) (*pointer);
176			TRACE(dump, "%s - %s%d\n", dhcp6r_clock(), "HOPCOUNT: ", hop);
177		}
178
179		pointer += 1;
180
181	}
182	else {            /*got message from a client to be relayed */
183		(*pointer) = RELAY_FORW;
184		pointer += 1;
185		(*pointer) = 0; /* hop-count */
186		msg->hc_pointer = pointer;
187
188		if (max_count == 1) {
189			(*pointer) = MAXHOPCOUNT;
190			hop = (int) (*pointer);
191			TRACE(dump, "%s - %s%d\n", dhcp6r_clock(), "HOPCOUNT: ", hop);
192		}
193		pointer += 1;
194	}
195
196	msg->msg_type = RELAY_FORW;
197
198	device = get_interface(msg->interface_in);
199	if (device == NULL) {
200		printf("ProcessRELAYFORW--->ERROR NO INTERFACE FOUND!\n");
201		exit(1);
202	}
203
204	/* fill in link-address */
205
206	if (inet_pton(AF_INET6, msg->src_addr , &sap.sin6_addr) <= 0) {
207		printf("ProcessRELAYFORW1--->ERROR IN  inet_pton !\n");
208		exit(1);
209	}
210
211	if ((!IN6_IS_ADDR_LINKLOCAL(&sap.sin6_addr)) && (nr_of_devices == 1 )) {
212		memset(&sap.sin6_addr, 0, sizeof(sap.sin6_addr));
213		memcpy(pointer, &sap.sin6_addr, INET6_LEN);
214		pointer += INET6_LEN;
215	}
216	else {
217		check = 0;
218
219		memset(&sap.sin6_addr, 0, sizeof(sap.sin6_addr));
220
221		if (inet_pton(AF_INET6, device->ipv6addr->gaddr, &sap.sin6_addr) <= 0) {
222			printf("ProcessRELAYFORW1--->ERROR IN  inet_pton !\n");
223			exit(1);
224		}
225
226		memcpy(pointer, &sap.sin6_addr, INET6_LEN);
227		pointer += INET6_LEN;
228	}
229
230
231	/* fill in peer-addrees */
232	memset(&sap.sin6_addr, 0, sizeof(sap.sin6_addr));
233
234	if (inet_pton(AF_INET6, msg->src_addr , &sap.sin6_addr) <= 0) {
235		printf("ProcessRELAYFORW--->ERROR2 IN  inet_pton !\n");
236		exit(1);
237	}
238
239	memcpy(pointer, &sap.sin6_addr, INET6_LEN);
240	pointer += INET6_LEN;
241
242	/* Insert Interface_ID option to identify the interface */
243	p16 = (uint16_t *) pointer;
244	*p16 = htons(OPTION_INTERFACE_ID);
245	pointer += 2;
246	p16 = (uint16_t *) pointer;
247	*p16 = htons(4); /* 4 octeti length */
248	pointer += 2;
249	p32 = (uint32_t *) pointer;
250	*p32 = htonl(device->opaq);
251	pointer += 4;
252
253	p16 = (uint16_t *) pointer;
254	*p16 = htons(OPTION_RELAY_MSG);
255	pointer += 2;
256	optl = (uint16_t *) pointer;
257	pointer += 2;
258	*optl = htons(msg->datalength);
259
260	len = (pointer - head);
261	TRACE(dump, "%s - %s%d\n", dhcp6r_clock(), "RELAY_FORW HEADERLENGTH: ",
262	      len);
263	TRACE(dump, "%s - %s%d\n", dhcp6r_clock(), "ORIGINAL MESSAGE LENGTH: ",
264	      msg->datalength );
265
266	if ((len+ msg->datalength) > MAX_DHCP_MSG_LENGTH) {
267		printf(" ERROR FRAGMENTATION WILL OCCUR IF SENT, DROP THE PACKET"
268		       "......\n");
269		return 0;
270	}
271
272	pointer = newbuff;
273	memset(pointer, 0, MAX_DHCP_MSG_LENGTH);
274	memcpy(pointer, head, len);
275	pointer += len;
276	memcpy(pointer, msg->buffer, msg->datalength);
277	msg->datalength += len; /* final length for sending */
278	free(msg->buffer);
279	free(head);
280	msg->buffer = newbuff;
281
282	return 1;
283}
284
285int
286process_RELAY_REPL(struct msg_parser *msg)
287{
288	uint8_t *newbuff = (uint8_t *) malloc(MAX_DHCP_MSG_LENGTH*sizeof(uint8_t));
289	uint8_t *pointer, *pstart, *psp;
290	struct interface *device = NULL;
291	struct sockaddr_in6 sap;
292	int check = 0;
293	uint16_t *p16, option, opaqlen, msglen;
294	uint32_t *p32;
295	int len, opaq;
296	struct IPv6_address *ipv6a;
297	char *s;
298
299	if (newbuff == NULL) {
300		printf("ProcessRELAYREPL--> ERROR, NO MORE MEMRY AVAILABLE  \n");
301		exit(1);
302	}
303
304	pointer = msg->buffer;
305	pstart = pointer;
306
307	if (( ((int) msg->buffer) - ((int) (pointer - pstart)) ) <
308	    MESSAGE_HEADER_LENGTH ) {
309		printf("ProcessRELAYREPL()--> opt_length has 0 value for "
310		       "MESSAGE_HEADER_LENGTH, DROPING... \n");
311		return 0;
312	}
313
314	if (*pointer != RELAY_REPL)
315		return 0;
316
317	pointer += 1;  /* RELAY_FORW */
318	msg->hop = *pointer;
319	pointer += 1;    /* hop-count */
320	msg->msg_type = RELAY_REPL;
321
322	if (( ((int) msg->buffer) - ((int) (pointer - pstart)) ) < (2*INET6_LEN) ) {
323		printf("ProcessRELAYREPL()--> opt_length has 0 value for "
324		       "INET6_LEN, DROPING... \n");
325		return 0;
326	}
327
328	/* extract link_address */
329	memset(msg->link_addr, 0, INET6_ADDRSTRLEN);
330	memset(&sap.sin6_addr, 0, sizeof(sap.sin6_addr));
331	memcpy(&sap.sin6_addr, pointer, INET6_LEN);
332	pointer += INET6_LEN;
333
334	if (inet_ntop(AF_INET6, &sap.sin6_addr, msg->link_addr,
335	              INET6_ADDRSTRLEN ) <=0 ) {
336		printf("ProcessRELAYREPL1--->ERROR IN inet_ntop  !\n");
337		exit(1);
338	}
339
340	/* extract peer address */
341	memset(msg->peer_addr, 0, INET6_ADDRSTRLEN);
342	memset(&sap.sin6_addr, 0, sizeof(sap.sin6_addr));
343	memcpy(&sap.sin6_addr, pointer, INET6_LEN);
344	pointer += INET6_LEN;
345
346	if (inet_ntop(AF_INET6, &sap.sin6_addr, msg->peer_addr,
347	              INET6_ADDRSTRLEN ) <=0 ) {
348		printf("ProcessRELAYREPL1--->ERROR IN inet_ntop  !\n");
349		exit(1);
350	}
351
352	if (( ((int) msg->buffer) - ((int) (pointer - pstart)) ) <
353	    MESSAGE_HEADER_LENGTH ) {
354		printf("ProcessRELAYREPL()--> opt_length has 0 value for "
355		       "MESSAGE_HEADER_LENGTH, DROPING... \n");
356		return 0;
357	}
358
359	p16 = (uint16_t *) pointer;
360	option = ntohs(*p16);
361
362	if (option == OPTION_INTERFACE_ID) {
363		pointer += 2;
364		p16 = (uint16_t *) pointer;
365		opaqlen = ntohs(*p16);
366		pointer += 2;
367
368		if (( ((int) msg->buffer) - ((int) (pointer - pstart)) ) <  opaqlen) {
369			printf("ProcessRELAYREPL()--> opt_length has 0 value for "
370			       "opaqlen, DROPING... \n");
371			return 0;
372		}
373
374		p32 = (uint32_t *) pointer;
375		opaq = ntohl(*p32);
376		pointer += opaqlen;
377
378		if (( ((int) msg->buffer) - ((int) (pointer - pstart)) ) <
379		    MESSAGE_HEADER_LENGTH ) {
380			printf("ProcessRELAYREPL()--> opt_length has 0 value for "
381			       "MESSAGE_HEADER_LENGTH, DROPING... \n");
382			return 0;
383		}
384
385		p16 = (uint16_t *) pointer;
386		option = ntohs(*p16);
387
388		if (option == OPTION_RELAY_MSG) {
389			pointer += 2;
390			p16 = (uint16_t *) pointer;
391			msglen = ntohs(*p16);
392			pointer += 2;
393			if (( ((int) msg->buffer) - ((int)(pointer - pstart)) ) < msglen ) {
394				printf("ProcessRELAYREPL()--> opt_length has 0 value for "
395				       "msglen, DROPING... \n");
396				return 0;
397			}
398
399			/*--------------------------*/
400			if (*pointer == RELAY_FORW)
401				*pointer = RELAY_REPL; /* is the job of the server to set to
402				                         RELAY_REPL? */
403			/*--------------------------*/
404			for (device = interface_list.next; device != &interface_list;
405			     device = device->next) {
406				if (device->opaq == opaq)
407					break;
408			}
409
410			if (device != &interface_list ) {
411				msg->if_index = device->devindex;
412				memset(newbuff, 0, MAX_DHCP_MSG_LENGTH);
413				len = (pointer - msg->buffer);
414				len = (msg->datalength - len);
415				memcpy(newbuff, pointer, len);
416				msg->datalength = len;
417				free(msg->buffer);
418				msg->buffer = newbuff;
419				return 1;
420
421			}
422			else {
423				s = msg->link_addr;
424
425				for (device = interface_list.next; device != &interface_list;
426				     device = device->next) {
427					ipv6a = device->ipv6addr;
428
429					while(ipv6a!= NULL) {
430						if (strcmp(s, ipv6a->gaddr) == 0) {
431							msg->if_index = device->devindex;
432							check = 1;
433							break;
434						}
435						ipv6a = ipv6a->next;
436					}
437
438					if (check == 1)
439						break;
440				}
441
442				if (check == 0) {
443					printf("ProcessRELAYREPL--->ERROR NO INTERFACE FOUND!\n");
444					return 0;
445				}
446
447				memset(newbuff, 0, MAX_DHCP_MSG_LENGTH);
448				len = (pointer - msg->buffer);
449				len = (msg->datalength - len);
450				memcpy(newbuff, pointer, len);
451				msg->datalength = len;
452				free(msg->buffer);
453				msg->buffer = newbuff;
454				return 1;
455			}
456		}
457		else { /* OPTION_RELAY_MSG */
458			printf("ProcessRELAYREPL--->ERROR MESSAGE IS MALFORMED NO "
459			       "OPTION_RELAY_MSG FOUND, DROPING...!\n");
460			return 0;
461		}
462	} /* OPTION_INTERFACE_ID */
463
464	if (option == OPTION_RELAY_MSG) {
465		pointer += 2;
466		p16 = (uint16_t *) pointer;
467		msglen = ntohs(*p16);
468		pointer += 2;
469
470		if (( ((int) msg->buffer) - ((int) (pointer - pstart)) ) < msglen ) {
471			printf("ProcessRELAYREPL()--> opt_length has 0 value for "
472			       "msglen, DROPING... \n");
473			return 0;
474		}
475
476		opaq = 0;
477		psp = (pointer + msglen); /* jump over message, seek for
478		                              OPTION_INTERFACE_ID */
479
480		if (( ((int) msg->buffer) - ((int) (psp - pstart)) ) >=
481		    MESSAGE_HEADER_LENGTH ) {
482			if (option == OPTION_INTERFACE_ID) {
483				psp += 2;
484				p16 = (uint16_t *) psp;
485				opaqlen = ntohs(*p16);
486				psp += 2;
487
488				if (( ((int) msg->buffer) - ((int) (psp - pstart)) ) <
489				    opaqlen) {
490					printf("ProcessRELAYREPL()--> opt_length has 0 value "
491					       "for opaqlen, DROPING... \n");
492					return 0;
493				}
494
495				p32 = (uint32_t *) psp;
496				opaq = ntohl(*p32);
497				psp += opaqlen;
498			}
499		}
500
501		/*--------------------------*/
502		if (*pointer == RELAY_FORW)
503			*pointer = RELAY_REPL; /* is the job of the server to set to
504		                          RELAY_REPL? */
505		/*--------------------------*/
506		for (device = interface_list.next; device != &interface_list;
507		     device = device->next) {
508			if (device->opaq == opaq)
509				break;
510		}
511
512		if (device != &interface_list) {
513			msg->if_index = device->devindex;
514			memset(newbuff, 0, MAX_DHCP_MSG_LENGTH);
515			len = (pointer - msg->buffer);
516			len = (msg->datalength - len);
517			memcpy(newbuff, pointer, len);
518			msg->datalength = len;
519			free(msg->buffer);
520			msg->buffer = newbuff;
521			return 1;
522		}
523		else {
524			s = msg->link_addr;
525
526			for (device = interface_list.next; device != &interface_list;
527		     	device = device->next) {
528				ipv6a = device->ipv6addr;
529
530				while(ipv6a != NULL) {
531					if (strcmp(s, ipv6a->gaddr) == 0) {
532						msg->if_index = device->devindex;
533						check = 1;
534						break;
535					}
536					ipv6a = ipv6a->next;
537				}
538
539				if (check == 1)
540					break;
541			}
542
543			if (check == 0) {
544				printf("ProcessRELAYREPL--->ERROR NO INTERFACE FOUND!\n");
545				return 0;
546			}
547
548			memset(newbuff, 0, MAX_DHCP_MSG_LENGTH);
549			len = (pointer - msg->buffer);
550			len = (msg->datalength - len);
551			memcpy(newbuff, pointer, len);
552			msg->datalength = len;
553			free(msg->buffer);
554			msg->buffer = newbuff;
555			return 1;
556		}
557	}
558	else { /* OPTION_RELAY_MSG */
559		printf("ProcessRELAYREPL--->ERROR MESSAGE IS MALFORMED NO "
560		       "OPTION_RELAY_MSG FOUND, DROPING...!\n");
561		return 0;
562	}
563
564	return 1;
565}
566