1 /*from $KAME: dhcp6c_script.c,v 1.11 2004/11/28 10:48:38 jinmei Exp $ */
4 * Copyright (C) 2003 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/queue.h>
38 #if TIME_WITH_SYS_TIME
39 # include <sys/time.h>
43 # include <sys/time.h>
49 #include <netinet/in.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
*));
70 relay6_script(scriptpath
, client
, dh6
, len
)
72 struct sockaddr_in6
*client
;
76 struct dhcp6_optinfo optinfo
;
77 struct dhcp6opt
*optend
;
78 int i
, j
, iapds
, ianas
, envc
, elen
, ret
= 0;
80 struct dhcp6_listval
*v
;
83 /* if a script is not specified, do nothing */
84 if (scriptpath
== NULL
|| strlen(scriptpath
) == 0)
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?",
98 optend
= (struct dhcp6opt
*)((caddr_t
) dh6
+ len
);
99 dhcp6_init_options(&optinfo
);
100 if (dhcp6_get_options((struct dhcp6opt
*)(dh6
+ 1), optend
,
102 dprintf(LOG_INFO
, FNAME
, "failed to parse options");
106 /* initialize counters */
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
))
115 for (v
= TAILQ_FIRST(&optinfo
.iana_list
); v
; v
= TAILQ_NEXT(v
, link
))
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
);
126 memset(envp
, 0, sizeof (char *) * envc
);
129 * Copy the parameters as environment variables
133 t
= addr2str((struct sockaddr
*) client
);
135 dprintf(LOG_NOTICE
, FNAME
,
136 "failed to get address of client");
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");
148 snprintf(s
, elen
, "%s=%s", client_str
, t
);
151 for (v
= TAILQ_FIRST(&optinfo
.iapd_list
); v
;
152 v
= TAILQ_NEXT(v
, link
)) {
153 if ((s
= envp
[i
++] = iapd2str(j
++, v
)) == NULL
) {
159 for (v
= TAILQ_FIRST(&optinfo
.iana_list
); v
;
160 v
= TAILQ_NEXT(v
, link
)) {
161 if ((s
= envp
[i
++] = iana2str(j
++, v
)) == NULL
) {
167 /* launch the script */
170 dprintf(LOG_ERR
, FNAME
, "failed to fork: %s", strerror(errno
));
177 wpid
= wait(&wstatus
);
178 } while (wpid
!= pid
&& wpid
> 0);
181 dprintf(LOG_ERR
, FNAME
, "wait: %s", strerror(errno
));
183 dprintf(LOG_DEBUG
, FNAME
,
184 "script \"%s\" terminated", scriptpath
);
190 argv
[0] = scriptpath
;
193 if (safefile(scriptpath
)) {
194 dprintf(LOG_ERR
, FNAME
,
195 "script \"%s\" cannot be executed safely",
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
)
209 execve(scriptpath
, argv
, envp
);
211 dprintf(LOG_ERR
, FNAME
, "child: exec failed: %s",
217 for (i
= 0; i
< envc
; i
++)
220 dhcp6_clear_options(&optinfo
);
228 struct dhcp6_listval
*iav
;
230 struct dhcp6_listval
*siav
;
234 memset(s
, 0, BUFSIZ
);
236 snprintf(s
, BUFSIZ
, "iapd_%d=", num
);
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
),
245 in6addr2str(&siav
->val_prefix6
.addr
, 0),
246 siav
->val_prefix6
.plen
);
250 case DHCP6_LISTVAL_STCODE
:
251 snprintf(s
+ strlen(s
), BUFSIZ
- strlen(s
),
252 "%s#%d", comma
, siav
->val_num16
);
257 dprintf(LOG_ERR
, FNAME
, "impossible subopt");
261 if ((r
= strdup(s
)) == NULL
)
262 dprintf(LOG_ERR
, FNAME
, "failed to allocate iapd_%d", num
);
269 struct dhcp6_listval
*iav
;
271 struct dhcp6_listval
*siav
;
275 memset(s
, 0, BUFSIZ
);
277 snprintf(s
, BUFSIZ
, "iana_%d=", num
);
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
),
286 in6addr2str(&siav
->val_statefuladdr6
.addr
, 0));
290 case DHCP6_LISTVAL_STCODE
:
291 snprintf(s
+ strlen(s
), BUFSIZ
- strlen(s
),
292 "%s#%d", comma
, siav
->val_num16
);
297 dprintf(LOG_ERR
, FNAME
, "impossible subopt");
301 if ((r
= strdup(s
)) == NULL
)
302 dprintf(LOG_ERR
, FNAME
, "failed to allocate iana_%d", num
);