svn commit: trunk/busybox: include networking networking/udhcp

vda at busybox.net vda at busybox.net
Mon Nov 20 19:40:37 UTC 2006


Author: vda
Date: 2006-11-20 11:40:36 -0800 (Mon, 20 Nov 2006)
New Revision: 16592

Log:
dhcprelay: new applet


Added:
   trunk/busybox/networking/udhcp/dhcprelay.c

Modified:
   trunk/busybox/include/applets.h
   trunk/busybox/include/usage.h
   trunk/busybox/networking/ifupdown.c
   trunk/busybox/networking/udhcp/Config.in
   trunk/busybox/networking/udhcp/Kbuild
   trunk/busybox/networking/udhcp/socket.c


Changeset:
Modified: trunk/busybox/include/applets.h
===================================================================
--- trunk/busybox/include/applets.h	2006-11-20 16:40:19 UTC (rev 16591)
+++ trunk/busybox/include/applets.h	2006-11-20 19:40:36 UTC (rev 16592)
@@ -94,6 +94,7 @@
 USE_DELUSER(APPLET(deluser, _BB_DIR_BIN, _BB_SUID_NEVER))
 USE_DEVFSD(APPLET(devfsd, _BB_DIR_SBIN, _BB_SUID_NEVER))
 USE_DF(APPLET(df, _BB_DIR_BIN, _BB_SUID_NEVER))
+USE_APP_DHCPRELAY(APPLET(dhcprelay, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
 USE_DIFF(APPLET(diff, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
 USE_DIRNAME(APPLET(dirname, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
 USE_DMESG(APPLET(dmesg, _BB_DIR_BIN, _BB_SUID_NEVER))

Modified: trunk/busybox/include/usage.h
===================================================================
--- trunk/busybox/include/usage.h	2006-11-20 16:40:19 UTC (rev 16591)
+++ trunk/busybox/include/usage.h	2006-11-20 19:40:36 UTC (rev 16592)
@@ -539,6 +539,16 @@
 	"Filesystem           1k-blocks      Used Available Use% Mounted on\n" \
 	"/dev/sda3              8690864   8553540    137324  98% /\n"
 
+#define dhcprelay_trivial_usage \
+	"[client_device_list] [server_device]"
+#define dhcprelay_full_usage \
+	"Relays dhcp requests from client devices to server device"
+
+#define dhcprelay_trivial_usage \
+	"[client_device_list] [server_device]"
+#define dhcprelay_full_usage \
+	"Relays dhcp requests from client devices to server device"
+
 #define diff_trivial_usage \
 	"[-abdiNqrTstw] [-L LABEL] [-S FILE] [-U LINES] FILE1 FILE2"
 #define diff_full_usage \

Modified: trunk/busybox/networking/ifupdown.c
===================================================================
--- trunk/busybox/networking/ifupdown.c	2006-11-20 16:40:19 UTC (rev 16591)
+++ trunk/busybox/networking/ifupdown.c	2006-11-20 19:40:36 UTC (rev 16592)
@@ -598,6 +598,9 @@
 {
 	int i;
 
+	if (!name)
+		return NULL;
+
 	for (i = 0; af[i]; i++) {
 		if (strcmp(af[i]->name, name) == 0) {
 			return af[i];
@@ -610,6 +613,9 @@
 {
 	int i;
 
+	if (!name)
+		return NULL;
+
 	for (i = 0; i < af->n_methods; i++) {
 		if (strcmp(af->method[i].name, name) == 0) {
 			return &af->method[i];
@@ -620,6 +626,9 @@
 
 static const llist_t *find_list_string(const llist_t *list, const char *string)
 {
+	if (string == NULL)
+		return NULL;
+
 	while (list) {
 		if (strcmp(list->data, string) == 0) {
 			return list;

Modified: trunk/busybox/networking/udhcp/Config.in
===================================================================
--- trunk/busybox/networking/udhcp/Config.in	2006-11-20 16:40:19 UTC (rev 16591)
+++ trunk/busybox/networking/udhcp/Config.in	2006-11-20 19:40:36 UTC (rev 16592)
@@ -12,6 +12,15 @@
 
 	  See http://udhcp.busybox.net for further details.
 
+config APP_DHCPRELAY
+	bool "dhcprelay"
+	default n
+	depends on APP_UDHCPD
+	help
+	  dhcprelay listens for dhcp requests on one or more interfaces
+	  and forwards these requests to a different interface or dhcp
+	  server.
+
 config APP_DUMPLEASES
 	bool "Lease display utility (dumpleases)"
 	default n

Modified: trunk/busybox/networking/udhcp/Kbuild
===================================================================
--- trunk/busybox/networking/udhcp/Kbuild	2006-11-20 16:40:19 UTC (rev 16591)
+++ trunk/busybox/networking/udhcp/Kbuild	2006-11-20 19:40:36 UTC (rev 16592)
@@ -15,3 +15,4 @@
 lib-$(CONFIG_APP_UDHCPD)	+= dhcpd.o arpping.o files.o leases.o \
 				   serverpacket.o static_leases.o
 lib-$(CONFIG_APP_DUMPLEASES)	+= dumpleases.o
+lib-$(CONFIG_APP_DHCPRELAY)     += dhcprelay.o

Added: trunk/busybox/networking/udhcp/dhcprelay.c
===================================================================
--- trunk/busybox/networking/udhcp/dhcprelay.c	2006-11-20 16:40:19 UTC (rev 16591)
+++ trunk/busybox/networking/udhcp/dhcprelay.c	2006-11-20 19:40:36 UTC (rev 16592)
@@ -0,0 +1,339 @@
+/* vi: set sw=4 ts=4: */
+/* Port to Busybox Copyright (C) 2006 Jesse Dutton <jessedutton at gmail.com>
+ *
+ * Licensed under GPL v2, see file LICENSE in this tarball for details.
+ *
+ * DHCP Relay for 'DHCPv4 Configuration of IPSec Tunnel Mode' support 
+ * Copyright (C) 2002 Mario Strasser <mast at gmx.net>, 
+ *                   Zuercher Hochschule Winterthur,
+ *                   Netbeat AG 
+ * Upstream has GPL v2 or later
+ */
+
+#include "common.h"
+#include "dhcpd.h"
+#include "options.h"
+
+/* constants */
+#define SELECT_TIMEOUT 5 /* select timeout in sec. */
+#define MAX_LIFETIME 2*60 /* lifetime of an xid entry in sec. */
+#define MAX_INTERFACES 9
+
+
+/* This list holds information about clients. The xid_* functions manipulate this list. */
+struct xid_item {
+	u_int32_t xid;
+	struct sockaddr_in ip;
+	int client;
+	time_t timestamp;
+	struct xid_item *next;
+} dhcprelay_xid_list = {0, {0}, 0, 0, NULL};
+
+
+static struct xid_item * xid_add(u_int32_t xid, struct sockaddr_in *ip, int client)
+{
+	struct xid_item *item;
+ 
+	/* create new xid entry */
+	item = xmalloc(sizeof(struct xid_item));
+ 
+	/* add xid entry */
+	item->ip = *ip;
+	item->xid = xid;
+	item->client = client;
+	item->timestamp = time(NULL);
+	item->next = dhcprelay_xid_list.next;
+	dhcprelay_xid_list.next = item;
+
+	return item;
+}
+
+
+static void xid_expire(void)
+{
+	struct xid_item *item = dhcprelay_xid_list.next;
+	struct xid_item *last = &dhcprelay_xid_list;
+	time_t current_time = time(NULL);
+
+	while (item != NULL) {
+		if ((current_time-item->timestamp) > MAX_LIFETIME) {
+			last->next = item->next;
+			free(item);
+			item = last->next;
+		} else {
+			last = item;
+			item = item->next;
+		}
+	}
+}
+
+static struct xid_item * xid_find(u_int32_t xid)
+{
+	struct xid_item *item = dhcprelay_xid_list.next;
+	while (item != NULL) {
+		if (item->xid == xid) {
+			return item;
+		}
+		item = item->next;
+	}
+	return NULL;
+}
+
+static void xid_del(u_int32_t xid)
+{
+	struct xid_item *item = dhcprelay_xid_list.next;
+	struct xid_item *last = &dhcprelay_xid_list;
+	while (item != NULL) {
+		if (item->xid == xid) {
+			last->next = item->next;
+			free(item);
+			item = last->next;
+		} else {
+			last = item;
+			item = item->next;
+		}
+	}
+}
+
+
+/**
+ * get_dhcp_packet_type - gets the message type of a dhcp packet
+ * p - pointer to the dhcp packet
+ * returns the message type on success, -1 otherwise
+ */
+static int get_dhcp_packet_type(struct dhcpMessage *p)
+{
+	u_char *op;
+
+	/* it must be either a BOOTREQUEST or a BOOTREPLY */
+	if (p->op != BOOTREQUEST && p->op != BOOTREPLY)
+		return -1;
+	/* get message type option */
+	op = get_option(p, DHCP_MESSAGE_TYPE);
+	if (op != NULL)
+		return op[0];
+	return -1;
+}
+
+/**
+ * signal_handler - handles signals ;-)
+ * sig - sent signal
+ */
+static int dhcprelay_stopflag;
+static void dhcprelay_signal_handler(int sig)
+{
+	dhcprelay_stopflag = 1;
+}
+
+/**
+ * get_client_devices - parses the devices list
+ * dev_list - comma separated list of devices
+ * returns array
+ */
+static char ** get_client_devices(char *dev_list, int *client_number)
+{
+	char *s, *list, **client_dev;
+	int i, cn=1;
+
+	/* copy list */
+	list = xstrdup(dev_list);
+	if (list == NULL) return NULL;
+
+	/* get number of items */
+	for (s = dev_list; *s; s++) if (*s == ',')
+		cn++;
+
+	client_dev = xzalloc(cn * sizeof(*client_dev));
+
+	/* parse list */
+	s = strtok(list, ",");
+	i = 0;
+	while (s != NULL) {
+		client_dev[i++] = xstrdup(s);
+		s = strtok(NULL, ",");
+	}
+
+	/* free copy and exit */
+	free(list);
+	*client_number = cn;
+	return client_dev;
+}
+
+
+/* Creates listen sockets (in fds) and returns the number allocated. */
+static int init_sockets(char **client, int num_clients,
+			char *server, int *fds, int *max_socket)
+{
+	int i;
+
+	// talk to real server on bootps
+	fds[0] = listen_socket(htonl(INADDR_ANY), 67, server);
+	if (fds[0] < 0) return -1;
+	*max_socket = fds[0];
+	
+	// array starts at 1 since server is 0
+	num_clients++;
+
+	for (i=1; i < num_clients; i++) {
+		// listen for clients on bootps
+		fds[i] = listen_socket(htonl(INADDR_ANY), 67, client[i-1]);
+		if (fds[i] < 0) return -1;
+		if (fds[i] > *max_socket) *max_socket = fds[i];
+	}
+
+	return i;
+}
+
+
+/**
+ * pass_on() - forwards dhcp packets from client to server
+ * p - packet to send
+ * client - number of the client
+ */
+static void pass_on(struct dhcpMessage *p, int packet_len, int client, int *fds,
+			struct sockaddr_in *client_addr, struct sockaddr_in *server_addr)
+{
+	int res, type;
+	struct xid_item *item;
+
+	/* check packet_type */
+	type = get_dhcp_packet_type(p);
+	if (type != DHCPDISCOVER && type != DHCPREQUEST
+	 && type != DHCPDECLINE && type != DHCPRELEASE
+	 && type != DHCPINFORM
+	) {
+		return;
+	}
+
+	/* create new xid entry */
+	item = xid_add(p->xid, client_addr, client);
+
+	/* forward request to LAN (server) */
+	res = sendto(fds[0], p, packet_len, 0, (struct sockaddr*)server_addr,
+			sizeof(struct sockaddr_in));
+	if (res != packet_len) {
+		bb_perror_msg("pass_on");
+		return;
+	}
+}
+
+/**
+ * pass_back() - forwards dhcp packets from server to client
+ * p - packet to send
+ */
+static void pass_back(struct dhcpMessage *p, int packet_len, int *fds)
+{
+	int res, type;
+	struct xid_item *item;
+
+	/* check xid */
+	item = xid_find(p->xid);
+	if (!item) {
+		return;
+	}
+
+	/* check packet type */
+	type = get_dhcp_packet_type(p);
+	if (type != DHCPOFFER && type != DHCPACK && type != DHCPNAK) {
+		return;
+	}
+
+	if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY))
+		item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST);
+	if (item->client > MAX_INTERFACES)
+		return;
+	res = sendto(fds[item->client], p, packet_len, 0, (struct sockaddr*)(&item->ip),
+				sizeof(item->ip));
+	if (res != packet_len) {
+		bb_perror_msg("pass_back");
+		return;
+	}
+
+	/* remove xid entry */
+	xid_del(p->xid);
+}
+
+static void dhcprelay_loop(int *fds, int num_sockets, int max_socket, char **clients,
+		struct sockaddr_in *server_addr, uint32_t gw_ip)
+{
+	struct dhcpMessage dhcp_msg;
+	fd_set rfds;
+	size_t packlen, addr_size;
+	struct sockaddr_in client_addr;
+	struct timeval tv;
+	int i;
+
+	while (!dhcprelay_stopflag) {
+		FD_ZERO(&rfds);
+		for (i = 0; i < num_sockets; i++)
+			FD_SET(fds[i], &rfds);
+		tv.tv_sec = SELECT_TIMEOUT;
+		tv.tv_usec = 0;
+		if (select(max_socket + 1, &rfds, NULL, NULL, &tv) > 0) {
+			/* server */
+			if (FD_ISSET(fds[0], &rfds)) {
+				packlen = udhcp_get_packet(&dhcp_msg, fds[0]);
+				if (packlen > 0) {
+					pass_back(&dhcp_msg, packlen, fds); 
+				}
+			}
+			for (i = 1; i < num_sockets; i++) {
+				/* clients */
+				if (!FD_ISSET(fds[i], &rfds))
+					continue;
+				addr_size = sizeof(struct sockaddr_in);
+				packlen = recvfrom(fds[i], &dhcp_msg, sizeof(dhcp_msg), 0,
+							(struct sockaddr *)(&client_addr), &addr_size);
+				if (packlen <= 0)
+					continue;
+				if (read_interface(clients[i-1], NULL, &dhcp_msg.giaddr, NULL) < 0)
+					dhcp_msg.giaddr = gw_ip;
+				pass_on(&dhcp_msg, packlen, i, fds, &client_addr, server_addr);
+			}
+		}
+		xid_expire();
+	}
+}
+
+int dhcprelay_main(int argc, char **argv)
+{
+	int i, num_sockets, max_socket, fds[MAX_INTERFACES];
+	uint32_t gw_ip;
+	char **clients;
+	struct sockaddr_in server_addr;
+
+	server_addr.sin_family = AF_INET;
+	server_addr.sin_port = htons(67);
+	if (argc == 4) {
+		if (!inet_aton(argv[3], &server_addr.sin_addr))
+			bb_perror_msg_and_die("didn't grok server");
+	} else if (argc == 3) {
+		server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
+	} else {
+		bb_show_usage();
+	}
+	clients = get_client_devices(argv[1], &num_sockets);
+	if (!clients) return 0;
+
+	signal(SIGTERM, dhcprelay_signal_handler);
+	signal(SIGQUIT, dhcprelay_signal_handler);
+	signal(SIGINT, dhcprelay_signal_handler);
+ 
+	num_sockets = init_sockets(clients, num_sockets, argv[2], fds, &max_socket);
+	if (num_sockets == -1)
+		bb_perror_msg_and_die("init_sockets() failed");
+
+	if (read_interface(argv[2], NULL, &gw_ip, NULL) == -1)
+		return 1;
+
+	dhcprelay_loop(fds, num_sockets, max_socket, clients, &server_addr, gw_ip);
+
+	if (ENABLE_FEATURE_CLEAN_UP) {
+		for (i = 0; i < num_sockets; i++) {
+			close(fds[i]);
+			free(clients[i]);
+		}
+	}
+
+	return 0;
+}

Modified: trunk/busybox/networking/udhcp/socket.c
===================================================================
--- trunk/busybox/networking/udhcp/socket.c	2006-11-20 16:40:19 UTC (rev 16591)
+++ trunk/busybox/networking/udhcp/socket.c	2006-11-20 19:40:36 UTC (rev 16592)
@@ -63,23 +63,27 @@
 		DEBUG("%s (our ip) = %s", ifr.ifr_name, inet_ntoa(our_ip->sin_addr));
 	}
 
-	if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) {
-		bb_perror_msg("SIOCGIFINDEX failed");
-		close(fd);
-		return -1;
+	if (ifindex) {
+		if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) {
+			bb_perror_msg("SIOCGIFINDEX failed");
+			close(fd);
+			return -1;
+		}
+		DEBUG("adapter index %d", ifr.ifr_ifindex);
+		*ifindex = ifr.ifr_ifindex;
 	}
 
-	DEBUG("adapter index %d", ifr.ifr_ifindex);
-	*ifindex = ifr.ifr_ifindex;
-	if (ioctl(fd, SIOCGIFHWADDR, &ifr) != 0) {
-		bb_perror_msg("SIOCGIFHWADDR failed");
-		close(fd);
-		return -1;
+	if (arp) {
+		if (ioctl(fd, SIOCGIFHWADDR, &ifr) != 0) {
+			bb_perror_msg("SIOCGIFHWADDR failed");
+			close(fd);
+			return -1;
+		}
+		memcpy(arp, ifr.ifr_hwaddr.sa_data, 6);
+		DEBUG("adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x",
+			arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]);
 	}
 
-	memcpy(arp, ifr.ifr_hwaddr.sa_data, 6);
-	DEBUG("adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x",
-		arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]);
 	return 0;
 }
 




More information about the busybox-cvs mailing list