callouts.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. #include <hooks/hooks.h>
  2. #include <dhcp/pkt4.h>
  3. #include <dhcp/hwaddr.h>
  4. #include <dhcpsrv/subnet.h>
  5. #include <dhcpsrv/lease.h>
  6. #include <dhcpsrv/host.h>
  7. #include <util/strutil.h>
  8. #include <util/encode/hex.h>
  9. #include <dhcp/option_string.h>
  10. #include <dhcp/option4_addrlst.h>
  11. #include <dhcp/docsis3_option_defs.h>
  12. #include <string>
  13. #include <dhcp/dhcp6.h>
  14. #include <dhcp/pkt6.h>
  15. #include <dhcp/option6_ia.h>
  16. #include <boost/foreach.hpp>
  17. #include "logger.h"
  18. #include "common.h"
  19. using namespace isc::dhcp;
  20. using namespace isc::hooks;
  21. extern "C" {
  22. #include <numeric> //inner_product
  23. #include <functional> //plus, equal_to, not2
  24. #include <algorithm>
  25. #include <string>
  26. #include <stdexcept>
  27. #include "mysql_connection.h"
  28. MySQLConnection conn;
  29. std::string getMacFromPacket(Pkt4Ptr);
  30. /**
  31. * Get the cablemodem mac from (option 82) or if vendor_class is *docsis* get the c_hwaddr
  32. */
  33. std::string getMacFromPacket(Pkt4Ptr pkt)
  34. {
  35. std::string rtr = "";
  36. if (pkt->getOption(DHO_DHCP_AGENT_OPTIONS)) {
  37. rtr = pkt->getOption(DHO_DHCP_AGENT_OPTIONS)->toHexString(false).substr(6,12);
  38. std::vector<uint8_t> binary;
  39. isc::util::str::decodeFormattedHexString(rtr, binary);
  40. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("getMacFromPacket -> from option 82 " + rtr);
  41. } else if (pkt->getOption(DHO_VENDOR_CLASS_IDENTIFIER)) {
  42. std::string docsis_vendor_class = pkt->getOption(DHO_VENDOR_CLASS_IDENTIFIER)->toString().substr(2,6);
  43. if (docsis_vendor_class.compare("docsis") == 0) {
  44. rtr = pkt->getMAC(HWAddr::HWADDR_SOURCE_RAW)->toText(false);
  45. isc::util::str::uppercase(rtr);
  46. rtr.erase(std::remove(rtr.begin(), rtr.end(), ':'), rtr.end());
  47. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("getMacFromPacket -> is vendor class 'docsis' chwaddr..." + rtr);
  48. }
  49. }
  50. return rtr;
  51. }
  52. enum HostType{ CABLEMODEM, EMTA, CPE };
  53. std::string HostClass[] = { "cm", "mta", "cpe" };
  54. std::string HexHostClass[] = { "636d2d", "6d74612d", "6370652d" };
  55. HostType getHostType(Pkt4Ptr pkt)
  56. {
  57. HostType rtr = CPE;
  58. std::string cm_mac = getMacFromPacket(pkt);
  59. //Non Empty MAC
  60. if (cm_mac.size() != 0) {
  61. std::string chwdr = pkt->getHWAddr()->toText(false);
  62. isc::util::str::uppercase(chwdr);
  63. chwdr.erase(std::remove(chwdr.begin(), chwdr.end(), ':'), chwdr.end());
  64. std::string opt82mac = "";
  65. if (pkt->getOption(DHO_DHCP_AGENT_OPTIONS)) {
  66. opt82mac = pkt->getOption(DHO_DHCP_AGENT_OPTIONS)->toHexString(false).substr(6,12);
  67. std::vector<uint8_t> binary;
  68. isc::util::str::decodeFormattedHexString(opt82mac, binary);
  69. }
  70. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("getHostType -> hwaddr: " + chwdr);
  71. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("getHostType -> remoteid: " + opt82mac);
  72. if (chwdr == opt82mac) {
  73. rtr = CABLEMODEM;
  74. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("getHostType -> option 82 mac == chwdr ==> CABLEMODEM");
  75. } else {
  76. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("getHostType -> dou't " + chwdr + " !== " + opt82mac);
  77. if (pkt->getOption(DHO_VENDOR_CLASS_IDENTIFIER)) {
  78. std::string docsis_vendor_class = pkt->getOption(DHO_VENDOR_CLASS_IDENTIFIER)->toString().substr(0,6);
  79. std::string pktc_vendor_class = pkt->getOption(DHO_VENDOR_CLASS_IDENTIFIER)->toString().substr(0,4);
  80. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("getHostType -> docsis_vendor_class: " + docsis_vendor_class);
  81. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("getHostType -> pktc_vendor_class: " + pktc_vendor_class);
  82. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("getHostType -> Checking Vendor Class ID");
  83. if (docsis_vendor_class.compare("docsis") == 0) {
  84. rtr = CABLEMODEM;
  85. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("getHostType -> docsis en vendor class ==> CABLEMODEM");
  86. } else {
  87. if (pktc_vendor_class.compare("pktc") == 0) {
  88. rtr = EMTA;
  89. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("getHostType -> pktc en vendor class ==> EMTA");
  90. } else {
  91. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("getHostType -> vendor class unknown");
  92. }
  93. }
  94. } else {
  95. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("getHostType -> no vendor class");
  96. }
  97. }
  98. } else {
  99. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("getHostType -> Empty MAC from getMacFromPacket ==> CPE " + std::to_string(cm_mac.size()));
  100. if (pkt->isRelayed()) {
  101. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("getHostType -> Packet Relayed");
  102. }
  103. }
  104. return rtr;
  105. }
  106. /// @brief This callout is called at the "host4_identifier" hook.
  107. ///
  108. /// It retrieves v4 packet and then generates flexible identifier for it.
  109. ///
  110. /// @param handle CalloutHandle which provides access to context.
  111. ///
  112. /// @return 0 upon success, non-zero otherwise.
  113. int host4_identifier(CalloutHandle& handle)
  114. {
  115. Pkt4Ptr query;
  116. handle.getArgument("query4", query);
  117. std::string mac = getMacFromPacket(query);
  118. HostType ht = getHostType(query);
  119. Host::IdentifierType type = Host::IDENT_FLEX;
  120. //std::vector<uint8_t> id((me + "-" + mac).begin(), (me + "-" + mac).end());
  121. std::string flex_id = std::string(HexHostClass[ht] + mac);
  122. std::vector<uint8_t> id;
  123. id.assign(flex_id.begin(), flex_id.end());
  124. handle.setArgument("id_value", id);
  125. handle.setArgument("id_type", type);
  126. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("host4_identifier -> cablemodem flex_id = " + isc::util::encode::encodeHex(id) + "(" + HostClass[ht] + "*-*" + mac + ").");
  127. return CalloutHandle::NEXT_STEP_CONTINUE;
  128. }
  129. /* IPv4 callouts */
  130. int pkt4_receive(CalloutHandle& handle)
  131. {
  132. Pkt4Ptr query;
  133. handle.getArgument("query4", query);
  134. // Busco la class para la mac que viene en el paquete
  135. // en fd3_dhcp.host, si no existe el host cargado no tiene class
  136. std::string mac = getMacFromPacket(query);
  137. std::string MAC = mac;
  138. std::transform(mac.begin(), mac.end(), mac.begin(), ::tolower);
  139. std::string sql_query = "SELECT state FROM `host` WHERE `mac` LIKE '" + mac + "';";
  140. std::string class_map = conn.executeQuery((sql_query).c_str());
  141. if (class_map != "") {
  142. cm_map[MAC] = class_map;
  143. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("pkt4_receive -> cablemodem " + mac + " class " + class_map);
  144. } else {
  145. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("pkt4_receive -> cablemodem " + mac + " class not found ");
  146. }
  147. std::vector<std::string> list_class;
  148. HWAddrPtr remote_id;
  149. HostType ht = getHostType(query);
  150. list_class.push_back(HostClass[ht]);
  151. std::map<std::string,std::string>::iterator it = cm_map.find(MAC);
  152. if (it != cm_map.end()) {
  153. list_class.push_back(cm_map[MAC]);
  154. }
  155. std::string me, me2;
  156. BOOST_FOREACH(me, list_class) {
  157. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("pkt4_receive -> class : " + me);
  158. BOOST_FOREACH(me2, list_class) {
  159. if (me.compare(me2) != 0) {
  160. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("pkt4_receive -> class : " + me + "-" + me2);
  161. query->addClass(me + "-" + me2);
  162. }
  163. }
  164. query->addClass(me);
  165. }
  166. return 0;
  167. }
  168. int pkt4_send(CalloutHandle& handle)
  169. {
  170. Pkt4Ptr response;
  171. Pkt4Ptr query;
  172. handle.getArgument("response4", response);
  173. handle.getArgument("query4", query);
  174. uint8_t ufile_name[128] = "";
  175. std::string mac;
  176. HostType ht = getHostType(query);
  177. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("pkt4_send -> HostType : " + std::to_string(ht));
  178. if (ht == CABLEMODEM or ht == EMTA) {
  179. mac = getMacFromPacket(query);
  180. }
  181. if (ht == CABLEMODEM) {
  182. std::string file = mac + ".bin";
  183. isc::util::str::lowercase(file);
  184. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("pkt4_send -> file : " + file);
  185. strcpy((char*)ufile_name, file.c_str());
  186. response->setFile(ufile_name, strlen((char *)ufile_name));
  187. std::map<std::string,std::string>::iterator it = option122_map.find(mac);
  188. if (it != option122_map.end()) {
  189. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("pkt4_send -> cablemodem " + mac + " found for MTA Activation on " + option122_map[mac]);
  190. OptionPtr option1(new Option(Option::V4, 122));
  191. Option4AddrLstPtr opt_server(new Option4AddrLst(1));
  192. opt_server->setAddress(isc::asiolink::IOAddress("255.255.255.255"));//option122_map[mac]));
  193. OptionStringPtr opt_basic1(new OptionString(Option::V4, 6, "BASIC.1"));
  194. option1->addOption(opt_server);
  195. option1->addOption(opt_basic1);
  196. response->addOption(option1);
  197. } else {
  198. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("pkt4_send -> cablemodem " + mac + " not found for MTA Activation");
  199. }
  200. }
  201. if (ht == EMTA) {
  202. std::string file = mac + ".mta.bin";
  203. isc::util::str::lowercase(file);
  204. std::map<std::string,std::string>::iterator it = option122_map.find(mac);
  205. if (it != option122_map.end()) {
  206. std::string file = mac + ".mta.bin";
  207. isc::util::str::lowercase(file);
  208. LOG_INFO(runscript_logger, FLOWDAT_DEBUG_STRING).arg("pkt4_send -> EMTA file : " + file);
  209. strcpy((char*)ufile_name, file.c_str());
  210. response->setFile(ufile_name, strlen((char *)ufile_name));
  211. isc::util::str::lowercase(mac);
  212. OptionStringPtr opt_domain(new OptionString(Option::V4, DHO_HOST_NAME, mac));
  213. response->addOption(opt_domain);
  214. }
  215. }
  216. return 0;
  217. }
  218. // @TODO: Implementar para DHCPv6
  219. /* IPv6 callouts */
  220. int pkt6_receive(CalloutHandle& handle) {
  221. std::vector<std::string> env;
  222. Pkt6Ptr query;
  223. handle.getArgument("query6", query);
  224. // std::string mac = getMacFromPacket(query);
  225. // std::string class_map = conn->executeQuery("SELECT state FROM fd3_dhcp.host WHERE mac=" + string(mac));
  226. // cm_map[mac] = class_map;
  227. return 0;
  228. }
  229. } // end extern "C"