├── .gitignore ├── EasyDrcom ├── drcom_dealer.hpp ├── drcom_dealer_base.hpp ├── drcom_dealer_u31.hpp ├── drcom_dealer_u62.hpp ├── eap_dealer.hpp ├── easy_drcom_exception.hpp ├── get_nic_addr.hpp ├── log.hpp ├── main.cpp ├── md5.c ├── md5.h ├── udp_dealer.hpp └── utils.hpp ├── LICENSE ├── README.md └── Release └── EasyDrcom_v0.7_for_OpenWrt_mips_AR7xxx_AR9xxx.zip /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Compiled Dynamic libraries 8 | *.so 9 | *.dylib 10 | *.dll 11 | 12 | # Compiled Static libraries 13 | *.lai 14 | *.la 15 | *.a 16 | *.lib 17 | 18 | # Executables 19 | *.exe 20 | *.out 21 | *.app 22 | 23 | # Project files 24 | *.xcodeproj 25 | 26 | # Other files 27 | *.txt 28 | *.log 29 | -------------------------------------------------------------------------------- /EasyDrcom/drcom_dealer.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014 Shindo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __INCLUDE_DRCOM_DEALER__ 18 | #define __INCLUDE_DRCOM_DEALER__ 19 | 20 | #include "udp_dealer.hpp" 21 | #include "drcom_dealer_base.hpp" 22 | #include "drcom_dealer_u31.hpp" 23 | #include "drcom_dealer_u62.hpp" 24 | 25 | #endif // __INCLUDE_DRCOM_DEALER__ -------------------------------------------------------------------------------- /EasyDrcom/drcom_dealer_base.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014 Shindo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | #ifndef __INCLUDE_DRCOM_DEALER_BASE__ 19 | #define __INCLUDE_DRCOM_DEALER_BASE__ 20 | 21 | class drcom_dealer_base { 22 | public: 23 | drcom_dealer_base() {} 24 | virtual ~drcom_dealer_base() {} 25 | }; // Just for base 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /EasyDrcom/drcom_dealer_u31.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014 Shindo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | #ifndef __INCLUDE_DRCOM_DEALER_BASE_U31__ 19 | #define __INCLUDE_DRCOM_DEALER_BASE_U31__ 20 | 21 | class drcom_dealer_u31 : public drcom_dealer_base { 22 | public: 23 | drcom_dealer_u31(std::vector local_mac, std::string local_ip, std::string username, std::string password, 24 | std::string gateway_ip, uint32_t gateway_port, std::string hostname, std::string kernel_version 25 | ) : local_mac(local_mac), local_ip(str_ip_to_vec(local_ip)), 26 | hostname(hostname), kernel_version(kernel_version), 27 | username(username), password(password), 28 | total_time(0), total_flux(0), balance(0), online_time(0), pkt_id(0), misc1_flux(0), misc3_flux(0), 29 | udp(gateway_ip, gateway_port, local_ip) 30 | {} 31 | 32 | int start_request() 33 | { 34 | U31_LOG_INFO("Start Request." << std::endl); 35 | 36 | std::vector pkt_data; 37 | 38 | // fixed length = 20 39 | // Code, Retry, N/A, N/A, Version 40 | pkt_data.insert(pkt_data.end(), { 0x01, 0x00, 0x00, 0x00, 0x0a }); 41 | pkt_data.insert(pkt_data.end(), 15, 0x00); 42 | 43 | challenge.clear(); 44 | 45 | auto handler_success = [&](std::vector recv) -> int { 46 | U31_LOG_RECV_DUMP("Start Request"); 47 | 48 | if (recv[0] == 0x4d) // Notification 49 | { 50 | U31_LOG_INFO("Received 'Notification', Send Start Request again." << std::endl); 51 | return start_request(); 52 | } 53 | 54 | if (recv[0] != 0x02) // Start Response 55 | return -1; 56 | 57 | U31_LOG_INFO("Gateway return: Start Response." << std::endl); 58 | challenge.resize(4); 59 | memcpy(&challenge[0], &recv[4], 4); // Challenge 60 | return 0; 61 | }; 62 | 63 | U31_HANDLE_ERROR("Start Request"); 64 | U31_AUTO_RETRY("Start Request"); 65 | } 66 | 67 | int send_login_auth() 68 | { 69 | if (challenge.empty()) return -1; 70 | 71 | U31_LOG_INFO("Send Login Auth." << std::endl); 72 | U31_LOG_DBG("username = " << username << ", password = " << password << std::endl); 73 | 74 | auth_info.clear(); 75 | 76 | std::vector pkt_data; 77 | 78 | /********************** Header *************************/ 79 | // Code, Type, EOF, UserName Length + 20 80 | auto length = ((username.length() <= 36) ? username.length() : 36) + 20; 81 | pkt_data.insert(pkt_data.end(), { 0x03, 0x01, 0x00, (uint8_t) length }); 82 | 83 | /********************** MD5A **************************/ 84 | // Function_MD5A = MD5(code + type + Challenge + Password) 85 | std::vector md5a_content = { 0x03, 0x01 /* Code, Type */ }; 86 | md5a_content.insert(md5a_content.end(), challenge.begin(), challenge.end()); 87 | md5a_content.insert(md5a_content.end(), password.begin(), password.end()); 88 | 89 | login_md5_a = get_md5_digest(md5a_content); 90 | pkt_data.insert(pkt_data.end(), login_md5_a.begin(), login_md5_a.end()); 91 | 92 | /********************** UserName *********************/ 93 | std::vector username_block(36, 0); // fixed length = 36 94 | memcpy(&username_block[0], &username[0], username.length() <= 36 ? username.length() : 36); 95 | pkt_data.insert(pkt_data.end(), username_block.begin(), username_block.end()); 96 | 97 | /********************** Conf *************************/ 98 | // 0x20, 0x05 On Windows 99 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00 });// On OSX 100 | 101 | /********************** MAC xor MD5A *****************/ 102 | for (int i = 0; i < local_mac.size(); i++) 103 | pkt_data.push_back(local_mac[i] ^ login_md5_a[i]); 104 | 105 | /********************** MD5B *************************/ 106 | // Function MD5B = MD5(0x01 + password + challenge + 0x00 *4) 107 | std::vector md5b_content = { 0x01 }; 108 | md5b_content.insert(md5b_content.end(), password.begin(), password.end()); 109 | md5b_content.insert(md5b_content.end(), challenge.begin(), challenge.end()); 110 | md5b_content.insert(md5b_content.end(), 4, 0x00); 111 | 112 | auto login_md5_b = get_md5_digest(md5b_content); 113 | pkt_data.insert(pkt_data.end(), login_md5_b.begin(), login_md5_b.end()); 114 | 115 | /********************** NIC **************************/ 116 | pkt_data.push_back(1); // NIC Count 117 | // 4 NIC's IPs in total 118 | pkt_data.insert(pkt_data.end(), local_ip.begin(), local_ip.end()); 119 | pkt_data.insert(pkt_data.end(), 12, 0x00); // Fill remaining 3 NIC's IP with zero. 120 | 121 | /********************** Checksum 1 *******************/ 122 | std::vector checksum_content(pkt_data); 123 | checksum_content.insert(checksum_content.end(), { 0x14, 0x00, 0x07, 0x0b }); // MD5 Tail 124 | 125 | auto checksum_1 = get_md5_digest(checksum_content); 126 | pkt_data.insert(pkt_data.end(), checksum_1.begin(), checksum_1.begin() + 8); // Only need 8 bytes 127 | 128 | /********************** IP Dog & Fill ***************/ 129 | pkt_data.push_back(0x01); // IP Dog 130 | pkt_data.insert(pkt_data.end(), 4, 0x00); // Fill 0x00 *4 131 | 132 | /********************** Host Name *******************/ 133 | // fixed length = 32 134 | std::vector hostname_block(32, 0); 135 | memcpy(&hostname_block[0], &hostname[0], hostname.length() <= 32 ? hostname.length() : 32); 136 | pkt_data.insert(pkt_data.end(), hostname_block.begin(), hostname_block.end()); 137 | 138 | /********************** DNS & DHCP & Fill ***********/ 139 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00, 0x00, 0x00 }); // Primary DNS 140 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00, 0x00, 0x00 }); // DHCP 141 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00, 0x00, 0x00 }); // Secondary DNS 142 | pkt_data.insert(pkt_data.end(), 8, 0x00); // Fill 0x00 *8 143 | 144 | /********************** Host System Info & Fill *****/ 145 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00, 0x00, 0x00 }); // Unknown 1 146 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00, 0x00, 0x00 }); // OS major 147 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00, 0x00, 0x00 }); // OS minor 148 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00, 0x00, 0x00 }); // OS build 149 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00, 0x00, 0x02 }); // Unknown 2 150 | 151 | std::vector kernel_version_block(32, 0); // fixed length = 32 152 | memcpy(&kernel_version_block[0], &kernel_version[0], kernel_version.length() <= 32 ? kernel_version.length() : 32); 153 | pkt_data.insert(pkt_data.end(), kernel_version_block.begin(), kernel_version_block.end()); 154 | 155 | pkt_data.insert(pkt_data.end(), 96, 0x00); // Fill 0x00 *96 156 | 157 | /********************** Checksum 2 *****************/ 158 | // Version 159 | std::vector checksum_2 = { 0x0a, 0x00, 0x02, 0x0c }; 160 | checksum_2.insert(checksum_2.end(), checksum_1.begin() + 10, checksum_1.begin() + 10 + 4); // 4 bytes from Checksum1 161 | checksum_2.insert(checksum_2.end(), { 0x00, 0x00 } ); // Unkown: 2 bytes 162 | pkt_data.insert(pkt_data.end(), checksum_2.begin(), checksum_2.end()); 163 | 164 | /********************** MAC ************************/ 165 | pkt_data.insert(pkt_data.end(), local_mac.begin(), local_mac.end()); 166 | 167 | /********************** Conf ***********************/ 168 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00 }); // Auto_Logout, Multicast_Mode 169 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00 }); // Unkown: 2 bytes 170 | 171 | U31_LOG_SEND_DUMP 172 | 173 | auto handler_success = [&](std::vector recv) -> int { 174 | U31_LOG_RECV_DUMP("Send Login Auth"); 175 | 176 | if (recv[0] != 0x04 && recv[0] != 0x05) // Success/Failure 177 | return -1; 178 | 179 | if (recv[0] == 0x05) // Failure 180 | { 181 | switch (recv[4]) 182 | { 183 | case 0x01: // Already online 184 | U31_LOG_ERR("This account has already been online at IP: " << (int)recv[5] << "." << (int)recv[6] << "." << (int)recv[7] << "." << (int)recv[8] << ", MAC: " << hex_to_str(&recv[9], 6, ':') << std::endl); 185 | break; 186 | 187 | case 0x03: // Username or password wrong! 188 | U31_LOG_ERR("Username or password wrong!" << std::endl); 189 | break; 190 | 191 | case 0x05: // No money 192 | U31_LOG_ERR("No money in your account!" << std::endl); 193 | break; 194 | 195 | case 0x0b: // Wrong MAC 196 | U31_LOG_ERR("Wrong MAC, should be " << hex_to_str(&recv[5], 6, ':') << std::endl); 197 | break; 198 | 199 | default: 200 | U31_LOG_ERR("Unkown failure: 0x" << std::hex << (int)recv[4] << std::endl); 201 | break; 202 | } 203 | return 1; // Don't retry when failure 204 | } 205 | 206 | U31_LOG_INFO("Gateway return: Success." << std::endl); 207 | 208 | // Success 209 | auth_info.insert(auth_info.end(), recv.begin() + 23, recv.begin() + 23 + 16); // 16 bytes from Success 210 | 211 | // Captured 212 | memcpy(&total_time, &recv[5], 4); 213 | memcpy(&total_flux, &recv[9], 4); 214 | memcpy(&balance, &recv[13], 4); 215 | 216 | #ifdef OPENWRT 217 | // network order on openwrt 218 | total_time = TO_LITTLE_ENDIAN(total_time); 219 | total_flux = TO_LITTLE_ENDIAN(total_flux); 220 | balance = TO_LITTLE_ENDIAN(balance); 221 | #endif 222 | 223 | U31_LOG_INFO("Login auth succeeded! User info: " << std::endl); 224 | U31_LOG_INFO("Used Time: " << total_time << " Minutes, Used Flux: " << (total_flux & 0x0FFFFFFFF) / 1024.0 << " MB, Balance: " << (balance & 0x0FFFFFFFF) / 100.0 << " RMB" << std::endl); 225 | 226 | return 0; 227 | }; 228 | 229 | U31_HANDLE_ERROR("Send Login Auth"); 230 | U31_AUTO_RETRY("Send Login Auth"); 231 | } 232 | 233 | int send_alive_pkt1(int retry_times = 0) 234 | { 235 | U31_LOG_INFO("Send Alive Packet 1." << std::endl); 236 | 237 | std::vector pkt_data; 238 | pkt_data.push_back(0x07); // Code 239 | pkt_data.push_back(pkt_id); 240 | pkt_data.insert(pkt_data.end(), { 0x28, 0x00 }); // Type 241 | pkt_data.insert(pkt_data.end(), { 0x0B, 0x01 }); // Step 242 | pkt_data.insert(pkt_data.end(), client_version.begin(), client_version.end()); // Client Version 243 | pkt_data.insert(pkt_data.end(), { 0xDE, 0xAD }); // Handshake Code 244 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00, 0x00, 0x00 }); // some time 245 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00 }); // Fixed Unknown 246 | 247 | // some flux 248 | pkt_data.insert(pkt_data.end(), 4, 0x00); 249 | memcpy(&pkt_data[16], &misc1_flux, 4); 250 | 251 | pkt_data.insert(pkt_data.end(), 8, 0x00); // Fixed Unknown, 0x00 *8 252 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00, 0x00, 0x00 }); // Client IP (Fixed: 0.0.0.0) 253 | pkt_data.insert(pkt_data.end(), 8, 0x00); // Fixed Unknown, 0x00 *8 254 | 255 | U31_LOG_SEND_DUMP 256 | 257 | auto handler_success = [&](std::vector recv) -> int { 258 | U31_LOG_RECV_DUMP("Alive Packet 1"); 259 | 260 | if (recv[0] != 0x07) // Misc 261 | return -1; 262 | 263 | if (recv[5] == 0x06) // File 264 | { 265 | U31_LOG_INFO("Received 'Misc, File', Send Keep Alive Packet 1 again." << std::endl); 266 | 267 | // fetch client version 268 | memcpy(&client_version[0], &recv[6], 2); 269 | 270 | // exceed retry times? 271 | if (retry_times < 10) 272 | { 273 | return send_alive_pkt1(retry_times + 1); 274 | } 275 | else 276 | { 277 | U31_LOG_INFO("Send Too Many Keep Alive Packets!" << std::endl); 278 | return -1; 279 | } 280 | } 281 | else 282 | { 283 | U31_LOG_INFO("Gateway return: Response for Alive Packet 1." << std::endl); 284 | 285 | pkt_id++; 286 | U31_LOG_DBG("next packet id = " << (int) pkt_id << std::endl); 287 | 288 | memcpy(&misc3_flux, &recv[16], 4); 289 | return 0; 290 | } 291 | }; 292 | 293 | U31_HANDLE_ERROR("Send Alive Packet 1"); 294 | U31_AUTO_RETRY("Send Alive Packet 1"); 295 | } 296 | 297 | int send_alive_pkt2() 298 | { 299 | U31_LOG_INFO("Send Alive Packet 2." << std::endl); 300 | 301 | std::vector pkt_data; 302 | pkt_data.push_back(0x07); // Code 303 | pkt_data.push_back(pkt_id); 304 | pkt_data.insert(pkt_data.end(), { 0x28, 0x00 }); // Type 305 | pkt_data.insert(pkt_data.end(), { 0x0B, 0x03 }); // Step 306 | pkt_data.insert(pkt_data.end(), client_version.begin(), client_version.end()); // Client Version 307 | pkt_data.insert(pkt_data.end(), { 0xDE, 0xAD }); // Handshake Code 308 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00, 0x00, 0x00 }); // some time 309 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00 }); // Fixed Unknown 310 | 311 | // some flux 312 | pkt_data.insert(pkt_data.end(), 4, 0x00); 313 | memcpy(&pkt_data[16], &misc3_flux, 4); 314 | 315 | pkt_data.insert(pkt_data.end(), 8, 0x00); // Fixed Unknown, 0x00 *8 316 | pkt_data.insert(pkt_data.end(), local_ip.begin(), local_ip.end()); // Client IP 317 | pkt_data.insert(pkt_data.end(), 8, 0x00); // Fixed Unknown, 0x00 *8 318 | 319 | U31_LOG_SEND_DUMP 320 | 321 | auto handler_success = [&](std::vector recv) -> int { 322 | U31_LOG_RECV_DUMP("Alive Packet 2"); 323 | 324 | if (recv[0] != 0x07 && recv[5] != 0x04) // Misc 4 325 | return -1; 326 | 327 | U31_LOG_INFO("Gateway return: Response for Alive Packet 2." << std::endl); 328 | 329 | pkt_id++; 330 | U31_LOG_DBG("next packet id = " << (int) pkt_id << std::endl); 331 | 332 | memcpy(&misc1_flux, &recv[16], 4); 333 | return 0; 334 | }; 335 | 336 | U31_HANDLE_ERROR("Send Alive Packet 2"); 337 | U31_AUTO_RETRY("Send Alive Packet 2"); 338 | } 339 | 340 | int send_alive_request() 341 | { 342 | if (login_md5_a.empty()) return -1; 343 | if (auth_info.empty()) return -1; 344 | 345 | U31_LOG_INFO("Send Alive Request." << std::endl); 346 | 347 | std::vector pkt_data; 348 | pkt_data.push_back(0xFF); // Code 349 | pkt_data.insert(pkt_data.end(), login_md5_a.begin(), login_md5_a.end()); 350 | pkt_data.insert(pkt_data.end(), 3, 0x00); // Fill 0x00 *3 351 | pkt_data.insert(pkt_data.end(), auth_info.begin(), auth_info.end()); 352 | pkt_data.insert(pkt_data.end(), 2, 0x00); // Fill 0x00 *2 for timestamp 353 | 354 | uint16_t now_time = (uint16_t)(time(NULL) % 86400); 355 | 356 | U31_LOG_SEND_DUMP 357 | 358 | auto handler_success = [&](std::vector recv) -> int { 359 | U31_LOG_RECV_DUMP("Send Alive Request"); 360 | 361 | if (recv[0] == 0x4d) // Notification 362 | { 363 | U31_LOG_INFO("Received 'Notification', Send Keep Alive Request again." << std::endl); 364 | return send_alive_request(); 365 | } 366 | 367 | if (recv[0] != 0x07 && recv[5] != 0x00) // Response for Alive 368 | return -1; 369 | 370 | U31_LOG_INFO("Gateway return: Response for alive." << std::endl); 371 | 372 | // Captured 373 | memcpy(&online_time, &recv[32], 4); 374 | memcpy(&total_time, &recv[44], 4); 375 | memcpy(&total_flux, &recv[48], 4); 376 | memcpy(&balance, &recv[52], 4); 377 | 378 | #ifdef OPENWRT 379 | // network order on openwrt 380 | online_time = TO_LITTLE_ENDIAN(online_time); 381 | total_time = TO_LITTLE_ENDIAN(total_time); 382 | total_flux = TO_LITTLE_ENDIAN(total_flux); 383 | balance = TO_LITTLE_ENDIAN(balance); 384 | #endif 385 | 386 | U31_LOG_INFO("Keep Alive succeeded! Timestamp = " << now_time << ", user info:" << std::endl); 387 | U31_LOG_INFO("Online Time: " << online_time << " Seconds, Used Time: " << total_time << " Minutes, Used Flux: " << (total_flux & 0x0FFFFFFFF) / 1024.0 << " MB, Balance: " << (balance & 0x0FFFFFFFF) / 10000.0 << " RMB" << std::endl); 388 | 389 | return 0; 390 | }; 391 | 392 | U31_HANDLE_ERROR("Send Alive Request"); 393 | U31_AUTO_RETRY("Send Alive Request"); 394 | } 395 | 396 | int send_logout_auth() 397 | { 398 | if (challenge.empty()) return -1; 399 | if (auth_info.empty()) return -1; 400 | 401 | U31_LOG_INFO("Send Logout Auth." << std::endl); 402 | 403 | std::vector pkt_data; 404 | 405 | /************************ Header *******************/ 406 | // Code, Type, EOF, UserName Length + 20 407 | auto length = ((username.length() <= 36) ? username.length() : 36) + 20; 408 | pkt_data.insert(pkt_data.end(), { 0x06, 0x01, 0x00, (uint8_t) length }); 409 | 410 | /********************** MD5A **************************/ 411 | // Function_MD5A = MD5(code + type + Challenge + Password) 412 | std::vector md5a_content = { 0x06, 0x01 /* Code, Type */ }; 413 | md5a_content.insert(md5a_content.end(), challenge.begin(), challenge.end()); 414 | md5a_content.insert(md5a_content.end(), password.begin(), password.end()); 415 | 416 | login_md5_a = get_md5_digest(md5a_content); 417 | pkt_data.insert(pkt_data.end(), login_md5_a.begin(), login_md5_a.end()); 418 | 419 | /********************** UserName *********************/ 420 | std::vector username_block(36, 0); // fixed length = 36 421 | memcpy(&username_block[0], &username[0], username.length() <= 36 ? username.length() : 36); 422 | pkt_data.insert(pkt_data.end(), username_block.begin(), username_block.end()); 423 | 424 | /********************** Conf *************************/ 425 | // 0x20, 0x05 On Windows 426 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00 });// On OSX 427 | 428 | /********************** MAC xor MD5A *****************/ 429 | for (int i = 0; i < local_mac.size(); i++) 430 | pkt_data.push_back(local_mac[i] ^ login_md5_a[i]); 431 | 432 | /********************** Auth Info ********************/ 433 | pkt_data.insert(pkt_data.end(), auth_info.begin(), auth_info.end()); 434 | 435 | U31_LOG_SEND_DUMP 436 | 437 | auto handler_success = [&](std::vector recv) -> int { 438 | U31_LOG_RECV_DUMP("Send Logout Auth"); 439 | 440 | if (recv[0] != 0x04) // Success 441 | return -1; 442 | 443 | U31_LOG_INFO("Logged out." << std::endl); 444 | challenge.clear(); login_md5_a.clear(); auth_info.clear(); 445 | total_time = total_flux = balance = online_time = pkt_id = misc3_flux = misc1_flux = 0; 446 | return 0; 447 | }; 448 | 449 | U31_HANDLE_ERROR("Send Logout Auth"); 450 | U31_AUTO_RETRY("Send Logout Auth"); 451 | } 452 | 453 | private: 454 | udp_dealer udp; 455 | 456 | // Const 457 | std::vector local_mac, local_ip; 458 | std::string username, password, hostname, kernel_version; 459 | 460 | // Send Login Auth 461 | std::vector challenge; 462 | 463 | // Used by Alive 464 | std::vector login_md5_a; 465 | 466 | // Recv from Success 467 | std::vector auth_info; 468 | 469 | // Update from Succes & Alive 470 | uint32_t total_time, total_flux, balance, online_time; 471 | 472 | // Client Version, used by misc1,3 473 | std::vector client_version = { 0x1F, 0x00 }; 474 | 475 | // Send Misc1, 3 476 | uint8_t pkt_id; 477 | uint32_t misc1_flux, misc3_flux; 478 | }; 479 | 480 | #endif 481 | -------------------------------------------------------------------------------- /EasyDrcom/drcom_dealer_u62.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014 Shindo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __INCLUDE_DRCOM_DEALER_U62__ 18 | #define __INCLUDE_DRCOM_DEALER_U62__ 19 | 20 | class drcom_dealer_u62 : public drcom_dealer_base { 21 | public: 22 | drcom_dealer_u62(std::vector local_mac, std::string local_ip, std::string username, std::string password, 23 | std::string gateway_ip, uint32_t gateway_port, std::string hostname, std::string kernel_version 24 | ) : local_mac(local_mac), local_ip(str_ip_to_vec(local_ip)), 25 | hostname(hostname), kernel_version(kernel_version), 26 | username(username), password(password), 27 | pkt_id(0), misc1_flux(0), misc3_flux(0), 28 | udp(gateway_ip, gateway_port, local_ip) 29 | {} 30 | 31 | int send_alive_pkt1(int retry_times = 0) 32 | { 33 | U62_LOG_INFO("Send Alive Packet 1." << std::endl); 34 | 35 | std::vector pkt_data; 36 | pkt_data.push_back(0x07); // Code 37 | pkt_data.push_back(pkt_id); 38 | pkt_data.insert(pkt_data.end(), { 0x28, 0x00 }); // Type 39 | pkt_data.insert(pkt_data.end(), { 0x0B, 0x01 }); // Step 40 | pkt_data.insert(pkt_data.end(), client_version.begin(), client_version.end()); // Client Version 41 | pkt_data.insert(pkt_data.end(), { 0xDE, 0xAD }); // Handshake Code 42 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00, 0x00, 0x00 }); // some time 43 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00 }); // Fixed Unknown 44 | 45 | // some flux 46 | pkt_data.insert(pkt_data.end(), 4, 0x00); 47 | memcpy(&pkt_data[16], &misc1_flux, 4); 48 | 49 | pkt_data.insert(pkt_data.end(), 8, 0x00); // Fixed Unknown, 0x00 *8 50 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00, 0x00, 0x00 }); // Client IP (Fixed: 0.0.0.0) 51 | pkt_data.insert(pkt_data.end(), 8, 0x00); // Fixed Unknown, 0x00 *8 52 | 53 | U62_LOG_SEND_DUMP 54 | 55 | auto handler_success = [&](std::vector recv) -> int { 56 | U62_LOG_RECV_DUMP("Alive Packet 1"); 57 | 58 | if (recv[0] != 0x07) // Misc 59 | return -1; 60 | 61 | if (recv[5] == 0x06) // File 62 | { 63 | U62_LOG_INFO("Received 'Misc, File', Send Keep Alive Packet 1 again." << std::endl); 64 | 65 | // fetch client version 66 | memcpy(&client_version[0], &recv[6], 2); 67 | 68 | // exceed retry times? 69 | if (retry_times < 10) 70 | { 71 | return send_alive_pkt1(retry_times + 1); 72 | } 73 | else 74 | { 75 | U62_LOG_INFO("Send Too Many Keep Alive Packets!" << std::endl); 76 | return -1; 77 | } 78 | } 79 | else 80 | { 81 | U62_LOG_INFO("Gateway return: Response for Alive Packet 1." << std::endl); 82 | 83 | pkt_id++; 84 | U62_LOG_DBG("next packet id = " << (int) pkt_id << std::endl); 85 | 86 | memcpy(&misc3_flux, &recv[16], 4); 87 | return 0; 88 | } 89 | }; 90 | 91 | U62_HANDLE_ERROR("Send Alive Packet 1"); 92 | U62_AUTO_RETRY("Send Alive Packet 1"); 93 | } 94 | 95 | int send_alive_pkt2() 96 | { 97 | U62_LOG_INFO("Send Alive Packet 2." << std::endl); 98 | 99 | std::vector pkt_data; 100 | pkt_data.push_back(0x07); // Code 101 | pkt_data.push_back(pkt_id); 102 | pkt_data.insert(pkt_data.end(), { 0x28, 0x00 }); // Type 103 | pkt_data.insert(pkt_data.end(), { 0x0B, 0x03 }); // Step 104 | pkt_data.insert(pkt_data.end(), client_version.begin(), client_version.end()); // Client Version 105 | pkt_data.insert(pkt_data.end(), { 0xDE, 0xAD }); // Handshake Code 106 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00, 0x00, 0x00 }); // some time 107 | pkt_data.insert(pkt_data.end(), { 0x00, 0x00 }); // Fixed Unknown 108 | 109 | // some flux 110 | pkt_data.insert(pkt_data.end(), 4, 0x00); 111 | memcpy(&pkt_data[16], &misc3_flux, 4); 112 | 113 | pkt_data.insert(pkt_data.end(), 8, 0x00); // Fixed Unknown, 0x00 *8 114 | pkt_data.insert(pkt_data.end(), local_ip.begin(), local_ip.end()); // Client IP 115 | pkt_data.insert(pkt_data.end(), 8, 0x00); // Fixed Unknown, 0x00 *8 116 | 117 | U62_LOG_SEND_DUMP 118 | 119 | auto handler_success = [&](std::vector recv) -> int { 120 | U62_LOG_RECV_DUMP("Alive Packet 2"); 121 | 122 | if (recv[0] != 0x07 && recv[5] != 0x04) // Misc 4 123 | return -1; 124 | 125 | U62_LOG_INFO("Gateway return: Response for Alive Packet 2." << std::endl); 126 | 127 | pkt_id++; 128 | U62_LOG_DBG("next packet id = " << (int) pkt_id << std::endl); 129 | 130 | memcpy(&misc1_flux, &recv[16], 4); 131 | return 0; 132 | }; 133 | 134 | U62_HANDLE_ERROR("Send Alive Packet 2"); 135 | U62_AUTO_RETRY("Send Alive Packet 2"); 136 | } 137 | 138 | private: 139 | udp_dealer udp; 140 | 141 | // Const 142 | std::vector local_mac, local_ip; 143 | std::string username, password, hostname, kernel_version; 144 | 145 | // Client Version, used by misc1,3 146 | std::vector client_version = { 0x1F, 0x00 }; 147 | 148 | // Send Misc1, 3 149 | uint8_t pkt_id; 150 | uint32_t misc1_flux, misc3_flux; 151 | }; 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /EasyDrcom/eap_dealer.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014 Shindo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __INCLUDE_EAP_DEALER__ 18 | #define __INCLUDE_EAP_DEALER__ 19 | 20 | #include 21 | 22 | #define DRCOM_EAP_FRAME_SIZE (0x60) 23 | #define EAP_MD5_VALUE_SIZE (0x10) 24 | 25 | #define EAP_AUTO_RETRY(step) EAP_AUTO_RETRY_EX(step, pkt_data, handler_success, handler_error) 26 | 27 | #define EAP_AUTO_RETRY_EX(step, data, success, error) \ 28 | { \ 29 | int retry_times = 0, ret; \ 30 | try { \ 31 | while ((ret = pcap.send(data, success, error)) < 0 && retry_times < MAX_RETRY_TIME) \ 32 | { \ 33 | retry_times++; \ 34 | EAP_LOG_ERR("Failed to perform " << step << ", retry times = " << retry_times << std::endl);\ 35 | EAP_LOG_INFO("Try to perform " << step << " after 2 seconds." << std::endl); \ 36 | std::this_thread::sleep_for(std::chrono::seconds(2)); \ 37 | } \ 38 | if (retry_times == MAX_RETRY_TIME) \ 39 | { \ 40 | EAP_LOG_ERR("Failed to perfrom " << step << ", stopped." << std::endl); \ 41 | return -1; \ 42 | } \ 43 | } catch (std::exception &e) { \ 44 | EAP_LOG_ERR(step << ": " << e.what() << std::endl); \ 45 | } \ 46 | return ret; \ 47 | } 48 | 49 | #define EAP_HANDLE_ERROR(step) \ 50 | auto handler_error = [&](std::string error) { \ 51 | EAP_LOG_ERR(step << ": " << error << std::endl) \ 52 | }; 53 | 54 | #define EAP_SHOW_PACKET_TYPE(step) \ 55 | EAP_LOG_DBG("Recevied after " << step << ", " \ 56 | << "eapol_type = 0x" << std::hex << (int) eap_header->eapol_type \ 57 | << ", eap_id = 0x" << std::hex << (int) eap_header->eap_id \ 58 | << ", eap_type = 0x" << std::hex << (int) eap_header->eap_type \ 59 | << ", eap_length = " << (int) eap_header->eap_length << std::endl); 60 | 61 | #if defined (WIN32) 62 | #define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ 63 | #define ETHERNET_HEADER_SIZE 14 /* length of two Ethernet address plus ether type*/ 64 | struct ether_header 65 | { 66 | u_char ether_dhost[ETHER_ADDR_LEN]; 67 | u_char ether_shost[ETHER_ADDR_LEN]; 68 | u_short ether_type; 69 | }; 70 | #endif 71 | 72 | struct eap_header 73 | { 74 | uint8_t eapol_version; 75 | uint8_t eapol_type; // 0x01 - Start, 0x02 - Logoff, 0x00 - EAP Packet 76 | uint16_t eapol_length; // equal to eap_length 77 | uint8_t eap_code; 78 | uint8_t eap_id; 79 | uint16_t eap_length; 80 | uint8_t eap_type; 81 | uint8_t eap_md5_value_size; 82 | uint8_t eap_md5_value[16]; 83 | }; 84 | 85 | class pcap_dealer 86 | { 87 | public: 88 | pcap_dealer(std::string nic, std::vector mac) 89 | { 90 | const int SNAP_LEN = 1518; 91 | char errbuf[PCAP_ERRBUF_SIZE] = {0}; 92 | char filter[100]; 93 | struct bpf_program fp; 94 | 95 | if (NULL == (handle = pcap_open_live(nic.c_str(), SNAP_LEN, 1, conf.local.eap_timeout, errbuf))) 96 | throw easy_drcom_exception("pcap_open_live: " + std::string(errbuf)); 97 | 98 | if (pcap_datalink(handle) != DLT_EN10MB) 99 | throw easy_drcom_exception("pcap_datalink: not an Ethernet device."); 100 | 101 | sprintf(filter, "ether dst %02x:%02x:%02x:%02x:%02x:%02x and ether proto 0x888e", 102 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 103 | 104 | if (pcap_compile(handle, &fp, filter, 0, 0) == -1) 105 | throw easy_drcom_exception(std::string("pcap_compile: ") + pcap_geterr(handle)); 106 | 107 | if (pcap_setfilter(handle, &fp) == -1) 108 | throw easy_drcom_exception(std::string("pcap_setfilter: ") + pcap_geterr(handle)); 109 | 110 | pcap_freecode(&fp); 111 | } 112 | 113 | ~pcap_dealer() 114 | { 115 | pcap_close(handle); 116 | } 117 | 118 | int send(std::vector data, std::function)> success, std::function error = nullptr) 119 | { 120 | try 121 | { 122 | if (pcap_sendpacket(handle, &data[0], (int) data.size()) != 0) 123 | throw easy_drcom_exception("pcap_sendpacket: " + std::string(pcap_geterr(handle))); 124 | 125 | struct pcap_pkthdr *header; 126 | const uint8_t *pkt_data; 127 | int ret = pcap_next_ex(handle, &header, &pkt_data); 128 | std::vector recv; 129 | 130 | switch (ret) 131 | { 132 | case 0: // Timeout 133 | throw easy_drcom_exception("pcap_next_ex: timeout."); 134 | 135 | case 1: // Success 136 | recv.resize(header->len); 137 | memcpy(&recv[0], pkt_data, header->len); 138 | return success(recv); 139 | 140 | default: 141 | throw easy_drcom_exception(std::string("pcap_next_ex: ") + pcap_geterr(handle)); 142 | } 143 | } 144 | catch (std::exception& e) 145 | { 146 | if (error != nullptr) 147 | error(e.what()); 148 | 149 | return -1; 150 | } 151 | } 152 | 153 | private: 154 | pcap_t *handle; 155 | std::thread thread_loop; 156 | }; 157 | 158 | class eap_dealer 159 | { 160 | public: 161 | eap_dealer(std::string nic, std::vector local_mac, std::string local_ip, std::string identity, std::string key) : key(str_to_vec(key)), // the local_ip can be used to detect 'IP conflict!' 162 | local_mac(local_mac), pcap(nic, local_mac) 163 | { 164 | auto ip = str_ip_to_vec(local_ip); 165 | 166 | resp_id = str_to_vec(identity); 167 | resp_id.insert(resp_id.end(), { 0x00, 0x44, 0x61, 0x00, 0x00 }); 168 | resp_id.insert(resp_id.end(), ip.begin(), ip.end()); 169 | 170 | resp_md5_id = str_to_vec(identity); 171 | resp_md5_id.insert(resp_md5_id.end(), { 0x00, 0x44, 0x61, 0x0a, 0x00 }); 172 | resp_md5_id.insert(resp_md5_id.end(), ip.begin(), ip.end()); 173 | } 174 | 175 | int start(std::vector gateway_mac) 176 | { 177 | EAP_LOG_INFO("Start." << std::endl); 178 | 179 | std::vector pkt_data(DRCOM_EAP_FRAME_SIZE, 0); 180 | 181 | uint8_t eapol_start[] = { 182 | 0x01, // Version: 802.1X-2001 183 | 0x01, // Type: Start 184 | 0x00, 0x00 // Length: 0 185 | }; 186 | 187 | struct ether_header eth_header = get_eth_header(gateway_mac, local_mac); 188 | 189 | memcpy(&pkt_data[0], ð_header, sizeof(eth_header)); 190 | memcpy(&pkt_data[sizeof(eth_header)], eapol_start, 4); 191 | 192 | auto handler_success = [&](std::vector recv) -> int { 193 | struct ether_header *eth_header; 194 | struct eap_header *eap_header; 195 | 196 | eth_header = (struct ether_header*) &recv[0]; 197 | eap_header = (struct eap_header*) (&recv[0] + sizeof(struct ether_header)); 198 | 199 | EAP_SHOW_PACKET_TYPE("Start"); 200 | 201 | if (eap_header->eapol_type != 0x00) // EAP Packet 202 | return -1; 203 | 204 | // EAP Request // EAP Failure 205 | if (eap_header->eap_code != 0x01 /*&& eap_header->eap_code != 0x04*/) 206 | return -1; 207 | 208 | // We don't retry at this time when failure occurs. 209 | /*if (eap_header->eap_code == 0x04) // Failure 210 | { 211 | EAP_LOG_INFO("Failure, send Start again." << std::endl); 212 | 213 | // Typically because abnormal exit last time 214 | // So send a logoff packet and then retry 215 | 216 | logoff(gateway_mac); 217 | return start(gateway_mac); 218 | }*/ 219 | 220 | // Now, only eap_code = 0x01 packets, select eap_type = 0x01 packet 221 | if (eap_header->eap_type != 0x01) // Request, Identity 222 | return -1; 223 | 224 | EAP_LOG_INFO("Gateway returns: Request, Identity" << std::endl); 225 | resp_eap_id = eap_header->eap_id; 226 | 227 | return 0; 228 | }; 229 | 230 | EAP_HANDLE_ERROR("Start"); 231 | EAP_AUTO_RETRY("Start"); 232 | } 233 | 234 | int logoff(std::vector gateway_mac) // this a function typically returns success 235 | { 236 | EAP_LOG_INFO("Logoff." << std::endl); 237 | 238 | std::vector pkt_data(DRCOM_EAP_FRAME_SIZE, 0); 239 | 240 | uint8_t eapol_logoff[] = { 241 | 0x01, // Version: 802.1X-2001 242 | 0x02, // Type: Logoff 243 | 0x00, 0x00 // Length: 0 244 | }; 245 | 246 | struct ether_header eth_header = get_eth_header(gateway_mac, local_mac); 247 | memcpy(&pkt_data[0], ð_header, sizeof(eth_header)); 248 | memcpy(&pkt_data[sizeof(eth_header)], eapol_logoff, 4); 249 | 250 | auto handler_success = [&](std::vector recv) -> int { 251 | struct ether_header *eth_header; 252 | struct eap_header *eap_header; 253 | 254 | eth_header = (struct ether_header*) &recv[0]; 255 | eap_header = (struct eap_header*) (&recv[0] + sizeof(struct ether_header)); 256 | 257 | EAP_SHOW_PACKET_TYPE("Logoff"); 258 | 259 | // We needn't to deal with the packet back 260 | return 0; 261 | }; 262 | 263 | auto handler_error = [&](std::string) { 264 | // We needn't to deal with the packet back 265 | }; 266 | 267 | try 268 | { 269 | pcap.send(pkt_data, handler_success, handler_error); 270 | } 271 | catch (std::exception &e) 272 | { 273 | EAP_LOG_ERR("Logoff :" << e.what() << std::endl); 274 | } 275 | return 0; 276 | } 277 | 278 | int response_identity(std::vector gateway_mac) 279 | { 280 | EAP_LOG_INFO("Response, Identity." << std::endl); 281 | 282 | std::vector pkt_data(DRCOM_EAP_FRAME_SIZE, 0); 283 | 284 | std::vector eap_resp_id = { 285 | 0x01, // Version: 802.1X-2001 286 | 0x00, // Type: EAP Packet 287 | 0x00, 0x00, // EAP Length 288 | 0x02, // Code: Reponse 289 | (uint8_t) resp_eap_id, // Id 290 | 0x00, 0x00, // EAP Length 291 | 0x01 // Type: Identity 292 | }; 293 | 294 | uint16_t eap_length = htons(5 + resp_id.size()); 295 | 296 | memcpy(&eap_resp_id[2], &eap_length, 2); 297 | memcpy(&eap_resp_id[6], &eap_length, 2); 298 | 299 | struct ether_header eth_header = get_eth_header(gateway_mac, local_mac); 300 | 301 | memcpy(&pkt_data[0], ð_header, sizeof(eth_header)); 302 | memcpy(&pkt_data[sizeof(eth_header)], &eap_resp_id[0], eap_resp_id.size()); 303 | 304 | memcpy(&pkt_data[sizeof(eth_header) + eap_resp_id.size()], &resp_id[0], resp_id.size()); 305 | 306 | auto handler_success = [&](std::vector recv) -> int { 307 | struct ether_header *eth_header; 308 | struct eap_header *eap_header; 309 | 310 | eth_header = (struct ether_header*) &recv[0]; 311 | eap_header = (struct eap_header*) (&recv[0] + sizeof(struct ether_header)); 312 | 313 | EAP_SHOW_PACKET_TYPE("Response, Identity"); 314 | 315 | if (eap_header->eapol_type != 0x00) // EAP Packet 316 | return -1; 317 | 318 | // EAP Request // Request, MD5-Challenge EAP 319 | if (eap_header->eap_code != 0x01 && eap_header->eap_type != 0x04) 320 | return -1; 321 | 322 | EAP_LOG_INFO("Gateway returns: Request, MD5-Challenge EAP" << std::endl); 323 | resp_md5_eap_id = eap_header->eap_id; 324 | resp_md5_attach_key = std::vector(eap_header->eap_md5_value, eap_header->eap_md5_value + EAP_MD5_VALUE_SIZE); 325 | 326 | return 0; 327 | }; 328 | 329 | EAP_HANDLE_ERROR("Response, Identity"); 330 | EAP_AUTO_RETRY("Response, Identity"); 331 | } 332 | 333 | int response_md5_challenge(std::vector gateway_mac) 334 | { 335 | EAP_LOG_INFO("Response, MD5-Challenge EAP." << std::endl); 336 | 337 | std::vector pkt_data(DRCOM_EAP_FRAME_SIZE, 0); 338 | 339 | std::vector eap_resp_md5_ch = { 340 | 0x01, // Version: 802.1X-2001 341 | 0x00, // Type: EAP Packet 342 | 0x00, 0x00, // EAP Length 343 | 0x02, // Code: Reponse 344 | (uint8_t) resp_md5_eap_id, // Id 345 | 0x00, 0x00, // EAP Length 346 | 0x04, // Type: MD5-Challenge EAP 347 | EAP_MD5_VALUE_SIZE // EAP-MD5 Value-Size = 16 348 | }; 349 | 350 | uint16_t eap_length = htons(6 + EAP_MD5_VALUE_SIZE + resp_md5_id.size()); 351 | 352 | memcpy(&eap_resp_md5_ch[2], &eap_length, 2); 353 | memcpy(&eap_resp_md5_ch[6], &eap_length, 2); 354 | 355 | struct ether_header eth_header = get_eth_header(gateway_mac, local_mac); 356 | 357 | memcpy(&pkt_data[0], ð_header, sizeof(eth_header)); 358 | memcpy(&pkt_data[sizeof(eth_header)], &eap_resp_md5_ch[0], eap_resp_md5_ch.size()); 359 | 360 | std::vector eap_key(1 + // EAP Id 361 | key.size() + EAP_MD5_VALUE_SIZE); 362 | eap_key[0] = resp_md5_eap_id; 363 | memcpy(&eap_key[1], &key[0], key.size()); 364 | memcpy(&eap_key[1 + key.size()], &resp_md5_attach_key[0], EAP_MD5_VALUE_SIZE); 365 | 366 | std::vector md5_value = get_md5_digest(eap_key); 367 | memcpy(&pkt_data[sizeof(eth_header) + eap_resp_md5_ch.size()], &md5_value[0], md5_value.size()); 368 | 369 | memcpy(&pkt_data[sizeof(eth_header) + eap_resp_md5_ch.size() + EAP_MD5_VALUE_SIZE], &resp_md5_id[0], resp_md5_id.size()); 370 | 371 | auto handler_success = [&](std::vector recv) -> int { 372 | struct ether_header *eth_header; 373 | struct eap_header *eap_header; 374 | 375 | eth_header = (struct ether_header*) &recv[0]; 376 | eap_header = (struct eap_header*) (&recv[0] + sizeof(struct ether_header)); 377 | 378 | EAP_SHOW_PACKET_TYPE("Response, MD5-Challenge EAP"); 379 | 380 | if (eap_header->eapol_type != 0x00) // EAP Packet 381 | return -1; 382 | 383 | // Request // Success 384 | if (eap_header->eap_code != 0x01 && eap_header->eap_code != 0x03) 385 | return -1; 386 | 387 | if (eap_header->eap_code == 0x01) // Request 388 | { 389 | if (eap_header->eap_type != 0x02) // Notification 390 | return -1; 391 | 392 | std::string noti(ntohs(eap_header->eap_length) - 5, 0); // 1 for NULL Terminator 393 | memcpy(¬i[0], ((uint8_t*)eap_header + 4 + 5), // 4 - EAPol Header, 5 - EAP Header 394 | ntohs(eap_header->eap_length) - 5); 395 | 396 | EAP_LOG_INFO("Gateway returns: Request, Notification: " << noti << std::endl); 397 | 398 | if (!noti.compare("userid error1")) 399 | EAP_LOG_INFO("Tips: Account or password authentication fails, the system does not exist in this account." << std::endl); 400 | 401 | if (!noti.compare("userid error3")) 402 | EAP_LOG_INFO("Tips: Account or password authentication fails, the system does not exist in this account or your account has arrears down." << std::endl); 403 | 404 | logoff(gateway_mac); // Need to send a logoff, or the gateway will always send notification 405 | 406 | return 1; // Don't retry when notification 407 | } 408 | 409 | // In fact, this condition is always true 410 | if (eap_header->eap_code == 0x03) // Success 411 | EAP_LOG_INFO("Gateway returns: Success" << std::endl); 412 | 413 | return 0; 414 | }; 415 | 416 | EAP_HANDLE_ERROR("Response, MD5-Challenge EAP"); 417 | EAP_AUTO_RETRY("Response, MD5-Challenge EAP"); 418 | } 419 | 420 | struct ether_header get_eth_header(std::vector gateway_mac, std::vector local_mac) 421 | { 422 | struct ether_header eth_header; 423 | 424 | memcpy(eth_header.ether_dhost, &gateway_mac[0], 6); 425 | memcpy(eth_header.ether_shost, &local_mac[0], 6); 426 | eth_header.ether_type = htons(0x888e); // 802.1X Authentication (0x888e) 427 | 428 | return eth_header; 429 | } 430 | 431 | private: 432 | pcap_dealer pcap; 433 | 434 | // Const 435 | std::vector local_mac; 436 | std::vector resp_id, resp_md5_id, key; 437 | 438 | // Recved from Request, Identity 439 | int resp_eap_id; 440 | 441 | // Recved from Request, MD5-Challenge EAP 442 | int resp_md5_eap_id; 443 | std::vector resp_md5_attach_key; 444 | }; 445 | #endif // __INCLUDE_EAP_DEALER__ 446 | -------------------------------------------------------------------------------- /EasyDrcom/easy_drcom_exception.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014 Shindo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __INCLUDE_EASYDRCOMEXCEPTION__ 18 | #define __INCLUDE_EASYDRCOMEXCEPTION__ 19 | 20 | class easy_drcom_exception : public std::exception 21 | { 22 | public: 23 | easy_drcom_exception(const std::string& message) : message(message) { } 24 | easy_drcom_exception(const std::string& message, int err) { 25 | std::stringstream stream; 26 | stream << message << ", errno = " << err << ", desc: " << strerror(err); 27 | this->message = stream.str(); 28 | } 29 | const char* what() const throw() { return message.c_str(); } 30 | 31 | ~easy_drcom_exception() throw() {} 32 | 33 | private: 34 | std::string message; 35 | }; 36 | 37 | #endif // __INCLUDE_EASYDRCOMEXCEPTION__ -------------------------------------------------------------------------------- /EasyDrcom/get_nic_addr.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014 Shindo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #if defined(WIN32) 18 | #include 19 | #include 20 | #elif defined(__APPLE__) 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #elif defined(LINUX) || defined(linux) 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #endif 35 | 36 | #if defined(WIN32) || defined(UNDER_CE) 37 | std::vector get_mac_address(std::string nic) 38 | { 39 | std::vector ret(6, 0); 40 | IP_ADAPTER_INFO AdapterInfo[16]; // Allocate information 41 | DWORD dwBufLen = sizeof(AdapterInfo); // Save memory size of buffer 42 | 43 | if(GetAdaptersInfo(AdapterInfo, &dwBufLen) == ERROR_SUCCESS) 44 | { 45 | bool found = false; 46 | for (auto ptr = AdapterInfo; ptr != NULL; ptr = ptr->Next) 47 | if (strstr(nic.c_str(), ptr->AdapterName)) 48 | { 49 | memcpy(&ret[0], ptr->Address, 6); 50 | found = true; break; 51 | } 52 | 53 | if (!found) 54 | throw easy_drcom_exception("get_mac_address: NIC '" + nic + "' not found"); 55 | } 56 | else 57 | throw easy_drcom_exception("get_mac_address: GetAdaptersInfo failed"); 58 | 59 | return ret; 60 | } 61 | #elif defined(__APPLE__) 62 | std::vector get_mac_address(std::string nic) 63 | { 64 | int mib[6] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 }; 65 | size_t len; 66 | char* buf; 67 | uint8_t *ptr; 68 | struct if_msghdr *ifm; 69 | struct sockaddr_dl *sdl; 70 | std::vector ret(6, 0); 71 | 72 | 73 | if ((mib[5] = if_nametoindex(nic.c_str())) == 0) 74 | throw easy_drcom_exception("get_mac_address: if_nametoindex failed", errno); 75 | 76 | if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) 77 | throw easy_drcom_exception("get_mac_address: sysctl failed", errno); 78 | 79 | buf = new char[len]; 80 | if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) 81 | throw easy_drcom_exception("get_mac_address: sysctl failed", errno); 82 | 83 | ifm = (struct if_msghdr *) buf; 84 | sdl = (struct sockaddr_dl *)(ifm + 1); 85 | ptr = (uint8_t *) LLADDR(sdl); 86 | 87 | memcpy(&ret[0], ptr, 6); 88 | delete buf; 89 | return ret; 90 | } 91 | #elif defined(LINUX) || defined(linux) 92 | std::vector get_mac_address(std::string nic) 93 | { 94 | int sock; 95 | struct ifreq dev; 96 | 97 | if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 98 | throw easy_drcom_exception("get_mac_address: socket failed", errno); 99 | 100 | strncpy(dev.ifr_name, nic.c_str(), sizeof(dev.ifr_name)); 101 | dev.ifr_name[sizeof(dev.ifr_name)-1] = '\0'; 102 | 103 | if (ioctl(sock, SIOCGIFHWADDR, &dev) < 0) 104 | throw easy_drcom_exception("get_mac_address: ioctl failed", errno); 105 | 106 | std::vector ret(6, 0); 107 | memcpy(&ret[0], dev.ifr_hwaddr.sa_data, 6); 108 | return ret; 109 | } 110 | #else 111 | #error "get_mac_address: platform is not supported." 112 | #endif 113 | 114 | 115 | #if defined(WIN32) 116 | std::string get_ip_address(std::string nic) 117 | { 118 | std::string ip; 119 | 120 | IP_ADAPTER_INFO AdapterInfo[16]; // Allocate information 121 | DWORD dwBufLen = sizeof(AdapterInfo); // Save memory size of buffer 122 | 123 | if(GetAdaptersInfo(AdapterInfo, &dwBufLen) == ERROR_SUCCESS) 124 | { 125 | bool found = false; 126 | for (auto ptr = AdapterInfo; ptr != NULL; ptr = ptr->Next) 127 | if (strstr(nic.c_str(), ptr->AdapterName)) 128 | { 129 | ip = ptr->IpAddressList.IpAddress.String; 130 | found = true; break; 131 | } 132 | 133 | if (!found) 134 | throw easy_drcom_exception("get_ip_address: NIC '" + nic + "' not found"); 135 | } 136 | else 137 | throw easy_drcom_exception("get_ip_address: GetAdaptersInfo failed"); 138 | 139 | return ip; 140 | } 141 | #elif defined(__APPLE__) || defined(LINUX) || defined(linux) 142 | std::string get_ip_address(std::string nic) 143 | { 144 | struct ifaddrs *ifaddr = NULL; 145 | std::string ip; 146 | 147 | if (getifaddrs(&ifaddr) < 0) 148 | throw easy_drcom_exception("get_ip_address: getifaddrs failed", errno); 149 | 150 | bool found = false; 151 | for (auto ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) 152 | { 153 | if (!strcmp(ifa->ifa_name, nic.c_str())) 154 | if (ifa->ifa_addr->sa_family == AF_INET) // only deal with IPv4 155 | { 156 | ip = inet_ntoa(((struct sockaddr_in*)ifa->ifa_addr)->sin_addr); 157 | found = true; break; 158 | } 159 | } 160 | 161 | if (!found) 162 | throw easy_drcom_exception("get_ip_address: NIC '" + nic + "' not found."); 163 | 164 | return ip; 165 | } 166 | #else 167 | #error "get_ip_address: platform is not supported." 168 | #endif -------------------------------------------------------------------------------- /EasyDrcom/log.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014 Shindo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __INCLUDE_LOG__ 18 | #define __INCLUDE_LOG__ 19 | 20 | std::string log_now() 21 | { 22 | time_t now = time(NULL); 23 | auto tm = localtime(&now); 24 | 25 | char buf[128]; 26 | sprintf(buf, "%4d-%02d-%02d %02d:%02d:%02d", 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); 27 | 28 | std::string str(buf); 29 | return str; 30 | } 31 | 32 | #define LOG { \ 33 | std::stringstream for_log_use_stream; \ 34 | for_log_use_stream 35 | 36 | #define PRINT_INFO \ 37 | std::clog << log_now() << " " << for_log_use_stream.str(); \ 38 | std::cout << for_log_use_stream.str(); 39 | #define PRINT_ERR \ 40 | std::clog << log_now() << " " << for_log_use_stream.str(); \ 41 | std::cerr << for_log_use_stream.str(); 42 | #ifdef EASYDRCOM_PRINT_DBG_ON_SCREEN 43 | #define PRINT_DBG \ 44 | std::clog << log_now() << " " << for_log_use_stream.str(); \ 45 | std::cout << for_log_use_stream.str(); 46 | #else 47 | #define PRINT_DBG \ 48 | std::clog << log_now() << " " << for_log_use_stream.str(); 49 | #endif 50 | 51 | #define LOG_INFO(section, info) \ 52 | LOG << "[" << section << " Info] " << info; PRINT_INFO } 53 | #define LOG_ERR(section, err) \ 54 | LOG << "[" << section << " Error] " << err; PRINT_ERR } 55 | #ifdef EASYDRCOM_DEBUG 56 | #define LOG_DBG(section, db) \ 57 | LOG << "[" << section << " Debug] " << db; PRINT_DBG } 58 | #else 59 | #define LOG_DBG(db) 60 | #endif 61 | 62 | #define U31_LOG_INFO(info) LOG_INFO("U31", info) 63 | #define U31_LOG_ERR(err) LOG_ERR("U31", err) 64 | #define U31_LOG_DBG(db) LOG_DBG("U31", db) 65 | 66 | #define U62_LOG_INFO(info) LOG_INFO("U62", info) 67 | #define U62_LOG_ERR(err) LOG_ERR("U62", err) 68 | #define U62_LOG_DBG(db) LOG_DBG("U62", db) 69 | 70 | #define EAP_LOG_INFO(info) LOG_INFO("EAP", info) 71 | #define EAP_LOG_ERR(err) LOG_ERR("EAP", err) 72 | #define EAP_LOG_DBG(db) LOG_DBG("EAP", db) 73 | 74 | #define SYS_LOG_INFO(info) LOG_INFO("EasyDrcom", info) 75 | #define SYS_LOG_ERR(err) LOG_ERR("EasyDrcom", err) 76 | #define SYS_LOG_DBG(db) LOG_DBG("EasyDrcom", db) 77 | 78 | #endif // __INCLUDE_LOG__ 79 | -------------------------------------------------------------------------------- /EasyDrcom/main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014 Shindo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #if defined(__APPLE__) || defined(LINUX) || defined(linux) 34 | #include 35 | #include 36 | #include 37 | #include 38 | #endif 39 | 40 | #include "easy_drcom_exception.hpp" 41 | 42 | struct easy_drcom_config { 43 | struct config_general { 44 | int mode; 45 | std::string username; 46 | std::string password; 47 | bool auto_online; 48 | bool auto_redial; 49 | } general; 50 | 51 | struct config_remote { 52 | std::string ip; 53 | uint32_t port; 54 | 55 | bool use_broadcast; 56 | std::vector mac; 57 | } remote; 58 | 59 | struct config_local { 60 | std::string nic; 61 | std::string hostname; 62 | std::string kernel_version; 63 | 64 | std::string ip; 65 | std::vector mac; 66 | 67 | uint32_t eap_timeout; 68 | uint32_t udp_timeout; 69 | } local; 70 | 71 | struct config_fake { 72 | bool enable; 73 | std::vector mac; 74 | std::string username; 75 | std::string password; 76 | } fake; 77 | } conf; 78 | 79 | // Log Config 80 | #define EASYDRCOM_DEBUG 81 | //#define EASYDRCOM_PRINT_DBG_ON_SCREEN 82 | #include "log.hpp" 83 | 84 | #define MAX_RETRY_TIME 2 85 | #include "utils.hpp" 86 | #include "drcom_dealer.hpp" 87 | #include "eap_dealer.hpp" 88 | 89 | #define MAJOR_VERSION "v0.9" 90 | 91 | #if defined (WIN32) 92 | #define VERSION (MAJOR_VERSION " for Windows") 93 | #elif defined __APPLE__ 94 | #define VERSION (MAJOR_VERSION " for Mac OSX") 95 | #elif defined (OPENWRT) 96 | #define VERSION (MAJOR_VERSION " for OpenWrt (mips AR7xxx/9xxx)") 97 | #elif defined (LINUX) 98 | #define VERSION (MAJOR_VERSION " for Linux") 99 | #endif 100 | 101 | int read_config(std::string path) 102 | { 103 | boost::property_tree::ptree pt; 104 | try { 105 | boost::property_tree::ini_parser::read_ini(path, pt); 106 | conf.general.mode = pt.get("General.Mode"); 107 | conf.general.username = pt.get("General.UserName"); 108 | conf.general.password = pt.get("General.PassWord"); 109 | conf.local.nic = pt.get("Local.NIC"); 110 | } 111 | catch (std::exception& e) { 112 | SYS_LOG_ERR("Failed to read '" << path << "' - " << e.what() << std::endl); 113 | return EBADF; 114 | } 115 | 116 | conf.general.auto_online = pt.get("General.AutoOnline", true); 117 | conf.general.auto_redial = pt.get("General.AutoRedial", true); 118 | 119 | conf.remote.ip = pt.get("Remote.IP", "172.25.8.4"); 120 | conf.remote.port = pt.get("Remote.Port", 61440); 121 | conf.remote.use_broadcast = pt.get("Remote.UseBroadcast", true); 122 | 123 | if (!conf.remote.use_broadcast) 124 | conf.remote.mac = str_mac_to_vec(pt.get("Remote.MAC", "00:1a:a9:c3:3a:59")); 125 | 126 | conf.local.hostname = pt.get("Local.HostName", "EasyDrcom for HITwh"); 127 | conf.local.kernel_version = pt.get("Local.KernelVersion", VERSION); 128 | 129 | conf.local.eap_timeout = pt.get("Local.EAPTimeout", 1000); 130 | conf.local.udp_timeout = pt.get("Local.UDPTimeout", 2000); 131 | 132 | conf.fake.enable = pt.get("Fake.Enable", 0); 133 | 134 | SYS_LOG_DBG("General.UserName = " << conf.general.username << ", General.PassWord = " << conf.general.password << ", General.Mode = " << conf.general.mode << std::endl); 135 | SYS_LOG_DBG("General.AutoOnline = " << (conf.general.auto_online ? "True" : "False") << ", General.AutoRedial = " << (conf.general.auto_redial ? "True" : "False" ) << std::endl); 136 | SYS_LOG_DBG("Remote.IP:Port = " << conf.remote.ip << ":" << conf.remote.port << ", Remote.UseBroadcast = " << (conf.remote.use_broadcast ? "True" : "False" ) << std::endl); 137 | if (!conf.remote.use_broadcast) SYS_LOG_DBG("Remote.MAC = " << hex_to_str(&conf.remote.mac[0], 6, ':') << std::endl); 138 | SYS_LOG_DBG("Local.NIC = " << conf.local.nic << ", Local.HostName = " << conf.local.hostname << ", Local.KernelVersion = " << conf.local.kernel_version << std::endl); 139 | SYS_LOG_DBG("Local.EAPTimeout = " << conf.local.eap_timeout << ", Local.UDPTimeout = " << conf.local.udp_timeout << std::endl); 140 | 141 | try { 142 | conf.local.ip = get_ip_address(conf.local.nic); 143 | conf.local.mac = get_mac_address(conf.local.nic); 144 | 145 | SYS_LOG_INFO("Fetch NIC IP & MAC successfully." << std::endl); 146 | SYS_LOG_INFO("Local.IP = " << conf.local.ip << ", Local.MAC = " << hex_to_str(&conf.local.mac[0], 6, ':') << std::endl); 147 | } 148 | catch (std::exception& e) { 149 | SYS_LOG_ERR("Failed to fetch NIC info - " << e.what() << std::endl); 150 | return EBADF; 151 | } 152 | 153 | if (conf.fake.enable) // fake user 154 | { 155 | try { 156 | conf.fake.mac = str_mac_to_vec(pt.get("Fake.MAC")); 157 | conf.fake.username = pt.get("Fake.UserName"); 158 | conf.fake.password = pt.get("Fake.PassWord"); 159 | } 160 | catch (std::exception& e) { 161 | SYS_LOG_ERR("Failed to read fake settings - " << e.what() << std::endl); 162 | return EBADF; 163 | } 164 | 165 | SYS_LOG_INFO("Fetch fake settings successfully." << std::endl); 166 | SYS_LOG_INFO("Fake.MAC = " << hex_to_str(&conf.fake.mac[0], 6, ':') << ", Fake.UserName = " << conf.fake.username << ", Fake.PassWord = " << conf.fake.password << std::endl); 167 | 168 | } 169 | SYS_LOG_INFO("Loaded config successfully." << std::endl); 170 | 171 | return 0; 172 | } 173 | 174 | std::shared_ptr eap; 175 | std::shared_ptr drcom; 176 | 177 | enum ONLINE_STATE 178 | { 179 | OFFLINE_PROCESSING, 180 | OFFLINE_NOTIFY, 181 | OFFLINE, 182 | ONLINE_PROCESSING, 183 | ONLINE, 184 | }; 185 | ONLINE_STATE state = OFFLINE; 186 | 187 | std::mutex mtx; 188 | std::condition_variable cv; 189 | 190 | std::vector broadcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 191 | std::vector nearest_mac = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; 192 | 193 | void online_func() 194 | { 195 | do 196 | { 197 | try 198 | { 199 | do 200 | { 201 | state = ONLINE_PROCESSING; 202 | try 203 | { 204 | if (conf.general.mode != 1) // 宿舍区认证模式 205 | { 206 | if (conf.remote.use_broadcast) 207 | { 208 | eap->logoff(nearest_mac); 209 | eap->logoff(nearest_mac); 210 | 211 | if (eap->start(broadcast_mac)) break; 212 | if (eap->response_identity(broadcast_mac)) break; 213 | if (eap->response_md5_challenge(broadcast_mac)) break; 214 | } 215 | else 216 | { 217 | eap->logoff(conf.remote.mac); 218 | eap->logoff(conf.remote.mac); 219 | 220 | if (eap->start(conf.remote.mac)) break; 221 | if (eap->response_identity(conf.remote.mac)) break; 222 | if (eap->response_md5_challenge(conf.remote.mac)) break; 223 | } 224 | } 225 | 226 | if (conf.general.mode <= 1) // U31.R0 227 | { 228 | std::shared_ptr dealer = std::dynamic_pointer_cast(drcom); 229 | 230 | if (dealer->start_request()) break; 231 | if (dealer->send_login_auth()) break; 232 | } 233 | else // U62.R0 234 | { 235 | std::shared_ptr dealer = std::dynamic_pointer_cast(drcom); 236 | } 237 | 238 | while (true && state != OFFLINE_PROCESSING) // Keep Alive 239 | { 240 | try 241 | { 242 | if (conf.general.mode <= 1) // U31.R0 243 | { 244 | std::shared_ptr dealer = std::dynamic_pointer_cast(drcom); 245 | 246 | if (dealer->send_alive_request()) break; 247 | if (dealer->send_alive_pkt1()) break; 248 | if (dealer->send_alive_pkt2()) break; 249 | } 250 | else // U62.R0 251 | { 252 | std::shared_ptr dealer = std::dynamic_pointer_cast(drcom); 253 | 254 | if (dealer->send_alive_pkt1()) break; 255 | if (dealer->send_alive_pkt2()) break; 256 | } 257 | 258 | state = ONLINE; 259 | 260 | std::unique_lock lock(mtx); 261 | cv.wait_for(lock, std::chrono::seconds(20)); 262 | } 263 | catch (std::exception& e) 264 | { 265 | state = OFFLINE; 266 | SYS_LOG_ERR("Keep Alive: " << e.what() << std::endl); 267 | break; 268 | } 269 | } 270 | } 271 | catch (std::exception& e) 272 | { 273 | state = OFFLINE; 274 | SYS_LOG_ERR("Go Online: " << e.what() << std::endl); 275 | break; 276 | } 277 | 278 | if (state != OFFLINE_PROCESSING) 279 | state = OFFLINE; 280 | } 281 | while (false); // run once 282 | 283 | if (state != OFFLINE_PROCESSING) 284 | { 285 | SYS_LOG_INFO("Connection broken, try to redial after 5 seconds." << std::endl); 286 | std::this_thread::sleep_for(std::chrono::seconds(5)); 287 | } 288 | } 289 | catch (std::exception& e) 290 | { 291 | SYS_LOG_ERR("Thread Online: " << e.what() << std::endl); 292 | } 293 | } while (conf.general.auto_redial && state != OFFLINE_PROCESSING); // auto redial 294 | 295 | std::unique_lock lock(mtx); 296 | state = OFFLINE_NOTIFY; 297 | cv.notify_one(); 298 | } 299 | 300 | void offline_func() 301 | { 302 | try 303 | { 304 | state = OFFLINE_PROCESSING; 305 | 306 | std::unique_lock lock(mtx); 307 | cv.notify_one(); 308 | 309 | while (state != OFFLINE_NOTIFY) 310 | cv.wait(lock); // wait for signal 311 | 312 | if (conf.general.mode <= 1) // U31.R0 313 | { 314 | std::shared_ptr dealer = std::dynamic_pointer_cast(drcom); 315 | 316 | dealer->send_alive_request(); 317 | dealer->start_request(); 318 | dealer->send_logout_auth(); 319 | } 320 | // U62.R0 needn't do anything 321 | } 322 | catch (std::exception& e) 323 | { 324 | SYS_LOG_ERR("Go Offline: " << e.what() << std::endl); 325 | } 326 | 327 | if (conf.general.mode == 0 || conf.general.mode == 2) // 宿舍区 328 | { 329 | if (conf.remote.use_broadcast) 330 | { 331 | eap->logoff(broadcast_mac); 332 | eap->logoff(nearest_mac); 333 | } 334 | else 335 | { 336 | eap->logoff(conf.remote.mac); 337 | } 338 | } 339 | 340 | state = OFFLINE; 341 | SYS_LOG_INFO("Offline." << std::endl); 342 | } 343 | 344 | int main(int argc, const char * argv[]) 345 | { 346 | int ret = 0; 347 | bool background = false, redirect_to_null = false; 348 | std::string config_path = "EasyDrcom.conf"; 349 | auto clog_def = std::clog.rdbuf(); 350 | auto cout_def = std::cout.rdbuf(); 351 | auto cerr_def = std::cerr.rdbuf(); 352 | #ifdef OPENWRT 353 | std::string log_path = "/tmp/EasyDrcom.log"; 354 | #else 355 | std::string log_path = "EasyDrcom.log"; 356 | #endif 357 | 358 | for (int i = 1; i < argc; i++) 359 | { 360 | if (!strcmp(argv[i], "-b")) 361 | background = true; 362 | else if (!strcmp(argv[i], "-r")) 363 | redirect_to_null = true; 364 | else if (!strcmp(argv[i], "-c")) 365 | { 366 | if (i + 1 < argc) 367 | config_path = argv[i+1]; 368 | } 369 | else if (!strcmp(argv[i], "-o")) 370 | { 371 | if (i + 1 < argc) 372 | log_path = argv[i+1]; 373 | } 374 | } 375 | 376 | std::ofstream log(log_path); 377 | if (!log.is_open()) 378 | { 379 | std::cerr << "[Error] Failed to open log '" << log_path << "', quitting..." << std::endl; 380 | return ENOENT; 381 | } 382 | std::clog.rdbuf(log.rdbuf()); 383 | 384 | std::ofstream null("/dev/null"); 385 | if (redirect_to_null) 386 | { 387 | std::cout.rdbuf(null.rdbuf()); 388 | std::cerr.rdbuf(null.rdbuf()); 389 | } 390 | 391 | SYS_LOG_INFO("EasyDrcom " << VERSION << " (build on " << __DATE__ << " " << __TIME__ << ")" << std::endl); 392 | SYS_LOG_INFO("Code by Shindo, Contributors: mylight, SwimmingTiger." << std::endl << std::endl); 393 | SYS_LOG_INFO("Initializing..." << std::endl); 394 | SYS_LOG_INFO("Loading config from '" << config_path << "'..." << std::endl); 395 | 396 | // Initialization 397 | if ((ret = read_config(config_path)) != 0) 398 | goto end; 399 | 400 | 401 | #if defined(WIN32) 402 | WSADATA wsa; 403 | WSAStartup(MAKEWORD(2, 2), &wsa); 404 | #endif 405 | 406 | try 407 | { 408 | eap = std::shared_ptr(new eap_dealer(conf.local.nic, conf.local.mac, conf.local.ip, conf.general.username, conf.general.password)); // the fucking "Segmentation fault", so we must have to use this line all the time!!! 409 | 410 | if (!conf.fake.enable) 411 | { 412 | if (conf.general.mode <= 1) // U31.R0 413 | drcom = std::shared_ptr(new drcom_dealer_u31(conf.local.mac, conf.local.ip, conf.general.username, conf.general.password, conf.remote.ip, conf.remote.port, conf.local.hostname, conf.local.kernel_version)); 414 | else // U62.R0 415 | drcom = std::shared_ptr(new drcom_dealer_u62(conf.local.mac, conf.local.ip, conf.general.username, conf.general.password, conf.remote.ip, conf.remote.port, conf.local.hostname, conf.local.kernel_version)); 416 | } 417 | else 418 | { 419 | if (conf.general.mode <= 1) // U31.R0 420 | drcom = std::shared_ptr(new drcom_dealer_u31(conf.fake.mac, conf.local.ip, conf.fake.username, conf.fake.password, conf.remote.ip, conf.remote.port, conf.local.hostname, conf.local.kernel_version)); 421 | else // U62.R0 422 | drcom = std::shared_ptr(new drcom_dealer_u62(conf.fake.mac, conf.local.ip, conf.fake.username, conf.fake.password, conf.remote.ip, conf.remote.port, conf.local.hostname, conf.local.kernel_version)); 423 | } 424 | } 425 | catch (std::exception& e) 426 | { 427 | SYS_LOG_ERR(e.what() << std::endl); 428 | ret = ENETRESET; 429 | goto end; 430 | } 431 | 432 | SYS_LOG_INFO("Initialization done!" << std::endl); 433 | 434 | if (background) 435 | { 436 | SYS_LOG_INFO("Start in background, turn on Auto Online & Auto Redial." << std::endl); 437 | conf.general.auto_online = true; 438 | conf.general.auto_redial = true; 439 | } 440 | 441 | if (!background) 442 | SYS_LOG_INFO("Enter 'help' to get help." << std::endl); 443 | 444 | if (!conf.general.auto_online) 445 | { 446 | SYS_LOG_INFO("Enter 'online' to go online!" << std::endl); 447 | } 448 | else 449 | { 450 | SYS_LOG_INFO("Going online..." << std::endl); 451 | std::thread(online_func).detach(); 452 | } 453 | 454 | if (background) 455 | { 456 | std::thread(online_func).join(); 457 | } 458 | else 459 | { 460 | // Command Loop 461 | std::string cmd; 462 | while (true) 463 | { 464 | std::cin >> cmd; 465 | if (!cmd.compare("online")) 466 | { 467 | if (state == ONLINE) 468 | { 469 | SYS_LOG_INFO("Already online!" << std::endl); 470 | } 471 | else if (state == ONLINE_PROCESSING) 472 | { 473 | SYS_LOG_INFO("Online Processing!" << std::endl); 474 | } 475 | else if (state == OFFLINE_PROCESSING || state == OFFLINE_NOTIFY) 476 | { 477 | SYS_LOG_INFO("Offline Processing!" << std::endl); 478 | } 479 | else if (state == OFFLINE) 480 | { 481 | SYS_LOG_INFO("Going online..." << std::endl); 482 | std::thread(online_func).detach(); 483 | } 484 | } 485 | else if (!cmd.compare("offline")) 486 | { 487 | if (state == OFFLINE) 488 | { 489 | SYS_LOG_INFO("Haven't been online!" << std::endl); 490 | } 491 | else if (state == ONLINE_PROCESSING) 492 | { 493 | SYS_LOG_INFO("Online Processing!" << std::endl); 494 | } 495 | else if (state == OFFLINE_PROCESSING) 496 | { 497 | SYS_LOG_INFO("Offline Processing!" << std::endl); 498 | } 499 | else if (state == ONLINE) 500 | { 501 | SYS_LOG_INFO("Going offline..." << std::endl); 502 | std::thread(offline_func).detach(); 503 | } 504 | } 505 | else if (!cmd.compare("quit")) 506 | { 507 | if (state == ONLINE_PROCESSING) 508 | { 509 | SYS_LOG_INFO("Please wait for online processing finished." << std::endl); 510 | continue; 511 | } 512 | 513 | if (state == OFFLINE_PROCESSING) 514 | { 515 | SYS_LOG_INFO("Please wait for offline processing finished." << std::endl); 516 | continue; 517 | } 518 | 519 | if (state == ONLINE) 520 | { 521 | SYS_LOG_INFO("Going offline..." << std::endl); 522 | offline_func(); 523 | } 524 | 525 | SYS_LOG_INFO("Quitting..." << std::endl); 526 | std::cout << "[EasyDrcom Info] Bye Bye!" << std::endl; 527 | break; 528 | } 529 | else if (!cmd.compare("help")) 530 | { 531 | SYS_LOG_INFO("EasyDrcom " << VERSION << " (build on " << __DATE__ << " " << __TIME__ << ")" << std::endl); 532 | SYS_LOG_INFO("Code by Shindo, Contributors: mylight, SwimmingTiger." << std::endl << std::endl); 533 | SYS_LOG_INFO("Command list:" << std::endl); 534 | SYS_LOG_INFO("online - go online." << std::endl); 535 | SYS_LOG_INFO("offline - go offline." << std::endl); 536 | SYS_LOG_INFO("quit - quit EasyDrcom." << std::endl); 537 | } 538 | else 539 | { 540 | SYS_LOG_INFO("Wrong command: " << cmd << std::endl); 541 | } 542 | } 543 | } 544 | 545 | end: 546 | std::cout.rdbuf(cout_def); 547 | std::cerr.rdbuf(cerr_def); 548 | std::clog.rdbuf(clog_def); 549 | 550 | log.close(); 551 | null.close(); 552 | 553 | #if defined (WIN32) 554 | WSACleanup(); 555 | #endif 556 | return ret; 557 | } 558 | -------------------------------------------------------------------------------- /EasyDrcom/md5.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. 3 | 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, 9 | including commercial applications, and to alter it and redistribute it 10 | freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must not 13 | claim that you wrote the original software. If you use this software 14 | in a product, an acknowledgment in the product documentation would be 15 | appreciated but is not required. 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 3. This notice may not be removed or altered from any source distribution. 19 | 20 | L. Peter Deutsch 21 | ghost@aladdin.com 22 | 23 | */ 24 | /* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ 25 | /* 26 | Independent implementation of MD5 (RFC 1321). 27 | 28 | This code implements the MD5 Algorithm defined in RFC 1321, whose 29 | text is available at 30 | http://www.ietf.org/rfc/rfc1321.txt 31 | The code is derived from the text of the RFC, including the test suite 32 | (section A.5) but excluding the rest of Appendix A. It does not include 33 | any code or documentation that is identified in the RFC as being 34 | copyrighted. 35 | 36 | The original and principal author of md5.c is L. Peter Deutsch 37 | . Other authors are noted in the change history 38 | that follows (in reverse chronological order): 39 | 40 | 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order 41 | either statically or dynamically; added missing #include 42 | in library. 43 | 2002-03-11 lpd Corrected argument list for main(), and added int return 44 | type, in test program and T value program. 45 | 2002-02-21 lpd Added missing #include in test program. 46 | 2000-07-03 lpd Patched to eliminate warnings about "constant is 47 | unsigned in ANSI C, signed in traditional"; made test program 48 | self-checking. 49 | 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 50 | 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 51 | 1999-05-03 lpd Original version. 52 | */ 53 | 54 | #include "md5.h" 55 | #include 56 | 57 | #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ 58 | #ifdef ARCH_IS_BIG_ENDIAN 59 | # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) 60 | #else 61 | # define BYTE_ORDER 0 62 | #endif 63 | 64 | #define T_MASK ((md5_word_t)~0) 65 | #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) 66 | #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) 67 | #define T3 0x242070db 68 | #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) 69 | #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) 70 | #define T6 0x4787c62a 71 | #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) 72 | #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) 73 | #define T9 0x698098d8 74 | #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) 75 | #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) 76 | #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) 77 | #define T13 0x6b901122 78 | #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) 79 | #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) 80 | #define T16 0x49b40821 81 | #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) 82 | #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) 83 | #define T19 0x265e5a51 84 | #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) 85 | #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) 86 | #define T22 0x02441453 87 | #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) 88 | #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) 89 | #define T25 0x21e1cde6 90 | #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) 91 | #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) 92 | #define T28 0x455a14ed 93 | #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) 94 | #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) 95 | #define T31 0x676f02d9 96 | #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) 97 | #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) 98 | #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) 99 | #define T35 0x6d9d6122 100 | #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) 101 | #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) 102 | #define T38 0x4bdecfa9 103 | #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) 104 | #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) 105 | #define T41 0x289b7ec6 106 | #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) 107 | #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) 108 | #define T44 0x04881d05 109 | #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) 110 | #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) 111 | #define T47 0x1fa27cf8 112 | #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) 113 | #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) 114 | #define T50 0x432aff97 115 | #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) 116 | #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) 117 | #define T53 0x655b59c3 118 | #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) 119 | #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) 120 | #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) 121 | #define T57 0x6fa87e4f 122 | #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) 123 | #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) 124 | #define T60 0x4e0811a1 125 | #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) 126 | #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) 127 | #define T63 0x2ad7d2bb 128 | #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) 129 | 130 | 131 | static void 132 | md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) 133 | { 134 | md5_word_t 135 | a = pms->abcd[0], b = pms->abcd[1], 136 | c = pms->abcd[2], d = pms->abcd[3]; 137 | md5_word_t t; 138 | #if BYTE_ORDER > 0 139 | /* Define storage only for big-endian CPUs. */ 140 | md5_word_t X[16]; 141 | #else 142 | /* Define storage for little-endian or both types of CPUs. */ 143 | md5_word_t xbuf[16]; 144 | const md5_word_t *X; 145 | #endif 146 | 147 | { 148 | #if BYTE_ORDER == 0 149 | /* 150 | * Determine dynamically whether this is a big-endian or 151 | * little-endian machine, since we can use a more efficient 152 | * algorithm on the latter. 153 | */ 154 | static const int w = 1; 155 | 156 | if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ 157 | #endif 158 | #if BYTE_ORDER <= 0 /* little-endian */ 159 | { 160 | /* 161 | * On little-endian machines, we can process properly aligned 162 | * data without copying it. 163 | */ 164 | if (!((data - (const md5_byte_t *)0) & 3)) { 165 | /* data are properly aligned */ 166 | X = (const md5_word_t *)data; 167 | } else { 168 | /* not aligned */ 169 | memcpy(xbuf, data, 64); 170 | X = xbuf; 171 | } 172 | } 173 | #endif 174 | #if BYTE_ORDER == 0 175 | else /* dynamic big-endian */ 176 | #endif 177 | #if BYTE_ORDER >= 0 /* big-endian */ 178 | { 179 | /* 180 | * On big-endian machines, we must arrange the bytes in the 181 | * right order. 182 | */ 183 | const md5_byte_t *xp = data; 184 | int i; 185 | 186 | # if BYTE_ORDER == 0 187 | X = xbuf; /* (dynamic only) */ 188 | # else 189 | # define xbuf X /* (static only) */ 190 | # endif 191 | for (i = 0; i < 16; ++i, xp += 4) 192 | xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); 193 | } 194 | #endif 195 | } 196 | 197 | #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) 198 | 199 | /* Round 1. */ 200 | /* Let [abcd k s i] denote the operation 201 | a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ 202 | #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) 203 | #define SET(a, b, c, d, k, s, Ti)\ 204 | t = a + F(b,c,d) + X[k] + Ti;\ 205 | a = ROTATE_LEFT(t, s) + b 206 | /* Do the following 16 operations. */ 207 | SET(a, b, c, d, 0, 7, T1); 208 | SET(d, a, b, c, 1, 12, T2); 209 | SET(c, d, a, b, 2, 17, T3); 210 | SET(b, c, d, a, 3, 22, T4); 211 | SET(a, b, c, d, 4, 7, T5); 212 | SET(d, a, b, c, 5, 12, T6); 213 | SET(c, d, a, b, 6, 17, T7); 214 | SET(b, c, d, a, 7, 22, T8); 215 | SET(a, b, c, d, 8, 7, T9); 216 | SET(d, a, b, c, 9, 12, T10); 217 | SET(c, d, a, b, 10, 17, T11); 218 | SET(b, c, d, a, 11, 22, T12); 219 | SET(a, b, c, d, 12, 7, T13); 220 | SET(d, a, b, c, 13, 12, T14); 221 | SET(c, d, a, b, 14, 17, T15); 222 | SET(b, c, d, a, 15, 22, T16); 223 | #undef SET 224 | 225 | /* Round 2. */ 226 | /* Let [abcd k s i] denote the operation 227 | a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ 228 | #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) 229 | #define SET(a, b, c, d, k, s, Ti)\ 230 | t = a + G(b,c,d) + X[k] + Ti;\ 231 | a = ROTATE_LEFT(t, s) + b 232 | /* Do the following 16 operations. */ 233 | SET(a, b, c, d, 1, 5, T17); 234 | SET(d, a, b, c, 6, 9, T18); 235 | SET(c, d, a, b, 11, 14, T19); 236 | SET(b, c, d, a, 0, 20, T20); 237 | SET(a, b, c, d, 5, 5, T21); 238 | SET(d, a, b, c, 10, 9, T22); 239 | SET(c, d, a, b, 15, 14, T23); 240 | SET(b, c, d, a, 4, 20, T24); 241 | SET(a, b, c, d, 9, 5, T25); 242 | SET(d, a, b, c, 14, 9, T26); 243 | SET(c, d, a, b, 3, 14, T27); 244 | SET(b, c, d, a, 8, 20, T28); 245 | SET(a, b, c, d, 13, 5, T29); 246 | SET(d, a, b, c, 2, 9, T30); 247 | SET(c, d, a, b, 7, 14, T31); 248 | SET(b, c, d, a, 12, 20, T32); 249 | #undef SET 250 | 251 | /* Round 3. */ 252 | /* Let [abcd k s t] denote the operation 253 | a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ 254 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 255 | #define SET(a, b, c, d, k, s, Ti)\ 256 | t = a + H(b,c,d) + X[k] + Ti;\ 257 | a = ROTATE_LEFT(t, s) + b 258 | /* Do the following 16 operations. */ 259 | SET(a, b, c, d, 5, 4, T33); 260 | SET(d, a, b, c, 8, 11, T34); 261 | SET(c, d, a, b, 11, 16, T35); 262 | SET(b, c, d, a, 14, 23, T36); 263 | SET(a, b, c, d, 1, 4, T37); 264 | SET(d, a, b, c, 4, 11, T38); 265 | SET(c, d, a, b, 7, 16, T39); 266 | SET(b, c, d, a, 10, 23, T40); 267 | SET(a, b, c, d, 13, 4, T41); 268 | SET(d, a, b, c, 0, 11, T42); 269 | SET(c, d, a, b, 3, 16, T43); 270 | SET(b, c, d, a, 6, 23, T44); 271 | SET(a, b, c, d, 9, 4, T45); 272 | SET(d, a, b, c, 12, 11, T46); 273 | SET(c, d, a, b, 15, 16, T47); 274 | SET(b, c, d, a, 2, 23, T48); 275 | #undef SET 276 | 277 | /* Round 4. */ 278 | /* Let [abcd k s t] denote the operation 279 | a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ 280 | #define I(x, y, z) ((y) ^ ((x) | ~(z))) 281 | #define SET(a, b, c, d, k, s, Ti)\ 282 | t = a + I(b,c,d) + X[k] + Ti;\ 283 | a = ROTATE_LEFT(t, s) + b 284 | /* Do the following 16 operations. */ 285 | SET(a, b, c, d, 0, 6, T49); 286 | SET(d, a, b, c, 7, 10, T50); 287 | SET(c, d, a, b, 14, 15, T51); 288 | SET(b, c, d, a, 5, 21, T52); 289 | SET(a, b, c, d, 12, 6, T53); 290 | SET(d, a, b, c, 3, 10, T54); 291 | SET(c, d, a, b, 10, 15, T55); 292 | SET(b, c, d, a, 1, 21, T56); 293 | SET(a, b, c, d, 8, 6, T57); 294 | SET(d, a, b, c, 15, 10, T58); 295 | SET(c, d, a, b, 6, 15, T59); 296 | SET(b, c, d, a, 13, 21, T60); 297 | SET(a, b, c, d, 4, 6, T61); 298 | SET(d, a, b, c, 11, 10, T62); 299 | SET(c, d, a, b, 2, 15, T63); 300 | SET(b, c, d, a, 9, 21, T64); 301 | #undef SET 302 | 303 | /* Then perform the following additions. (That is increment each 304 | of the four registers by the value it had before this block 305 | was started.) */ 306 | pms->abcd[0] += a; 307 | pms->abcd[1] += b; 308 | pms->abcd[2] += c; 309 | pms->abcd[3] += d; 310 | } 311 | 312 | void 313 | md5_init(md5_state_t *pms) 314 | { 315 | pms->count[0] = pms->count[1] = 0; 316 | pms->abcd[0] = 0x67452301; 317 | pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; 318 | pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; 319 | pms->abcd[3] = 0x10325476; 320 | } 321 | 322 | void 323 | md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) 324 | { 325 | const md5_byte_t *p = data; 326 | int left = nbytes; 327 | int offset = (pms->count[0] >> 3) & 63; 328 | md5_word_t nbits = (md5_word_t)(nbytes << 3); 329 | 330 | if (nbytes <= 0) 331 | return; 332 | 333 | /* Update the message length. */ 334 | pms->count[1] += nbytes >> 29; 335 | pms->count[0] += nbits; 336 | if (pms->count[0] < nbits) 337 | pms->count[1]++; 338 | 339 | /* Process an initial partial block. */ 340 | if (offset) { 341 | int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); 342 | 343 | memcpy(pms->buf + offset, p, copy); 344 | if (offset + copy < 64) 345 | return; 346 | p += copy; 347 | left -= copy; 348 | md5_process(pms, pms->buf); 349 | } 350 | 351 | /* Process full blocks. */ 352 | for (; left >= 64; p += 64, left -= 64) 353 | md5_process(pms, p); 354 | 355 | /* Process a final partial block. */ 356 | if (left) 357 | memcpy(pms->buf, p, left); 358 | } 359 | 360 | void 361 | md5_finish(md5_state_t *pms, md5_byte_t digest[16]) 362 | { 363 | static const md5_byte_t pad[64] = { 364 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 365 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 366 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 367 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 368 | }; 369 | md5_byte_t data[8]; 370 | int i; 371 | 372 | /* Save the length before padding. */ 373 | for (i = 0; i < 8; ++i) 374 | data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); 375 | /* Pad to 56 bytes mod 64. */ 376 | md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); 377 | /* Append the length. */ 378 | md5_append(pms, data, 8); 379 | for (i = 0; i < 16; ++i) 380 | digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); 381 | } 382 | -------------------------------------------------------------------------------- /EasyDrcom/md5.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. 3 | 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, 9 | including commercial applications, and to alter it and redistribute it 10 | freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must not 13 | claim that you wrote the original software. If you use this software 14 | in a product, an acknowledgment in the product documentation would be 15 | appreciated but is not required. 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 3. This notice may not be removed or altered from any source distribution. 19 | 20 | L. Peter Deutsch 21 | ghost@aladdin.com 22 | 23 | */ 24 | /* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ 25 | /* 26 | Independent implementation of MD5 (RFC 1321). 27 | 28 | This code implements the MD5 Algorithm defined in RFC 1321, whose 29 | text is available at 30 | http://www.ietf.org/rfc/rfc1321.txt 31 | The code is derived from the text of the RFC, including the test suite 32 | (section A.5) but excluding the rest of Appendix A. It does not include 33 | any code or documentation that is identified in the RFC as being 34 | copyrighted. 35 | 36 | The original and principal author of md5.h is L. Peter Deutsch 37 | . Other authors are noted in the change history 38 | that follows (in reverse chronological order): 39 | 40 | 2002-04-13 lpd Removed support for non-ANSI compilers; removed 41 | references to Ghostscript; clarified derivation from RFC 1321; 42 | now handles byte order either statically or dynamically. 43 | 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 44 | 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); 45 | added conditionalization for C++ compilation from Martin 46 | Purschke . 47 | 1999-05-03 lpd Original version. 48 | */ 49 | 50 | #ifndef md5_INCLUDED 51 | # define md5_INCLUDED 52 | 53 | /* 54 | * This package supports both compile-time and run-time determination of CPU 55 | * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be 56 | * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is 57 | * defined as non-zero, the code will be compiled to run only on big-endian 58 | * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to 59 | * run on either big- or little-endian CPUs, but will run slightly less 60 | * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. 61 | */ 62 | 63 | typedef unsigned char md5_byte_t; /* 8-bit byte */ 64 | typedef unsigned int md5_word_t; /* 32-bit word */ 65 | 66 | /* Define the state of the MD5 Algorithm. */ 67 | typedef struct md5_state_s { 68 | md5_word_t count[2]; /* message length in bits, lsw first */ 69 | md5_word_t abcd[4]; /* digest buffer */ 70 | md5_byte_t buf[64]; /* accumulate block */ 71 | } md5_state_t; 72 | 73 | #ifdef __cplusplus 74 | extern "C" 75 | { 76 | #endif 77 | 78 | /* Initialize the algorithm. */ 79 | void md5_init(md5_state_t *pms); 80 | 81 | /* Append a string to the message. */ 82 | void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); 83 | 84 | /* Finish the message and return the digest. */ 85 | void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); 86 | 87 | #ifdef __cplusplus 88 | } /* end extern "C" */ 89 | #endif 90 | 91 | #endif /* md5_INCLUDED */ 92 | -------------------------------------------------------------------------------- /EasyDrcom/udp_dealer.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014 Shindo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __INCLUDE__UDP_DEALER__ 18 | #define __INCLUDE__UDP_DEALER__ 19 | 20 | #if defined(__APPLE__) || defined(__MACH__) || defined(LINUX) || defined(linux) 21 | #include 22 | #endif 23 | 24 | #if defined(__APPLE__) || defined(__MACH__) 25 | #ifndef MSG_NOSIGNAL 26 | #define MSG_NOSIGNAL SO_NOSIGPIPE 27 | #endif 28 | #endif 29 | 30 | #if defined(LINUX) || defined(linux) 31 | #include 32 | #endif 33 | 34 | const size_t buffer_size = 2048; 35 | 36 | class udp_dealer 37 | { 38 | public: 39 | udp_dealer(std::string gateway_ip, uint32_t gateway_port, std::string local_ip) 40 | { 41 | sock = socket(AF_INET, SOCK_DGRAM, 0); 42 | if (sock < 0) 43 | throw easy_drcom_exception("socket", errno); 44 | 45 | #if defined (WIN32) 46 | u_long mode = 1; 47 | ioctlsocket(sock, FIONBIO, &mode); 48 | #else 49 | auto flag = fcntl(sock, F_GETFL, 0); 50 | fcntl(sock, F_SETFL, flag | O_NONBLOCK); 51 | #endif 52 | 53 | struct sockaddr_in local; 54 | local.sin_family = AF_INET; 55 | local.sin_port = 0; // system defined 56 | local.sin_addr.s_addr = inet_addr(local_ip.c_str()); 57 | 58 | if (bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0) 59 | throw easy_drcom_exception("bind", errno); 60 | 61 | gateway.sin_family = AF_INET; 62 | gateway.sin_port = htons(gateway_port); 63 | gateway.sin_addr.s_addr = inet_addr(gateway_ip.c_str()); 64 | } 65 | 66 | int post(std::vector& data, std::function)> success, std::function error = nullptr) 67 | { 68 | try 69 | { 70 | int total = 0; 71 | int left = (int) data.size(); 72 | while (total < data.size()) 73 | { 74 | #if defined (WIN32) 75 | int len = (int) sendto(sock, (const char*) &data[0], data.size(), NULL, (struct sockaddr *)&gateway, sizeof(gateway)); 76 | #else 77 | int len = (int) sendto(sock, &data[0], data.size(), MSG_NOSIGNAL, (struct sockaddr *)&gateway, sizeof(gateway)); 78 | #endif 79 | if (len < 0) 80 | { 81 | if (errno == EWOULDBLOCK && left > 0) 82 | continue; 83 | else 84 | throw easy_drcom_exception("sendto", errno); 85 | } 86 | 87 | total += len; 88 | left -= len; 89 | } 90 | 91 | int ret = wait_socket(); 92 | if (ret < 0) 93 | throw easy_drcom_exception("select", errno); 94 | if (ret == 0) 95 | throw easy_drcom_exception("select: timeout"); 96 | 97 | std::vector recv; 98 | while (true) 99 | { 100 | std::vector buf(buffer_size, 0); 101 | int len = (int) ::recv(sock, (char*) &buf[0], buffer_size, 0); 102 | 103 | if (len <= 0) 104 | break; // connection closed 105 | 106 | buf.resize(len); 107 | recv.insert(recv.end(), buf.begin(), buf.end()); 108 | 109 | if (len < buffer_size) 110 | break; 111 | } 112 | 113 | return success(recv); 114 | } 115 | catch (std::exception& e) 116 | { 117 | if (error != nullptr) 118 | error(e.what()); 119 | 120 | return -1; 121 | } 122 | } 123 | 124 | private: 125 | int wait_socket() 126 | { 127 | fd_set fds; 128 | struct timeval tv; 129 | 130 | FD_ZERO(&fds); 131 | FD_SET(sock, &fds); 132 | 133 | tv.tv_usec = 0; 134 | tv.tv_sec = conf.local.udp_timeout / 1000; 135 | 136 | return select(sock + 1, &fds, NULL, NULL, &tv); 137 | } 138 | 139 | private: 140 | int sock; 141 | struct sockaddr_in gateway; 142 | }; 143 | 144 | #define U31_AUTO_RETRY(step) U31_AUTO_RETRY_EX(step, pkt_data, handler_success, handler_error) 145 | 146 | #define U31_AUTO_RETRY_EX(step, data, success, error) \ 147 | { \ 148 | int retry_times = 0, ret; \ 149 | try { \ 150 | while ((ret = udp.post(data, success, error)) < 0 && retry_times < MAX_RETRY_TIME) \ 151 | { \ 152 | retry_times++; \ 153 | U31_LOG_ERR("Failed to perform " << step << ", retry times = " << retry_times << std::endl);\ 154 | U31_LOG_INFO("Try to perform " << step << " after 2 seconds." << std::endl); \ 155 | std::this_thread::sleep_for(std::chrono::seconds(2)); \ 156 | } \ 157 | if (retry_times == MAX_RETRY_TIME) \ 158 | { \ 159 | U31_LOG_ERR("Failed to perfrom " << step << ", stopped." << std::endl); \ 160 | return -1; \ 161 | } \ 162 | } catch (std::exception &e) { \ 163 | U31_LOG_ERR(step << ": " << e.what() << std::endl); \ 164 | } \ 165 | return ret; \ 166 | } 167 | 168 | #define U31_HANDLE_ERROR(step) \ 169 | auto handler_error = [&](std::string error) { \ 170 | U31_LOG_ERR(step << ": " << error << std::endl) \ 171 | }; 172 | 173 | #define U31_LOG_RECV_DUMP(step) \ 174 | { \ 175 | U31_LOG_DBG("Received after " << step << ", dump:" << std::endl); \ 176 | hexdump(recv); \ 177 | } 178 | 179 | #define U31_LOG_SEND_DUMP \ 180 | { \ 181 | U31_LOG_DBG("send packet data dump:" << std::endl); \ 182 | hexdump(pkt_data); \ 183 | } 184 | 185 | #define U62_AUTO_RETRY(step) U62_AUTO_RETRY_EX(step, pkt_data, handler_success, handler_error) 186 | 187 | #define U62_AUTO_RETRY_EX(step, data, success, error) \ 188 | { \ 189 | int retry_times = 0, ret; \ 190 | try { \ 191 | while ((ret = udp.post(data, success, error)) < 0 && retry_times < MAX_RETRY_TIME) \ 192 | { \ 193 | retry_times++; \ 194 | U62_LOG_ERR("Failed to perform " << step << ", retry times = " << retry_times << std::endl);\ 195 | U62_LOG_INFO("Try to perform " << step << " after 2 seconds." << std::endl); \ 196 | std::this_thread::sleep_for(std::chrono::seconds(2)); \ 197 | } \ 198 | if (retry_times == MAX_RETRY_TIME) \ 199 | { \ 200 | U62_LOG_ERR("Failed to perfrom " << step << ", stopped." << std::endl); \ 201 | return -1; \ 202 | } \ 203 | } catch (std::exception &e) { \ 204 | U62_LOG_ERR(step << ": " << e.what() << std::endl); \ 205 | } \ 206 | return ret; \ 207 | } 208 | 209 | #define U62_HANDLE_ERROR(step) \ 210 | auto handler_error = [&](std::string error) { \ 211 | U62_LOG_ERR(step << ": " << error << std::endl) \ 212 | }; 213 | 214 | #define U62_LOG_RECV_DUMP(step) \ 215 | { \ 216 | U62_LOG_DBG("Received after " << step << ", dump:" << std::endl); \ 217 | hexdump(recv); \ 218 | } 219 | 220 | #define U62_LOG_SEND_DUMP \ 221 | { \ 222 | U62_LOG_DBG("send packet data dump:" << std::endl); \ 223 | hexdump(pkt_data); \ 224 | } 225 | 226 | #endif // __INCLUDE__UDP_DEALER__ 227 | -------------------------------------------------------------------------------- /EasyDrcom/utils.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014 Shindo 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __INCLUDE_UTILS__ 18 | #define __INCLUDE_UTILS__ 19 | 20 | /*#include 21 | namespace asio = boost::asio; 22 | using asio::ip::udp;*/ 23 | 24 | // We don't know why some version of OpenWrt defines LITTLE ENDIAN but actually use BIG ENDIAN. 25 | #ifdef OPENWRT 26 | #define TO_LITTLE_ENDIAN(n) (((((unsigned long)(n) & 0xFF)) << 24) | \ 27 | ((((unsigned long)(n) & 0xFF00)) << 8) | \ 28 | ((((unsigned long)(n) & 0xFF0000)) >> 8) | \ 29 | ((((unsigned long)(n) & 0xFF000000)) >> 24)) 30 | #endif 31 | 32 | #include "get_nic_addr.hpp" 33 | #include "md5.h" 34 | 35 | std::vector get_md5_digest(std::vector& data) 36 | { 37 | md5_byte_t digest[16]; 38 | md5_state_t state; 39 | 40 | md5_init(&state); 41 | md5_append(&state, &data[0], (int) data.size()); 42 | md5_finish(&state, digest); 43 | 44 | return std::vector(digest, digest + 16); 45 | } 46 | 47 | std::string hex_to_str(uint8_t *hex, size_t len, char separator) 48 | { 49 | char buf[1024] = {0}; 50 | for (int i = 0; i < len; i++) 51 | sprintf(buf + strlen(buf), "%02x%c", hex[i], (i < len - 1) ? separator : 0); 52 | 53 | return std::string(buf); 54 | } 55 | 56 | void hexdump(std::vector hex) 57 | { 58 | char buf[1024]; 59 | 60 | for (int i = 0; i < hex.size(); i += 16) 61 | { 62 | sprintf(buf, "%08x: ", i); 63 | for (int j = 0; j < 16; j++) 64 | { 65 | if (i + j < hex.size()) 66 | sprintf(buf + strlen(buf), "%02x ", hex[i+j]); 67 | else 68 | strcat(buf, " "); 69 | 70 | if (j == 7) strcat(buf, " "); 71 | } 72 | 73 | strcat(buf, " "); 74 | for (int j = 0; j < 16; j++) 75 | if (i + j < hex.size()) 76 | sprintf(buf + strlen(buf), "%c", isprint(hex[i+j]) ? hex[i+j] : '.'); 77 | 78 | #ifdef EASYDRCOM_DEBUG 79 | std::clog << buf << std::endl; 80 | #ifdef EASYDRCOM_PRINT_DBG_ON_SCREEN 81 | std::cout << buf << std::endl; 82 | #endif 83 | #endif 84 | } 85 | } 86 | 87 | std::vector split_string(std::string src, char delimiter = ' ', bool append_last = true) 88 | { 89 | std::string::size_type pos = 0; 90 | std::vector ret; 91 | 92 | while ((pos = src.find(delimiter)) != std::string::npos) 93 | { 94 | ret.push_back(src.substr(0, pos)); 95 | src = src.substr(pos + 1); 96 | } 97 | 98 | // the last element 99 | if (append_last) ret.push_back(src); 100 | 101 | return ret; 102 | } 103 | 104 | std::vector str_ip_to_vec(std::string ip) 105 | { 106 | std::vector ret(4, 0); 107 | 108 | auto vec_addr = split_string(ip, '.'); 109 | if (vec_addr.size() < 4) 110 | return ret; 111 | 112 | unsigned long addr = (atol(vec_addr[0].c_str()) << 24) + (atol(vec_addr[1].c_str()) << 16) + (atol(vec_addr[2].c_str()) << 8) + atol(vec_addr[3].c_str()); 113 | addr = ntohl(addr); 114 | 115 | memcpy(&ret[0], &addr, 4); 116 | 117 | return ret; 118 | } 119 | 120 | std::vector str_mac_to_vec(std::string mac) 121 | { 122 | std::vector ret; 123 | 124 | auto chartohex = [](char c) -> uint8_t { 125 | if (c >= '0' && c <= '9') 126 | return c - '0'; 127 | 128 | if (c >= 'a' && c <= 'f') 129 | return (c - 'a') + 0x0a; 130 | 131 | if (c >= 'A' && c <= 'F') 132 | return (c - 'A') + 0x0a; 133 | 134 | return 0xFF; 135 | }; 136 | 137 | for (int i = 0; i <= 15; i += 3) 138 | { 139 | uint8_t b = (chartohex(mac[i]) << 4) + chartohex(mac[i+1]); 140 | ret.push_back(b); 141 | } 142 | 143 | return ret; 144 | } 145 | 146 | std::vector str_to_vec(std::string str) 147 | { 148 | std::vector ret(str.length(), 0); 149 | memcpy(&ret[0], &str[0], str.length()); 150 | return ret; 151 | } 152 | 153 | #endif // __INCLUDE_UTILS__ 154 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EasyDrcom 2 | ## Current Version: v0.9 3 | 4 | #### Download: (v0.7)[https://github.com/coverxit/EasyDrcom/raw/master/Release/EasyDrcom_v0.7_for_OpenWrt_mips_AR7xxx_AR9xxx.zip] 5 | 6 | #### GUI Wrapper: https://github.com/coverxit/EasyDrcomGUI 7 | 8 | ### License 9 | --- 10 | Copyright (C) 2014 Shindo 11 | 12 | Licensed under the Apache License, Version 2.0 (the "License"); 13 | you may not use this file except in compliance with the License. 14 | You may obtain a copy of the License at 15 | 16 | http://www.apache.org/licenses/LICENSE-2.0 17 | 18 | Unless required by applicable law or agreed to in writing, software 19 | distributed under the License is distributed on an "AS IS" BASIS, 20 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | See the License for the specific language governing permissions and 22 | limitations under the License. 23 | 24 | ### What's EasyDrcom? 25 | --- 26 | **EasyDrcom** 是 **_Shindo_** 编写的为哈尔滨工业大学(威海)量身定制的**第三方Dr.COM客户端**,可在教学区、家属区、学生区使用,可运行于_Windows, Mac OS X, Linux_(包括_OpenWrt_)。 27 | 28 | **EasyDrcom** 将校园网转换为无线信号,从此手机、平板上校园网无需使用学校提供的客户端、无需打开电脑共享Wifi。 29 | 30 | 有关如何使用 **EasyDrcom**, 请访问 http://bbs.ghtt.net/thread-1984091-1-1.html 31 | 32 | 此外,EasyDrcom已推出GUI版,详情请访问:http://bbs.ghtt.net/thread-2013765-1-1.html 33 | 34 | 欲获取 EasyDrcomGUI 源代码,请访问:https://github.com/coverxit/EasyDrcomGUI 35 | 36 | ### Other projects 37 | --- 38 | 如果需要Python版本(支持d, p, x三版),请参考:https://github.com/drcoms/drcom-generic 39 | 40 | 此外,这里还有一个增加了802.1X心跳包的版本:https://github.com/sunke-github/Drcom8021x_Openwrt 41 | 42 | ### Compile Tips 43 | --- 44 | #### 下面以向Linux平台编译为例。 45 | 46 | 编译 **EasyDrcom** 是十分简单的: 47 | 48 | g++ -DLINUX -Os -s -std=c++0x -o EasyDrcom md5.c main.cpp -lpcap -lpthread 49 | 50 | 你或许已经发现了,**EasyDrcom** 依赖于: 51 | 52 |    libpcap (1.5.3), 仅头文件 53 | 54 |    boost (1.55.0) 55 | 56 | _括号里标注的是作者使用的版本_ 57 | 58 | 如果你需要指定boost和libpcap的路径,请使用-I来指定头文件目录以及-L来指定库文件目录。 59 | 60 | g++ -DLINUX -Os -s -std=c++0x -I/path/to/boost/ -I/path/to/libpcap/ -L/path/to/libpcap/ -o EasyDrcom md5.c main.cpp -lpcap -lpthread 61 | 62 | 请注意,如果向OpenWrt编译的话,请再加上编译参数,并且把他放在-DLINUX前面: 63 | 64 | -DOPENWRT 65 | 66 | 这样的话,整体看起来像这样: 67 | 68 | g++ -DOPENWRT -DLINUX -Os -s -std=c++0x -o EasyDrcom md5.c main.cpp -lpcap -lpthread 69 | 70 | ### Special Thanks 71 | --- 72 | **EasyDrcom** 的诞生离不开无数前辈的努力,下面列出的是参照的项目: 73 | 74 | * jdrcom (@Google Code: http://code.google.com/p/jdrcom/) 75 | 76 | 此外,十分感谢下面同学们代码的贡献(按照首次合并Pull Request时间排序): 77 | 78 | * mylight (https://github.com/mylight) 79 | * SwimmingTiger (https://github.com/SwimmingTiger) 80 | 81 | 同时,也离不开许多同学的测试,这里不再一一列举。 82 | -------------------------------------------------------------------------------- /Release/EasyDrcom_v0.7_for_OpenWrt_mips_AR7xxx_AR9xxx.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coverxit/EasyDrcom/cf3aae15be76dce7bddcaf63b1ec420caeff137b/Release/EasyDrcom_v0.7_for_OpenWrt_mips_AR7xxx_AR9xxx.zip --------------------------------------------------------------------------------