diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2021-09-02 16:23:24 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2021-09-02 16:24:52 +0200 |
commit | 3f2d969db9023e273a327418b32ebd4ed88893c4 (patch) | |
tree | 8796e8dc29994a8b6de62f23d6fef89e4a8abf0c | |
parent | 62d0c8e02872d444ba20b4bdf638ac26c509a3dd (diff) | |
download | busybox-w32-3f2d969db9023e273a327418b32ebd4ed88893c4.tar.gz busybox-w32-3f2d969db9023e273a327418b32ebd4ed88893c4.tar.bz2 busybox-w32-3f2d969db9023e273a327418b32ebd4ed88893c4.zip |
udhcp: clarify aspects of relay operation, add TODOs and FIXMEs, tweak --help
function old new delta
packed_usage 33891 33920 +29
dhcprelay_main 943 926 -17
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 29/-17) Total: 12 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/udhcp/dhcpd.c | 7 | ||||
-rw-r--r-- | networking/udhcp/dhcprelay.c | 61 |
2 files changed, 46 insertions, 22 deletions
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index b67dfc3bc..0f5edb75c 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c | |||
@@ -614,6 +614,10 @@ static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt) | |||
614 | udhcp_send_kernel_packet(dhcp_pkt, | 614 | udhcp_send_kernel_packet(dhcp_pkt, |
615 | server_data.server_nip, SERVER_PORT, | 615 | server_data.server_nip, SERVER_PORT, |
616 | dhcp_pkt->gateway_nip, SERVER_PORT, | 616 | dhcp_pkt->gateway_nip, SERVER_PORT, |
617 | /* Yes, relay agents receive (and send) all their packets on SERVER_PORT, | ||
618 | * even those which are clients' requests and would normally | ||
619 | * (i.e. without relay) use CLIENT_PORT. See RFC 1542. | ||
620 | */ | ||
617 | server_data.interface); | 621 | server_data.interface); |
618 | } | 622 | } |
619 | 623 | ||
@@ -1025,6 +1029,9 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
1025 | * socket read inside this call is restarted on caught signals. | 1029 | * socket read inside this call is restarted on caught signals. |
1026 | */ | 1030 | */ |
1027 | bytes = udhcp_recv_kernel_packet(&packet, server_socket); | 1031 | bytes = udhcp_recv_kernel_packet(&packet, server_socket); |
1032 | //NB: we do not check source port here. Should we? | ||
1033 | //It should be CLIENT_PORT for clients, | ||
1034 | //or SERVER_PORT for relay agents (in which case giaddr must be != 0.0.0.0) | ||
1028 | if (bytes < 0) { | 1035 | if (bytes < 0) { |
1029 | /* bytes can also be -2 ("bad packet data") */ | 1036 | /* bytes can also be -2 ("bad packet data") */ |
1030 | if (bytes == -1 && errno != EINTR) { | 1037 | if (bytes == -1 && errno != EINTR) { |
diff --git a/networking/udhcp/dhcprelay.c b/networking/udhcp/dhcprelay.c index ef9447b4b..de3e4b0e1 100644 --- a/networking/udhcp/dhcprelay.c +++ b/networking/udhcp/dhcprelay.c | |||
@@ -17,7 +17,8 @@ | |||
17 | //usage:#define dhcprelay_trivial_usage | 17 | //usage:#define dhcprelay_trivial_usage |
18 | //usage: "CLIENT_IFACE[,CLIENT_IFACE2]... SERVER_IFACE [SERVER_IP]" | 18 | //usage: "CLIENT_IFACE[,CLIENT_IFACE2]... SERVER_IFACE [SERVER_IP]" |
19 | //usage:#define dhcprelay_full_usage "\n\n" | 19 | //usage:#define dhcprelay_full_usage "\n\n" |
20 | //usage: "Relay DHCP requests between clients and server" | 20 | //usage: "Relay DHCP requests between clients and server.\n" |
21 | //usage: "Without SERVER_IP, requests are broadcast on SERVER_IFACE." | ||
21 | 22 | ||
22 | #include "common.h" | 23 | #include "common.h" |
23 | 24 | ||
@@ -31,7 +32,7 @@ | |||
31 | /* This list holds information about clients. The xid_* functions manipulate this list. */ | 32 | /* This list holds information about clients. The xid_* functions manipulate this list. */ |
32 | struct xid_item { | 33 | struct xid_item { |
33 | unsigned timestamp; | 34 | unsigned timestamp; |
34 | int client; | 35 | unsigned iface_no; |
35 | uint32_t xid; | 36 | uint32_t xid; |
36 | struct sockaddr_in ip; | 37 | struct sockaddr_in ip; |
37 | struct xid_item *next; | 38 | struct xid_item *next; |
@@ -40,7 +41,7 @@ struct xid_item { | |||
40 | #define dhcprelay_xid_list (*(struct xid_item*)bb_common_bufsiz1) | 41 | #define dhcprelay_xid_list (*(struct xid_item*)bb_common_bufsiz1) |
41 | #define INIT_G() do { setup_common_bufsiz(); } while (0) | 42 | #define INIT_G() do { setup_common_bufsiz(); } while (0) |
42 | 43 | ||
43 | static struct xid_item *xid_add(uint32_t xid, struct sockaddr_in *ip, int client) | 44 | static struct xid_item *xid_add(uint32_t xid, struct sockaddr_in *ip, unsigned iface_no) |
44 | { | 45 | { |
45 | struct xid_item *item; | 46 | struct xid_item *item; |
46 | 47 | ||
@@ -50,7 +51,7 @@ static struct xid_item *xid_add(uint32_t xid, struct sockaddr_in *ip, int client | |||
50 | /* add xid entry */ | 51 | /* add xid entry */ |
51 | item->ip = *ip; | 52 | item->ip = *ip; |
52 | item->xid = xid; | 53 | item->xid = xid; |
53 | item->client = client; | 54 | item->iface_no = iface_no; |
54 | item->timestamp = monotonic_sec(); | 55 | item->timestamp = monotonic_sec(); |
55 | item->next = dhcprelay_xid_list.next; | 56 | item->next = dhcprelay_xid_list.next; |
56 | dhcprelay_xid_list.next = item; | 57 | dhcprelay_xid_list.next = item; |
@@ -127,7 +128,7 @@ static int get_dhcp_packet_type(struct dhcp_packet *p) | |||
127 | * make_iface_list - parses client/server interface names | 128 | * make_iface_list - parses client/server interface names |
128 | * returns array | 129 | * returns array |
129 | */ | 130 | */ |
130 | static char **make_iface_list(char **client_and_server_ifaces, int *client_number) | 131 | static char **make_iface_list(char **client_and_server_ifaces, unsigned *client_number) |
131 | { | 132 | { |
132 | char *s, **iface_list; | 133 | char *s, **iface_list; |
133 | int i, cn; | 134 | int i, cn; |
@@ -165,9 +166,9 @@ static char **make_iface_list(char **client_and_server_ifaces, int *client_numbe | |||
165 | /* Creates listen sockets (in fds) bound to client and server ifaces, | 166 | /* Creates listen sockets (in fds) bound to client and server ifaces, |
166 | * and returns numerically max fd. | 167 | * and returns numerically max fd. |
167 | */ | 168 | */ |
168 | static int init_sockets(char **iface_list, int num_clients, int *fds) | 169 | static unsigned init_sockets(char **iface_list, unsigned num_clients, int *fds) |
169 | { | 170 | { |
170 | int i, n; | 171 | unsigned i, n; |
171 | 172 | ||
172 | n = 0; | 173 | n = 0; |
173 | for (i = 0; i < num_clients; i++) { | 174 | for (i = 0; i < num_clients; i++) { |
@@ -195,13 +196,14 @@ static int sendto_ip4(int sock, const void *msg, int msg_len, struct sockaddr_in | |||
195 | * p - packet to send | 196 | * p - packet to send |
196 | * client - number of the client | 197 | * client - number of the client |
197 | */ | 198 | */ |
198 | static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, int *fds, | 199 | static void pass_to_server(struct dhcp_packet *p, int packet_len, unsigned from_iface_no, int *fds, |
199 | struct sockaddr_in *client_addr, struct sockaddr_in *server_addr) | 200 | struct sockaddr_in *client_addr, struct sockaddr_in *server_addr) |
200 | { | 201 | { |
201 | int type; | 202 | int type; |
202 | 203 | ||
203 | /* check packet_type */ | 204 | /* check packet_type */ |
204 | type = get_dhcp_packet_type(p); | 205 | type = get_dhcp_packet_type(p); |
206 | //FIXME: the above does not consider packet_len! | ||
205 | if (type != DHCPDISCOVER && type != DHCPREQUEST | 207 | if (type != DHCPDISCOVER && type != DHCPREQUEST |
206 | && type != DHCPDECLINE && type != DHCPRELEASE | 208 | && type != DHCPDECLINE && type != DHCPRELEASE |
207 | && type != DHCPINFORM | 209 | && type != DHCPINFORM |
@@ -210,7 +212,10 @@ static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, in | |||
210 | } | 212 | } |
211 | 213 | ||
212 | /* create new xid entry */ | 214 | /* create new xid entry */ |
213 | xid_add(p->xid, client_addr, client); | 215 | xid_add(p->xid, client_addr, from_iface_no); |
216 | //TODO: since we key request/reply pairs on xid values, shouldn't we drop new requests | ||
217 | //with xid accidentally matching a xid of one of requests we currently hold | ||
218 | //waiting for their replies? | ||
214 | 219 | ||
215 | /* forward request to server */ | 220 | /* forward request to server */ |
216 | /* note that we send from fds[0] which is bound to SERVER_PORT (67). | 221 | /* note that we send from fds[0] which is bound to SERVER_PORT (67). |
@@ -229,25 +234,30 @@ static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds) | |||
229 | int type; | 234 | int type; |
230 | struct xid_item *item; | 235 | struct xid_item *item; |
231 | 236 | ||
232 | /* check xid */ | ||
233 | item = xid_find(p->xid); | ||
234 | if (!item) { | ||
235 | return; | ||
236 | } | ||
237 | |||
238 | /* check packet type */ | 237 | /* check packet type */ |
239 | type = get_dhcp_packet_type(p); | 238 | type = get_dhcp_packet_type(p); |
239 | //FIXME: the above does not consider packet_len! | ||
240 | if (type != DHCPOFFER && type != DHCPACK && type != DHCPNAK) { | 240 | if (type != DHCPOFFER && type != DHCPACK && type != DHCPNAK) { |
241 | return; | 241 | return; |
242 | } | 242 | } |
243 | 243 | ||
244 | /* check xid */ | ||
245 | item = xid_find(p->xid); | ||
246 | if (!item) { | ||
247 | return; | ||
248 | } | ||
249 | //NB: RFC 1542 section 4.1 seems to envision the logic that | ||
250 | //relay agents use giaddr (dhcp_msg.gateway_nip in our code) | ||
251 | //to find out on which interface to reply. | ||
252 | //(server is meant to copy giaddr from our request packet to its reply). | ||
253 | //Above, we don't use that logic, instead we use xid as a key. | ||
254 | |||
244 | //TODO: also do it if (p->flags & htons(BROADCAST_FLAG)) is set! | 255 | //TODO: also do it if (p->flags & htons(BROADCAST_FLAG)) is set! |
245 | if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY)) | 256 | if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY)) |
246 | item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST); | 257 | item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST); |
247 | 258 | ||
248 | if (sendto_ip4(fds[item->client], p, packet_len, &item->ip) != 0) { | 259 | sendto_ip4(fds[item->iface_no], p, packet_len, &item->ip); |
249 | return; /* send error occurred */ | 260 | /* ^^^ if send error occurred, we can't do much, hence no check */ |
250 | } | ||
251 | 261 | ||
252 | /* remove xid entry */ | 262 | /* remove xid entry */ |
253 | xid_del(p->xid); | 263 | xid_del(p->xid); |
@@ -259,7 +269,7 @@ int dhcprelay_main(int argc UNUSED_PARAM, char **argv) | |||
259 | struct sockaddr_in server_addr; | 269 | struct sockaddr_in server_addr; |
260 | char **iface_list; | 270 | char **iface_list; |
261 | int *fds; | 271 | int *fds; |
262 | int num_sockets, max_socket; | 272 | unsigned num_sockets, max_socket; |
263 | uint32_t our_nip; | 273 | uint32_t our_nip; |
264 | 274 | ||
265 | INIT_G(); | 275 | INIT_G(); |
@@ -293,7 +303,7 @@ int dhcprelay_main(int argc UNUSED_PARAM, char **argv) | |||
293 | // every N minutes? | 303 | // every N minutes? |
294 | fd_set rfds; | 304 | fd_set rfds; |
295 | struct timeval tv; | 305 | struct timeval tv; |
296 | int i; | 306 | unsigned i; |
297 | 307 | ||
298 | FD_ZERO(&rfds); | 308 | FD_ZERO(&rfds); |
299 | for (i = 0; i < num_sockets; i++) | 309 | for (i = 0; i < num_sockets; i++) |
@@ -304,15 +314,17 @@ int dhcprelay_main(int argc UNUSED_PARAM, char **argv) | |||
304 | int packlen; | 314 | int packlen; |
305 | struct dhcp_packet dhcp_msg; | 315 | struct dhcp_packet dhcp_msg; |
306 | 316 | ||
307 | /* server */ | 317 | /* from server */ |
308 | if (FD_ISSET(fds[0], &rfds)) { | 318 | if (FD_ISSET(fds[0], &rfds)) { |
309 | packlen = udhcp_recv_kernel_packet(&dhcp_msg, fds[0]); | 319 | packlen = udhcp_recv_kernel_packet(&dhcp_msg, fds[0]); |
320 | //NB: we do not check source port here. Should we? | ||
321 | //It should be SERVER_PORT. | ||
310 | if (packlen > 0) { | 322 | if (packlen > 0) { |
311 | pass_to_client(&dhcp_msg, packlen, fds); | 323 | pass_to_client(&dhcp_msg, packlen, fds); |
312 | } | 324 | } |
313 | } | 325 | } |
314 | 326 | ||
315 | /* clients */ | 327 | /* from clients */ |
316 | for (i = 1; i < num_sockets; i++) { | 328 | for (i = 1; i < num_sockets; i++) { |
317 | struct sockaddr_in client_addr; | 329 | struct sockaddr_in client_addr; |
318 | socklen_t addr_size; | 330 | socklen_t addr_size; |
@@ -325,6 +337,11 @@ int dhcprelay_main(int argc UNUSED_PARAM, char **argv) | |||
325 | (struct sockaddr *)(&client_addr), &addr_size); | 337 | (struct sockaddr *)(&client_addr), &addr_size); |
326 | if (packlen <= 0) | 338 | if (packlen <= 0) |
327 | continue; | 339 | continue; |
340 | //NB: we do not check source port here. Should we? | ||
341 | //It should be CLIENT_PORT for clients. | ||
342 | //It can be SERVER_PORT for relay agents (in which case giaddr must be != 0.0.0.0), | ||
343 | //but is it even supported to chain relay agents like this? | ||
344 | //(we still copy client_addr.port and use it to reply to the port we got request from) | ||
328 | 345 | ||
329 | /* Get our IP on corresponding client_iface */ | 346 | /* Get our IP on corresponding client_iface */ |
330 | // RFC 1542 | 347 | // RFC 1542 |