VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxTAP/dhcp.c@ 14647

Last change on this file since 14647 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.6 KB
Line 
1/*
2 * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
3 * on Windows. Originally derived from the CIPE-Win32
4 * project by Damion K. Wilson, with extensive modifications by
5 * James Yonan.
6 *
7 * All source code which derives from the CIPE-Win32 project is
8 * Copyright (C) Damion K. Wilson, 2003, and is released under the
9 * GPL version 2 (see below).
10 *
11 * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
12 * and is released under the GPL version 2 (see below).
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2
16 * as published by the Free Software Foundation.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program (see the file COPYING included with this
25 * distribution); if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 */
28
29//=========================
30// Code to set DHCP options
31//=========================
32
33VOID
34SetDHCPOpt (DHCPMsg *m, void *data, unsigned int len)
35{
36 if (!m->overflow)
37 {
38 if (m->optlen + len <= DHCP_OPTIONS_BUFFER_SIZE)
39 {
40 if (len)
41 {
42 NdisMoveMemory (m->msg.options + m->optlen, data, len);
43 m->optlen += len;
44 }
45 }
46 else
47 {
48 m->overflow = TRUE;
49 }
50 }
51}
52
53VOID
54SetDHCPOpt0 (DHCPMsg *msg, int type)
55{
56 DHCPOPT0 opt;
57 opt.type = (UCHAR) type;
58 SetDHCPOpt (msg, &opt, sizeof (opt));
59}
60
61VOID
62SetDHCPOpt8 (DHCPMsg *msg, int type, ULONG data)
63{
64 DHCPOPT8 opt;
65 opt.type = (UCHAR) type;
66 opt.len = sizeof (opt.data);
67 opt.data = (UCHAR) data;
68 SetDHCPOpt (msg, &opt, sizeof (opt));
69}
70
71VOID
72SetDHCPOpt32 (DHCPMsg *msg, int type, ULONG data)
73{
74 DHCPOPT32 opt;
75 opt.type = (UCHAR) type;
76 opt.len = sizeof (opt.data);
77 opt.data = data;
78 SetDHCPOpt (msg, &opt, sizeof (opt));
79}
80
81//==============
82// Checksum code
83//==============
84
85USHORT
86ip_checksum (const UCHAR *buf, const int len_ip_header)
87{
88 USHORT word16;
89 ULONG sum = 0;
90 int i;
91
92 // make 16 bit words out of every two adjacent 8 bit words in the packet
93 // and add them up
94 for (i = 0; i < len_ip_header - 1; i += 2) {
95 word16 = ((buf[i] << 8) & 0xFF00) + (buf[i+1] & 0xFF);
96 sum += (ULONG) word16;
97 }
98
99 // take only 16 bits out of the 32 bit sum and add up the carries
100 while (sum >> 16)
101 sum = (sum & 0xFFFF) + (sum >> 16);
102
103 // one's complement the result
104 return ((USHORT) ~sum);
105}
106
107USHORT
108udp_checksum (const UCHAR *buf,
109 const int len_udp,
110 const UCHAR *src_addr,
111 const UCHAR *dest_addr)
112{
113 USHORT word16;
114 ULONG sum = 0;
115 int i;
116
117 // make 16 bit words out of every two adjacent 8 bit words and
118 // calculate the sum of all 16 bit words
119 for (i = 0; i < len_udp; i += 2){
120 word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_udp) ? (buf[i+1] & 0xFF) : 0);
121 sum += word16;
122 }
123
124 // add the UDP pseudo header which contains the IP source and destination addresses
125 for (i = 0; i < 4; i += 2){
126 word16 =((src_addr[i] << 8) & 0xFF00) + (src_addr[i+1] & 0xFF);
127 sum += word16;
128 }
129 for (i = 0; i < 4; i += 2){
130 word16 =((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i+1] & 0xFF);
131 sum += word16;
132 }
133
134 // the protocol number and the length of the UDP packet
135 sum += (USHORT) IPPROTO_UDP + (USHORT) len_udp;
136
137 // keep only the last 16 bits of the 32 bit calculated sum and add the carries
138 while (sum >> 16)
139 sum = (sum & 0xFFFF) + (sum >> 16);
140
141 // Take the one's complement of sum
142 return ((USHORT) ~sum);
143}
144
145//================================
146// Set IP and UDP packet checksums
147//================================
148
149VOID
150SetChecksumDHCPMsg (DHCPMsg *m)
151{
152 // Set IP checksum
153 m->msg.pre.ip.check = htons (ip_checksum ((UCHAR *) &m->msg.pre.ip, sizeof (IPHDR)));
154
155 // Set UDP Checksum
156 m->msg.pre.udp.check = htons (udp_checksum ((UCHAR *) &m->msg.pre.udp,
157 sizeof (UDPHDR) + sizeof (DHCP) + m->optlen,
158 (UCHAR *)&m->msg.pre.ip.saddr,
159 (UCHAR *)&m->msg.pre.ip.daddr));
160}
161
162//===================
163// DHCP message tests
164//===================
165
166int
167GetDHCPMessageType (const DHCP *dhcp, const int optlen)
168{
169 const UCHAR *p = (UCHAR *) (dhcp + 1);
170 int i;
171
172 for (i = 0; i < optlen; ++i)
173 {
174 const UCHAR type = p[i];
175 const int room = optlen - i - 1;
176 if (type == DHCP_END) // didn't find what we were looking for
177 return -1;
178 else if (type == DHCP_PAD) // no-operation
179 ;
180 else if (type == DHCP_MSG_TYPE) // what we are looking for
181 {
182 if (room >= 2)
183 {
184 if (p[i+1] == 1) // message length should be 1
185 return p[i+2]; // return message type
186 }
187 return -1;
188 }
189 else // some other message
190 {
191 if (room >= 1)
192 {
193 const int len = p[i+1]; // get message length
194 i += (len + 1); // advance to next message
195 }
196 }
197 }
198 return -1;
199}
200
201BOOLEAN
202DHCPMessageOurs (const TapAdapterPointer p_Adapter,
203 const ETH_HEADER *eth,
204 const IPHDR *ip,
205 const UDPHDR *udp,
206 const DHCP *dhcp)
207{
208 // Must be UDPv4 protocol
209 if (!(eth->proto == htons (ETH_P_IP) && ip->protocol == IPPROTO_UDP))
210 return FALSE;
211
212 // Source MAC must be our adapter
213 if (!MAC_EQUAL (eth->src, p_Adapter->m_MAC))
214 return FALSE;
215
216 // Dest MAC must be either broadcast or our virtual DHCP server
217 if (!(MAC_EQUAL (eth->dest, p_Adapter->m_MAC_Broadcast)
218 || MAC_EQUAL (eth->dest, p_Adapter->m_dhcp_server_mac)))
219 return FALSE;
220
221 // Port numbers must be correct
222 if (!(udp->dest == htons (BOOTPS_PORT)
223 && udp->source == htons (BOOTPC_PORT)))
224 return FALSE;
225
226 // Hardware address must be MAC addr sized
227 if (!(dhcp->hlen == sizeof (MACADDR)))
228 return FALSE;
229
230 // Hardware address must match our adapter
231 if (!MAC_EQUAL (eth->src, dhcp->chaddr))
232 return FALSE;
233
234 return TRUE;
235}
236
237
238//=====================================================
239// Build all of DHCP packet except for DHCP options.
240// Assume that *p has been zeroed before we are called.
241//=====================================================
242
243VOID
244BuildDHCPPre (const TapAdapterPointer a,
245 DHCPPre *p,
246 const ETH_HEADER *eth,
247 const IPHDR *ip,
248 const UDPHDR *udp,
249 const DHCP *dhcp,
250 const int optlen,
251 const int type)
252{
253 // Should we broadcast or direct to a specific MAC / IP address?
254 const BOOLEAN broadcast = (type == DHCPNAK
255 || MAC_EQUAL (eth->dest, a->m_MAC_Broadcast));
256 // Build ethernet header
257
258 COPY_MAC (p->eth.src, a->m_dhcp_server_mac);
259
260 if (broadcast)
261 COPY_MAC (p->eth.dest, a->m_MAC_Broadcast);
262 else
263 COPY_MAC (p->eth.dest, eth->src);
264
265 p->eth.proto = htons (ETH_P_IP);
266
267 // Build IP header
268
269 p->ip.version_len = (4 << 4) | (sizeof (IPHDR) >> 2);
270 p->ip.tos = 0;
271 p->ip.tot_len = htons (sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + optlen);
272 p->ip.id = 0;
273 p->ip.frag_off = 0;
274 p->ip.ttl = 16;
275 p->ip.protocol = IPPROTO_UDP;
276 p->ip.check = 0;
277 p->ip.saddr = a->m_dhcp_server_ip;
278
279 if (broadcast)
280 p->ip.daddr = ~0;
281 else
282 p->ip.daddr = a->m_dhcp_addr;
283
284 // Build UDP header
285
286 p->udp.source = htons (BOOTPS_PORT);
287 p->udp.dest = htons (BOOTPC_PORT);
288 p->udp.len = htons (sizeof (UDPHDR) + sizeof (DHCP) + optlen);
289 p->udp.check = 0;
290
291 // Build DHCP response
292
293 p->dhcp.op = BOOTREPLY;
294 p->dhcp.htype = 1;
295 p->dhcp.hlen = sizeof (MACADDR);
296 p->dhcp.hops = 0;
297 p->dhcp.xid = dhcp->xid;
298 p->dhcp.secs = 0;
299 p->dhcp.flags = 0;
300 p->dhcp.ciaddr = 0;
301
302 if (type == DHCPNAK)
303 p->dhcp.yiaddr = 0;
304 else
305 p->dhcp.yiaddr = a->m_dhcp_addr;
306
307 p->dhcp.siaddr = a->m_dhcp_server_ip;
308 p->dhcp.giaddr = 0;
309 COPY_MAC (p->dhcp.chaddr, eth->src);
310 p->dhcp.magic = htonl (0x63825363);
311}
312//=============================
313// Build specific DHCP messages
314//=============================
315
316VOID
317SendDHCPMsg (const TapAdapterPointer a,
318 const int type,
319 const ETH_HEADER *eth,
320 const IPHDR *ip,
321 const UDPHDR *udp,
322 const DHCP *dhcp)
323{
324 DHCPMsg *pkt;
325
326 if (!(type == DHCPOFFER || type == DHCPACK || type == DHCPNAK))
327 {
328 DEBUGP (("[TAP] SendDHCPMsg: Bad DHCP type: %d\n", type));
329 return;
330 }
331
332 pkt = (DHCPMsg *) MemAlloc (sizeof (DHCPMsg), TRUE);
333
334 if (pkt)
335 {
336 //-----------------------
337 // Build DHCP options
338 //-----------------------
339
340 // Message Type
341 SetDHCPOpt8 (pkt, DHCP_MSG_TYPE, type);
342
343 // Server ID
344 SetDHCPOpt32 (pkt, DHCP_SERVER_ID, a->m_dhcp_server_ip);
345
346 if (type == DHCPOFFER || type == DHCPACK)
347 {
348 // Lease Time
349 SetDHCPOpt32 (pkt, DHCP_LEASE_TIME, htonl (a->m_dhcp_lease_time));
350
351 // Netmask
352 SetDHCPOpt32 (pkt, DHCP_NETMASK, a->m_dhcp_netmask);
353
354 // Other user-defined options
355 SetDHCPOpt (pkt,
356 a->m_dhcp_user_supplied_options_buffer,
357 a->m_dhcp_user_supplied_options_buffer_len);
358 }
359
360 // End
361 SetDHCPOpt0 (pkt, DHCP_END);
362
363 if (!DHCPMSG_OVERFLOW (pkt))
364 {
365 // The initial part of the DHCP message (not including options) gets built here
366 BuildDHCPPre (a,
367 &pkt->msg.pre,
368 eth,
369 ip,
370 udp,
371 dhcp,
372 DHCPMSG_LEN_OPT (pkt),
373 type);
374
375 SetChecksumDHCPMsg (pkt);
376
377 DUMP_PACKET ("DHCPMsg",
378 DHCPMSG_BUF (pkt),
379 DHCPMSG_LEN_FULL (pkt));
380
381 // Return DHCP response to kernel
382 InjectPacket (a,
383 DHCPMSG_BUF (pkt),
384 DHCPMSG_LEN_FULL (pkt));
385 }
386 else
387 {
388 DEBUGP (("[TAP] SendDHCPMsg: DHCP buffer overflow\n"));
389 }
390
391 MemFree (pkt, sizeof (DHCPMsg));
392 }
393}
394
395//===================================================================
396// Handle a BOOTPS packet produced by the local system to
397// resolve the address/netmask of this adapter.
398// If we are in TAP_IOCTL_CONFIG_DHCP_MASQ mode, reply
399// to the message. Return TRUE if we processed the passed
400// message, so that downstream stages can ignore it.
401//===================================================================
402
403BOOLEAN
404ProcessDHCP (TapAdapterPointer p_Adapter,
405 const ETH_HEADER *eth,
406 const IPHDR *ip,
407 const UDPHDR *udp,
408 const DHCP *dhcp,
409 int optlen)
410{
411 int msg_type;
412
413 // Sanity check IP header
414 if (!(ntohs (ip->tot_len) == sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + optlen
415 && (ntohs (ip->frag_off) & IP_OFFMASK) == 0))
416 return TRUE;
417
418 // Does this message belong to us?
419 if (!DHCPMessageOurs (p_Adapter, eth, ip, udp, dhcp))
420 return FALSE;
421
422 msg_type = GetDHCPMessageType (dhcp, optlen);
423
424 // Drop non-BOOTREQUEST messages
425 if (dhcp->op != BOOTREQUEST)
426 return TRUE;
427
428 // Drop any messages except DHCPDISCOVER or DHCPREQUEST
429 if (!(msg_type == DHCPDISCOVER || msg_type == DHCPREQUEST))
430 return TRUE;
431
432 // Should we reply with DHCPOFFER, DHCPACK, or DHCPNAK?
433 if (msg_type == DHCPREQUEST
434 && ((dhcp->ciaddr && dhcp->ciaddr != p_Adapter->m_dhcp_addr)
435 || !p_Adapter->m_dhcp_received_discover
436 || p_Adapter->m_dhcp_bad_requests >= BAD_DHCPREQUEST_NAK_THRESHOLD))
437 SendDHCPMsg (p_Adapter,
438 DHCPNAK,
439 eth, ip, udp, dhcp);
440 else
441 SendDHCPMsg (p_Adapter,
442 (msg_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK),
443 eth, ip, udp, dhcp);
444
445 // Remember if we received a DHCPDISCOVER
446 if (msg_type == DHCPDISCOVER)
447 p_Adapter->m_dhcp_received_discover = TRUE;
448
449 // Is this a bad DHCPREQUEST?
450 if (msg_type == DHCPREQUEST && dhcp->ciaddr != p_Adapter->m_dhcp_addr)
451 ++p_Adapter->m_dhcp_bad_requests;
452
453 return TRUE;
454}
455
456#if DBG
457
458const char *
459message_op_text (int op)
460{
461 switch (op)
462 {
463 case BOOTREQUEST:
464 return "BOOTREQUEST";
465 case BOOTREPLY:
466 return "BOOTREPLY";
467 default:
468 return "???";
469 }
470}
471
472const char *
473message_type_text (int type)
474{
475 switch (type)
476 {
477 case DHCPDISCOVER:
478 return "DHCPDISCOVER";
479 case DHCPOFFER:
480 return "DHCPOFFER";
481 case DHCPREQUEST:
482 return "DHCPREQUEST";
483 case DHCPDECLINE:
484 return "DHCPDECLINE";
485 case DHCPACK:
486 return "DHCPACK";
487 case DHCPNAK:
488 return "DHCPNAK";
489 case DHCPRELEASE:
490 return "DHCPRELEASE";
491 case DHCPINFORM:
492 return "DHCPINFORM";
493 default:
494 return "???";
495 }
496}
497
498const char *
499port_name (int port)
500{
501 switch (port)
502 {
503 case BOOTPS_PORT:
504 return "BOOTPS";
505 case BOOTPC_PORT:
506 return "BOOTPC";
507 default:
508 return "unknown";
509 }
510}
511
512VOID
513DumpDHCP (const ETH_HEADER *eth,
514 const IPHDR *ip,
515 const UDPHDR *udp,
516 const DHCP *dhcp,
517 const int optlen)
518{
519 DEBUGP ((" %s", message_op_text (dhcp->op)));
520 DEBUGP ((" %s ", message_type_text (GetDHCPMessageType (dhcp, optlen))));
521 PrIP (ip->saddr);
522 DEBUGP ((":%s[", port_name (ntohs (udp->source))));
523 PrMac (eth->src);
524 DEBUGP (("] -> "));
525 PrIP (ip->daddr);
526 DEBUGP ((":%s[", port_name (ntohs (udp->dest))));
527 PrMac (eth->dest);
528 DEBUGP (("]"));
529 if (dhcp->ciaddr)
530 {
531 DEBUGP ((" ci="));
532 PrIP (dhcp->ciaddr);
533 }
534 if (dhcp->yiaddr)
535 {
536 DEBUGP ((" yi="));
537 PrIP (dhcp->yiaddr);
538 }
539 if (dhcp->siaddr)
540 {
541 DEBUGP ((" si="));
542 PrIP (dhcp->siaddr);
543 }
544 if (dhcp->hlen == sizeof (MACADDR))
545 {
546 DEBUGP ((" ch="));
547 PrMac (dhcp->chaddr);
548 }
549
550 DEBUGP ((" xid=0x%08x", ntohl (dhcp->xid)));
551
552 if (ntohl (dhcp->magic) != 0x63825363)
553 DEBUGP ((" ma=0x%08x", ntohl (dhcp->magic)));
554 if (dhcp->htype != 1)
555 DEBUGP ((" htype=%d", dhcp->htype));
556 if (dhcp->hops)
557 DEBUGP ((" hops=%d", dhcp->hops));
558 if (ntohs (dhcp->secs))
559 DEBUGP ((" secs=%d", ntohs (dhcp->secs)));
560 if (ntohs (dhcp->flags))
561 DEBUGP ((" flags=0x%04x", ntohs (dhcp->flags)));
562
563 // extra stuff
564
565 if (ip->version_len != 0x45)
566 DEBUGP ((" vl=0x%02x", ip->version_len));
567 if (ntohs (ip->tot_len) != sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + optlen)
568 DEBUGP ((" tl=%d", ntohs (ip->tot_len)));
569 if (ntohs (udp->len) != sizeof (UDPHDR) + sizeof (DHCP) + optlen)
570 DEBUGP ((" ul=%d", ntohs (udp->len)));
571
572 if (ip->tos)
573 DEBUGP ((" tos=0x%02x", ip->tos));
574 if (ntohs (ip->id))
575 DEBUGP ((" id=0x%04x", ntohs (ip->id)));
576 if (ntohs (ip->frag_off))
577 DEBUGP ((" frag_off=0x%04x", ntohs (ip->frag_off)));
578
579 DEBUGP ((" ttl=%d", ip->ttl));
580 DEBUGP ((" ic=0x%04x [0x%04x]", ntohs (ip->check),
581 ip_checksum ((UCHAR*)ip, sizeof (IPHDR))));
582 DEBUGP ((" uc=0x%04x [0x%04x/%d]", ntohs (udp->check),
583 udp_checksum ((UCHAR *) udp,
584 sizeof (UDPHDR) + sizeof (DHCP) + optlen,
585 (UCHAR *) &ip->saddr,
586 (UCHAR *) &ip->daddr),
587 optlen));
588
589 // Options
590 {
591 const UCHAR *opt = (UCHAR *) (dhcp + 1);
592 int i;
593
594 DEBUGP ((" OPT"));
595 for (i = 0; i < optlen; ++i)
596 {
597 const UCHAR data = opt[i];
598 DEBUGP ((".%d", data));
599 }
600 }
601}
602
603#endif /* DEBUG */
Note: See TracBrowser for help on using the repository browser.

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