From 1ebe2ad920bce1f9ea85c56fce469674b83c650c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 24 Apr 2015 23:31:51 -0700 Subject: NDIS6 driver with VS project to build -- builds correctly, not customized for ZT yet. --- windows/TapDriver6/dhcp.c | 710 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 710 insertions(+) create mode 100644 windows/TapDriver6/dhcp.c (limited to 'windows/TapDriver6/dhcp.c') diff --git a/windows/TapDriver6/dhcp.c b/windows/TapDriver6/dhcp.c new file mode 100644 index 00000000..30b22f4f --- /dev/null +++ b/windows/TapDriver6/dhcp.c @@ -0,0 +1,710 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "tap.h" + +//========================= +// Code to set DHCP options +//========================= + +VOID +SetDHCPOpt( + __in DHCPMsg *m, + __in void *data, + __in unsigned int len + ) +{ + if (!m->overflow) + { + if (m->optlen + len <= DHCP_OPTIONS_BUFFER_SIZE) + { + if (len) + { + NdisMoveMemory (m->msg.options + m->optlen, data, len); + m->optlen += len; + } + } + else + { + m->overflow = TRUE; + } + } +} + +VOID +SetDHCPOpt0( + __in DHCPMsg *msg, + __in int type + ) +{ + DHCPOPT0 opt; + opt.type = (UCHAR) type; + SetDHCPOpt (msg, &opt, sizeof (opt)); +} + +VOID +SetDHCPOpt8( + __in DHCPMsg *msg, + __in int type, + __in ULONG data + ) +{ + DHCPOPT8 opt; + opt.type = (UCHAR) type; + opt.len = sizeof (opt.data); + opt.data = (UCHAR) data; + SetDHCPOpt (msg, &opt, sizeof (opt)); +} + +VOID +SetDHCPOpt32( + __in DHCPMsg *msg, + __in int type, + __in ULONG data + ) +{ + DHCPOPT32 opt; + opt.type = (UCHAR) type; + opt.len = sizeof (opt.data); + opt.data = data; + SetDHCPOpt (msg, &opt, sizeof (opt)); +} + +//============== +// Checksum code +//============== + +USHORT +ip_checksum( + __in const UCHAR *buf, + __in const int len_ip_header + ) +{ + USHORT word16; + ULONG sum = 0; + int i; + + // make 16 bit words out of every two adjacent 8 bit words in the packet + // and add them up + for (i = 0; i < len_ip_header - 1; i += 2) + { + word16 = ((buf[i] << 8) & 0xFF00) + (buf[i+1] & 0xFF); + sum += (ULONG) word16; + } + + // take only 16 bits out of the 32 bit sum and add up the carries + while (sum >> 16) + { + sum = (sum & 0xFFFF) + (sum >> 16); + } + + // one's complement the result + return ((USHORT) ~sum); +} + +USHORT +udp_checksum ( + __in const UCHAR *buf, + __in const int len_udp, + __in const UCHAR *src_addr, + __in const UCHAR *dest_addr + ) +{ + USHORT word16; + ULONG sum = 0; + int i; + + // make 16 bit words out of every two adjacent 8 bit words and + // calculate the sum of all 16 bit words + for (i = 0; i < len_udp; i += 2) + { + word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_udp) ? (buf[i+1] & 0xFF) : 0); + sum += word16; + } + + // add the UDP pseudo header which contains the IP source and destination addresses + for (i = 0; i < 4; i += 2) + { + word16 =((src_addr[i] << 8) & 0xFF00) + (src_addr[i+1] & 0xFF); + sum += word16; + } + + for (i = 0; i < 4; i += 2) + { + word16 =((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i+1] & 0xFF); + sum += word16; + } + + // the protocol number and the length of the UDP packet + sum += (USHORT) IPPROTO_UDP + (USHORT) len_udp; + + // keep only the last 16 bits of the 32 bit calculated sum and add the carries + while (sum >> 16) + { + sum = (sum & 0xFFFF) + (sum >> 16); + } + + // Take the one's complement of sum + return ((USHORT) ~sum); +} + +//================================ +// Set IP and UDP packet checksums +//================================ + +VOID +SetChecksumDHCPMsg( + __in DHCPMsg *m + ) +{ + // Set IP checksum + m->msg.pre.ip.check = htons (ip_checksum ((UCHAR *) &m->msg.pre.ip, sizeof (IPHDR))); + + // Set UDP Checksum + m->msg.pre.udp.check = htons (udp_checksum ((UCHAR *) &m->msg.pre.udp, + sizeof (UDPHDR) + sizeof (DHCP) + m->optlen, + (UCHAR *)&m->msg.pre.ip.saddr, + (UCHAR *)&m->msg.pre.ip.daddr)); +} + +//=================== +// DHCP message tests +//=================== + +int +GetDHCPMessageType( + __in const DHCP *dhcp, + __in const int optlen + ) +{ + const UCHAR *p = (UCHAR *) (dhcp + 1); + int i; + + for (i = 0; i < optlen; ++i) + { + const UCHAR type = p[i]; + const int room = optlen - i - 1; + + if (type == DHCP_END) // didn't find what we were looking for + return -1; + else if (type == DHCP_PAD) // no-operation + ; + else if (type == DHCP_MSG_TYPE) // what we are looking for + { + if (room >= 2) + { + if (p[i+1] == 1) // message length should be 1 + return p[i+2]; // return message type + } + return -1; + } + else // some other message + { + if (room >= 1) + { + const int len = p[i+1]; // get message length + i += (len + 1); // advance to next message + } + } + } + return -1; +} + +BOOLEAN +DHCPMessageOurs ( + __in const PTAP_ADAPTER_CONTEXT Adapter, + __in const ETH_HEADER *eth, + __in const IPHDR *ip, + __in const UDPHDR *udp, + __in const DHCP *dhcp + ) +{ + // Must be UDPv4 protocol + if (!(eth->proto == htons (NDIS_ETH_TYPE_IPV4) && ip->protocol == IPPROTO_UDP)) + { + return FALSE; + } + + // Source MAC must be our adapter + if (!MAC_EQUAL (eth->src, Adapter->CurrentAddress)) + { + return FALSE; + } + + // Dest MAC must be either broadcast or our virtual DHCP server + if (!(ETH_IS_BROADCAST(eth->dest) + || MAC_EQUAL (eth->dest, Adapter->m_dhcp_server_mac))) + { + return FALSE; + } + + // Port numbers must be correct + if (!(udp->dest == htons (BOOTPS_PORT) + && udp->source == htons (BOOTPC_PORT))) + { + return FALSE; + } + + // Hardware address must be MAC addr sized + if (!(dhcp->hlen == sizeof (MACADDR))) + { + return FALSE; + } + + // Hardware address must match our adapter + if (!MAC_EQUAL (eth->src, dhcp->chaddr)) + { + return FALSE; + } + + return TRUE; +} + + +//===================================================== +// Build all of DHCP packet except for DHCP options. +// Assume that *p has been zeroed before we are called. +//===================================================== + +VOID +BuildDHCPPre ( + __in const PTAP_ADAPTER_CONTEXT Adapter, + __inout DHCPPre *p, + __in const ETH_HEADER *eth, + __in const IPHDR *ip, + __in const UDPHDR *udp, + __in const DHCP *dhcp, + __in const int optlen, + __in const int type) +{ + // Should we broadcast or direct to a specific MAC / IP address? + const BOOLEAN broadcast = (type == DHCPNAK + || ETH_IS_BROADCAST(eth->dest)); + + // + // Build ethernet header + // + ETH_COPY_NETWORK_ADDRESS (p->eth.src, Adapter->m_dhcp_server_mac); + + if (broadcast) + { + memset(p->eth.dest,0xFF,ETH_LENGTH_OF_ADDRESS); + } + else + { + ETH_COPY_NETWORK_ADDRESS (p->eth.dest, eth->src); + } + + p->eth.proto = htons (NDIS_ETH_TYPE_IPV4); + + // + // Build IP header + // + p->ip.version_len = (4 << 4) | (sizeof (IPHDR) >> 2); + p->ip.tos = 0; + p->ip.tot_len = htons (sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + optlen); + p->ip.id = 0; + p->ip.frag_off = 0; + p->ip.ttl = 16; + p->ip.protocol = IPPROTO_UDP; + p->ip.check = 0; + p->ip.saddr = Adapter->m_dhcp_server_ip; + + if (broadcast) + { + p->ip.daddr = ~0; + } + else + { + p->ip.daddr = Adapter->m_dhcp_addr; + } + + // + // Build UDP header + // + p->udp.source = htons (BOOTPS_PORT); + p->udp.dest = htons (BOOTPC_PORT); + p->udp.len = htons (sizeof (UDPHDR) + sizeof (DHCP) + optlen); + p->udp.check = 0; + + // Build DHCP response + + p->dhcp.op = BOOTREPLY; + p->dhcp.htype = 1; + p->dhcp.hlen = sizeof (MACADDR); + p->dhcp.hops = 0; + p->dhcp.xid = dhcp->xid; + p->dhcp.secs = 0; + p->dhcp.flags = 0; + p->dhcp.ciaddr = 0; + + if (type == DHCPNAK) + { + p->dhcp.yiaddr = 0; + } + else + { + p->dhcp.yiaddr = Adapter->m_dhcp_addr; + } + + p->dhcp.siaddr = Adapter->m_dhcp_server_ip; + p->dhcp.giaddr = 0; + ETH_COPY_NETWORK_ADDRESS (p->dhcp.chaddr, eth->src); + p->dhcp.magic = htonl (0x63825363); +} + +//============================= +// Build specific DHCP messages +//============================= + +VOID +SendDHCPMsg( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in const int type, + __in const ETH_HEADER *eth, + __in const IPHDR *ip, + __in const UDPHDR *udp, + __in const DHCP *dhcp + ) +{ + DHCPMsg *pkt; + + if (!(type == DHCPOFFER || type == DHCPACK || type == DHCPNAK)) + { + DEBUGP (("[TAP] SendDHCPMsg: Bad DHCP type: %d\n", type)); + return; + } + + pkt = (DHCPMsg *) MemAlloc (sizeof (DHCPMsg), TRUE); + + if(pkt) + { + //----------------------- + // Build DHCP options + //----------------------- + + // Message Type + SetDHCPOpt8 (pkt, DHCP_MSG_TYPE, type); + + // Server ID + SetDHCPOpt32 (pkt, DHCP_SERVER_ID, Adapter->m_dhcp_server_ip); + + if (type == DHCPOFFER || type == DHCPACK) + { + // Lease Time + SetDHCPOpt32 (pkt, DHCP_LEASE_TIME, htonl (Adapter->m_dhcp_lease_time)); + + // Netmask + SetDHCPOpt32 (pkt, DHCP_NETMASK, Adapter->m_dhcp_netmask); + + // Other user-defined options + SetDHCPOpt ( + pkt, + Adapter->m_dhcp_user_supplied_options_buffer, + Adapter->m_dhcp_user_supplied_options_buffer_len); + } + + // End + SetDHCPOpt0 (pkt, DHCP_END); + + if (!DHCPMSG_OVERFLOW (pkt)) + { + // The initial part of the DHCP message (not including options) gets built here + BuildDHCPPre ( + Adapter, + &pkt->msg.pre, + eth, + ip, + udp, + dhcp, + DHCPMSG_LEN_OPT (pkt), + type); + + SetChecksumDHCPMsg (pkt); + + DUMP_PACKET ("DHCPMsg", + DHCPMSG_BUF (pkt), + DHCPMSG_LEN_FULL (pkt)); + + // Return DHCP response to kernel + IndicateReceivePacket( + Adapter, + DHCPMSG_BUF (pkt), + DHCPMSG_LEN_FULL (pkt) + ); + } + else + { + DEBUGP (("[TAP] SendDHCPMsg: DHCP buffer overflow\n")); + } + + MemFree (pkt, sizeof (DHCPMsg)); + } +} + +//=================================================================== +// Handle a BOOTPS packet produced by the local system to +// resolve the address/netmask of this adapter. +// If we are in TAP_WIN_IOCTL_CONFIG_DHCP_MASQ mode, reply +// to the message. Return TRUE if we processed the passed +// message, so that downstream stages can ignore it. +//=================================================================== + +BOOLEAN +ProcessDHCP( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in const ETH_HEADER *eth, + __in const IPHDR *ip, + __in const UDPHDR *udp, + __in const DHCP *dhcp, + __in int optlen + ) +{ + int msg_type; + + // Sanity check IP header + if (!(ntohs (ip->tot_len) == sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + optlen + && (ntohs (ip->frag_off) & IP_OFFMASK) == 0)) + { + return TRUE; + } + + // Does this message belong to us? + if (!DHCPMessageOurs (Adapter, eth, ip, udp, dhcp)) + { + return FALSE; + } + + msg_type = GetDHCPMessageType (dhcp, optlen); + + // Drop non-BOOTREQUEST messages + if (dhcp->op != BOOTREQUEST) + { + return TRUE; + } + + // Drop any messages except DHCPDISCOVER or DHCPREQUEST + if (!(msg_type == DHCPDISCOVER || msg_type == DHCPREQUEST)) + { + return TRUE; + } + + // Should we reply with DHCPOFFER, DHCPACK, or DHCPNAK? + if (msg_type == DHCPREQUEST + && ((dhcp->ciaddr && dhcp->ciaddr != Adapter->m_dhcp_addr) + || !Adapter->m_dhcp_received_discover + || Adapter->m_dhcp_bad_requests >= BAD_DHCPREQUEST_NAK_THRESHOLD)) + { + SendDHCPMsg( + Adapter, + DHCPNAK, + eth, ip, udp, dhcp + ); + } + else + { + SendDHCPMsg( + Adapter, + (msg_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK), + eth, ip, udp, dhcp + ); + } + + // Remember if we received a DHCPDISCOVER + if (msg_type == DHCPDISCOVER) + { + Adapter->m_dhcp_received_discover = TRUE; + } + + // Is this a bad DHCPREQUEST? + if (msg_type == DHCPREQUEST && dhcp->ciaddr && dhcp->ciaddr != Adapter->m_dhcp_addr) + { + ++Adapter->m_dhcp_bad_requests; + } + + return TRUE; +} + +#if DBG + +const char * + message_op_text (int op) +{ + switch (op) + { + case BOOTREQUEST: + return "BOOTREQUEST"; + + case BOOTREPLY: + return "BOOTREPLY"; + + default: + return "???"; + } +} + +const char * + message_type_text (int type) +{ + switch (type) + { + case DHCPDISCOVER: + return "DHCPDISCOVER"; + + case DHCPOFFER: + return "DHCPOFFER"; + + case DHCPREQUEST: + return "DHCPREQUEST"; + + case DHCPDECLINE: + return "DHCPDECLINE"; + + case DHCPACK: + return "DHCPACK"; + + case DHCPNAK: + return "DHCPNAK"; + + case DHCPRELEASE: + return "DHCPRELEASE"; + + case DHCPINFORM: + return "DHCPINFORM"; + + default: + return "???"; + } +} + +const char * +port_name (int port) +{ + switch (port) + { + case BOOTPS_PORT: + return "BOOTPS"; + + case BOOTPC_PORT: + return "BOOTPC"; + + default: + return "unknown"; + } +} + +VOID +DumpDHCP ( + const ETH_HEADER *eth, + const IPHDR *ip, + const UDPHDR *udp, + const DHCP *dhcp, + const int optlen + ) +{ + DEBUGP ((" %s", message_op_text (dhcp->op))); + DEBUGP ((" %s ", message_type_text (GetDHCPMessageType (dhcp, optlen)))); + PrIP (ip->saddr); + DEBUGP ((":%s[", port_name (ntohs (udp->source)))); + PrMac (eth->src); + DEBUGP (("] -> ")); + PrIP (ip->daddr); + DEBUGP ((":%s[", port_name (ntohs (udp->dest)))); + PrMac (eth->dest); + DEBUGP (("]")); + if (dhcp->ciaddr) + { + DEBUGP ((" ci=")); + PrIP (dhcp->ciaddr); + } + if (dhcp->yiaddr) + { + DEBUGP ((" yi=")); + PrIP (dhcp->yiaddr); + } + if (dhcp->siaddr) + { + DEBUGP ((" si=")); + PrIP (dhcp->siaddr); + } + if (dhcp->hlen == sizeof (MACADDR)) + { + DEBUGP ((" ch=")); + PrMac (dhcp->chaddr); + } + + DEBUGP ((" xid=0x%08x", ntohl (dhcp->xid))); + + if (ntohl (dhcp->magic) != 0x63825363) + DEBUGP ((" ma=0x%08x", ntohl (dhcp->magic))); + if (dhcp->htype != 1) + DEBUGP ((" htype=%d", dhcp->htype)); + if (dhcp->hops) + DEBUGP ((" hops=%d", dhcp->hops)); + if (ntohs (dhcp->secs)) + DEBUGP ((" secs=%d", ntohs (dhcp->secs))); + if (ntohs (dhcp->flags)) + DEBUGP ((" flags=0x%04x", ntohs (dhcp->flags))); + + // extra stuff + + if (ip->version_len != 0x45) + DEBUGP ((" vl=0x%02x", ip->version_len)); + if (ntohs (ip->tot_len) != sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + optlen) + DEBUGP ((" tl=%d", ntohs (ip->tot_len))); + if (ntohs (udp->len) != sizeof (UDPHDR) + sizeof (DHCP) + optlen) + DEBUGP ((" ul=%d", ntohs (udp->len))); + + if (ip->tos) + DEBUGP ((" tos=0x%02x", ip->tos)); + if (ntohs (ip->id)) + DEBUGP ((" id=0x%04x", ntohs (ip->id))); + if (ntohs (ip->frag_off)) + DEBUGP ((" frag_off=0x%04x", ntohs (ip->frag_off))); + + DEBUGP ((" ttl=%d", ip->ttl)); + DEBUGP ((" ic=0x%04x [0x%04x]", ntohs (ip->check), + ip_checksum ((UCHAR*)ip, sizeof (IPHDR)))); + DEBUGP ((" uc=0x%04x [0x%04x/%d]", ntohs (udp->check), + udp_checksum ((UCHAR *) udp, + sizeof (UDPHDR) + sizeof (DHCP) + optlen, + (UCHAR *) &ip->saddr, + (UCHAR *) &ip->daddr), + optlen)); + + // Options + { + const UCHAR *opt = (UCHAR *) (dhcp + 1); + int i; + + DEBUGP ((" OPT")); + for (i = 0; i < optlen; ++i) + { + const UCHAR data = opt[i]; + DEBUGP ((".%d", data)); + } + } +} + +#endif /* DBG */ -- cgit v1.2.3