- Timestamp:
- Mar 13, 2009 1:34:03 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/NetworkServices/DHCP/VBoxNetDHCP.cpp
r17782 r17786 38 38 #include <iprt/param.h> 39 39 #include <iprt/getopt.h> 40 #include <iprt/string.h> 40 41 41 42 #include <VBox/sup.h> … … 379 380 void makeDhcpReply(uint8_t uMsgType, VBoxNetDhcpLease *pLease, PCRTNETBOOTP pDhcpMsg, size_t cb); 380 381 381 VBoxNetDhcpLease *findLeaseByMacAddress(PCRTMAC pMacAddress );382 VBoxNetDhcpLease *findLeaseByIpv4AndMacAddresses(RTNETADDRIPV4 IPv4Addr, PCRTMAC pMacAddress );382 VBoxNetDhcpLease *findLeaseByMacAddress(PCRTMAC pMacAddress, bool fAnyState); 383 VBoxNetDhcpLease *findLeaseByIpv4AndMacAddresses(RTNETADDRIPV4 IPv4Addr, PCRTMAC pMacAddress, bool fAnyState); 383 384 VBoxNetDhcpLease *newLease(PCRTNETBOOTP pDhcpMsg, size_t cb); 384 385 … … 440 441 { 441 442 m_enmState = kState_Offer; 443 m_xid = xid; 442 444 RTTimeNow(&m_ExpireTime); 443 445 RTTimeSpecAddSeconds(&m_ExpireTime, 60); … … 538 540 pDefCfg->m_DNSes.push_back(Addr); 539 541 pDefCfg->m_DomainName = "vboxnetdhcp.org"; 542 #if 0 540 543 pDefCfg->m_cSecLease = 60*60; /* 1 hour */ 544 #else 545 pDefCfg->m_cSecLease = 30; /* sec */ 546 #endif 541 547 pDefCfg->m_TftpServer = "10.0.2.3"; //?? 542 548 this->addConfig(pDefCfg); … … 942 948 { 943 949 size_t cb; 944 void *pv = VBoxNetUDPMatch(m_pIfBuf, 67 /* bootps */, &m_MacAddress,950 void *pv = VBoxNetUDPMatch(m_pIfBuf, RTNETIPV4_PORT_BOOTPS, &m_MacAddress, 945 951 VBOXNETUDP_MATCH_UNICAST | VBOXNETUDP_MATCH_BROADCAST | VBOXNETUDP_MATCH_CHECKSUM 946 952 | (m_cVerbosity > 2 ? VBOXNETUDP_MATCH_PRINT_STDERR : 0), … … 1027 1033 { 1028 1034 /* 1029 * First, see if there is already a lease for this client. It may have rebooted, 1030 * crashed or whatever that have caused it to forget its existing lease. 1031 * If none was found, create a new lease for it and then construct a reply. 1032 */ 1033 VBoxNetDhcpLease *pLease = findLeaseByMacAddress(&pDhcpMsg->bp_chaddr.Mac); 1034 if ( !pLease 1035 || !pLease->isInCurrentConfig()) 1036 pLease = newLease(pDhcpMsg, cb); 1035 * The newLease() method contains logic for finding current leases 1036 * and reusing them in case the client is forgetful. 1037 */ 1038 VBoxNetDhcpLease *pLease = newLease(pDhcpMsg, cb); 1037 1039 if (!pLease) 1038 1040 return false; … … 1063 1065 /** @todo Probably need to match the server IP here to work correctly with 1064 1066 * other servers. */ 1065 /** @todo check this against the RFC and real code. the code is kind of 1066 * fishy... */ 1067 1068 /* 1069 * Windows will reissue these requests when rejoining a network if it thinks it 1070 * already has an address on the network. If we cannot find a valid lease, 1071 * make a new one and return NAC. 1072 */ 1073 RTNETADDRIPV4 IPv4Addr; 1074 if (findOptionIPv4Addr(RTNET_DHCP_OPT_REQ_ADDR, pDhcpMsg, cb, &IPv4Addr)) 1075 { 1076 VBoxNetDhcpLease *pLease = findLeaseByIpv4AndMacAddresses(IPv4Addr, &pDhcpMsg->bp_chaddr.Mac); 1077 if ( pLease 1078 && pLease->isInCurrentConfig()) 1079 { 1080 if (pLease->isBeingOffered()) 1067 /** @todo This code isn't entirely correct and quite a bit of a hack, but it 1068 * will have to do for now as the right thing (tm) is very complex. 1069 * Part of the fun is verifying that the request is something we can 1070 * and should handle. */ 1071 1072 /* 1073 * Try find the lease by the requested address + client MAC address. 1074 */ 1075 VBoxNetDhcpLease *pLease = NULL; 1076 RTNETADDRIPV4 IPv4Addr; 1077 bool fReqAddr = findOptionIPv4Addr(RTNET_DHCP_OPT_REQ_ADDR, pDhcpMsg, cb, &IPv4Addr); 1078 if (fReqAddr) 1079 { 1080 fReqAddr = true; 1081 pLease = findLeaseByIpv4AndMacAddresses(IPv4Addr, &pDhcpMsg->bp_chaddr.Mac, true /* fAnyState */); 1082 } 1083 1084 /* 1085 * Try find the lease by the client IP address + client MAC address. 1086 */ 1087 if ( !pLease 1088 && pDhcpMsg->bp_ciaddr.u) 1089 pLease = findLeaseByIpv4AndMacAddresses(pDhcpMsg->bp_ciaddr, &pDhcpMsg->bp_chaddr.Mac, true /* fAnyState */); 1090 1091 #if 0 /** @todo client id stuff - it doesn't make sense here imho, we need IP + MAC. What would make sense 1092 though is to compare the client id with what we've got in the lease and use it to root out 1093 bad requests. */ 1094 /* 1095 * Try find the lease by using the client id. 1096 */ 1097 if (!pLease) 1098 { 1099 size_t cbClientID = 0; 1100 uint8_t const *pbClientID = findOption(RTNET_DHCP_OPT_CLIENT_ID, pDhcpMsg, cb, &cbClientID); 1101 if ( pbClientID 1102 && cbClientID == sizeof(RTMAC) + 1 1103 && pbClientID[0] == RTNET_ARP_ETHER 1104 && 1105 ) 1106 { 1107 pLease = findLeaseByIpv4AndMacAddresses(pDhcpMsg->bp_ciaddr, &pDhcpMsg->bp_chaddr.Mac, true /* fAnyState */); 1108 } 1109 } 1110 #endif 1111 1112 /* 1113 * Validate the lease that's requested. 1114 * We've already check the MAC and IP addresses. 1115 */ 1116 bool fAckIt = false; 1117 if (pLease) 1118 { 1119 if (pLease->isBeingOffered()) 1120 { 1121 if (pLease->m_xid == pDhcpMsg->bp_xid) 1122 { 1123 fAckIt = true; 1081 1124 debugPrint(2, true, "REQUEST for offered lease."); 1082 else1083 debugPrint(1, true, "REQUEST for lease not on offer.");1084 1085 /* Check if the xid matches, if it doesn't it's not our call. */1086 #if 0 /** @todo check how windows treats bp_xid here, it should match I think. If1087 * it doesn't we've no way of filtering out broadcast replies to other1088 * DHCP servers. Fix this later.1089 */1090 if (pDhcpMsg->bp_xid != pLease->m_xid)1091 {1092 debugPrint(1, true, "bp_xid %#x != lease %#x", pDhcpMsg->bp_xid, pLease->m_xid);1093 return true;1094 }1095 #endif1096 /* Check if the config has changed since the offer was given? NAK it then? */1097 1098 /*1099 * Ack it.1100 */1101 pLease->activate(pDhcpMsg->bp_xid);1102 makeDhcpReply(RTNET_DHCP_MT_ACK, pLease, pDhcpMsg, cb);1103 }1104 else1105 {1106 /*1107 * Try make a new offer and see if we get the requested IP and config, that1108 * will make the (windows) client happy apparently...1109 */1110 pLease = newLease(pDhcpMsg, cb);1111 if ( pLease1112 && pLease->m_IPv4Address.u == IPv4Addr.u1113 /** @todo match requested config later */)1114 {1115 /* ACK it. */1116 debugPrint(1, true, "REQUEST for lease not on offer, new lease matches.");1117 1125 pLease->activate(); 1118 makeDhcpReply(RTNET_DHCP_MT_ACK, pLease, pDhcpMsg, cb);1119 1126 } 1120 1127 else 1121 { 1122 /* NAK it */ 1123 debugPrint(1, true, "REQUEST for lease not on offer, NACnig it."); 1124 if (pLease) 1125 pLease->release(); 1126 pLease->activate(); 1127 makeDhcpReply(RTNET_DHCP_MT_NAC, NULL, pDhcpMsg, cb); 1128 } 1129 } 1128 debugPrint(2, true, "REQUEST for offered lease, xid mismatch. Expected %#x, got %#x.", 1129 pLease->m_xid, pDhcpMsg->bp_xid); 1130 } 1131 else if (!pLease->isInCurrentConfig()) 1132 debugPrint(1, true, "REQUEST for obsolete lease -> NAK"); 1133 else if (fReqAddr != (pDhcpMsg->bp_ciaddr.u != 0)) // ??? 1134 { 1135 /** @todo this ain't safe. */ 1136 debugPrint(1, true, "REQUEST for lease not on offer, assuming renewal. lease_xid=%#x bp_xid=%#x", 1137 pLease->m_xid, pDhcpMsg->bp_xid); 1138 fAckIt = true; 1139 pLease->activate(pDhcpMsg->bp_xid); 1140 } 1141 else 1142 debugPrint(1, true, "REQUEST for lease not on offer, NAK it."); 1143 } 1144 1145 /* 1146 * NAK if if no lease was found. 1147 */ 1148 if (fAckIt) 1149 { 1150 debugPrint(1, false, "ACK'ing DHCP_REQUEST"); 1151 makeDhcpReply(RTNET_DHCP_MT_ACK, pLease, pDhcpMsg, cb); 1130 1152 } 1131 1153 else 1132 debugPrint(1, true, "No requested address option"); 1154 { 1155 debugPrint(1, false, "NAK'ing DHCP_REQUEST"); 1156 makeDhcpReply(RTNET_DHCP_MT_NAC, NULL, pDhcpMsg, cb); 1157 } 1133 1158 1134 1159 return true; … … 1156 1181 1157 1182 /** @todo this is not required in the initial implementation, do it later. */ 1183 debugPrint(1, true, "DECLINE is not implemented"); 1158 1184 return true; 1159 1185 } … … 1192 1218 1193 1219 /** @todo this is not required in the initial implementation, do it later. */ 1220 debugPrint(1, true, "RELEASE is not implemented"); 1194 1221 return true; 1195 1222 } … … 1205 1232 uint8_t *m_pbEnd; /**< The end the current option space. */ 1206 1233 uint8_t *m_pfOverload; /**< Pointer to the flags of the overload option. */ 1234 uint8_t m_fUsed; /**< Overload fields that have been used. */ 1207 1235 PRTNETDHCPOPT m_pOpt; /**< The current option. */ 1208 1236 PRTNETBOOTP m_pDhcp; /**< The DHCP packet. */ … … 1215 1243 m_pbEnd((uint8_t *)pDhcp + cbDhcp), 1216 1244 m_pfOverload(NULL), 1245 m_fUsed(0), 1217 1246 m_pOpt(NULL), 1218 1247 m_pDhcp(pDhcp), … … 1232 1261 1233 1262 /** 1263 * Try use the bp_file field. 1264 * @returns true if not overloaded, false otherwise. 1265 */ 1266 bool useBpFile(void) 1267 { 1268 if ( m_pfOverload 1269 && (*m_pfOverload & 1)) 1270 return false; 1271 m_fUsed |= 1 /* bp_file flag*/; 1272 return true; 1273 } 1274 1275 1276 /** 1234 1277 * Try overload more BOOTP fields 1235 1278 */ … … 1239 1282 uint8_t *pbNew; 1240 1283 uint8_t *pbNewEnd; 1284 uint8_t fField; 1285 if (!(m_fUsed & 1)) 1286 { 1287 fField = 1; 1288 pbNew = &m_pDhcp->bp_file[0]; 1289 pbNewEnd = &m_pDhcp->bp_file[sizeof(m_pDhcp->bp_file)]; 1290 } 1291 else if (!(m_fUsed & 2)) 1292 { 1293 fField = 2; 1294 pbNew = &m_pDhcp->bp_sname[0]; 1295 pbNewEnd = &m_pDhcp->bp_sname[sizeof(m_pDhcp->bp_sname)]; 1296 } 1297 else 1298 return false; 1299 1241 1300 if (!m_pfOverload) 1242 1301 { 1243 1302 /* Add an overload option. */ 1244 1303 *m_pbCur++ = RTNET_DHCP_OPT_OPTION_OVERLOAD; 1245 *m_pbCur++ = 1;1304 *m_pbCur++ = fField; 1246 1305 m_pfOverload = m_pbCur; 1247 1306 *m_pbCur++ = 1; /* bp_file flag */ 1248 1249 pbNew = &m_pDhcp->bp_file[0];1250 pbNewEnd = &m_pDhcp->bp_file[sizeof(m_pDhcp->bp_file)];1251 }1252 else if (!(*m_pfOverload & 2))1253 {1254 *m_pfOverload |= 2; /* bp_sname flag */1255 1256 pbNew = &m_pDhcp->bp_sname[0];1257 pbNewEnd = &m_pDhcp->bp_sname[sizeof(m_pDhcp->bp_sname)];1258 1307 } 1259 1308 else 1260 return false;1309 *m_pfOverload |= fField; 1261 1310 1262 1311 /* pad current option field */ … … 1264 1313 *m_pbCur++ = RTNET_DHCP_OPT_PAD; /** @todo not sure if this stuff is at all correct... */ 1265 1314 1315 /* switch */ 1266 1316 m_pbCur = pbNew; 1267 1317 m_pbEnd = pbNewEnd; … … 1285 1335 1286 1336 /* Check if we need to overload more stuff. */ 1287 if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + 3)1337 if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + (m_pfOverload ? 1 : 3)) 1288 1338 { 1289 1339 m_pOpt = NULL; … … 1293 1343 AssertMsgFailedReturn(("%u %#x\n", uOption, cb), false); 1294 1344 } 1295 if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + 3)1345 if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + 1) 1296 1346 { 1297 1347 m_fOverflowed = true; … … 1511 1561 pReply->bp_ciaddr.u = 0; 1512 1562 pReply->bp_yiaddr.u = pLease ? pLease->m_IPv4Address.u : 0xffffffff; 1513 pReply->bp_siaddr.u = pLease && pLease->m_pCfg ? pLease->m_pCfg->m_TftpServerAddr.u : 0; 1563 pReply->bp_siaddr.u = pLease && pLease->m_pCfg ? pLease->m_pCfg->m_TftpServerAddr.u : 0; /* (next server == TFTP)*/ 1514 1564 pReply->bp_giaddr.u = 0; 1515 1565 memset(&pReply->bp_chaddr, '\0', sizeof(pReply->bp_chaddr)); … … 1543 1593 1544 1594 /* The PXE config. */ 1595 if (pCfg->m_BootfileName.size()) 1596 { 1597 if (Cursor.useBpFile()) 1598 RTStrPrintf((char *)&pReply->bp_file[0], sizeof(pReply->bp_file), "%s", pCfg->m_BootfileName.c_str()); 1599 else 1600 Cursor.optStr(RTNET_DHCP_OPT_BOOTFILE_NAME, pCfg->m_BootfileName); 1601 } 1545 1602 } 1546 1603 … … 1554 1611 int rc; 1555 1612 #if 0 1556 if ( pDhcpMsg->bp_flags & RTNET_DHCP_FLAGS_NO_BROADCAST)1613 if (!(pDhcpMsg->bp_flags & RTNET_DHCP_FLAGS_NO_BROADCAST)) /** @todo need to see someone set this flag to check that it's correct. */ 1557 1614 { 1558 1615 RTNETADDRIPV4 IPv4AddrBrdCast; … … 1574 1631 1575 1632 1576 1577 1633 /** 1578 1634 * Look up a lease by MAC address. … … 1580 1636 * @returns Pointer to the lease if found, NULL if not found. 1581 1637 * @param pMacAddress The mac address. 1582 */ 1583 VBoxNetDhcpLease *VBoxNetDhcp::findLeaseByMacAddress(PCRTMAC pMacAddress) 1638 * @param fAnyState Any state. 1639 */ 1640 VBoxNetDhcpLease *VBoxNetDhcp::findLeaseByMacAddress(PCRTMAC pMacAddress, bool fAnyState) 1584 1641 { 1585 1642 size_t iLease = m_Leases.size(); … … 1590 1647 && pLease->m_MacAddress.au16[0] == pMacAddress->au16[0] 1591 1648 && pLease->m_MacAddress.au16[1] == pMacAddress->au16[1] 1592 && pLease->m_MacAddress.au16[2] == pMacAddress->au16[2]) 1649 && pLease->m_MacAddress.au16[2] == pMacAddress->au16[2] 1650 && ( fAnyState 1651 || (pLease->m_enmState != VBoxNetDhcpLease::kState_Free)) ) 1593 1652 return pLease; 1594 1653 } … … 1604 1663 * @param IPv4Addr The IPv4 address. 1605 1664 * @param pMacAddress The mac address. 1606 */ 1607 VBoxNetDhcpLease *VBoxNetDhcp::findLeaseByIpv4AndMacAddresses(RTNETADDRIPV4 IPv4Addr, PCRTMAC pMacAddress) 1665 * @param fAnyState Any state. 1666 */ 1667 VBoxNetDhcpLease *VBoxNetDhcp::findLeaseByIpv4AndMacAddresses(RTNETADDRIPV4 IPv4Addr, PCRTMAC pMacAddress, bool fAnyState) 1608 1668 { 1609 1669 size_t iLease = m_Leases.size(); … … 1615 1675 && pLease->m_MacAddress.au16[0] == pMacAddress->au16[0] 1616 1676 && pLease->m_MacAddress.au16[1] == pMacAddress->au16[1] 1617 && pLease->m_MacAddress.au16[2] == pMacAddress->au16[2]) 1677 && pLease->m_MacAddress.au16[2] == pMacAddress->au16[2] 1678 && ( fAnyState 1679 || (pLease->m_enmState != VBoxNetDhcpLease::kState_Free)) ) 1618 1680 return pLease; 1619 1681 } … … 1844 1906 { 1845 1907 const char *pszMsg = m_uCurMsgType != UINT8_MAX ? debugDhcpName(m_uCurMsgType) : ""; 1846 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: debug: %8s chaddr=%.6Rhxs ciaddr=%d.%d.%d.%d yiaddr=%d.%d.%d.%d siaddr=%d.%d.%d.%d \n",1908 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: debug: %8s chaddr=%.6Rhxs ciaddr=%d.%d.%d.%d yiaddr=%d.%d.%d.%d siaddr=%d.%d.%d.%d xid=%#x\n", 1847 1909 pszMsg, 1848 1910 &m_pCurMsg->bp_chaddr, 1849 1911 m_pCurMsg->bp_ciaddr.au8[0], m_pCurMsg->bp_ciaddr.au8[1], m_pCurMsg->bp_ciaddr.au8[2], m_pCurMsg->bp_ciaddr.au8[3], 1850 1912 m_pCurMsg->bp_yiaddr.au8[0], m_pCurMsg->bp_yiaddr.au8[1], m_pCurMsg->bp_yiaddr.au8[2], m_pCurMsg->bp_yiaddr.au8[3], 1851 m_pCurMsg->bp_siaddr.au8[0], m_pCurMsg->bp_siaddr.au8[1], m_pCurMsg->bp_siaddr.au8[2], m_pCurMsg->bp_siaddr.au8[3]); 1913 m_pCurMsg->bp_siaddr.au8[0], m_pCurMsg->bp_siaddr.au8[1], m_pCurMsg->bp_siaddr.au8[2], m_pCurMsg->bp_siaddr.au8[3], 1914 m_pCurMsg->bp_xid); 1852 1915 } 1853 1916 }
Note:
See TracChangeset
for help on using the changeset viewer.