aboutsummaryrefslogtreecommitdiff
path: root/networking
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2011-01-04 19:40:30 +0700
committerNguyễn Thái Ngọc Duy <pclouds@gmail.com>2011-01-04 19:40:30 +0700
commit3b5c308768d76298bb964814ecc34de47bcac0b4 (patch)
tree795340e9d8f5e5bf9e8d895641099af343eec2a0 /networking
parent2b9a0e715ec459198f486653023d963b79291da7 (diff)
parent5fe2f863b9cee5ab0e7ac873538bce48846dbad8 (diff)
downloadbusybox-w32-3b5c308768d76298bb964814ecc34de47bcac0b4.tar.gz
busybox-w32-3b5c308768d76298bb964814ecc34de47bcac0b4.tar.bz2
busybox-w32-3b5c308768d76298bb964814ecc34de47bcac0b4.zip
Merge commit '06f719fd79fe15ce6fd5431bc58fcb22851de24d^'
Diffstat (limited to 'networking')
-rw-r--r--networking/Config.src2
-rw-r--r--networking/nbd-client.c153
-rw-r--r--networking/nc_bloaty.c3
-rw-r--r--networking/ntpd.c13
-rw-r--r--networking/udhcp/common.c4
-rw-r--r--networking/udhcp/common.h2
-rw-r--r--networking/udhcp/dhcpc.c17
-rw-r--r--networking/udhcp/dhcprelay.c189
8 files changed, 301 insertions, 82 deletions
diff --git a/networking/Config.src b/networking/Config.src
index 9fc122bf3..6dd7df754 100644
--- a/networking/Config.src
+++ b/networking/Config.src
@@ -804,7 +804,7 @@ config TELNETD
804 804
805 mount -t devpts devpts /dev/pts 805 mount -t devpts devpts /dev/pts
806 806
807 You need to be sure that Busybox has LOGIN and 807 You need to be sure that busybox has LOGIN and
808 FEATURE_SUID enabled. And finally, you should make 808 FEATURE_SUID enabled. And finally, you should make
809 certain that Busybox has been installed setuid root: 809 certain that Busybox has been installed setuid root:
810 810
diff --git a/networking/nbd-client.c b/networking/nbd-client.c
new file mode 100644
index 000000000..5ac190c32
--- /dev/null
+++ b/networking/nbd-client.c
@@ -0,0 +1,153 @@
1/*
2 * Copyright 2010 Rob Landley <rob@landley.net>
3 *
4 * Licensed under GPLv2, see file LICENSE in this source tree.
5 */
6#include "libbb.h"
7#include <netinet/tcp.h>
8#include <linux/fs.h>
9
10//applet:IF_NBDCLIENT(APPLET_ODDNAME(nbd-client, nbdclient, _BB_DIR_USR_SBIN, _BB_SUID_DROP, nbdclient))
11
12//kbuild:lib-$(CONFIG_NBDCLIENT) += nbd-client.o
13
14//config:config NBDCLIENT
15//config: bool "nbd-client"
16//config: default y
17//config: help
18//config: Network block device client
19
20#define NBD_SET_SOCK _IO(0xab, 0)
21#define NBD_SET_BLKSIZE _IO(0xab, 1)
22#define NBD_SET_SIZE _IO(0xab, 2)
23#define NBD_DO_IT _IO(0xab, 3)
24#define NBD_CLEAR_SOCK _IO(0xab, 4)
25#define NBD_CLEAR_QUEUE _IO(0xab, 5)
26#define NBD_PRINT_DEBUG _IO(0xab, 6)
27#define NBD_SET_SIZE_BLOCKS _IO(0xab, 7)
28#define NBD_DISCONNECT _IO(0xab, 8)
29#define NBD_SET_TIMEOUT _IO(0xab, 9)
30
31//usage:#define nbdclient_trivial_usage
32//usage: "HOST PORT BLOCKDEV"
33//usage:#define nbdclient_full_usage "\n\n"
34//usage: "Connect to HOST and provide a network block device on BLOCKDEV"
35
36//TODO: more compat with nbd-client version 2.9.13 -
37//Usage: nbd-client [bs=blocksize] [timeout=sec] host port nbd_device [-swap] [-persist] [-nofork]
38//Or : nbd-client -d nbd_device
39//Or : nbd-client -c nbd_device
40//Default value for blocksize is 1024 (recommended for ethernet)
41//Allowed values for blocksize are 512,1024,2048,4096
42//Note, that kernel 2.4.2 and older ones do not work correctly with
43//blocksizes other than 1024 without patches
44
45int nbdclient_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
46int nbdclient_main(int argc, char **argv)
47{
48 unsigned long timeout = 0;
49 int nofork = 0;
50 char *host, *port, *device;
51 struct nbd_header_t {
52 uint64_t magic1; // "NBDMAGIC"
53 uint64_t magic2; // 0x420281861253 big endian
54 uint64_t devsize;
55 uint32_t flags;
56 char data[124];
57 } nbd_header;
58 struct bug_check {
59 char c[offsetof(struct nbd_header_t, data) == 8+8+8+4 ? 1 : -1];
60 };
61
62 // Parse command line stuff (just a stub now)
63 if (argc != 4)
64 bb_show_usage();
65
66#if !BB_MMU
67 bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
68#endif
69
70 host = argv[1];
71 port = argv[2];
72 device = argv[3];
73
74 // Repeat until spanked (-persist behavior)
75 for (;;) {
76 int sock, nbd;
77 int ro;
78
79 // Make sure the /dev/nbd exists
80 nbd = xopen(device, O_RDWR);
81
82 // Find and connect to server
83 sock = create_and_connect_stream_or_die(host, xatou16(port));
84 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &const_int_1, sizeof(const_int_1));
85
86 // Log on to the server
87 xread(sock, &nbd_header, 8+8+8+4 + 124);
88 if (memcmp(&nbd_header.magic1, "NBDMAGIC""\x00\x00\x42\x02\x81\x86\x12\x53", 16) != 0)
89 bb_error_msg_and_die("login failed");
90
91 // Set 4k block size. Everything uses that these days
92 ioctl(nbd, NBD_SET_BLKSIZE, 4096);
93 ioctl(nbd, NBD_SET_SIZE_BLOCKS, SWAP_BE64(nbd_header.devsize) / 4096);
94 ioctl(nbd, NBD_CLEAR_SOCK);
95
96 // If the sucker was exported read only, respect that locally
97 ro = (nbd_header.flags & SWAP_BE32(2)) / SWAP_BE32(2);
98 if (ioctl(nbd, BLKROSET, &ro) < 0)
99 bb_perror_msg_and_die("BLKROSET");
100
101 if (timeout)
102 if (ioctl(nbd, NBD_SET_TIMEOUT, timeout))
103 bb_perror_msg_and_die("NBD_SET_TIMEOUT");
104 if (ioctl(nbd, NBD_SET_SOCK, sock))
105 bb_perror_msg_and_die("NBD_SET_SOCK");
106
107 // if (swap) mlockall(MCL_CURRENT|MCL_FUTURE);
108
109#if BB_MMU
110 // Open the device to force reread of the partition table.
111 // Need to do it in a separate process, since open(device)
112 // needs some other process to sit in ioctl(nbd, NBD_DO_IT).
113 if (fork() == 0) {
114 char *s = strrchr(device, '/');
115 sprintf(nbd_header.data, "/sys/block/%.32s/pid", s ? s + 1 : device);
116 // Is it up yet?
117 for (;;) {
118 int fd = open(nbd_header.data, O_RDONLY);
119 if (fd >= 0) {
120 //close(fd);
121 break;
122 }
123 sleep(1);
124 }
125 open(device, O_RDONLY);
126 return 0;
127 }
128
129 // Daemonize here
130 if (!nofork) {
131 daemon(0, 0);
132 nofork = 1;
133 }
134#endif
135
136 // This turns us (the process that calls this ioctl)
137 // into a dedicated NBD request handler.
138 // We block here for a long time.
139 // When exactly ioctl returns? On a signal,
140 // or if someone does ioctl(NBD_DISCONNECT) [nbd-client -d].
141 if (ioctl(nbd, NBD_DO_IT) >= 0 || errno == EBADR) {
142 // Flush queue and exit
143 ioctl(nbd, NBD_CLEAR_QUEUE);
144 ioctl(nbd, NBD_CLEAR_SOCK);
145 break;
146 }
147
148 close(sock);
149 close(nbd);
150 }
151
152 return 0;
153}
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c
index 6b5b176c9..8594a67a6 100644
--- a/networking/nc_bloaty.c
+++ b/networking/nc_bloaty.c
@@ -57,7 +57,8 @@
57//usage:#define nc_trivial_usage 57//usage:#define nc_trivial_usage
58//usage: "[OPTIONS] HOST PORT - connect" 58//usage: "[OPTIONS] HOST PORT - connect"
59//usage: IF_NC_SERVER("\n" 59//usage: IF_NC_SERVER("\n"
60//usage: "nc [OPTIONS] -l -p PORT [HOST] [PORT] - listen") 60//usage: "nc [OPTIONS] -l -p PORT [HOST] [PORT] - listen"
61//usage: )
61//usage:#define nc_full_usage "\n\n" 62//usage:#define nc_full_usage "\n\n"
62//usage: "Options:" 63//usage: "Options:"
63//usage: "\n -e PROG Run PROG after connect (must be last)" 64//usage: "\n -e PROG Run PROG after connect (must be last)"
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 6707e9bdb..ca4afa045 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -1765,6 +1765,10 @@ recv_and_process_client_pkt(void /*int fd*/)
1765 /* this time was obtained between poll() and recv() */ 1765 /* this time was obtained between poll() and recv() */
1766 msg.m_rectime = d_to_lfp(G.cur_time); 1766 msg.m_rectime = d_to_lfp(G.cur_time);
1767 msg.m_xmttime = d_to_lfp(gettime1900d()); /* this instant */ 1767 msg.m_xmttime = d_to_lfp(gettime1900d()); /* this instant */
1768 if (G.peer_cnt == 0) {
1769 /* we have no peers: "stratum 1 server" mode. reftime = our own time */
1770 G.reftime = G.cur_time;
1771 }
1768 msg.m_reftime = d_to_lfp(G.reftime); 1772 msg.m_reftime = d_to_lfp(G.reftime);
1769 msg.m_orgtime = query_xmttime; 1773 msg.m_orgtime = query_xmttime;
1770 msg.m_rootdelay = d_to_sfp(G.rootdelay); 1774 msg.m_rootdelay = d_to_sfp(G.rootdelay);
@@ -1902,8 +1906,13 @@ static NOINLINE void ntp_init(char **argv)
1902 bb_show_usage(); 1906 bb_show_usage();
1903// if (opts & OPT_x) /* disable stepping, only slew is allowed */ 1907// if (opts & OPT_x) /* disable stepping, only slew is allowed */
1904// G.time_was_stepped = 1; 1908// G.time_was_stepped = 1;
1905 while (peers) 1909 if (peers) {
1906 add_peers(llist_pop(&peers)); 1910 while (peers)
1911 add_peers(llist_pop(&peers));
1912 } else {
1913 /* -l but no peers: "stratum 1 server" mode */
1914 G.stratum = 1;
1915 }
1907 if (!(opts & OPT_n)) { 1916 if (!(opts & OPT_n)) {
1908 bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO, argv); 1917 bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO, argv);
1909 logmode = LOGMODE_NONE; 1918 logmode = LOGMODE_NONE;
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index 97ab4cdbb..b6b274d91 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -37,6 +37,7 @@ const struct dhcp_optflag dhcp_optflags[] = {
37 { OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */ 37 { OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */
38 { OPTION_U16 , 0x1a }, /* DHCP_MTU */ 38 { OPTION_U16 , 0x1a }, /* DHCP_MTU */
39 { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */ 39 { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */
40 { OPTION_IP_PAIR | OPTION_LIST , 0x21 }, /* DHCP_ROUTES */
40 { OPTION_STRING , 0x28 }, /* DHCP_NIS_DOMAIN */ 41 { OPTION_STRING , 0x28 }, /* DHCP_NIS_DOMAIN */
41 { OPTION_IP | OPTION_LIST , 0x29 }, /* DHCP_NIS_SERVER */ 42 { OPTION_IP | OPTION_LIST , 0x29 }, /* DHCP_NIS_SERVER */
42 { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER */ 43 { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER */
@@ -54,6 +55,7 @@ const struct dhcp_optflag dhcp_optflags[] = {
54 { OPTION_SIP_SERVERS , 0x78 }, /* DHCP_SIP_SERVERS */ 55 { OPTION_SIP_SERVERS , 0x78 }, /* DHCP_SIP_SERVERS */
55#endif 56#endif
56 { OPTION_STATIC_ROUTES , 0x79 }, /* DHCP_STATIC_ROUTES */ 57 { OPTION_STATIC_ROUTES , 0x79 }, /* DHCP_STATIC_ROUTES */
58 { OPTION_STATIC_ROUTES , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */
57 { OPTION_STRING , 0xfc }, /* DHCP_WPAD */ 59 { OPTION_STRING , 0xfc }, /* DHCP_WPAD */
58 60
59 /* Options below have no match in dhcp_option_strings[], 61 /* Options below have no match in dhcp_option_strings[],
@@ -95,6 +97,7 @@ const char dhcp_option_strings[] ALIGN1 =
95 "ipttl" "\0" /* DHCP_IP_TTL */ 97 "ipttl" "\0" /* DHCP_IP_TTL */
96 "mtu" "\0" /* DHCP_MTU */ 98 "mtu" "\0" /* DHCP_MTU */
97 "broadcast" "\0" /* DHCP_BROADCAST */ 99 "broadcast" "\0" /* DHCP_BROADCAST */
100 "routes" "\0" /* DHCP_ROUTES */
98 "nisdomain" "\0" /* DHCP_NIS_DOMAIN */ 101 "nisdomain" "\0" /* DHCP_NIS_DOMAIN */
99 "nissrv" "\0" /* DHCP_NIS_SERVER */ 102 "nissrv" "\0" /* DHCP_NIS_SERVER */
100 "ntpsrv" "\0" /* DHCP_NTP_SERVER */ 103 "ntpsrv" "\0" /* DHCP_NTP_SERVER */
@@ -114,6 +117,7 @@ const char dhcp_option_strings[] ALIGN1 =
114// doesn't work in udhcpd.conf since OPTION_STATIC_ROUTES 117// doesn't work in udhcpd.conf since OPTION_STATIC_ROUTES
115// is not handled yet by "string->option" conversion code: 118// is not handled yet by "string->option" conversion code:
116 "staticroutes" "\0"/* DHCP_STATIC_ROUTES */ 119 "staticroutes" "\0"/* DHCP_STATIC_ROUTES */
120 "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */
117 "wpad" "\0" /* DHCP_WPAD */ 121 "wpad" "\0" /* DHCP_WPAD */
118 ; 122 ;
119 123
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index c5abf17d5..9020b9c96 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -123,6 +123,7 @@ enum {
123//#define DHCP_IP_TTL 0x17 123//#define DHCP_IP_TTL 0x17
124//#define DHCP_MTU 0x1a 124//#define DHCP_MTU 0x1a
125//#define DHCP_BROADCAST 0x1c 125//#define DHCP_BROADCAST 0x1c
126//#define DHCP_ROUTES 0x21
126//#define DHCP_NIS_DOMAIN 0x28 127//#define DHCP_NIS_DOMAIN 0x28
127//#define DHCP_NIS_SERVER 0x29 128//#define DHCP_NIS_SERVER 0x29
128//#define DHCP_NTP_SERVER 0x2a 129//#define DHCP_NTP_SERVER 0x2a
@@ -144,6 +145,7 @@ enum {
144//#define DHCP_DOMAIN_SEARCH 0x77 /* RFC 3397. set of ASCIZ string, DNS-style compressed */ 145//#define DHCP_DOMAIN_SEARCH 0x77 /* RFC 3397. set of ASCIZ string, DNS-style compressed */
145//#define DHCP_SIP_SERVERS 0x78 /* RFC 3361. flag byte, then: 0: domain names, 1: IP addrs */ 146//#define DHCP_SIP_SERVERS 0x78 /* RFC 3361. flag byte, then: 0: domain names, 1: IP addrs */
146//#define DHCP_STATIC_ROUTES 0x79 /* RFC 3442. (mask,ip,router) tuples */ 147//#define DHCP_STATIC_ROUTES 0x79 /* RFC 3442. (mask,ip,router) tuples */
148//#define DHCP_MS_STATIC_ROUTES 0xf9 /* Microsoft's pre-RFC 3442 code for 0x79? */
147//#define DHCP_WPAD 0xfc /* MSIE's Web Proxy Autodiscovery Protocol */ 149//#define DHCP_WPAD 0xfc /* MSIE's Web Proxy Autodiscovery Protocol */
148#define DHCP_END 0xff 150#define DHCP_END 0xff
149 151
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index de1b79844..27d6ad1a8 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -89,6 +89,7 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
89 89
90 /* option points to OPT_DATA, need to go back and get OPT_LEN */ 90 /* option points to OPT_DATA, need to go back and get OPT_LEN */
91 len = option[OPT_LEN - OPT_DATA]; 91 len = option[OPT_LEN - OPT_DATA];
92
92 type = optflag->flags & OPTION_TYPE_MASK; 93 type = optflag->flags & OPTION_TYPE_MASK;
93 optlen = dhcp_option_lengths[type]; 94 optlen = dhcp_option_lengths[type];
94 upper_length = len_of_option_as_string[type] * ((unsigned)len / (unsigned)optlen); 95 upper_length = len_of_option_as_string[type] * ((unsigned)len / (unsigned)optlen);
@@ -97,17 +98,16 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
97 dest += sprintf(ret, "%s=", opt_name); 98 dest += sprintf(ret, "%s=", opt_name);
98 99
99 while (len >= optlen) { 100 while (len >= optlen) {
101 unsigned ip_ofs = 0;
102
100 switch (type) { 103 switch (type) {
101 case OPTION_IP_PAIR: 104 case OPTION_IP_PAIR:
102 dest += sprint_nip(dest, "", option); 105 dest += sprint_nip(dest, "", option);
103 *dest++ = '/'; 106 *dest++ = '/';
104 option += 4; 107 ip_ofs = 4;
105 optlen = 4; 108 /* fall through */
106 case OPTION_IP: 109 case OPTION_IP:
107 dest += sprint_nip(dest, "", option); 110 dest += sprint_nip(dest, "", option + ip_ofs);
108// TODO: it can be a list only if (optflag->flags & OPTION_LIST).
109// Should we bail out/warn if we see multi-ip option which is
110// not allowed to be such? For example, DHCP_BROADCAST...
111 break; 111 break;
112// case OPTION_BOOLEAN: 112// case OPTION_BOOLEAN:
113// dest += sprintf(dest, *option ? "yes" : "no"); 113// dest += sprintf(dest, *option ? "yes" : "no");
@@ -218,7 +218,10 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
218 } /* switch */ 218 } /* switch */
219 option += optlen; 219 option += optlen;
220 len -= optlen; 220 len -= optlen;
221 if (len <= 0) 221// TODO: it can be a list only if (optflag->flags & OPTION_LIST).
222// Should we bail out/warn if we see multi-ip option which is
223// not allowed to be such (for example, DHCP_BROADCAST)? -
224 if (len <= 0 /* || !(optflag->flags & OPTION_LIST) */)
222 break; 225 break;
223 *dest++ = ' '; 226 *dest++ = ' ';
224 *dest = '\0'; 227 *dest = '\0';
diff --git a/networking/udhcp/dhcprelay.c b/networking/udhcp/dhcprelay.c
index a2c7f359d..759a4ba03 100644
--- a/networking/udhcp/dhcprelay.c
+++ b/networking/udhcp/dhcprelay.c
@@ -11,9 +11,12 @@
11 */ 11 */
12#include "common.h" 12#include "common.h"
13 13
14#define SERVER_PORT 67 14#define SERVER_PORT 67
15#define SELECT_TIMEOUT 5 /* select timeout in sec. */ 15
16#define MAX_LIFETIME 2*60 /* lifetime of an xid entry in sec. */ 16/* lifetime of an xid entry in sec. */
17#define MAX_LIFETIME 2*60
18/* select timeout in sec. */
19#define SELECT_TIMEOUT (MAX_LIFETIME / 8)
17 20
18/* This list holds information about clients. The xid_* functions manipulate this list. */ 21/* This list holds information about clients. The xid_* functions manipulate this list. */
19struct xid_item { 22struct xid_item {
@@ -67,11 +70,11 @@ static struct xid_item *xid_find(uint32_t xid)
67 struct xid_item *item = dhcprelay_xid_list.next; 70 struct xid_item *item = dhcprelay_xid_list.next;
68 while (item != NULL) { 71 while (item != NULL) {
69 if (item->xid == xid) { 72 if (item->xid == xid) {
70 return item; 73 break;
71 } 74 }
72 item = item->next; 75 item = item->next;
73 } 76 }
74 return NULL; 77 return item;
75} 78}
76 79
77static void xid_del(uint32_t xid) 80static void xid_del(uint32_t xid)
@@ -110,62 +113,72 @@ static int get_dhcp_packet_type(struct dhcp_packet *p)
110} 113}
111 114
112/** 115/**
113 * get_client_devices - parses the devices list 116 * make_iface_list - parses client/server interface names
114 * dev_list - comma separated list of devices
115 * returns array 117 * returns array
116 */ 118 */
117static char **get_client_devices(char *dev_list, int *client_number) 119static char **make_iface_list(char **client_and_server_ifaces, int *client_number)
118{ 120{
119 char *s, **client_dev; 121 char *s, **iface_list;
120 int i, cn; 122 int i, cn;
121 123
122 /* copy list */ 124 /* get number of items */
123 dev_list = xstrdup(dev_list); 125 cn = 2; /* 1 server iface + at least 1 client one */
124 126 s = client_and_server_ifaces[0]; /* list of client ifaces */
125 /* get number of items, replace ',' with NULs */
126 s = dev_list;
127 cn = 1;
128 while (*s) { 127 while (*s) {
129 if (*s == ',') { 128 if (*s == ',')
130 *s = '\0';
131 cn++; 129 cn++;
132 }
133 s++; 130 s++;
134 } 131 }
135 *client_number = cn; 132 *client_number = cn;
136 133
137 /* create vector of pointers */ 134 /* create vector of pointers */
138 client_dev = xzalloc(cn * sizeof(*client_dev)); 135 iface_list = xzalloc(cn * sizeof(iface_list[0]));
139 client_dev[0] = dev_list; 136
137 iface_list[0] = client_and_server_ifaces[1]; /* server iface */
138
140 i = 1; 139 i = 1;
141 while (i != cn) { 140 s = xstrdup(client_and_server_ifaces[0]); /* list of client ifaces */
142 client_dev[i] = client_dev[i - 1] + strlen(client_dev[i - 1]) + 1; 141 goto store_client_iface_name;
143 i++; 142
143 while (i < cn) {
144 if (*s++ == ',') {
145 s[-1] = '\0';
146 store_client_iface_name:
147 iface_list[i++] = s;
148 }
144 } 149 }
145 return client_dev; 150
151 return iface_list;
146} 152}
147 153
148/* Creates listen sockets (in fds) bound to client and server ifaces, 154/* Creates listen sockets (in fds) bound to client and server ifaces,
149 * and returns numerically max fd. 155 * and returns numerically max fd.
150 */ 156 */
151static int init_sockets(char **client_ifaces, int num_clients, 157static int init_sockets(char **iface_list, int num_clients, int *fds)
152 char *server_iface, int *fds)
153{ 158{
154 int i, n; 159 int i, n;
155 160
156 /* talk to real server on bootps */ 161 n = 0;
157 fds[0] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, server_iface); 162 for (i = 0; i < num_clients; i++) {
158 n = fds[0]; 163 fds[i] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, iface_list[i]);
159 164 if (n < fds[i])
160 for (i = 1; i < num_clients; i++) {
161 /* listen for clients on bootps */
162 fds[i] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, client_ifaces[i-1]);
163 if (fds[i] > n)
164 n = fds[i]; 165 n = fds[i];
165 } 166 }
166 return n; 167 return n;
167} 168}
168 169
170static int sendto_ip4(int sock, const void *msg, int msg_len, struct sockaddr_in *to)
171{
172 int err;
173
174 errno = 0;
175 err = sendto(sock, msg, msg_len, 0, (struct sockaddr*) to, sizeof(*to));
176 err -= msg_len;
177 if (err)
178 bb_perror_msg("sendto");
179 return err;
180}
181
169/** 182/**
170 * pass_to_server() - forwards dhcp packets from client to server 183 * pass_to_server() - forwards dhcp packets from client to server
171 * p - packet to send 184 * p - packet to send
@@ -174,7 +187,7 @@ static int init_sockets(char **client_ifaces, int num_clients,
174static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, int *fds, 187static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, int *fds,
175 struct sockaddr_in *client_addr, struct sockaddr_in *server_addr) 188 struct sockaddr_in *client_addr, struct sockaddr_in *server_addr)
176{ 189{
177 int res, type; 190 int type;
178 191
179 /* check packet_type */ 192 /* check packet_type */
180 type = get_dhcp_packet_type(p); 193 type = get_dhcp_packet_type(p);
@@ -188,13 +201,12 @@ static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, in
188 /* create new xid entry */ 201 /* create new xid entry */
189 xid_add(p->xid, client_addr, client); 202 xid_add(p->xid, client_addr, client);
190 203
191 /* forward request to LAN (server) */ 204 /* forward request to server */
192 errno = 0; 205 /* note that we send from fds[0] which is bound to SERVER_PORT (67).
193 res = sendto(fds[0], p, packet_len, 0, (struct sockaddr*)server_addr, 206 * IOW: we send _from_ SERVER_PORT! Although this may look strange,
194 sizeof(struct sockaddr_in)); 207 * RFC 1542 not only allows, but prescribes this for BOOTP relays.
195 if (res != packet_len) { 208 */
196 bb_perror_msg("sendto"); 209 sendto_ip4(fds[0], p, packet_len, server_addr);
197 }
198} 210}
199 211
200/** 212/**
@@ -203,7 +215,7 @@ static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, in
203 */ 215 */
204static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds) 216static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds)
205{ 217{
206 int res, type; 218 int type;
207 struct xid_item *item; 219 struct xid_item *item;
208 220
209 /* check xid */ 221 /* check xid */
@@ -218,14 +230,12 @@ static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds)
218 return; 230 return;
219 } 231 }
220 232
233//TODO: also do it if (p->flags & htons(BROADCAST_FLAG)) is set!
221 if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY)) 234 if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY))
222 item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST); 235 item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST);
223 errno = 0; 236
224 res = sendto(fds[item->client], p, packet_len, 0, (struct sockaddr*) &(item->ip), 237 if (sendto_ip4(fds[item->client], p, packet_len, &item->ip) != 0) {
225 sizeof(item->ip)); 238 return; /* send error occurred */
226 if (res != packet_len) {
227 bb_perror_msg("sendto");
228 return;
229 } 239 }
230 240
231 /* remove xid entry */ 241 /* remove xid entry */
@@ -235,36 +245,30 @@ static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds)
235int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 245int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
236int dhcprelay_main(int argc, char **argv) 246int dhcprelay_main(int argc, char **argv)
237{ 247{
238 struct dhcp_packet dhcp_msg;
239 struct sockaddr_in server_addr; 248 struct sockaddr_in server_addr;
240 struct sockaddr_in client_addr; 249 char **iface_list;
241 fd_set rfds;
242 char **client_ifaces;
243 int *fds; 250 int *fds;
244 int num_sockets, max_socket; 251 int num_sockets, max_socket;
245 uint32_t our_nip; 252 uint32_t our_nip;
246 253
247 server_addr.sin_family = AF_INET; 254 server_addr.sin_family = AF_INET;
255 server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
248 server_addr.sin_port = htons(SERVER_PORT); 256 server_addr.sin_port = htons(SERVER_PORT);
249 257
250 /* dhcprelay client_iface1,client_iface2,... server_iface [server_IP] */ 258 /* dhcprelay CLIENT_IFACE1[,CLIENT_IFACE2...] SERVER_IFACE [SERVER_IP] */
251 if (argc == 4) { 259 if (argc == 4) {
252 if (!inet_aton(argv[3], &server_addr.sin_addr)) 260 if (!inet_aton(argv[3], &server_addr.sin_addr))
253 bb_perror_msg_and_die("bad server IP"); 261 bb_perror_msg_and_die("bad server IP");
254 } else if (argc == 3) { 262 } else if (argc != 3) {
255 server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
256 } else {
257 bb_show_usage(); 263 bb_show_usage();
258 } 264 }
259 265
260 /* Produce list of client ifaces */ 266 iface_list = make_iface_list(argv + 1, &num_sockets);
261 client_ifaces = get_client_devices(argv[1], &num_sockets);
262 267
263 num_sockets++; /* for server socket at fds[0] */
264 fds = xmalloc(num_sockets * sizeof(fds[0])); 268 fds = xmalloc(num_sockets * sizeof(fds[0]));
265 269
266 /* Create sockets and bind one to every iface */ 270 /* Create sockets and bind one to every iface */
267 max_socket = init_sockets(client_ifaces, num_sockets, argv[2], fds); 271 max_socket = init_sockets(iface_list, num_sockets, fds);
268 272
269 /* Get our IP on server_iface */ 273 /* Get our IP on server_iface */
270 if (udhcp_read_interface(argv[2], NULL, &our_nip, NULL)) 274 if (udhcp_read_interface(argv[2], NULL, &our_nip, NULL))
@@ -272,11 +276,10 @@ int dhcprelay_main(int argc, char **argv)
272 276
273 /* Main loop */ 277 /* Main loop */
274 while (1) { 278 while (1) {
275//reinit stuff from time to time? go back to get_client_devices 279// reinit stuff from time to time? go back to make_iface_list
276//every N minutes? 280// every N minutes?
281 fd_set rfds;
277 struct timeval tv; 282 struct timeval tv;
278 size_t packlen;
279 socklen_t addr_size;
280 int i; 283 int i;
281 284
282 FD_ZERO(&rfds); 285 FD_ZERO(&rfds);
@@ -285,6 +288,9 @@ int dhcprelay_main(int argc, char **argv)
285 tv.tv_sec = SELECT_TIMEOUT; 288 tv.tv_sec = SELECT_TIMEOUT;
286 tv.tv_usec = 0; 289 tv.tv_usec = 0;
287 if (select(max_socket + 1, &rfds, NULL, NULL, &tv) > 0) { 290 if (select(max_socket + 1, &rfds, NULL, NULL, &tv) > 0) {
291 int packlen;
292 struct dhcp_packet dhcp_msg;
293
288 /* server */ 294 /* server */
289 if (FD_ISSET(fds[0], &rfds)) { 295 if (FD_ISSET(fds[0], &rfds)) {
290 packlen = udhcp_recv_kernel_packet(&dhcp_msg, fds[0]); 296 packlen = udhcp_recv_kernel_packet(&dhcp_msg, fds[0]);
@@ -292,24 +298,65 @@ int dhcprelay_main(int argc, char **argv)
292 pass_to_client(&dhcp_msg, packlen, fds); 298 pass_to_client(&dhcp_msg, packlen, fds);
293 } 299 }
294 } 300 }
301
295 /* clients */ 302 /* clients */
296 for (i = 1; i < num_sockets; i++) { 303 for (i = 1; i < num_sockets; i++) {
304 struct sockaddr_in client_addr;
305 socklen_t addr_size;
306
297 if (!FD_ISSET(fds[i], &rfds)) 307 if (!FD_ISSET(fds[i], &rfds))
298 continue; 308 continue;
299 addr_size = sizeof(struct sockaddr_in); 309
310 addr_size = sizeof(client_addr);
300 packlen = recvfrom(fds[i], &dhcp_msg, sizeof(dhcp_msg), 0, 311 packlen = recvfrom(fds[i], &dhcp_msg, sizeof(dhcp_msg), 0,
301 (struct sockaddr *)(&client_addr), &addr_size); 312 (struct sockaddr *)(&client_addr), &addr_size);
302 if (packlen <= 0) 313 if (packlen <= 0)
303 continue; 314 continue;
304 315
305 /* Get our IP on corresponding client_iface */ 316 /* Get our IP on corresponding client_iface */
306//why? what if server can't route such IP? 317// RFC 1542
307 if (udhcp_read_interface(client_ifaces[i-1], NULL, &dhcp_msg.gateway_nip, NULL)) { 318// 4.1 General BOOTP Processing for Relay Agents
308 /* Fall back to our server_iface's IP */ 319// 4.1.1 BOOTREQUEST Messages
309//this makes more sense! 320// If the relay agent does decide to relay the request, it MUST examine
321// the 'giaddr' ("gateway" IP address) field. If this field is zero,
322// the relay agent MUST fill this field with the IP address of the
323// interface on which the request was received. If the interface has
324// more than one IP address logically associated with it, the relay
325// agent SHOULD choose one IP address associated with that interface and
326// use it consistently for all BOOTP messages it relays. If the
327// 'giaddr' field contains some non-zero value, the 'giaddr' field MUST
328// NOT be modified. The relay agent MUST NOT, under any circumstances,
329// fill the 'giaddr' field with a broadcast address as is suggested in
330// [1] (Section 8, sixth paragraph).
331
332// but why? what if server can't route such IP? Client ifaces may be, say, NATed!
333
334// 4.1.2 BOOTREPLY Messages
335// BOOTP relay agents relay BOOTREPLY messages only to BOOTP clients.
336// It is the responsibility of BOOTP servers to send BOOTREPLY messages
337// directly to the relay agent identified in the 'giaddr' field.
338// (yeah right, unless it is impossible... see comment above)
339// Therefore, a relay agent may assume that all BOOTREPLY messages it
340// receives are intended for BOOTP clients on its directly-connected
341// networks.
342//
343// When a relay agent receives a BOOTREPLY message, it should examine
344// the BOOTP 'giaddr', 'yiaddr', 'chaddr', 'htype', and 'hlen' fields.
345// These fields should provide adequate information for the relay agent
346// to deliver the BOOTREPLY message to the client.
347//
348// The 'giaddr' field can be used to identify the logical interface from
349// which the reply must be sent (i.e., the host or router interface
350// connected to the same network as the BOOTP client). If the content
351// of the 'giaddr' field does not match one of the relay agent's
352// directly-connected logical interfaces, the BOOTREPLY messsage MUST be
353// silently discarded.
354 if (udhcp_read_interface(iface_list[i], NULL, &dhcp_msg.gateway_nip, NULL)) {
355 /* Fall back to our IP on server iface */
356// this makes more sense!
310 dhcp_msg.gateway_nip = our_nip; 357 dhcp_msg.gateway_nip = our_nip;
311 } 358 }
312//maybe set dhcp_msg.flags |= BROADCAST_FLAG too? 359// maybe dhcp_msg.hops++? drop packets with too many hops (RFC 1542 says 4 or 16)?
313 pass_to_server(&dhcp_msg, packlen, i, fds, &client_addr, &server_addr); 360 pass_to_server(&dhcp_msg, packlen, i, fds, &client_addr, &server_addr);
314 } 361 }
315 } 362 }