VirtualBox

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

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

NAT: DHCPRELEASE implementation.

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

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