diff options
author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2011-01-04 19:40:30 +0700 |
---|---|---|
committer | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2011-01-04 19:40:30 +0700 |
commit | 3b5c308768d76298bb964814ecc34de47bcac0b4 (patch) | |
tree | 795340e9d8f5e5bf9e8d895641099af343eec2a0 /networking | |
parent | 2b9a0e715ec459198f486653023d963b79291da7 (diff) | |
parent | 5fe2f863b9cee5ab0e7ac873538bce48846dbad8 (diff) | |
download | busybox-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.src | 2 | ||||
-rw-r--r-- | networking/nbd-client.c | 153 | ||||
-rw-r--r-- | networking/nc_bloaty.c | 3 | ||||
-rw-r--r-- | networking/ntpd.c | 13 | ||||
-rw-r--r-- | networking/udhcp/common.c | 4 | ||||
-rw-r--r-- | networking/udhcp/common.h | 2 | ||||
-rw-r--r-- | networking/udhcp/dhcpc.c | 17 | ||||
-rw-r--r-- | networking/udhcp/dhcprelay.c | 189 |
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 | |||
45 | int nbdclient_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
46 | int 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. */ |
19 | struct xid_item { | 22 | struct 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 | ||
77 | static void xid_del(uint32_t xid) | 80 | static 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 | */ |
117 | static char **get_client_devices(char *dev_list, int *client_number) | 119 | static 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 | */ |
151 | static int init_sockets(char **client_ifaces, int num_clients, | 157 | static 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 | ||
170 | static 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, | |||
174 | static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, int *fds, | 187 | static 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 | */ |
204 | static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds) | 216 | static 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) | |||
235 | int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 245 | int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
236 | int dhcprelay_main(int argc, char **argv) | 246 | int 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 | } |