2010-12-24 20:42:41 +05:30
|
|
|
/* ifchange.c
|
2010-11-12 14:32:18 +05:30
|
|
|
*
|
|
|
|
* Functions to call the interface change daemon
|
|
|
|
*
|
2011-03-30 20:46:38 +05:30
|
|
|
* Nicholas J. Kain <njkain at gmail dot com> 2004-2011
|
2010-11-12 14:32:18 +05:30
|
|
|
*
|
|
|
|
* 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"
|
2010-12-24 16:30:37 +05:30
|
|
|
#include "config.h"
|
2010-11-12 14:32:18 +05:30
|
|
|
#include "packet.h"
|
|
|
|
#include "options.h"
|
|
|
|
#include "log.h"
|
2010-11-13 18:48:23 +05:30
|
|
|
#include "io.h"
|
2010-12-24 20:42:41 +05:30
|
|
|
#include "ifchange.h"
|
2010-11-12 14:32:18 +05:30
|
|
|
|
2011-03-30 20:09:11 +05:30
|
|
|
/* Fill buf with the ifchd command text of option 'option'. */
|
2010-11-13 06:13:16 +05:30
|
|
|
/* Returns 0 if successful, -1 if nothing was filled in. */
|
2011-03-30 20:46:38 +05:30
|
|
|
static int ifchd_cmd(char *buf, unsigned char *option, ssize_t optlen,
|
2011-03-30 19:43:34 +05:30
|
|
|
struct dhcp_option *type_p, unsigned int maxlen)
|
2010-11-12 14:32:18 +05:30
|
|
|
{
|
2011-03-30 20:09:11 +05:30
|
|
|
char *obuf = buf;
|
2011-03-30 20:46:38 +05:30
|
|
|
uint8_t *ooption = option;
|
2011-03-30 19:43:34 +05:30
|
|
|
enum option_type type = type_p->type;
|
|
|
|
ssize_t typelen = option_length(type);
|
|
|
|
uint8_t code = type_p->code;
|
2010-11-13 01:03:17 +05:30
|
|
|
|
2010-11-13 06:13:16 +05:30
|
|
|
if (!option)
|
|
|
|
return -1;
|
2011-03-30 20:09:11 +05:30
|
|
|
|
|
|
|
if (type == OPTION_STRING) {
|
2011-03-30 20:46:38 +05:30
|
|
|
buf += snprintf(buf, maxlen, "%s:", type_p->name);
|
|
|
|
if (maxlen < optlen + 1)
|
2011-03-30 20:09:11 +05:30
|
|
|
return -1;
|
2011-03-30 20:46:38 +05:30
|
|
|
memcpy(buf, option, optlen);
|
|
|
|
buf[optlen] = ':';
|
2011-03-30 20:09:11 +05:30
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Length and type checking.
|
2011-03-30 19:43:34 +05:30
|
|
|
if (optlen != typelen) {
|
|
|
|
if (option_valid_list(code)) {
|
|
|
|
if ((optlen % typelen)) {
|
|
|
|
log_warning("Bad data received - option list size mismatch: code=0x%02x proplen=0x%02x optlen=0x%02x",
|
|
|
|
code, typelen, optlen);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log_warning("Bad data received - option size mismatch: code=0x%02x proplen=0x%02x optlen=0x%02x",
|
|
|
|
code, typelen, optlen);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2010-11-13 01:03:17 +05:30
|
|
|
|
2011-03-30 20:46:38 +05:30
|
|
|
buf += snprintf(buf, maxlen, "%s:", type_p->name);
|
2010-11-13 01:03:17 +05:30
|
|
|
|
|
|
|
for(;;) {
|
|
|
|
switch (type) {
|
2011-03-30 20:46:38 +05:30
|
|
|
case OPTION_IP: {
|
|
|
|
if (inet_ntop(AF_INET, option, buf, maxlen - (buf - obuf) - 1))
|
|
|
|
buf += strlen(buf);
|
2010-11-13 01:03:17 +05:30
|
|
|
break;
|
2011-03-30 20:46:38 +05:30
|
|
|
}
|
2010-11-13 01:03:17 +05:30
|
|
|
case OPTION_U8:
|
2011-03-30 20:46:38 +05:30
|
|
|
buf += snprintf(buf, maxlen - (buf - obuf) - 1, "%u ", *option);
|
2010-11-13 01:03:17 +05:30
|
|
|
break;
|
2011-03-30 20:09:11 +05:30
|
|
|
case OPTION_U16: {
|
|
|
|
uint16_t val_u16;
|
2010-11-13 01:03:17 +05:30
|
|
|
memcpy(&val_u16, option, 2);
|
2011-03-30 20:46:38 +05:30
|
|
|
buf += snprintf(buf, maxlen - (buf - obuf) - 1, "%u ",
|
2011-03-30 20:09:11 +05:30
|
|
|
ntohs(val_u16));
|
2010-11-13 01:03:17 +05:30
|
|
|
break;
|
2011-03-30 20:09:11 +05:30
|
|
|
}
|
|
|
|
case OPTION_S16: {
|
|
|
|
int16_t val_s16;
|
2010-11-13 01:03:17 +05:30
|
|
|
memcpy(&val_s16, option, 2);
|
2011-03-30 20:46:38 +05:30
|
|
|
buf += snprintf(buf, maxlen - (buf - obuf) - 1, "%d ",
|
2011-03-30 20:09:11 +05:30
|
|
|
ntohs(val_s16));
|
2010-11-13 01:03:17 +05:30
|
|
|
break;
|
2011-03-30 20:09:11 +05:30
|
|
|
}
|
|
|
|
case OPTION_U32: {
|
|
|
|
uint32_t val_u32;
|
2010-11-13 01:03:17 +05:30
|
|
|
memcpy(&val_u32, option, 4);
|
2011-03-30 20:46:38 +05:30
|
|
|
buf += snprintf(buf, maxlen - (buf - obuf) - 1, "%u ",
|
2011-03-30 20:09:11 +05:30
|
|
|
ntohl(val_u32));
|
2010-11-13 01:03:17 +05:30
|
|
|
break;
|
2011-03-30 20:09:11 +05:30
|
|
|
}
|
|
|
|
case OPTION_S32: {
|
|
|
|
int32_t val_s32;
|
2010-11-13 01:03:17 +05:30
|
|
|
memcpy(&val_s32, option, 4);
|
2011-03-30 20:46:38 +05:30
|
|
|
buf += snprintf(buf, maxlen - (buf - obuf) - 1, "%d ",
|
2011-03-30 20:09:11 +05:30
|
|
|
ntohl(val_s32));
|
2010-11-13 01:03:17 +05:30
|
|
|
break;
|
2011-03-30 20:09:11 +05:30
|
|
|
}
|
|
|
|
default:
|
2011-03-30 19:43:34 +05:30
|
|
|
return 0;
|
2010-11-13 01:03:17 +05:30
|
|
|
}
|
2011-03-30 19:43:34 +05:30
|
|
|
option += typelen;
|
2011-03-30 20:46:38 +05:30
|
|
|
if ((option - ooption) >= optlen)
|
2010-11-13 04:34:54 +05:30
|
|
|
break;
|
2011-03-30 20:09:11 +05:30
|
|
|
*(buf++) = ':';
|
2010-11-13 01:03:17 +05:30
|
|
|
}
|
2011-03-30 20:46:38 +05:30
|
|
|
*(buf++) = ':';
|
2010-11-13 06:13:16 +05:30
|
|
|
return 0;
|
2010-11-12 14:32:18 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
static int open_ifch(void) {
|
2010-11-13 01:03:17 +05:30
|
|
|
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 14:32:18 +05:30
|
|
|
}
|
|
|
|
|
2010-11-13 05:14:49 +05:30
|
|
|
static void sockwrite(int fd, const char *buf, size_t count)
|
2010-11-12 14:32:18 +05:30
|
|
|
{
|
2010-11-13 18:48:23 +05:30
|
|
|
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-13 01:03:17 +05:30
|
|
|
}
|
2010-11-12 14:32:18 +05:30
|
|
|
|
|
|
|
static void deconfig_if(void)
|
|
|
|
{
|
2010-11-13 01:03:17 +05:30
|
|
|
int sockfd;
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
sockfd = open_ifch();
|
|
|
|
|
2010-11-14 05:44:16 +05:30
|
|
|
snprintf(buf, sizeof buf, "interface:%s:", client_config.interface);
|
2010-11-13 01:03:17 +05:30
|
|
|
sockwrite(sockfd, buf, strlen(buf));
|
|
|
|
|
|
|
|
snprintf(buf, sizeof buf, "ip:0.0.0.0:");
|
|
|
|
sockwrite(sockfd, buf, strlen(buf));
|
|
|
|
|
|
|
|
close(sockfd);
|
2010-11-12 14:32:18 +05:30
|
|
|
}
|
|
|
|
|
2011-03-30 20:46:38 +05:30
|
|
|
static void send_cmd(int sockfd, struct dhcpMessage *packet,
|
2011-03-30 17:32:25 +05:30
|
|
|
unsigned char code)
|
2010-11-13 01:03:17 +05:30
|
|
|
{
|
2011-03-30 20:46:38 +05:30
|
|
|
char buf[256];
|
2010-11-13 01:03:17 +05:30
|
|
|
unsigned char *p;
|
|
|
|
int i;
|
2011-03-30 17:32:25 +05:30
|
|
|
struct dhcp_option *opt = NULL;
|
2011-03-30 19:05:17 +05:30
|
|
|
ssize_t optlen;
|
2010-11-13 01:03:17 +05:30
|
|
|
|
2010-11-13 06:13:16 +05:30
|
|
|
if (!packet)
|
|
|
|
return;
|
2010-11-13 01:03:17 +05:30
|
|
|
|
2011-03-30 17:32:25 +05:30
|
|
|
for (i = 0; options[i].code; ++i) {
|
|
|
|
if (options[i].code == code) {
|
|
|
|
opt = &options[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!opt)
|
|
|
|
return;
|
|
|
|
|
2011-03-30 20:46:38 +05:30
|
|
|
memset(buf, '\0', sizeof buf);
|
2011-03-30 19:05:17 +05:30
|
|
|
p = get_option(packet, code, &optlen);
|
2011-03-30 20:46:38 +05:30
|
|
|
if (ifchd_cmd(buf, p, optlen, opt, sizeof buf) == -1)
|
2010-11-13 06:13:16 +05:30
|
|
|
return;
|
2010-11-13 01:03:17 +05:30
|
|
|
sockwrite(sockfd, buf, strlen(buf));
|
2010-11-12 14:32:18 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
static void bound_if(struct dhcpMessage *packet)
|
|
|
|
{
|
2010-11-13 01:03:17 +05:30
|
|
|
int sockfd;
|
2010-11-14 05:37:00 +05:30
|
|
|
char buf[256];
|
2010-11-13 01:03:17 +05:30
|
|
|
char ip[32];
|
|
|
|
|
2010-11-14 05:37:00 +05:30
|
|
|
if (!packet)
|
|
|
|
return;
|
2010-11-13 01:03:17 +05:30
|
|
|
|
|
|
|
sockfd = open_ifch();
|
|
|
|
|
|
|
|
snprintf(buf, sizeof buf, "interface:%s:", client_config.interface);
|
|
|
|
sockwrite(sockfd, buf, strlen(buf));
|
|
|
|
|
2011-03-30 20:46:38 +05:30
|
|
|
inet_ntop(AF_INET, &packet->yiaddr, ip, sizeof ip);
|
2010-11-13 01:03:17 +05:30
|
|
|
snprintf(buf, sizeof buf, "ip:%s:", ip);
|
|
|
|
sockwrite(sockfd, buf, strlen(buf));
|
|
|
|
|
2011-03-30 20:46:38 +05:30
|
|
|
send_cmd(sockfd, packet, DHCP_SUBNET);
|
|
|
|
send_cmd(sockfd, packet, DHCP_ROUTER);
|
|
|
|
send_cmd(sockfd, packet, DHCP_DNS_SERVER);
|
|
|
|
send_cmd(sockfd, packet, DHCP_HOST_NAME);
|
|
|
|
send_cmd(sockfd, packet, DHCP_DOMAIN_NAME);
|
|
|
|
send_cmd(sockfd, packet, DHCP_MTU);
|
|
|
|
send_cmd(sockfd, packet, DHCP_BROADCAST);
|
|
|
|
send_cmd(sockfd, packet, DHCP_WINS_SERVER);
|
2010-11-13 01:03:17 +05:30
|
|
|
|
|
|
|
close(sockfd);
|
2010-11-12 14:32:18 +05:30
|
|
|
}
|
|
|
|
|
2010-12-24 20:42:41 +05:30
|
|
|
void ifchange(struct dhcpMessage *packet, int mode)
|
2010-11-12 14:32:18 +05:30
|
|
|
{
|
2010-11-13 05:34:51 +05:30
|
|
|
switch (mode) {
|
2010-12-24 20:42:41 +05:30
|
|
|
case IFCHANGE_DECONFIG:
|
2010-11-13 05:34:51 +05:30
|
|
|
deconfig_if();
|
|
|
|
break;
|
2010-12-24 20:42:41 +05:30
|
|
|
case IFCHANGE_BOUND:
|
2010-11-13 05:34:51 +05:30
|
|
|
bound_if(packet);
|
|
|
|
break;
|
2010-12-24 20:42:41 +05:30
|
|
|
case IFCHANGE_RENEW:
|
2010-11-13 05:34:51 +05:30
|
|
|
bound_if(packet);
|
|
|
|
break;
|
2010-12-24 20:42:41 +05:30
|
|
|
case IFCHANGE_NAK:
|
2010-11-13 05:34:51 +05:30
|
|
|
deconfig_if();
|
|
|
|
break;
|
|
|
|
default:
|
2010-12-24 20:42:41 +05:30
|
|
|
log_error("invalid ifchange mode: %d", mode);
|
2010-11-13 05:34:51 +05:30
|
|
|
break;
|
2010-11-13 01:03:17 +05:30
|
|
|
}
|
2010-11-12 14:32:18 +05:30
|
|
|
}
|
|
|
|
|