2010-11-12 04:02:18 -05:00
|
|
|
/* script.c
|
|
|
|
*
|
|
|
|
* Functions to call the interface change daemon
|
|
|
|
*
|
|
|
|
* Russ Dill <Russ.Dill@asu.edu> July 2001
|
2010-11-12 14:33:17 -05:00
|
|
|
* Nicholas J. Kain <njkain at gmail dot com> 2004-2010
|
2010-11-12 04:02:18 -05:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include "options.h"
|
|
|
|
#include "dhcpd.h"
|
2010-12-24 06:00:37 -05:00
|
|
|
#include "config.h"
|
2010-11-12 04:02:18 -05:00
|
|
|
#include "packet.h"
|
|
|
|
#include "options.h"
|
|
|
|
#include "log.h"
|
2010-11-13 08:18:23 -05:00
|
|
|
#include "io.h"
|
2010-11-12 04:02:18 -05:00
|
|
|
#include "script.h"
|
|
|
|
|
2010-11-12 14:33:17 -05:00
|
|
|
static int snprintip(char *dest, size_t size, unsigned char *ip)
|
|
|
|
{
|
2010-11-13 19:04:28 -05:00
|
|
|
if (!dest)
|
|
|
|
return -1;
|
2010-11-12 14:33:17 -05:00
|
|
|
return snprintf(dest, size, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
|
2010-11-12 04:02:18 -05:00
|
|
|
}
|
|
|
|
|
2010-11-12 14:33:17 -05:00
|
|
|
static int sprintip(char *dest, size_t size, char *pre, unsigned char *ip)
|
|
|
|
{
|
2010-11-13 19:04:28 -05:00
|
|
|
if (!dest)
|
|
|
|
return -1;
|
2010-11-12 14:33:17 -05:00
|
|
|
return snprintf(dest, size, "%s%d.%d.%d.%d",
|
|
|
|
pre, ip[0], ip[1], ip[2], ip[3]);
|
2010-11-12 04:02:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Fill dest with the text of option 'option'. */
|
2010-11-12 19:43:16 -05:00
|
|
|
/* Returns 0 if successful, -1 if nothing was filled in. */
|
|
|
|
static int fill_options(char *dest, unsigned char *option,
|
2010-11-12 14:33:17 -05:00
|
|
|
struct dhcp_option *type_p, unsigned int maxlen)
|
2010-11-12 04:02:18 -05:00
|
|
|
{
|
2010-11-12 14:33:17 -05:00
|
|
|
int type, optlen;
|
|
|
|
uint16_t val_u16;
|
|
|
|
int16_t val_s16;
|
|
|
|
uint32_t val_u32;
|
|
|
|
int32_t val_s32;
|
|
|
|
char *odest;
|
|
|
|
|
2010-11-12 19:43:16 -05:00
|
|
|
if (!option)
|
|
|
|
return -1;
|
|
|
|
int len = option[OPT_LEN - 2];
|
|
|
|
|
2010-11-12 14:33:17 -05:00
|
|
|
odest = dest;
|
|
|
|
|
|
|
|
dest += snprintf(dest, maxlen, "%s=", type_p->name);
|
|
|
|
|
|
|
|
type = type_p->flags & TYPE_MASK;
|
|
|
|
optlen = option_lengths[type];
|
|
|
|
for(;;) {
|
|
|
|
switch (type) {
|
|
|
|
case OPTION_IP_PAIR:
|
|
|
|
dest += sprintip(dest, maxlen - (dest - odest), "", option);
|
|
|
|
*(dest++) = '/';
|
|
|
|
option += 4;
|
|
|
|
optlen = 4;
|
2010-11-12 18:04:54 -05:00
|
|
|
dest += sprintip(dest, maxlen - (dest - odest), "", option);
|
|
|
|
optlen = option_lengths[type];
|
|
|
|
break;
|
2010-11-12 14:33:17 -05:00
|
|
|
case OPTION_IP: /* Works regardless of host byte order. */
|
|
|
|
dest += sprintip(dest, maxlen - (dest - odest), "", option);
|
|
|
|
break;
|
|
|
|
case OPTION_BOOLEAN:
|
|
|
|
dest += snprintf(dest, maxlen - (dest - odest),
|
|
|
|
*option ? "yes " : "no ");
|
|
|
|
break;
|
|
|
|
case OPTION_U8:
|
|
|
|
dest += snprintf(dest, maxlen - (dest - odest),
|
|
|
|
"%u ", *option);
|
|
|
|
break;
|
|
|
|
case OPTION_U16:
|
|
|
|
memcpy(&val_u16, option, 2);
|
|
|
|
dest += snprintf(dest, maxlen - (dest - odest),
|
|
|
|
"%u ", ntohs(val_u16));
|
|
|
|
break;
|
|
|
|
case OPTION_S16:
|
|
|
|
memcpy(&val_s16, option, 2);
|
|
|
|
dest += snprintf(dest, maxlen - (dest - odest),
|
|
|
|
"%d ", ntohs(val_s16));
|
|
|
|
break;
|
|
|
|
case OPTION_U32:
|
|
|
|
memcpy(&val_u32, option, 4);
|
|
|
|
dest += snprintf(dest, maxlen - (dest - odest),
|
2010-11-13 06:42:52 -05:00
|
|
|
"%u ", (uint32_t) ntohl(val_u32));
|
2010-11-12 14:33:17 -05:00
|
|
|
break;
|
|
|
|
case OPTION_S32:
|
|
|
|
memcpy(&val_s32, option, 4);
|
|
|
|
dest += snprintf(dest, maxlen - (dest - odest),
|
2010-11-13 06:42:52 -05:00
|
|
|
"%d ", (int32_t) ntohl(val_s32));
|
2010-11-12 14:33:17 -05:00
|
|
|
break;
|
|
|
|
case OPTION_STRING:
|
2010-11-12 19:43:16 -05:00
|
|
|
if ( (maxlen - (dest - odest)) < (unsigned)len)
|
|
|
|
return -1;
|
2010-11-12 14:33:17 -05:00
|
|
|
memcpy(dest, option, len);
|
|
|
|
dest[len] = '\0';
|
2010-11-12 19:43:16 -05:00
|
|
|
return 0; /* Short circuit this case */
|
2010-11-12 14:33:17 -05:00
|
|
|
}
|
|
|
|
option += optlen;
|
|
|
|
len -= optlen;
|
2010-11-12 18:04:54 -05:00
|
|
|
if (len <= 0)
|
|
|
|
break;
|
|
|
|
*(dest++) = ':';
|
2010-11-12 14:33:17 -05:00
|
|
|
}
|
2010-11-12 19:43:16 -05:00
|
|
|
return 0;
|
2010-11-12 04:02:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static int open_ifch(void) {
|
2010-11-12 14:33:17 -05:00
|
|
|
int sockfd, ret;
|
|
|
|
struct sockaddr_un address = {
|
|
|
|
.sun_family = AF_UNIX,
|
|
|
|
.sun_path = "ifchange"
|
|
|
|
};
|
|
|
|
|
|
|
|
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
ret = connect(sockfd, (struct sockaddr *)&address, sizeof(address));
|
|
|
|
|
|
|
|
if (ret == -1) {
|
|
|
|
log_error("unable to connect to ifchd!");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return sockfd;
|
2010-11-12 04:02:18 -05:00
|
|
|
}
|
|
|
|
|
2010-11-12 18:44:49 -05:00
|
|
|
static void sockwrite(int fd, const char *buf, size_t count)
|
2010-11-12 04:02:18 -05:00
|
|
|
{
|
2010-11-13 08:18:23 -05:00
|
|
|
if (safe_write(fd, buf, count) == -1)
|
|
|
|
log_error("sockwrite: write failed: %s", strerror(errno));
|
|
|
|
else
|
|
|
|
log_line("sent to ifchd: %s", buf);
|
2010-11-12 14:33:17 -05:00
|
|
|
}
|
2010-11-12 04:02:18 -05:00
|
|
|
|
|
|
|
static void deconfig_if(void)
|
|
|
|
{
|
2010-11-12 14:33:17 -05:00
|
|
|
int sockfd;
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
sockfd = open_ifch();
|
|
|
|
|
2010-11-13 19:14:16 -05:00
|
|
|
snprintf(buf, sizeof buf, "interface:%s:", client_config.interface);
|
2010-11-12 14:33:17 -05:00
|
|
|
sockwrite(sockfd, buf, strlen(buf));
|
|
|
|
|
|
|
|
snprintf(buf, sizeof buf, "ip:0.0.0.0:");
|
|
|
|
sockwrite(sockfd, buf, strlen(buf));
|
|
|
|
|
|
|
|
close(sockfd);
|
2010-11-12 04:02:18 -05:00
|
|
|
}
|
|
|
|
|
2010-11-12 14:33:17 -05:00
|
|
|
static void translate_option(int sockfd, struct dhcpMessage *packet, int opt)
|
|
|
|
{
|
|
|
|
char buf[256], buf2[256];
|
|
|
|
unsigned char *p;
|
|
|
|
int i;
|
|
|
|
|
2010-11-12 19:43:16 -05:00
|
|
|
if (!packet)
|
|
|
|
return;
|
2010-11-12 14:33:17 -05:00
|
|
|
|
|
|
|
memset(buf, '\0', sizeof(buf));
|
|
|
|
memset(buf2, '\0', sizeof(buf2));
|
|
|
|
|
|
|
|
p = get_option(packet, options[opt].code);
|
2010-11-13 19:14:16 -05:00
|
|
|
if (fill_options(buf2, p, &options[opt], sizeof buf2 - 1) == -1)
|
2010-11-12 19:43:16 -05:00
|
|
|
return;
|
2010-11-12 14:33:17 -05:00
|
|
|
snprintf(buf, sizeof buf, "%s:", buf2);
|
2010-11-13 19:14:16 -05:00
|
|
|
for (i = 0; i < 256; i++) {
|
|
|
|
if (buf[i] == '\0')
|
|
|
|
break;
|
2010-11-12 14:33:17 -05:00
|
|
|
if (buf[i] == '=') {
|
|
|
|
buf[i] = ':';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sockwrite(sockfd, buf, strlen(buf));
|
2010-11-12 04:02:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void bound_if(struct dhcpMessage *packet)
|
|
|
|
{
|
2010-11-12 14:33:17 -05:00
|
|
|
int sockfd;
|
2010-11-13 19:07:00 -05:00
|
|
|
char buf[256];
|
2010-11-12 14:33:17 -05:00
|
|
|
char ip[32];
|
|
|
|
|
2010-11-13 19:07:00 -05:00
|
|
|
if (!packet)
|
|
|
|
return;
|
2010-11-12 14:33:17 -05:00
|
|
|
|
|
|
|
sockfd = open_ifch();
|
|
|
|
|
|
|
|
snprintf(buf, sizeof buf, "interface:%s:", client_config.interface);
|
|
|
|
sockwrite(sockfd, buf, strlen(buf));
|
|
|
|
|
|
|
|
snprintip(ip, sizeof ip, (unsigned char *) &packet->yiaddr);
|
|
|
|
snprintf(buf, sizeof buf, "ip:%s:", ip);
|
|
|
|
sockwrite(sockfd, buf, strlen(buf));
|
|
|
|
|
|
|
|
translate_option(sockfd, packet, 0);
|
|
|
|
translate_option(sockfd, packet, 2);
|
|
|
|
translate_option(sockfd, packet, 5);
|
|
|
|
translate_option(sockfd, packet, 9);
|
|
|
|
translate_option(sockfd, packet, 11);
|
|
|
|
translate_option(sockfd, packet, 15);
|
|
|
|
translate_option(sockfd, packet, 16);
|
|
|
|
translate_option(sockfd, packet, 17);
|
|
|
|
|
|
|
|
close(sockfd);
|
2010-11-12 04:02:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void run_script(struct dhcpMessage *packet, int mode)
|
|
|
|
{
|
2010-11-12 19:04:51 -05:00
|
|
|
switch (mode) {
|
|
|
|
case SCRIPT_DECONFIG:
|
|
|
|
deconfig_if();
|
|
|
|
break;
|
|
|
|
case SCRIPT_BOUND:
|
|
|
|
bound_if(packet);
|
|
|
|
break;
|
|
|
|
case SCRIPT_RENEW:
|
|
|
|
bound_if(packet);
|
|
|
|
break;
|
|
|
|
case SCRIPT_NAK:
|
|
|
|
deconfig_if();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
log_error("invalid script mode: %d", mode);
|
|
|
|
break;
|
2010-11-12 14:33:17 -05:00
|
|
|
}
|
2010-11-12 04:02:18 -05:00
|
|
|
}
|
|
|
|
|