cosmetics
[tomato.git] / release / src / router / dhcpv6 / dhcp6relay_script.c
blob82f5eab4b4259f328a1126a31d8783aea924a6f5
1 /*from $KAME: dhcp6c_script.c,v 1.11 2004/11/28 10:48:38 jinmei Exp $ */
3 /*
4 * Copyright (C) 2003 WIDE Project.
5 * All rights reserved.
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 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/queue.h>
35 #include <sys/wait.h>
36 #include <sys/stat.h>
38 #if TIME_WITH_SYS_TIME
39 # include <sys/time.h>
40 # include <time.h>
41 #else
42 # if HAVE_SYS_TIME_H
43 # include <sys/time.h>
44 # else
45 # include <time.h>
46 # endif
47 #endif
49 #include <netinet/in.h>
51 #include <fcntl.h>
52 #include <unistd.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <string.h>
56 #include <syslog.h>
57 #include <errno.h>
59 #include "dhcp6.h"
60 #include "config.h"
61 #include "common.h"
63 static char client_str[] = "client";
64 static char buf[BUFSIZ];
66 static char *iapd2str __P((int, struct dhcp6_listval *));
67 static char *iana2str __P((int, struct dhcp6_listval *));
69 int
70 relay6_script(scriptpath, client, dh6, len)
71 char *scriptpath;
72 struct sockaddr_in6 *client;
73 struct dhcp6 *dh6;
74 int len;
76 struct dhcp6_optinfo optinfo;
77 struct dhcp6opt *optend;
78 int i, j, iapds, ianas, envc, elen, ret = 0;
79 char **envp, *s, *t;
80 struct dhcp6_listval *v;
81 pid_t pid, wpid;
83 /* if a script is not specified, do nothing */
84 if (scriptpath == NULL || strlen(scriptpath) == 0)
85 return -1;
87 /* only replies are interesting */
88 if (dh6->dh6_msgtype != DH6_REPLY) {
89 if (dh6->dh6_msgtype != DH6_ADVERTISE) {
90 dprintf(LOG_INFO, FNAME, "forward msg#%d to client?",
91 dh6->dh6_msgtype);
92 return -1;
94 return 0;
97 /* parse options */
98 optend = (struct dhcp6opt *)((caddr_t) dh6 + len);
99 dhcp6_init_options(&optinfo);
100 if (dhcp6_get_options((struct dhcp6opt *)(dh6 + 1), optend,
101 &optinfo) < 0) {
102 dprintf(LOG_INFO, FNAME, "failed to parse options");
103 return -1;
106 /* initialize counters */
107 iapds = 0;
108 ianas = 0;
109 envc = 2; /* we at least include the address and the terminator */
111 /* count the number of variables */
112 for (v = TAILQ_FIRST(&optinfo.iapd_list); v; v = TAILQ_NEXT(v, link))
113 iapds++;
114 envc += iapds;
115 for (v = TAILQ_FIRST(&optinfo.iana_list); v; v = TAILQ_NEXT(v, link))
116 ianas++;
117 envc += ianas;
119 /* allocate an environments array */
120 if ((envp = malloc(sizeof (char *) * envc)) == NULL) {
121 dprintf(LOG_NOTICE, FNAME,
122 "failed to allocate environment buffer");
123 dhcp6_clear_options(&optinfo);
124 return -1;
126 memset(envp, 0, sizeof (char *) * envc);
129 * Copy the parameters as environment variables
131 i = 0;
132 /* address */
133 t = addr2str((struct sockaddr *) client);
134 if (t == NULL) {
135 dprintf(LOG_NOTICE, FNAME,
136 "failed to get address of client");
137 ret = -1;
138 goto clean;
140 elen = sizeof (client_str) + 1 + strlen(t) + 1;
141 if ((s = envp[i++] = malloc(elen)) == NULL) {
142 dprintf(LOG_NOTICE, FNAME,
143 "failed to allocate string for client");
144 ret = -1;
145 goto clean;
147 memset(s, 0, elen);
148 snprintf(s, elen, "%s=%s", client_str, t);
149 /* IAs */
150 j = 0;
151 for (v = TAILQ_FIRST(&optinfo.iapd_list); v;
152 v = TAILQ_NEXT(v, link)) {
153 if ((s = envp[i++] = iapd2str(j++, v)) == NULL) {
154 ret = -1;
155 goto clean;
158 j = 0;
159 for (v = TAILQ_FIRST(&optinfo.iana_list); v;
160 v = TAILQ_NEXT(v, link)) {
161 if ((s = envp[i++] = iana2str(j++, v)) == NULL) {
162 ret = -1;
163 goto clean;
167 /* launch the script */
168 pid = fork();
169 if (pid < 0) {
170 dprintf(LOG_ERR, FNAME, "failed to fork: %s", strerror(errno));
171 ret = -1;
172 goto clean;
173 } else if (pid) {
174 int wstatus;
176 do {
177 wpid = wait(&wstatus);
178 } while (wpid != pid && wpid > 0);
180 if (wpid < 0)
181 dprintf(LOG_ERR, FNAME, "wait: %s", strerror(errno));
182 else {
183 dprintf(LOG_DEBUG, FNAME,
184 "script \"%s\" terminated", scriptpath);
186 } else {
187 char *argv[2];
188 int fd;
190 argv[0] = scriptpath;
191 argv[1] = NULL;
193 if (safefile(scriptpath)) {
194 dprintf(LOG_ERR, FNAME,
195 "script \"%s\" cannot be executed safely",
196 scriptpath);
197 exit(1);
200 if (foreground == 0 &&
201 (fd = open("/dev/null", O_RDWR)) != -1) {
202 dup2(fd, STDIN_FILENO);
203 dup2(fd, STDOUT_FILENO);
204 dup2(fd, STDERR_FILENO);
205 if (fd > STDERR_FILENO)
206 close(fd);
209 execve(scriptpath, argv, envp);
211 dprintf(LOG_ERR, FNAME, "child: exec failed: %s",
212 strerror(errno));
213 exit(0);
216 clean:
217 for (i = 0; i < envc; i++)
218 free(envp[i]);
219 free(envp);
220 dhcp6_clear_options(&optinfo);
222 return ret;
225 static char *
226 iapd2str(num, iav)
227 int num;
228 struct dhcp6_listval *iav;
230 struct dhcp6_listval *siav;
231 char *s, *r, *comma;
233 s = buf;
234 memset(s, 0, BUFSIZ);
236 snprintf(s, BUFSIZ, "iapd_%d=", num);
237 comma = "";
239 for (siav = TAILQ_FIRST(&iav->sublist); siav;
240 siav = TAILQ_NEXT(siav, link)) {
241 switch (siav->type) {
242 case DHCP6_LISTVAL_PREFIX6:
243 snprintf(s + strlen(s), BUFSIZ - strlen(s),
244 "%s%s/%d", comma,
245 in6addr2str(&siav->val_prefix6.addr, 0),
246 siav->val_prefix6.plen);
247 comma = ",";
248 break;
250 case DHCP6_LISTVAL_STCODE:
251 snprintf(s + strlen(s), BUFSIZ - strlen(s),
252 "%s#%d", comma, siav->val_num16);
253 comma = ",";
254 break;
256 default:
257 dprintf(LOG_ERR, FNAME, "impossible subopt");
261 if ((r = strdup(s)) == NULL)
262 dprintf(LOG_ERR, FNAME, "failed to allocate iapd_%d", num);
263 return r;
266 static char *
267 iana2str(num, iav)
268 int num;
269 struct dhcp6_listval *iav;
271 struct dhcp6_listval *siav;
272 char *s, *r, *comma;
274 s = buf;
275 memset(s, 0, BUFSIZ);
277 snprintf(s, BUFSIZ, "iana_%d=", num);
278 comma = "";
280 for (siav = TAILQ_FIRST(&iav->sublist); siav;
281 siav = TAILQ_NEXT(siav, link)) {
282 switch (siav->type) {
283 case DHCP6_LISTVAL_STATEFULADDR6:
284 snprintf(s + strlen(s), BUFSIZ - strlen(s),
285 "%s%s", comma,
286 in6addr2str(&siav->val_statefuladdr6.addr, 0));
287 comma = ",";
288 break;
290 case DHCP6_LISTVAL_STCODE:
291 snprintf(s + strlen(s), BUFSIZ - strlen(s),
292 "%s#%d", comma, siav->val_num16);
293 comma = ",";
294 break;
296 default:
297 dprintf(LOG_ERR, FNAME, "impossible subopt");
301 if ((r = strdup(s)) == NULL)
302 dprintf(LOG_ERR, FNAME, "failed to allocate iana_%d", num);
303 return r;