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 <sys/types.h>
32#include <unistd.h>
33#include <signal.h>
34#include <string.h>
35#if TIME_WITH_SYS_TIME
36# include <sys/time.h>
37# include <sys/timeb.h>
38# include <time.h>
39#else
40# if HAVE_SYS_TIME_H
41#  include <sys/time.h>
42# else
43#  include <time.h>
44# endif
45#endif
46#include <sys/socket.h>
47#include <arpa/inet.h>
48
49#include "relay6_parser.h"
50#include "relay6_socket.h"
51#include "relay6_database.h"
52
53int
54main(argc, argv)
55	int argc;
56	char **argv;
57{
58	int err =0, i;
59	FILE *fp;
60	int sw = 0;
61	int du = 0;
62	struct interface *iface;
63	struct sockaddr_in6 sin6;
64	char *sf, *eth, *addr;
65	struct cifaces *ci;
66	struct sifaces *si;
67	struct IPv6_uniaddr *unia;
68	struct server *sa;
69	struct msg_parser *mesg;
70
71	fp = fopen(PIDFILE, "w+");
72	if (fp == NULL) {
73		printf("COULD NOT WRITE PID FILE\n");
74		exit(1);
75	}
76	fprintf(fp, "%d", getpid());
77	fclose(fp);
78
79	signal(SIGINT, handler);
80	init_relay();
81
82	if (argc > 1) {
83		for (i = 1; i < argc; ++i) {
84			if (strcmp(argv[i], "-d") == 0)
85				du = 1;
86		}
87		if (du == 0) {
88			dump = fopen(DUMPFILE, "w+");
89			if (dump == NULL) {
90				printf("COULD NOT WRITE DUMP FILE: %s\n", DUMPFILE);
91				exit(1);
92			}
93    	}
94		else {
95			dump = stderr;
96    	}
97
98		if (get_interface_info() == 0)
99			goto ERROR;
100
101		for(i = 1; i < argc; ++i) {
102			if (strcmp(argv[i], "-cm") == 0) {
103				i++;
104				if (get_interface_s(argv[i]) == NULL) {
105					err = 5;
106					goto ERROR;
107				}
108
109				sw = 1;
110				ci = (struct cifaces *) malloc(sizeof(struct cifaces));
111				if (ci == NULL) {
112					TRACE(dump, "%s - %s ", dhcp6r_clock(),
113					      "Main--> ERROR NO MORE MEMORY AVAILABLE\n");
114					exit(1);
115				}
116				ci->ciface = strdup(argv[i]);
117				ci->next = cifaces_list.next;
118				cifaces_list.next = ci;
119
120				TRACE(dump, "%s - %s'%s'\n", dhcp6r_clock(),
121				      "SETTING UP CLIENT INTERFACE: ", argv[i]);
122				continue;
123			}
124			else if (strcmp(argv[i], "-cu") == 0) {
125				multicast_off = 1;
126			}
127			else if (strcmp(argv[i], "-sm") == 0) {
128          		i++;
129          		if (get_interface_s(argv[i]) == NULL) {
130					err = 5;
131					goto ERROR;
132          		}
133				si = (struct sifaces *) malloc(sizeof(struct sifaces));
134				if (si == NULL) {
135					TRACE(dump, "%s - %s", dhcp6r_clock(),
136					      "Main--> ERROR NO MORE MEMORY AVAILABLE\n");
137					exit(1);
138				}
139				si->siface = strdup(argv[i]);
140				si->next = sifaces_list.next;
141				sifaces_list.next = si;
142
143				TRACE(dump, "%s - %s'%s'\n", dhcp6r_clock(),
144				      "SETTING UP SERVER INTERFACE: ", argv[i]);
145
146				continue;
147			}
148			else if (strcmp(argv[i], "-d") == 0) {
149				continue;
150			}
151			else if (strcmp(argv[i], "-su") == 0) {
152				i++;
153				/* destination address */
154				if (inet_pton(AF_INET6, argv[i] , &sin6.sin6_addr) <= 0) {
155					err = 3;
156					goto ERROR;
157				}
158
159				if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) {
160					err = 3;
161					goto ERROR;
162				}
163
164				unia = (struct IPv6_uniaddr *)
165				       malloc(sizeof(struct IPv6_uniaddr));
166				if (unia == NULL) {
167					TRACE(dump, "%s - %s", dhcp6r_clock(),
168				      	"Main--> ERROR NO MORE MEMORY AVAILABLE\n");
169   	            	exit(1);
170				}
171				unia->uniaddr = strdup(argv[i]);
172				unia->next = IPv6_uniaddr_list.next;
173				IPv6_uniaddr_list.next = unia;
174
175				TRACE(dump, "%s - %s'%s'\n", dhcp6r_clock(),
176				      "SETTING UP SERVER ADDRESS: ", argv[i]);
177				nr_of_uni_addr += 1;
178
179          		continue;
180			}
181			else if (strcmp(argv[i], "-sf") == 0) {
182				i++;
183				sf = strdup(argv[i]);
184
185				eth = strtok(sf, "+");
186				if (eth == NULL) {
187					err = 4;
188					goto ERROR;
189				}
190				addr = strtok((sf+strlen(eth)+1), "\0");
191				if (addr == NULL) {
192					err = 4;
193					goto ERROR;
194				}
195
196			 	/* destination address	*/
197				if (inet_pton(AF_INET6, addr , &sin6.sin6_addr) <= 0) {
198					err = 3;
199					goto ERROR;
200				}
201
202				if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr) ) {
203					err = 3;
204					goto ERROR;
205				}
206
207				if ((iface = get_interface_s(eth)) != NULL) {
208					sa = (struct server *) malloc(sizeof(struct server));
209					if (sa == NULL) {
210						TRACE(dump, "%s - %s", dhcp6r_clock(),
211						      "Main--> ERROR NO MORE MEMORY AVAILABLE\n");
212						exit(1);
213					}
214					sa->serv = strdup(addr);
215					sa->next = NULL;
216					if (iface->sname != NULL)
217						sa->next = iface->sname;
218					iface->sname = sa;
219					TRACE(dump, "%s - %s%s FOR INTERFACE: %s\n", dhcp6r_clock(),
220					      "SETTING UP SERVER ADDRESS: ", addr, eth);
221					free(sf);
222				}
223				else {
224					err = 5;
225					goto ERROR;
226				}
227
228				continue;
229			}
230			else if ((strcmp(argv[i], "-h") == 0) ||
231			         (strcmp(argv[i], "--help") == 0)) {
232				command_text();
233			}
234			else {
235				err = 4;
236				goto ERROR;
237			}
238		}
239	}
240	else {
241		dump = fopen(DUMPFILE, "w+");
242		if (dump == NULL) {
243			printf("COULD NOT WRITE DUMP FILE: %s\n", DUMPFILE);
244			exit(1);
245		}
246
247		if (get_interface_info() == 0)
248			goto ERROR;
249	}
250
251	if (sw == 1)
252		multicast_off = 0;
253
254	init_socket();
255
256	if (set_sock_opt() == 0)
257		goto ERROR;
258
259	if (fill_addr_struct() == 0)
260		goto ERROR;
261
262	if (du == 0) {
263		switch(fork()) {
264			case 0:
265				break;
266			case -1:
267				perror("fork");
268				exit(1);
269			default:
270				exit(0);
271		}
272	}
273
274	while (1) {
275		if (check_select() == 1) {
276			if (recv_data() == 1) {
277				if (get_recv_data() == 1) {
278					mesg = create_parser_obj();
279					if (put_msg_in_store (mesg) == 0)
280						mesg->sent = 1; /* mark it for deletion */
281				}
282			}
283		}
284
285		send_message();
286		delete_messages();
287	}
288
289ERROR:
290
291	if (err == 3) {
292		printf("dhcp6r: malformed address '%s'\n", argv[i]);
293		exit(1);
294	}
295
296	if (err == 4) {
297		printf("dhcp6r: option '%s' not recognized\n", argv[i]);
298		exit(1);
299	}
300
301	if (err == 5) {
302		printf("dhcp6r: interface '%s' does not exist \n", argv[i]);
303		exit(1);
304	}
305
306	printf("ERROR OCCURED IN THE RELAY AGENT LOOP, EXITING..........\n");
307	exit(1);
308}
309
310void
311command_text()
312{
313	printf("Usage:\n");
314	printf("       dhcp6r [-d] [-cu] [-cm <interface>] [-sm <interface>] "
315	       "[-su <address>] [-sf <interface>+<address>] \n");
316	exit(1);
317}
318
319char*
320dhcp6r_clock()
321{
322	time_t tim;
323	char *s, *p;
324
325	time(&tim);
326	s = ctime(&tim);
327
328	p = s;
329	do {
330		p = strstr(p, " ");
331		if (p != NULL) {
332			if (*(p-1) == '/')
333				*p = '0';
334			else
335				*p = '/';
336		}
337	} while(p != NULL);
338
339	p = strstr(s, "\n");
340	if (p != NULL)
341		*p = '\0';
342
343	return s;
344}
345
346void  handler(int signo) {
347	close(recvsock->recv_sock_desc);
348	close(sendsock->send_sock_desc);
349	TRACE(dump, "%s - %s", dhcp6r_clock(),
350	      "RELAY AGENT IS STOPPING............\n");
351	fflush(dump);
352
353	exit(0);
354}
355