VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/bootp.c@ 26817

最後變更 在這個檔案從26817是 26495,由 vboxsync 提交於 15 年 前

Devices: whitespace cleanup

  • 屬性 svn:eol-style 設為 native
檔案大小: 26.9 KB
 
1/*
2 * QEMU BOOTP/DHCP server
3 *
4 * Copyright (c) 2004 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24#include <slirp.h>
25
26/** Entry in the table of known DHCP clients. */
27typedef struct
28{
29 uint32_t xid;
30 bool allocated;
31 uint8_t macaddr[6];
32 struct in_addr addr;
33 int number;
34} BOOTPClient;
35/** Number of DHCP clients supported by NAT. */
36#define NB_ADDR 16
37
38#define bootp_clients ((BOOTPClient *)pData->pbootp_clients)
39
40/* XXX: only DHCP is supported */
41static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
42
43static void bootp_reply(PNATState pData, struct mbuf *m0, int offReply, uint16_t flags);
44
45static uint8_t *dhcp_find_option(uint8_t *vend, uint8_t tag)
46{
47 uint8_t *q = vend;
48 uint8_t len;
49 /*@todo magic validation */
50 q += 4; /*magic*/
51 while(*q != RFC1533_END)
52 {
53 if (*q == RFC1533_PAD)
54 continue;
55 if (*q == tag)
56 return q;
57 q++;
58 len = *q;
59 q += 1 + len;
60 }
61 return NULL;
62}
63
64static BOOTPClient *bc_alloc_client(PNATState pData)
65{
66 int i;
67 for (i = 0; i < NB_ADDR; i++)
68 {
69 if (!bootp_clients[i].allocated)
70 {
71 BOOTPClient *bc;
72
73 bc = &bootp_clients[i];
74 memset(bc, 0, sizeof(BOOTPClient));
75 bc->allocated = 1;
76 bc->number = i;
77 return bc;
78 }
79 }
80 return NULL;
81}
82
83static BOOTPClient *get_new_addr(PNATState pData, struct in_addr *paddr)
84{
85 BOOTPClient *bc;
86 bc = bc_alloc_client(pData);
87 if (!bc)
88 return NULL;
89
90 paddr->s_addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | (bc->number + START_ADDR));
91 bc->addr.s_addr = paddr->s_addr;
92 return bc;
93}
94
95static int release_addr(PNATState pData, struct in_addr *paddr)
96{
97 unsigned i;
98 for (i = 0; i < NB_ADDR; i++)
99 {
100 if (paddr->s_addr == bootp_clients[i].addr.s_addr)
101 {
102 memset(&bootp_clients[i], 0, sizeof(BOOTPClient));
103 return VINF_SUCCESS;
104 }
105 }
106 return VERR_NOT_FOUND;
107}
108
109/*
110 * from RFC 2131 4.3.1
111 * Field DHCPOFFER DHCPACK DHCPNAK
112 * ----- --------- ------- -------
113 * 'op' BOOTREPLY BOOTREPLY BOOTREPLY
114 * 'htype' (From "Assigned Numbers" RFC)
115 * 'hlen' (Hardware address length in octets)
116 * 'hops' 0 0 0
117 * 'xid' 'xid' from client 'xid' from client 'xid' from client
118 * DHCPDISCOVER DHCPREQUEST DHCPREQUEST
119 * message message message
120 * 'secs' 0 0 0
121 * 'ciaddr' 0 'ciaddr' from 0
122 * DHCPREQUEST or 0
123 * 'yiaddr' IP address offered IP address 0
124 * to client assigned to client
125 * 'siaddr' IP address of next IP address of next 0
126 * bootstrap server bootstrap server
127 * 'flags' 'flags' from 'flags' from 'flags' from
128 * client DHCPDISCOVER client DHCPREQUEST client DHCPREQUEST
129 * message message message
130 * 'giaddr' 'giaddr' from 'giaddr' from 'giaddr' from
131 * client DHCPDISCOVER client DHCPREQUEST client DHCPREQUEST
132 * message message message
133 * 'chaddr' 'chaddr' from 'chaddr' from 'chaddr' from
134 * client DHCPDISCOVER client DHCPREQUEST client DHCPREQUEST
135 * message message message
136 * 'sname' Server host name Server host name (unused)
137 * or options or options
138 * 'file' Client boot file Client boot file (unused)
139 * name or options name or options
140 * 'options' options options
141 *
142 * Option DHCPOFFER DHCPACK DHCPNAK
143 * ------ --------- ------- -------
144 * Requested IP address MUST NOT MUST NOT MUST NOT
145 * IP address lease time MUST MUST (DHCPREQUEST) MUST NOT
146 * MUST NOT (DHCPINFORM)
147 * Use 'file'/'sname' fields MAY MAY MUST NOT
148 * DHCP message type DHCPOFFER DHCPACK DHCPNAK
149 * Parameter request list MUST NOT MUST NOT MUST NOT
150 * Message SHOULD SHOULD SHOULD
151 * Client identifier MUST NOT MUST NOT MAY
152 * Vendor class identifier MAY MAY MAY
153 * Server identifier MUST MUST MUST
154 * Maximum message size MUST NOT MUST NOT MUST NOT
155 * All others MAY MAY MUST NOT
156 */
157static BOOTPClient *find_addr(PNATState pData, struct in_addr *paddr, const uint8_t *macaddr)
158{
159 int i;
160
161 for (i = 0; i < NB_ADDR; i++)
162 {
163 if (!memcmp(macaddr, bootp_clients[i].macaddr, 6))
164 {
165 BOOTPClient *bc;
166
167 bc = &bootp_clients[i];
168 bc->allocated = 1;
169 paddr->s_addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | (i + START_ADDR));
170 return bc;
171 }
172 }
173 return NULL;
174}
175
176static struct mbuf *dhcp_create_msg(PNATState pData, struct bootp_t *bp, struct mbuf *m, uint8_t type)
177{
178 struct bootp_t *rbp;
179 struct ethhdr *eh;
180 uint8_t *q;
181
182 eh = mtod(m, struct ethhdr *);
183 memcpy(eh->h_source, bp->bp_hwaddr, ETH_ALEN); /* XXX: if_encap just swap source with dest*/
184
185 m->m_data += if_maxlinkhdr; /*reserve ether header */
186
187 rbp = mtod(m, struct bootp_t *);
188 memset(rbp, 0, sizeof(struct bootp_t));
189 rbp->bp_op = BOOTP_REPLY;
190 rbp->bp_xid = bp->bp_xid; /* see table 3 of rfc2131*/
191 rbp->bp_flags = bp->bp_flags; /* figure 2 of rfc2131 */
192 rbp->bp_giaddr.s_addr = bp->bp_giaddr.s_addr;
193#if 0 /*check flags*/
194 saddr.sin_port = RT_H2N_U16_C(BOOTP_SERVER);
195 daddr.sin_port = RT_H2N_U16_C(BOOTP_CLIENT);
196#endif
197 rbp->bp_htype = 1;
198 rbp->bp_hlen = 6;
199 memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
200
201 memcpy(rbp->bp_vend, rfc1533_cookie, 4); /* cookie */
202 q = rbp->bp_vend;
203 q += 4;
204 *q++ = RFC2132_MSG_TYPE;
205 *q++ = 1;
206 *q++ = type;
207
208 return m;
209}
210
211static int dhcp_do_ack_offer(PNATState pData, struct mbuf *m, BOOTPClient *bc, int fDhcpRequest)
212{
213 struct bootp_t *rbp = NULL;
214 uint8_t *q;
215 struct in_addr saddr;
216 int val;
217
218 struct dns_entry *de = NULL;
219 struct dns_domain_entry *dd = NULL;
220 int added = 0;
221 uint8_t *q_dns_header = NULL;
222 uint32_t lease_time = RT_H2N_U32_C(LEASE_TIME);
223 uint32_t netmask = RT_H2N_U32(pData->netmask);
224
225 rbp = mtod(m, struct bootp_t *);
226 q = &rbp->bp_vend[0];
227 q += 7; /* !cookie rfc 2132 + TYPE*/
228
229 /*DHCP Offer specific*/
230 if ( tftp_prefix
231 && RTDirExists(tftp_prefix)
232 && bootp_filename)
233 RTStrPrintf((char*)rbp->bp_file, sizeof(rbp->bp_file), "%s", bootp_filename);
234
235 Log(("NAT: DHCP: bp_file:%s\n", &rbp->bp_file));
236 /* Address/port of the DHCP server. */
237 rbp->bp_yiaddr = bc->addr; /* Client IP address */
238 Log(("NAT: DHCP: bp_yiaddr:%R[IP4]\n", &rbp->bp_yiaddr));
239 rbp->bp_siaddr = pData->tftp_server; /* Next Server IP address, i.e. TFTP */
240 Log(("NAT: DHCP: bp_siaddr:%R[IP4]\n", &rbp->bp_siaddr));
241 if (fDhcpRequest)
242 {
243 rbp->bp_ciaddr.s_addr = bc->addr.s_addr; /* Client IP address */
244 }
245#ifndef VBOX_WITH_NAT_SERVICE
246 saddr.s_addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_ALIAS);
247#else
248 saddr.s_addr = pData->special_addr.s_addr;
249#endif
250 Log(("NAT: DHCP: s_addr:%R[IP4]\n", &saddr));
251
252#define FILL_BOOTP_EXT(q, tag, len, pvalue) \
253 do { \
254 struct bootp_ext *be = (struct bootp_ext *)(q); \
255 be->bpe_tag = (tag); \
256 be->bpe_len = (len); \
257 memcpy(&be[1], (pvalue), (len)); \
258 (q) = (uint8_t *)(&be[1]) + (len); \
259 }while(0)
260/* appending another value to tag, calculates len of whole block*/
261#define FILL_BOOTP_APP(head, q, tag, len, pvalue) \
262 do { \
263 struct bootp_ext *be = (struct bootp_ext *)(head); \
264 memcpy(q, (pvalue), (len)); \
265 (q) += (len); \
266 Assert(be->bpe_tag == (tag)); \
267 be->bpe_len += (len); \
268 }while(0)
269
270
271 FILL_BOOTP_EXT(q, RFC1533_NETMASK, 4, &netmask);
272 FILL_BOOTP_EXT(q, RFC1533_GATEWAY, 4, &saddr);
273
274 if (pData->use_dns_proxy || pData->use_host_resolver)
275 {
276 uint32_t addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_DNS);
277 FILL_BOOTP_EXT(q, RFC1533_DNS, 4, &addr);
278 goto skip_dns_servers;
279 }
280
281 if (!TAILQ_EMPTY(&pData->pDnsList))
282 {
283 de = TAILQ_LAST(&pData->pDnsList, dns_list_head);
284 q_dns_header = q;
285 FILL_BOOTP_EXT(q, RFC1533_DNS, 4, &de->de_addr.s_addr);
286 }
287
288 TAILQ_FOREACH_REVERSE(de, &pData->pDnsList, dns_list_head, de_list)
289 {
290 if (TAILQ_LAST(&pData->pDnsList, dns_list_head) == de)
291 continue; /* first value with head we've ingected before */
292 FILL_BOOTP_APP(q_dns_header, q, RFC1533_DNS, 4, &de->de_addr.s_addr);
293 }
294
295skip_dns_servers:
296 if (LIST_EMPTY(&pData->pDomainList))
297 {
298 /* Microsoft dhcp client doen't like domain-less dhcp and trimmed packets*/
299 /* dhcpcd client very sad if no domain name is passed */
300 FILL_BOOTP_EXT(q, RFC1533_DOMAINNAME, 1, " ");
301 }
302 if (pData->fPassDomain && !pData->use_host_resolver)
303 {
304 LIST_FOREACH(dd, &pData->pDomainList, dd_list)
305 {
306
307 if (dd->dd_pszDomain == NULL)
308 continue;
309 /* never meet valid separator here in RFC1533*/
310 if (added != 0)
311 FILL_BOOTP_EXT(q, RFC1533_DOMAINNAME, 1, ",");
312 else
313 added = 1;
314 val = (int)strlen(dd->dd_pszDomain);
315 FILL_BOOTP_EXT(q, RFC1533_DOMAINNAME, val, dd->dd_pszDomain);
316 }
317 }
318
319 FILL_BOOTP_EXT(q, RFC2132_LEASE_TIME, 4, &lease_time);
320
321 if (*slirp_hostname)
322 {
323 val = (int)strlen(slirp_hostname);
324 FILL_BOOTP_EXT(q, RFC1533_HOSTNAME, val, slirp_hostname);
325 }
326 slirp_arp_cache_update_or_add(pData, rbp->bp_yiaddr.s_addr, bc->macaddr);
327 return q - rbp->bp_vend; /*return offset */
328}
329
330static int dhcp_send_nack(PNATState pData, struct bootp_t *bp, BOOTPClient *bc, struct mbuf *m)
331{
332 struct bootp_t *rbp;
333 uint8_t *q = NULL;
334 rbp = mtod(m, struct bootp_t *);
335
336 dhcp_create_msg(pData, bp, m, DHCPNAK);
337 return 7;
338}
339
340static int dhcp_send_ack(PNATState pData, struct bootp_t *bp, BOOTPClient *bc, struct mbuf *m, int fDhcpRequest)
341{
342 struct bootp_t *rbp;
343 int offReply = 0; /* boot_reply will fill general options and add END before sending response */
344
345 dhcp_create_msg(pData, bp, m, DHCPACK);
346 offReply = dhcp_do_ack_offer(pData, m, bc, fDhcpRequest);
347 return offReply;
348}
349
350static int dhcp_send_offer(PNATState pData, struct bootp_t *bp, BOOTPClient *bc, struct mbuf *m)
351{
352 int offReply = 0; /* boot_reply will fill general options and add END before sending response */
353
354 dhcp_create_msg(pData, bp, m, DHCPOFFER);
355 offReply = dhcp_do_ack_offer(pData, m, bc, /* fDhcpRequest=*/ 0);
356 return offReply;
357}
358
359/**
360 * decoding client messages RFC2131 (4.3.6)
361 * ---------------------------------------------------------------------
362 * | |INIT-REBOOT |SELECTING |RENEWING |REBINDING |
363 * ---------------------------------------------------------------------
364 * |broad/unicast |broadcast |broadcast |unicast |broadcast |
365 * |server-ip |MUST NOT |MUST |MUST NOT |MUST NOT |
366 * |requested-ip |MUST |MUST |MUST NOT |MUST NOT |
367 * |ciaddr |zero |zero |IP address |IP address|
368 * ---------------------------------------------------------------------
369 *
370 */
371
372enum DHCP_REQUEST_STATES
373{
374 INIT_REBOOT,
375 SELECTING,
376 RENEWING,
377 REBINDING,
378 NONE
379};
380
381static int dhcp_decode_request(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size, struct mbuf *m)
382{
383 BOOTPClient *bc = NULL;
384 struct in_addr daddr;
385 int offReply;
386 uint8_t *opt;
387 uint8_t *req_ip = NULL;
388 uint8_t *server_ip = NULL;
389 uint32_t ui32;
390 enum DHCP_REQUEST_STATES dhcp_stat = NONE;
391
392 /* need to understand which type of request we get */
393 req_ip = dhcp_find_option(&bp->bp_vend[0], RFC2132_REQ_ADDR);
394 server_ip = dhcp_find_option(&bp->bp_vend[0], RFC2132_SRV_ID);
395 bc = find_addr(pData, &daddr, bp->bp_hwaddr);
396
397 if (server_ip != NULL)
398 {
399 /* selecting */
400 if (!bc)
401 {
402 LogRel(("NAT: DHCP no IP was allocated\n"));
403 return -1;
404 }
405
406 dhcp_stat = SELECTING;
407 Assert((bp->bp_ciaddr.s_addr == INADDR_ANY));
408 Assert((*(uint32_t *)(req_ip + 2) == bc->addr.s_addr)); /*the same address as in offer*/
409#if 0
410 /* DSL xid in request differ from offer */
411 Assert((bp->bp_xid == bc->xid));
412#endif
413 }
414 else
415 {
416 if (req_ip != NULL)
417 {
418 /* init-reboot */
419 dhcp_stat = INIT_REBOOT;
420 }
421 else
422 {
423 /* table 4 of rfc2131 */
424 if (bp->bp_flags & RT_H2N_U16_C(DHCP_FLAGS_B))
425 dhcp_stat = REBINDING;
426 else
427 dhcp_stat = RENEWING;
428 }
429 }
430
431 /*?? renewing ??*/
432 switch (dhcp_stat)
433 {
434 case RENEWING:
435 Assert((server_ip == NULL && req_ip == NULL && bp->bp_ciaddr.s_addr != INADDR_ANY));
436 if (bc != NULL)
437 {
438 Assert((bc->addr.s_addr == bp->bp_ciaddr.s_addr));
439 /*if it already here well just do ack, we aren't aware of dhcp time expiration*/
440 }
441 else
442 {
443 if ((bp->bp_ciaddr.s_addr & RT_H2N_U32(pData->netmask)) != pData->special_addr.s_addr)
444 {
445 LogRel(("NAT: Client %R[IP4] requested IP -- sending NAK\n", &bp->bp_ciaddr));
446 offReply = dhcp_send_nack(pData, bp, bc, m);
447 return offReply;
448 }
449
450 bc = bc_alloc_client(pData);
451 if (!bc)
452 {
453 LogRel(("NAT: can't alloc address. RENEW has been silently ignored.\n"));
454 return -1;
455 }
456
457 Assert((bp->bp_hlen == ETH_ALEN));
458 memcpy(bc->macaddr, bp->bp_hwaddr, bp->bp_hlen);
459 bc->addr.s_addr = bp->bp_ciaddr.s_addr;
460 }
461 break;
462
463 case INIT_REBOOT:
464 Assert(server_ip == NULL);
465 Assert(req_ip != NULL);
466 ui32 = *(uint32_t *)(req_ip + 2);
467 if ((ui32 & RT_H2N_U32(pData->netmask)) != pData->special_addr.s_addr)
468 {
469 LogRel(("NAT: address %R[IP4] has been requested -- sending NAK\n", &ui32));
470 offReply = dhcp_send_nack(pData, bp, bc, m);
471 return offReply;
472 }
473
474 bc = bc_alloc_client(pData);
475 if (!bc)
476 {
477 LogRel(("NAT: can't alloc address. RENEW has been silently ignored\n"));
478 return -1;
479 }
480 Assert((bp->bp_hlen == ETH_ALEN));
481 memcpy(bc->macaddr, bp->bp_hwaddr, bp->bp_hlen);
482 bc->addr.s_addr = ui32;
483 break;
484
485 case NONE:
486 Assert((dhcp_stat != NONE));
487 return -1;
488
489 default:
490 break;
491 }
492
493 LogRel(("NAT: DHCP offered IP address %R[IP4]\n", &bc->addr));
494 offReply = dhcp_send_ack(pData, bp, bc, m, /* fDhcpRequest=*/ 1);
495 return offReply;
496}
497
498static int dhcp_decode_discover(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size, int fDhcpDiscover, struct mbuf *m)
499{
500 BOOTPClient *bc;
501 struct in_addr daddr;
502 int offReply;
503
504 if (fDhcpDiscover)
505 {
506 bc = find_addr(pData, &daddr, bp->bp_hwaddr);
507 if (!bc)
508 {
509 bc = get_new_addr(pData, &daddr);
510 if (!bc)
511 {
512 LogRel(("NAT: DHCP no IP address left\n"));
513 Log(("no address left\n"));
514 return -1;
515 }
516 memcpy(bc->macaddr, bp->bp_hwaddr, 6);
517 }
518
519 bc->xid = bp->bp_xid;
520 LogRel(("NAT: DHCP offered IP address %R[IP4]\n", &bc->addr));
521 offReply = dhcp_send_offer(pData, bp, bc, m);
522 return offReply;
523 }
524 else
525 {
526 bc = find_addr(pData, &daddr, bp->bp_hwaddr);
527 if (!bc)
528 {
529 LogRel(("NAT: DHCP Inform was ignored no boot client was found\n"));
530 return -1;
531 }
532
533 LogRel(("NAT: DHCP offered IP address %R[IP4]\n", &bc->addr));
534 offReply = dhcp_send_ack(pData, bp, bc, m, /* fDhcpRequest=*/ 0);
535 return offReply;
536 }
537
538 return -1;
539}
540
541static int dhcp_decode_release(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size)
542{
543 int rc = release_addr(pData, &bp->bp_ciaddr);
544 LogRel(("NAT: %s %R[IP4]\n",
545 RT_SUCCESS(rc) ? "DHCP released IP address" : "Ignored DHCP release for IP address",
546 &bp->bp_ciaddr));
547 return 0;
548}
549/**
550 * fields for discovering t
551 * Field DHCPDISCOVER DHCPREQUEST DHCPDECLINE,
552 * DHCPINFORM DHCPRELEASE
553 * ----- ------------ ----------- -----------
554 * 'op' BOOTREQUEST BOOTREQUEST BOOTREQUEST
555 * 'htype' (From "Assigned Numbers" RFC)
556 * 'hlen' (Hardware address length in octets)
557 * 'hops' 0 0 0
558 * 'xid' selected by client 'xid' from server selected by
559 * DHCPOFFER message client
560 * 'secs' 0 or seconds since 0 or seconds since 0
561 * DHCP process started DHCP process started
562 * 'flags' Set 'BROADCAST' Set 'BROADCAST' 0
563 * flag if client flag if client
564 * requires broadcast requires broadcast
565 * reply reply
566 * 'ciaddr' 0 (DHCPDISCOVER) 0 or client's 0 (DHCPDECLINE)
567 * client's network address client's network
568 * network address (BOUND/RENEW/REBIND) address
569 * (DHCPINFORM) (DHCPRELEASE)
570 * 'yiaddr' 0 0 0
571 * 'siaddr' 0 0 0
572 * 'giaddr' 0 0 0
573 * 'chaddr' client's hardware client's hardware client's hardware
574 * address address address
575 * 'sname' options, if options, if (unused)
576 * indicated in indicated in
577 * 'sname/file' 'sname/file'
578 * option; otherwise option; otherwise
579 * unused unused
580 * 'file' options, if options, if (unused)
581 * indicated in indicated in
582 * 'sname/file' 'sname/file'
583 * option; otherwise option; otherwise
584 * unused unused
585 * 'options' options options (unused)
586 * Requested IP address MAY MUST (in MUST
587 * (DISCOVER) SELECTING or (DHCPDECLINE),
588 * MUST NOT INIT-REBOOT) MUST NOT
589 * (INFORM) MUST NOT (in (DHCPRELEASE)
590 * BOUND or
591 * RENEWING)
592 * IP address lease time MAY MAY MUST NOT
593 * (DISCOVER)
594 * MUST NOT
595 * (INFORM)
596 * Use 'file'/'sname' fields MAY MAY MAY
597 * DHCP message type DHCPDISCOVER/ DHCPREQUEST DHCPDECLINE/
598 * DHCPINFORM DHCPRELEASE
599 * Client identifier MAY MAY MAY
600 * Vendor class identifier MAY MAY MUST NOT
601 * Server identifier MUST NOT MUST (after MUST
602 * SELECTING)
603 * MUST NOT (after
604 * INIT-REBOOT,
605 * BOUND, RENEWING
606 * or REBINDING)
607 * Parameter request list MAY MAY MUST NOT
608 * Maximum message size MAY MAY MUST NOT
609 * Message SHOULD NOT SHOULD NOT SHOULD
610 * Site-specific MAY MAY MUST NOT
611 * All others MAY MAY MUST NOT
612 *
613 */
614static void dhcp_decode(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size)
615{
616 const uint8_t *p, *p_end;
617 int rc;
618 int pmsg_type;
619 struct in_addr req_ip;
620 int fDhcpDiscover = 0;
621 int len, tag;
622 struct mbuf *m = NULL;
623
624 pmsg_type = 0;
625 p = buf;
626 p_end = buf + size;
627 if (size < 5)
628 return;
629
630 if (memcmp(p, rfc1533_cookie, 4) != 0)
631 return;
632
633 p = dhcp_find_option(bp->bp_vend, RFC2132_MSG_TYPE);
634 Assert(p);
635 if (p == NULL)
636 return;
637
638#ifndef VBOX_WITH_SLIRP_BSD_MBUF
639 if ((m = m_get(pData)) == NULL)
640#else
641 if ((m = m_getcl(pData, M_DONTWAIT, MT_HEADER, M_PKTHDR)) == NULL)
642#endif
643 {
644 LogRel(("NAT: can't alocate memory for response!\n"));
645 return;
646 }
647
648 switch (*(p+2))
649 {
650 case DHCPDISCOVER:
651 fDhcpDiscover = 1;
652 /**/
653 case DHCPINFORM:
654 rc = dhcp_decode_discover(pData, bp, buf, size, fDhcpDiscover, m);
655 if (rc > 0)
656 goto reply;
657 break;
658
659 case DHCPREQUEST:
660 rc = dhcp_decode_request(pData, bp, buf, size, m);
661 if (rc > 0)
662 goto reply;
663 break;
664
665 case DHCPRELEASE:
666 rc = dhcp_decode_release(pData, bp, buf, size);
667 /* no reply required */
668 break;
669
670 case DHCPDECLINE:
671 p = dhcp_find_option(&bp->bp_vend[0], RFC2132_REQ_ADDR);
672 req_ip.s_addr = *(uint32_t *)(p + 2);
673 rc = bootp_cache_lookup_ether_by_ip(pData, req_ip.s_addr, NULL);
674 if (RT_FAILURE(rc))
675 {
676 /* Not registered */
677 BOOTPClient *bc;
678 bc = bc_alloc_client(pData);
679 Assert(bc);
680 bc->addr.s_addr = req_ip.s_addr;
681 slirp_arp_who_has(pData, bc->addr.s_addr);
682 LogRel(("NAT: %R[IP4] has been already registered\n", &req_ip));
683 }
684 /* no response required */
685 break;
686
687 default:
688 AssertMsgFailed(("unsupported DHCP message type"));
689 }
690 Assert(m);
691 /*silently ignore*/
692 m_free(pData, m);
693 return;
694
695reply:
696 bootp_reply(pData, m, rc, bp->bp_flags);
697 return;
698}
699
700static void bootp_reply(PNATState pData, struct mbuf *m, int offReply, uint16_t flags)
701{
702 struct sockaddr_in saddr, daddr;
703 struct bootp_t *rbp = NULL;
704 uint8_t *q = NULL;
705 int nack;
706 rbp = mtod(m, struct bootp_t *);
707 Assert((m));
708 Assert((rbp));
709 q = rbp->bp_vend;
710 nack = (q[6] == DHCPNAK);
711 q += offReply;
712
713#ifndef VBOX_WITH_NAT_SERVICE
714 saddr.sin_addr.s_addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_ALIAS);
715#else
716 saddr.sin_addr.s_addr = pData->special_addr.s_addr;
717#endif
718
719 FILL_BOOTP_EXT(q, RFC2132_SRV_ID, 4, &saddr.sin_addr);
720
721 *q++ = RFC1533_END; /* end of message */
722
723#ifdef VBOX_WITH_SLIRP_BSD_MBUF
724 m->m_pkthdr.header = mtod(m, void *);
725#endif
726 m->m_len = sizeof(struct bootp_t)
727 - sizeof(struct ip)
728 - sizeof(struct udphdr);
729 m->m_data += sizeof(struct udphdr)
730 + sizeof(struct ip);
731 if ( (flags & RT_H2N_U16_C(DHCP_FLAGS_B))
732 || nack != 0)
733 daddr.sin_addr.s_addr = INADDR_BROADCAST;
734 else
735 daddr.sin_addr.s_addr = rbp->bp_yiaddr.s_addr; /*unicast requested by client*/
736 saddr.sin_port = RT_H2N_U16_C(BOOTP_SERVER);
737 daddr.sin_port = RT_H2N_U16_C(BOOTP_CLIENT);
738 udp_output2(pData, NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
739}
740
741void bootp_input(PNATState pData, struct mbuf *m)
742{
743 struct bootp_t *bp = mtod(m, struct bootp_t *);
744
745 if (bp->bp_op == BOOTP_REQUEST)
746 dhcp_decode(pData, bp, bp->bp_vend, DHCP_OPT_LEN);
747}
748
749int bootp_cache_lookup_ip_by_ether(PNATState pData,const uint8_t* ether, uint32_t *pip)
750{
751 int i;
752
753 if (!ether || !pip)
754 return VERR_INVALID_PARAMETER;
755
756 for (i = 0; i < NB_ADDR; i++)
757 {
758 if ( bootp_clients[i].allocated
759 && memcmp(bootp_clients[i].macaddr, ether, ETH_ALEN) == 0)
760 {
761 *pip = bootp_clients[i].addr.s_addr;
762 return VINF_SUCCESS;
763 }
764 }
765
766 *pip = INADDR_ANY;
767 return VERR_NOT_FOUND;
768}
769
770int bootp_cache_lookup_ether_by_ip(PNATState pData, uint32_t ip, uint8_t *ether)
771{
772 int i;
773 for (i = 0; i < NB_ADDR; i++)
774 {
775 if ( bootp_clients[i].allocated
776 && ip == bootp_clients[i].addr.s_addr)
777 {
778 if (ether != NULL)
779 memcpy(ether, bootp_clients[i].macaddr, ETH_ALEN);
780 return VINF_SUCCESS;
781 }
782 }
783
784 return VERR_NOT_FOUND;
785}
786
787/*
788 * Initialize dhcp server
789 * @returns 0 - if initialization is ok, non-zero otherwise
790 */
791int bootp_dhcp_init(PNATState pData)
792{
793 pData->pbootp_clients = RTMemAllocZ(sizeof(BOOTPClient) * NB_ADDR);
794 if (!pData->pbootp_clients)
795 return VERR_NO_MEMORY;
796
797 return VINF_SUCCESS;
798}
799
800int bootp_dhcp_fini(PNATState pData)
801{
802 if (pData->pbootp_clients != NULL)
803 RTMemFree(pData->pbootp_clients);
804
805 return VINF_SUCCESS;
806}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette