// ============================================================================ // // = LIBRARY // ULib - c++ library // // = FILENAME // mod_nodog.cpp - this is a plugin nodog for userver // // = AUTHOR // Stefano Casazza // // ============================================================================ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef USE_LIBTDB # include #endif U_CREAT_FUNC(server_plugin_nodog, UNoDogPlugIn) int UNoDogPlugIn::fd_stderr; bool UNoDogPlugIn::bdifferent; bool UNoDogPlugIn::bnetwork_interface; bool UNoDogPlugIn::mac_from_dhcp_data_file; void* UNoDogPlugIn::pdata; uint32_t UNoDogPlugIn::T1; uint32_t UNoDogPlugIn::T2; uint32_t UNoDogPlugIn::check_expire; UString* UNoDogPlugIn::label; UString* UNoDogPlugIn::chrash; UString* UNoDogPlugIn::fw_env; UString* UNoDogPlugIn::fw_cmd; UString* UNoDogPlugIn::extdev; UString* UNoDogPlugIn::intdev; UString* UNoDogPlugIn::mac_old; UString* UNoDogPlugIn::label_old; UString* UNoDogPlugIn::hostname; UString* UNoDogPlugIn::localnet; UString* UNoDogPlugIn::info_data; UString* UNoDogPlugIn::arp_cache; UString* UNoDogPlugIn::allowed_members; UString* UNoDogPlugIn::IP_address_trust; UString* UNoDogPlugIn::auth_host; UString* UNoDogPlugIn::auth_deny; UString* UNoDogPlugIn::auth_info; UString* UNoDogPlugIn::auth_login; UString* UNoDogPlugIn::auth_notify; UString* UNoDogPlugIn::auth_service; UString* UNoDogPlugIn::auth_strict_notify; in_addr_t UNoDogPlugIn::addr; UCommand* UNoDogPlugIn::fw; UIPAllow* UNoDogPlugIn::pallow; UIptAccount* UNoDogPlugIn::ipt; UModNoDogPeer* UNoDogPlugIn::peer; UVector* UNoDogPlugIn::varp_cache; UVector* UNoDogPlugIn::vInternalDevice; UVector* UNoDogPlugIn::vLocalNetworkLabel; UVector* UNoDogPlugIn::vLocalNetworkSpec; UVector* UNoDogPlugIn::vLocalNetworkMask; UHttpClient* UNoDogPlugIn::client; UHashMap* UNoDogPlugIn::peers; UNoDogPlugIn::UNoDogPlugIn() : UEventTime(300L,0L) { U_TRACE_CTOR(0, UNoDogPlugIn, "") U_NEW(UCommand, fw, UCommand); U_NEW_STRING(label, UString); U_NEW_STRING(chrash, UString(U_CONSTANT_TO_PARAM("/tmp/nodog.chrash"))); U_NEW_STRING(fw_cmd, UString); U_NEW_STRING(fw_env, UString); U_NEW_STRING(extdev, UString); U_NEW_STRING(intdev, UString); U_NEW_STRING(mac_old, UString); U_NEW_STRING(label_old, UString); U_NEW_STRING(hostname, UString); U_NEW_STRING(localnet, UString); U_NEW_STRING(info_data, UString); U_NEW_STRING(arp_cache, UString); U_NEW_STRING(allowed_members, UString); U_NEW_STRING(IP_address_trust, UString); U_NEW_STRING(auth_host, UString); U_NEW_STRING(auth_deny, UString); U_NEW_STRING(auth_info, UString); U_NEW_STRING(auth_login, UString); U_NEW_STRING(auth_notify, UString); U_NEW_STRING(auth_service, UString); U_NEW_STRING(auth_strict_notify, UString); U_NEW(UVector, varp_cache, UVector); U_NEW(UVector, vInternalDevice, UVector); U_NEW(UVector, vLocalNetworkSpec, UVector); U_NEW(UVector, vLocalNetworkLabel, UVector); U_NEW(UVector, vLocalNetworkMask, UVector); U_NEW(UHttpClient, client, UHttpClient(U_NULLPTR)); client->UClient_Base::setTimeOut(UServer_Base::timeoutMS); if (UString::str_without_label == U_NULLPTR) UString::str_allocate(STR_ALLOCATE_NOCAT); } UNoDogPlugIn::~UNoDogPlugIn() { U_TRACE_DTOR(0, UNoDogPlugIn) U_DELETE(fw) U_DELETE(label) U_DELETE(chrash) U_DELETE(fw_cmd) U_DELETE(fw_env) U_DELETE(extdev) U_DELETE(intdev) U_DELETE(mac_old) U_DELETE(label_old) U_DELETE(hostname) U_DELETE(localnet) U_DELETE(info_data) U_DELETE(allowed_members) U_DELETE(IP_address_trust) U_DELETE(auth_host) U_DELETE(auth_deny) U_DELETE(auth_info) U_DELETE(auth_login) U_DELETE(auth_notify) U_DELETE(auth_service) U_DELETE(auth_strict_notify) U_DELETE(vInternalDevice) U_DELETE(vLocalNetworkSpec) U_DELETE(vLocalNetworkLabel) U_DELETE(vLocalNetworkMask) U_DELETE(client) if (ipt) U_DELETE(ipt) if (peers) U_DELETE(peers) U_DELETE(varp_cache) U_DELETE( arp_cache) // NB: must be here to avoid DEAD OF SOURCE STRING WITH CHILD ALIVE... #ifdef USE_LIBTDB if (pdata) U_DELETE((UTDB*)pdata) #endif } int UModNoDogPeer::handlerTime() { U_TRACE_NO_PARAM(0, "UModNoDogPeer::handlerTime()") UNoDogPlugIn::peer = this; if (U_peer_permit == false) UNoDogPlugIn::permit(U_peer_mac_from_dhcp_data_file ? *UString::str_without_mac : UNoDogPlugIn::peer->mac); U_RETURN(-1); // normal } U_NO_EXPORT void UNoDogPlugIn::makeInfoData(UFlatBuffer* pfb, void* param) { U_TRACE(0, "UNoDogPlugIn::makeInfoData(%p,%p)", pfb, param) char buffer[256]; pfb->String(buffer, getApInfo(buffer, sizeof(buffer), *label)); if (peers->first()) { uint32_t _ctime = peers->getIndexNode(); # ifdef HAVE_LINUX_NETFILTER_IPV4_IPT_ACCOUNT_H const char* table; struct ipt_acc_handle_ip* entry; for (uint32_t i = 0, n = vLocalNetworkMask->size(); i < n; ++i) { U_INTERNAL_ASSERT((*vLocalNetworkSpec)[i].isNullTerminated()) table = (*vLocalNetworkSpec)[i].data(); /** * struct ipt_acc_handle_ip { * uint32_t ip; * uint32_t src_packets; * uint32_t src_bytes; * uint32_t dst_packets; * uint32_t dst_bytes; * }; */ if (ipt->readEntries(table, true)) { while ((entry = ipt->getNextEntry())) { /* const unsigned char* bytep = (const unsigned char*) &(entry->ip); # ifdef HAVE_ARCH64 uint32_t ip_len = u__snprintf(buffer, sizeof(buffer), U_CONSTANT_TO_PARAM("%u.%u.%u.%u"), bytep[3], bytep[2], bytep[1], bytep[0]); # else uint32_t ip_len = u__snprintf(buffer, sizeof(buffer), U_CONSTANT_TO_PARAM("%u.%u.%u.%u"), bytep[0], bytep[1], bytep[2], bytep[3]); # endif U_SRV_LOG("IP: %.*s SRC packets: %u bytes: %u DST packets: %u bytes: %u", ip_len, buffer, entry->src_packets, entry->src_bytes, entry->dst_packets, entry->dst_bytes); peer = peers->at(buffer, ip_len); */ # ifdef HAVE_ARCH64 entry->ip = htonl(entry->ip); # endif peer = peers->at((const char*)&(entry->ip), sizeof(uint32_t)); U_SRV_LOG("IP: %v SRC packets: %u bytes: %u DST packets: %u bytes: %u peer = %p", UIPAddress::toString(entry->ip).rep, entry->src_packets, entry->src_bytes, entry->dst_packets, entry->dst_bytes, peer); if (peer) { U_INTERNAL_DUMP("peer = %p", peer) peer->ctraffic = (entry->src_bytes ? entry->src_bytes + entry->dst_bytes : 0); U_INTERNAL_DUMP("peer->ctraffic = %u peer->mac = %V peer->ip = %V peer->label = %V", peer->ctraffic, peer->mac.rep, peer->ip.rep, peer->label.rep) } } } } # endif peers->setIndexNodePointer(_ctime); do { peer = peers->elem(); U_INTERNAL_ASSERT(u_isIPv4Addr(U_STRING_TO_PARAM(peer->ip))) if (U_peer_allowed) continue; if (peer->ctraffic && U_peer_permit == false) { U_SRV_LOG("WARNING: Peer IP %v MAC %v has made traffic(%u bytes) but it has status DENY", peer->ip.rep, peer->mac.rep, peer->ctraffic); continue; } // ----------------------------------------------------------------------------------------------------------------------------------------- // $1 -> mac // $2 -> ip // $3 -> ap // $4 -> traffic // --------------------- // $5 -> time // $6 -> time_no_traffic // ----------------------------------------------------------------------------------------------------------------------------------------- u_getXMAC(peer->mac.data(), buffer); pfb->String(buffer, 12); pfb->IPAddress(peer->addr); pfb->String(peer->label); _ctime = u_now->tv_sec - peer->_ctime; peer->_ctime = u_now->tv_sec; if (peer->ctraffic) { pfb->UInt(peer->ctraffic); peer->ctraffic = 0; peer->time_no_traffic = 0U; /* pfb->UInt(_ctime); pfb->UInt(0U); */ } else { pfb->UInt(0U); peer->time_no_traffic += _ctime; /* pfb->UInt(0U); pfb->UInt(peer->time_no_traffic); */ U_SRV_LOG("Peer IP %v MAC %v has made no traffic for %u secs", peer->ip.rep, peer->mac.rep, peer->time_no_traffic); } } while (peers->next()); } } int UNoDogPlugIn::handlerTime() { U_TRACE_NO_PARAM(0, "UNoDogPlugIn::handlerTime()") U_SET_MODULE_NAME(nodog); U_SRV_LOG("Checking peers for info"); #ifdef HAVE_ARCH64 UFlatBufferSpaceLarge space; #else UFlatBufferSpaceShort space; #endif U_INTERNAL_ASSERT(info_data->isNull()) UFlatBuffer::toVector(*info_data, makeInfoData); U_SRV_LOG("info_data(%u) = %#V", info_data->size(), info_data->rep); (void) client->sendPOSTRequestAsync(*info_data, *auth_info, true); info_data->clear(); U_RESET_MODULE_NAME; U_RETURN(0); // monitoring } void UNoDogPlugIn::executeCommand(const char* type, uint32_t len, const UString& mac) { U_TRACE(0, "UNoDogPlugIn::executeCommand(%.*S,%u,%V)", len, type, len, mac.rep) U_INTERNAL_ASSERT_POINTER(peer) U_INTERNAL_ASSERT(u_isMacAddr(U_STRING_TO_PARAM(mac))) char buffer[256]; // NB: request(arp|deny|clear|reset|permit|openlist|initialize) mac ip class(Owner|Member|Public) UserDownloadRate UserUploadRate UCommand cmd(buffer, u__snprintf(buffer, sizeof(buffer), U_CONSTANT_TO_PARAM("/bin/sh %v %.*s %v %v Member 0 0"), fw_cmd->rep, len, type, mac.rep, peer->ip.rep), fw_env); (void) cmd.executeAndWait(U_NULLPTR, -1, fd_stderr); U_SRV_LOG_CMD_MSG_ERR(cmd, false); } U_NO_EXPORT bool UNoDogPlugIn::setMAC() { U_TRACE_NO_PARAM(0, "UNoDogPlugIn::setMAC()") if (peer->mac.empty() || peer->mac == *UString::str_without_mac) { UString ifname = (*vInternalDevice)[0]; if (pallow->device && pallow->device != ifname) { U_SRV_LOG("WARNING: different device (%v => %v) for peer: IP %v MAC %v", ifname.rep, pallow->device.rep, peer->ip.rep, peer->mac.rep); ifname = pallow->device; } U_INTERNAL_DUMP("ifname = %V", ifname.rep) U_INTERNAL_ASSERT(ifname.isNullTerminated()) peer->mac = USocketExt::getMacAddress(UServer_Base::csocket, ifname.data()); if (peer->mac.empty()) { (void) USocketExt::getARPCache(*arp_cache, *varp_cache); for (uint32_t i = 0, n = varp_cache->size(); i < n; i += 3) { if ((*varp_cache)[i].equal(peer->ip)) { peer->mac = (*varp_cache)[i+1].copy(); U_ASSERT_EQUALS(ifname, (*varp_cache)[i+2]) break; } } } U_INTERNAL_DUMP("peer->mac = %V", peer->mac.rep) if (peer->mac.empty()) { peer->mac = *UString::str_without_mac; U_RETURN(false); } U_INTERNAL_ASSERT(peer->mac) U_INTERNAL_ASSERT(u_isMacAddr(U_STRING_TO_PARAM(peer->mac))) U_ASSERT_EQUALS(peer->mac, USocketExt::getMacAddress(peer->ip)) if (peer->mac == *UString::str_without_mac) U_RETURN(false); } U_RETURN(true); } U_NO_EXPORT bool UNoDogPlugIn::setLabelAndMAC() { U_TRACE_NO_PARAM(0, "UNoDogPlugIn::setLabelAndMAC()") U_INTERNAL_DUMP("pdata = %p mac_from_dhcp_data_file = %b peer->label = %V", pdata, mac_from_dhcp_data_file, peer->label.rep) if (pdata == U_NULLPTR) { if (setMAC() == false) U_RETURN(false); } #ifdef USE_LIBTDB else { typedef struct { uint8_t hwaddr[6], ip[4]; } __attribute__((packed)) tdbkey_t; tdbkey_t ks; uint32_t t1, t2, t3, t4, start, sz = 0; if (U_SYSCALL(sscanf, "%p,%S,%p,%p,%p,%p", peer->ip.data(), "%u.%u.%u.%u", &t1, &t2, &t3, &t4) == 4) { ks.ip[0] = t4; ks.ip[1] = t3; ks.ip[2] = t2; ks.ip[3] = t1; sz = 4; start = 6; } if (mac_from_dhcp_data_file == false) { uint32_t t5, t6; if (setMAC() == false) U_RETURN(false); if (U_SYSCALL(sscanf, "%p,%S,%p,%p,%p,%p,%p,%p", peer->mac.data(), "%x:%x:%x:%x:%x:%x", &t1, &t2, &t3, &t4, &t5, &t6) == 6) { ks.hwaddr[0] = t1; ks.hwaddr[1] = t2; ks.hwaddr[2] = t3; ks.hwaddr[3] = t4; ks.hwaddr[4] = t5; ks.hwaddr[5] = t6; sz = 10; start = 0; } } if (sz) { UString value = ((UTDB*)pdata)->at((const char*)&ks+start, sz); if (value) { // typedef struct { uint32_t area; uint8_t hwaddr[6]; uint32_t leasetime; time_t expiration; } __attribute__((packed)) tdbdata; UString area(32U); uint32_t id = *(uint32_t*)value.data(); if (id == 16777215) (void) area.assign(U_CONSTANT_TO_PARAM("ffffff")); else area.setFromNumber32(id); if (peer->label != area) peer->label = area; if (mac_from_dhcp_data_file) { U_ASSERT_EQUALS(peer->mac, *UString::str_without_mac) UString mac(17U); const unsigned char* bytep = (const unsigned char*) value.c_pointer(sizeof(uint32_t)); mac.snprintf(U_CONSTANT_TO_PARAM("%02x:%02x:%02x:%02x:%02x:%02x"), bytep[0], bytep[1], bytep[2], bytep[3], bytep[4], bytep[5]); peer->mac = mac; U_INTERNAL_ASSERT(u_isMacAddr(U_STRING_TO_PARAM(mac))) } U_SRV_LOG("get data from DHCP_DATA_FILE - key: %#.*S data: %#.10S peer->label = %V peer->mac = %V", sz, (const char*)&ks+start, value.data(), peer->label.rep, peer->mac.rep); } } if (peer->mac.empty()) { peer->mac = *UString::str_without_mac; U_RETURN(false); } } #endif U_INTERNAL_DUMP("peer->label = %V peer->mac = %V", peer->label.rep, peer->mac.rep) if (peer->mac == *UString::str_without_mac) U_RETURN(false); U_RETURN(true); } bool UNoDogPlugIn::setNewPeer() { U_TRACE_NO_PARAM(0, "UNoDogPlugIn::setNewPeer()") U_INTERNAL_ASSERT_POINTER(peer) U_INTERNAL_DUMP("U_peer_index_network = %u", U_peer_index_network) if (U_peer_index_network == 0xFF) { U_SRV_LOG("WARNING: IP address for new peer %V not found in LocalNetworkMask %V", peer->ip.rep, localnet->rep); U_RETURN(false); } peer->label = ((uint32_t)U_peer_index_network >= vLocalNetworkLabel->size() ? *UString::str_without_label : (*vLocalNetworkLabel)[U_peer_index_network]); if (setLabelAndMAC()) { if (mac_from_dhcp_data_file) U_peer_flag |= U_PEER_MAC_FROM_DHCP_DATA_FILE; peers->insert((const char*)&(peer->addr), sizeof(uint32_t), peer); // peers->insert(peer->ip, peer); U_RETURN(true); } U_RETURN(false); } U_NO_EXPORT bool UNoDogPlugIn::getPeer() { U_TRACE_NO_PARAM(0, "UNoDogPlugIn::getPeer()") if (peers->empty() == false) { peer = peers->at((const char*)&addr, sizeof(uint32_t)); // peer = peers->at(U_CLIENT_ADDRESS_TO_PARAM); U_INTERNAL_DUMP("peer = %p", peer) if (peer) U_RETURN(true); } U_RETURN(false); } U_NO_EXPORT void UNoDogPlugIn::erasePeer() { U_TRACE_NO_PARAM(0, "UNoDogPlugIn::erasePeer()") U_INTERNAL_ASSERT_POINTER(peer) U_DELETE(peers->erase((const char*)&(peer->addr), sizeof(uint32_t))) // U_DELETE(peers->erase(peer->ip)) } /* U_NO_EXPORT void UNoDogPlugIn::printPeers(const char* msg, uint32_t len) { U_TRACE(0, "UNoDogPlugIn::printPeers(%.*S,%u)", len, msg, len) #if defined(DEBUG) && !defined(U_LOG_DISABLE) if (UServer_Base::isLog()) { typedef UHashMap uhashpeer; # ifdef HAVE_ARCH64 char buffer_output[16U * 1024U]; # else char buffer_output[ 1U * 1024U]; # endif uint32_t buffer_output_len = UObject2String(*peers, buffer_output, sizeof(buffer_output)); UServer_Base::log->log(U_CONSTANT_TO_PARAM("[nodog] %.*S peers = %.*S"), len, msg, buffer_output_len, buffer_output); } #endif } */ U_NO_EXPORT void UNoDogPlugIn::eraseTimer() { U_TRACE_NO_PARAM(0, "UNoDogPlugIn::eraseTimer()") if (U_peer_timer_active) { U_peer_flag &= ~U_PEER_TIMER_ACTIVE; UTimer::erase(peer); } } U_NO_EXPORT void UNoDogPlugIn::makeNotifyData(UFlatBuffer* pfb, void* param) { U_TRACE(0, "UNoDogPlugIn::makeNotifyData(%p,%p)", pfb, param) U_INTERNAL_DUMP("peer->mac = %V peer->ip = %V peer->label = %V", peer->mac.rep, peer->ip.rep, peer->label.rep) char buffer[256]; pfb->String(buffer, getApInfo(buffer, sizeof(buffer), peer->label)); u_getXMAC(peer->mac.data(), buffer); pfb->String(buffer, 12); pfb->String(peer->ip); } U_NO_EXPORT void UNoDogPlugIn::makeLoginData(UFlatBuffer* pfb, void* param) { U_TRACE(0, "UNoDogPlugIn::makeLoginData(%p,%p)", pfb, param) makeNotifyData(pfb, param); pfb->UInt(U_PTR2INT(peer)); if (bdifferent == false) { pfb->StringNull(); pfb->StringNull(); } else { char buffer[16]; bdifferent = false; u_getXMAC(mac_old->data(), buffer); pfb->String(*label_old); pfb->String(buffer, 12); } } U_NO_EXPORT void UNoDogPlugIn::sendLogin() { U_TRACE_NO_PARAM(0, "UNoDogPlugIn::sendLogin()") UFlatBufferSpaceUser space; (void) client->sendPOSTRequestAsync(UFlatBuffer::toVector(makeLoginData), *auth_login, true); } U_NO_EXPORT void UNoDogPlugIn::sendNotify() { U_TRACE_NO_PARAM(0, "UNoDogPlugIn::sendNotify()") if (U_peer_notify_disable == false) { UFlatBufferSpaceUser space; U_peer_flag |= U_PEER_NOTIFY_DISABLE; (void) client->sendPOSTRequestAsync(UFlatBuffer::toVector(makeNotifyData), *auth_notify, true); } } U_NO_EXPORT void UNoDogPlugIn::sendStrictNotify() { U_TRACE_NO_PARAM(0, "UNoDogPlugIn::sendStrictNotify()") if (U_peer_strict_notify_disable == false) { UFlatBufferSpaceUser space; U_peer_flag |= U_PEER_STRICT_NOTIFY_DISABLE; (void) client->sendPOSTRequestAsync(UFlatBuffer::toVector(makeNotifyData), *auth_strict_notify, true); } } // Server-wide hooks int UNoDogPlugIn::handlerConfig(UFileConfig& cfg) { U_TRACE(0, "UNoDogPlugIn::handlerConfig(%p)", &cfg) // ----------------------------------------------------------------------------------------------------------------------------------- // nodog - plugin parameters // ----------------------------------------------------------------------------------------------------------------------------------- // FW_CMD shell script to manage the firewall // FW_ENV environment for shell script to execute // DECRYPT_KEY DES3 password stuff // ALLOWED_MEMBERS file with list of allowed MAC/IP pairs or NETWORKS (default: /etc/nodog.allowed) // LOCAL_NETWORK_LABEL access point localization tag to be used from portal // CHECK_EXPIRE_INTERVAL Number of seconds to send client info to portal // ----------------------------------------------------------------------------------------------------------------------------------- if (cfg.loadTable()) { UString x = cfg.at(U_CONSTANT_TO_PARAM("FW_ENV")); if (x.empty()) U_RETURN(U_PLUGIN_HANDLER_ERROR); *fw_cmd = cfg.at(U_CONSTANT_TO_PARAM("FW_CMD")); *fw_env = UStringExt::prepareForEnvironmentVar(x); T1 = cfg.readLong(U_CONSTANT_TO_PARAM("T1"), 20); T2 = cfg.readLong(U_CONSTANT_TO_PARAM("T2"), 60); check_expire = cfg.readLong(U_CONSTANT_TO_PARAM("CHECK_EXPIRE_INTERVAL")); U_INTERNAL_DUMP("check_expire = %u T1 = %u T = %u", check_expire, T1, T2) if (check_expire) UEventTime::setTimeToExpire(check_expire); *intdev = UStringExt::getEnvironmentVar(U_CONSTANT_TO_PARAM("InternalDevice"), fw_env); if (intdev->empty()) { *intdev = UServer_Base::getNetworkDevice(extdev->data()); U_SRV_LOG("Autodetected InternalDevice %V", intdev->rep); if (intdev->empty()) U_ERROR("No InternalDevice detected"); } uint32_t num_radio = vInternalDevice->split(U_STRING_TO_PARAM(*intdev)); U_INTERNAL_DUMP("num_radio = %u", num_radio) U_ASSERT_EQUALS(num_radio, 1) *localnet = UStringExt::getEnvironmentVar(U_CONSTANT_TO_PARAM("LocalNetwork"), fw_env); if (localnet->empty()) { *localnet = UServer_Base::getNetworkAddress(intdev->data()); U_SRV_LOG("Autodetected LocalNetwork %V", localnet->rep); if (localnet->empty()) U_ERROR("No LocalNetwork detected"); } (void) UIPAllow::parseMask(*localnet, *vLocalNetworkMask, vLocalNetworkSpec); *extdev = UStringExt::getEnvironmentVar(U_CONSTANT_TO_PARAM("ExternalDevice"), fw_env); if (extdev->empty()) { *extdev = UServer_Base::getNetworkDevice(U_NULLPTR); U_SRV_LOG("Autodetected ExternalDevice %V", extdev->rep); if (extdev->empty()) U_ERROR("No ExternalDevice detected"); } *auth_host = UStringExt::getEnvironmentVar(U_CONSTANT_TO_PARAM("AuthServiceAddr"), fw_env); x = cfg.at(U_CONSTANT_TO_PARAM("LOCAL_NETWORK_LABEL")); if (x) (void) vLocalNetworkLabel->split(U_STRING_TO_PARAM(x)); U_ASSERT_EQUALS(vLocalNetworkLabel->size(), vLocalNetworkMask->size()) *label = (vLocalNetworkLabel->empty() ? *UString::str_without_label : (*vLocalNetworkLabel)[0]); x = UStringExt::getEnvironmentVar(U_CONSTANT_TO_PARAM("GatewayPort"), fw_env); UServer_Base::port = (x ? x.strtoul() : 5280); U_INTERNAL_DUMP("label = %V UServer_Base::port = %u", label->rep, UServer_Base::port) x = cfg.at(U_CONSTANT_TO_PARAM("ALLOWED_MEMBERS")); *allowed_members = UFile::contentOf(x ? x : *UString::str_allowed_members_default); # ifdef USE_LIBTDB x = cfg.at(U_CONSTANT_TO_PARAM("DHCP_DATA_FILE")); if (x) { U_NEW_WITHOUT_CHECK_MEMORY(UTDB, pdata, UTDB); U_INTERNAL_ASSERT(x.isNullTerminated()) if (((UTDB*)pdata)->open(x.data())) { U_SRV_LOG("open DHCP_DATA_FILE %V", x.rep); x = cfg.at(U_CONSTANT_TO_PARAM("MAC_FROM_DHCP_DATA_FILE")); if (x) mac_from_dhcp_data_file = x.strtob(); } else { U_SRV_LOG("WARNING: fail to open DHCP_DATA_FILE %V", x.rep); U_DELETE((UTDB*)pdata) pdata = U_NULLPTR; } } # endif } U_RETURN(U_PLUGIN_HANDLER_PROCESSED); } int UNoDogPlugIn::handlerInit() { U_TRACE_NO_PARAM(0, "UNoDogPlugIn::handlerInit()") if ( fw_cmd->empty() || auth_host->empty()) { U_RETURN(U_PLUGIN_HANDLER_ERROR); } // get IP address of AUTH host... UIPAddress auth_addr; Url auth_url(*auth_host); *auth_host = auth_url.getHost().copy(); *auth_service = auth_url.getService().copy(); if (auth_addr.setHostName(*auth_host, UClientImage_Base::bIPv6)) (void) UServer_Base::auth_ip->replace(auth_addr.getAddressString()); else { U_SRV_LOG("WARNING: unknown AUTH host %V", auth_host->rep); *UServer_Base::auth_ip = *auth_host; } *hostname = USocketExt::getNodeName(); U_INTERNAL_DUMP("host = %v:%u hostname = %V ip = %V", UServer_Base::IP_address->rep, UServer_Base::port, hostname->rep, UServer_Base::IP_address->rep) UUDPSocket cClientSocket(UClientImage_Base::bIPv6); if (cClientSocket.connectServer(*UServer_Base::auth_ip, 1001)) { const char* p = cClientSocket.getLocalInfo(); UString ip = UString(p, u__strlen(p, __PRETTY_FUNCTION__)); if (ip != *UServer_Base::IP_address) { U_FILE_WRITE_TO_TMP(ip, "IP_ADDRESS"); U_SRV_LOG("WARNING: SERVER IP ADDRESS differ from IP address: %V to connect to AUTH: %V", ip.rep, UServer_Base::auth_ip->rep); } } U_SRV_LOG("AUTH ip registered: %v", UServer_Base::auth_ip->rep); fw_env->snprintf_add(U_CONSTANT_TO_PARAM("'AuthServiceIP=%v'\n"), UServer_Base::auth_ip->rep); (void) UFile::_unlink(chrash->data()); bnetwork_interface = UIPAllow::getNetworkInterface(*vLocalNetworkMask); if (bnetwork_interface == false) { U_SRV_LOG("UIPAllow::getNetworkInterface() failed"); } else { for (uint32_t i = 0, n = vLocalNetworkMask->size(); i < n; ++i) { pallow = vLocalNetworkMask->at(i); U_SRV_LOG("vLocalNetworkMask->at(%u): host = %V device = %V", i, pallow->host.rep, pallow->device.rep); if (pallow->host.empty()) pallow->host = *UServer_Base::IP_address; } } *auth_info = getUrlForSendMsgToPortal(U_CONSTANT_TO_PARAM("/info")); *auth_deny = getUrlForSendMsgToPortal(U_CONSTANT_TO_PARAM("/deny")); *auth_login = getUrlForSendMsgToPortal(U_CONSTANT_TO_PARAM("/login")); *auth_notify = getUrlForSendMsgToPortal(U_CONSTANT_TO_PARAM("/notify")); *auth_strict_notify = getUrlForSendMsgToPortal(U_CONSTANT_TO_PARAM("/strict_notify")); #ifdef USE_LIBSSL UString content = UFile::contentOf(U_STRING_FROM_CONSTANT("../DES3_KEY.txt")); UDES3::setPassword(content.c_strndup()); #endif *IP_address_trust = UDES3::signData(U_CONSTANT_TO_PARAM("%v"), UServer_Base::IP_address->rep); // firewall cmd UString command(300U); command.snprintf(U_CONSTANT_TO_PARAM("/bin/sh %v initialize allowed_web_hosts"), fw_cmd->rep); fw->set(command, (char**)U_NULLPTR); fw->setEnvironment(fw_env); if (fd_stderr == 0) fd_stderr = UServices::getDevNull("/tmp/server_plugin_nodog.err"); // users monitoring U_INTERNAL_DUMP("check_expire = %u", check_expire) if (check_expire) { UTimer::insert(this); U_SRV_LOG("Monitoring set for every %d secs", UTimeVal::getSecond()); } // users traffic U_NEW(UIptAccount, ipt, UIptAccount(UClientImage_Base::bIPv6)); // users table #ifndef HAVE_ARCH64 U_NEW(UHashMap, peers, UHashMap( 256, UHashMap::setIndexIntHash)); #else U_NEW(UHashMap, peers, UHashMap(8192, UHashMap::setIndexIntHash)); #endif U_RETURN(U_PLUGIN_HANDLER_OK); } int UNoDogPlugIn::handlerFork() { U_TRACE_NO_PARAM(0, "UNoDogPlugIn::handlerFork()") // send msg start to portal char buffer[256]; bool bqueue = false, we_need_response = true; UString msg(200U), uptime(20U), allowed_web_hosts; uptime.setUpTime(); msg.snprintf(U_CONSTANT_TO_PARAM("/start_ap?ap=%.*s&public=%v%%3A%u&pid=%d&uptime=%v"), getApInfo(buffer, sizeof(buffer), *label), buffer, IP_address_trust->rep, UServer_Base::port, UFile::getSysParam(chrash->data()), uptime.rep); (void) UFile::writeTo(*chrash, u_pid_str, u_pid_str_len); U_INTERNAL_ASSERT_EQUALS(UClient_Base::queue_dir, U_NULLPTR) #ifndef U_LOG_DISABLE const char* result = "FAILED"; #endif loop: if (client->connectServer(getUrlForSendMsgToPortal(msg)) == false) { if (we_need_response) { U_SRV_LOG("send message to AUTH: %V FAILED", auth_host->rep); we_need_response = false; UClient_Base::queue_dir = UString::str_CLIENT_QUEUE_DIR; goto loop; } goto end; } if (client->sendRequest()) { (void) allowed_web_hosts.replace(client->getContent()); # ifndef U_LOG_DISABLE result = "success"; # endif } else { bqueue = true; # ifdef U_LOG_DISABLE (void) client->putRequestOnQueue(); # else if ( client->putRequestOnQueue()) result = "success"; # endif } end: U_INTERNAL_DUMP("we_need_response = %b UClient_Base::queue_dir = %p", we_need_response, UClient_Base::queue_dir) if (bqueue) { U_SRV_LOG("queue message %s to AUTH: %V", result, msg.rep); } UClient_Base::queue_dir = U_NULLPTR; client->reset(); // NB: url is referenced by UClient::url... // initialize the firewall: direct all port 80 traffic to us... U_INTERNAL_ASSERT(allowed_web_hosts.isNullTerminated()) fw->setArgument(4, allowed_web_hosts.data()); (void) fw->executeAndWait(U_NULLPTR, -1, fd_stderr); U_SRV_LOG_CMD_MSG_ERR(*fw, false); fw->delArgument(); fw->setLastArgument("openlist"); if (*allowed_members) { // 00:27:22:4f:69:f4 172.16.1.1 Member ### routed_ap-locoM2 UVector vtmp; uint32_t n = vtmp.loadFromData(*allowed_members); UString ip, UserUploadRate, UserDownloadRate; uint32_t index_network, increment = ((n % 3) ? 5 : 3); for (uint32_t i = 0; i < n; i += increment) { ip = vtmp[i+1]; index_network = UIPAllow::find(ip, *vLocalNetworkMask); U_INTERNAL_DUMP("index_network = %u", index_network) if (index_network == U_NOT_FOUND) { U_SRV_LOG("WARNING: IP address for allowed_members %V not found in LocalNetworkMask %V", ip.rep, localnet->rep); continue; } U_INTERNAL_ASSERT_EQUALS(vtmp[i+2], "Member") if (increment == 5) { UserDownloadRate = vtmp[i+3]; UserUploadRate = vtmp[i+4]; } U_NEW(UModNoDogPeer, peer, UModNoDogPeer); peer->ip = ip.copy(); peer->mac = vtmp[i]; U_peer_flag |= U_PEER_ALLOWED; U_peer_index_network = index_network; (void) setNewPeer(); permit(peer->mac); } } U_RETURN(U_PLUGIN_HANDLER_OK); } uint32_t UNoDogPlugIn::checkUrl(char* buffer, uint32_t buffer_len, uint32_t sz, const char* user, uint32_t user_len) { U_TRACE(0, "UNoDogPlugIn::checkUrl(%p,%u,%u,%.*S,%u)", buffer, buffer_len, sz, user_len, user, user_len) if (sz > (buffer_len / 3)) { U_SRV_LOG("url request size (%u bytes) too big from %.*s USER", sz, user_len, user); U_RETURN(0); } if (auth_host->equal(U_HTTP_HOST_TO_PARAM)) { U_SRV_LOG("request url (%.*S) invalid from %.*s USER", U_HTTP_HOST_TO_TRACE, user_len, user); U_RETURN(0); } sz = UHTTP::setUrl(buffer, buffer_len); U_INTERNAL_ASSERT_MAJOR(sz, 0) U_RETURN(sz); } // Connection-wide hooks int UNoDogPlugIn::handlerRequest() { U_TRACE_NO_PARAM(1, "UNoDogPlugIn::handlerRequest()") if (UHTTP::file->isRoot() || UClientImage_Base::isRequestNotFound()) { UString x; uint32_t sz, index_network; char buffer[U_BUFFER_SIZE-512]; U_http_info.nResponseCode = HTTP_NO_CONTENT; U_INTERNAL_DUMP("UServer_Base::client_address = %.*S", U_CLIENT_ADDRESS_TO_TRACE) U_SRV_LOG("Start REQUEST phase of plugin nodog: %.*S client_address = %.*S", U_HTTP_URI_TO_TRACE, U_CLIENT_ADDRESS_TO_TRACE); (void) UServer_Base::csocket->shutdown(SHUT_RD); if (UServer_Base::auth_ip->equal(U_CLIENT_ADDRESS_TO_PARAM)) { // ------------------------------------------ // request from AUTH, which may be: // ------------------------------------------ // 1) /login_validate - login user validation // 2) /logout - logout specific users // 3) /ping - check // ------------------------------------------ U_SRV_LOG("Start REQUEST_FROM_AUTH phase of plugin nodog"); if (U_HTTP_URI_STREQ("/login_validate")) { bool bdeny; char policy; UFlatBuffer fb, vec; fb.setRoot(*UHTTP::body); fb.AsVector(vec); // $1 -> peer // $2 -> deny|permit ('0'|'1') policy: notify|no_notify|strict_notify ('0'|'1'|'2') # if defined(HAVE_ARCH64) && defined(U_LINUX) peer = (UModNoDogPeer*) vec.AsVectorGet(0); # else peer = (UModNoDogPeer*) (vec.AsVectorGet(0) & 0x00000000ffffffffLL); # endif U_SRV_LOG("request to validate login: peer = %p", peer); U_INTERNAL_ASSERT_POINTER(peer) if (peers->findElement(peer) == false) goto bad; x = vec.AsVectorGet(1); bdeny = (x.first_char() == '0'); // deny|permit ('0'|'1') policy = x.c_char(1); // policy: notify|no_notify|strict_notify ('0'|'1'|'2') U_SRV_LOG("request to validate login for peer IP %v MAC %v: bdeny = %b policy = %C", peer->ip.rep, peer->mac.rep, bdeny, policy); U_INTERNAL_ASSERT(peer->mac) U_INTERNAL_ASSERT(u_isMacAddr(U_STRING_TO_PARAM(peer->mac))) if (bdeny) { eraseTimer(); if (U_peer_permit) deny(U_peer_mac_from_dhcp_data_file ? *UString::str_without_mac : peer->mac); erasePeer(); goto end; } U_peer_policy = policy; // policy: notify|no_notify|strict_notify ('0'|'1'|'2') /* if (U_peer_policy == '0') // '0' (notify) (1<=T1<=3599) (1<=T2<=3599) { } */ if (policy == '1') // '1' (no notify) (T1==T2==0) { eraseTimer(); if (U_peer_permit == false) permit(U_peer_mac_from_dhcp_data_file ? *UString::str_without_mac : peer->mac); goto end; } if (policy == '2') // '2' (strict notify) { if (U_peer_permit == false) { eraseTimer(); U_peer_flag |= U_PEER_DELAY_DISABLE; } } } else if (U_HTTP_URI_STREQ("/logout")) { UString mac, apId; uint32_t n, ip_peer; UFlatBuffer fb, vec; fb.setRoot(*UHTTP::body); fb.AsVector(vec); n = vec.GetSize(); U_SRV_LOG("AUTH request to logout %u users", n / 3); for (int32_t i = 0; i < (int32_t)n; i += 3) { // ---------- // $1 -> ip // $2 -> mac // $3 -> apId // ---------- ip_peer = vec.AsVectorGetIPAddress(i); peer = peers->at((const char*)&ip_peer, sizeof(uint32_t)); // (*peers)[UIPAddress::toString(vec[i])]; if (peer == U_NULLPTR) { U_SRV_LOG("AUTH request to logout user failed: IP %V", UIPAddress::toString(ip_peer).rep); continue; } U_INTERNAL_ASSERT(peer->mac) U_INTERNAL_ASSERT(u_isMacAddr(U_STRING_TO_PARAM(peer->mac))) U_SRV_LOG("AUTH request to logout user(%u): IP %v MAC %v", i, peer->ip.rep, peer->mac.rep); mac = vec.AsVectorGet(i+1); apId = vec.AsVectorGet(i+2); if (apId != peer->label || checkMAC(mac) == false) { U_SRV_LOG("WARNING: AUTH request to logout user with different mac or label (MAC %v LABEL %v) => (MAC %v LABEL %v)", mac.rep, apId.rep, peer->mac.rep, peer->label.rep); continue; } if (U_peer_permit) deny(U_peer_mac_from_dhcp_data_file ? *UString::str_without_mac : peer->mac); else { eraseTimer(); U_SRV_LOG("AUTH request to logout user with status DENY"); } erasePeer(); } } else if (U_HTTP_URI_STREQ("/ping") == false) { bad: UHTTP::setBadRequest(); } goto end; } // U_SRV_LOG("Start REQUEST_FROM_USER phase of plugin nodog"); // printPeers(U_CONSTANT_TO_PARAM("user request")); if (U_HTTP_URI_QUERY_LEN > (sizeof(buffer) / 4)) { U_SRV_LOG("request url query size (%u bytes) too big", U_HTTP_URI_QUERY_LEN); goto end; } sz = 7+U_http_host_len+U_HTTP_URI_QUERY_LEN; addr = UServer_Base::getClientAddress(); if (getPeer()) { // --------------------- // request from OLD user // --------------------- U_SRV_LOG("Start REQUEST_FROM_OLD_USER phase of plugin nodog: peer = %p", peer); U_INTERNAL_ASSERT(peer->mac) U_INTERNAL_ASSERT(peer->label) U_ASSERT(peer->ip.equal(U_CLIENT_ADDRESS_TO_PARAM)) U_INTERNAL_ASSERT(u_isMacAddr(U_STRING_TO_PARAM(peer->mac))) if (checkUrl(buffer, sizeof(buffer), sz, U_CONSTANT_TO_PARAM("OLD")) == 0) goto end; *mac_old = peer->mac; *label_old = peer->label; peer->mac.clear(); if (setLabelAndMAC() == false) { peer->mac = *mac_old; peer->label = *label_old; goto end; } if ( *mac_old != peer->mac || *label_old != peer->label) { // NB: we assume that the current peer is a different user that has acquired the same IP address from the DHCP... U_SRV_LOG("WARNING: different user for peer (IP %v): (MAC %v LABEL %v) => (MAC %v LABEL %v)", peer->ip.rep, mac_old->rep, label_old->rep, peer->mac.rep, peer->label.rep); U_INTERNAL_ASSERT(peer->mac) U_INTERNAL_ASSERT(peer->label) if (peer->mac != *mac_old) { bdifferent = true; if (U_peer_permit && U_peer_mac_from_dhcp_data_file == false) { deny(*mac_old); } goto log; } peer->label = *label_old; goto end; } if (U_HTTP_URI_MEMEQ("/nodog_peer_allow.sh")) { if (U_HTTP_QUERY_MEMEQ("url=") && U_peer_allow_disable == false) { /** * open firewall, respond with redirect to original request * * $1 -> url * $2 -> forced ('0'|'1') */ UString redirect; bool forced = false; uint32_t n = UHTTP::processForm(); UHTTP::getFormValue(redirect, U_CONSTANT_TO_PARAM("url"), 0, 1, n); if (n == 2*2) { UHTTP::getFormValue(x, U_CONSTANT_TO_PARAM("forced"), 0, 3, 4); if (x.first_char() == '1') forced = true; } if (forced) { sendStrictNotify(); goto next; } U_INTERNAL_DUMP("T2 = %u U_peer_policy = %C", T2, U_peer_policy) if (T2 < 3600 && U_peer_policy != '2') // (strict notify) { sendNotify(); next: eraseTimer(); if (U_peer_permit == false) permit(U_peer_mac_from_dhcp_data_file ? *UString::str_without_mac : peer->mac); UHTTP::setRedirectResponse(UHTTP::NO_BODY, U_STRING_TO_PARAM(redirect)); } } goto end; } if (U_HTTP_URI_MEMEQ("/nodog_peer_delay.sh")) { if (U_peer_delay_disable == false) { eraseTimer(); U_INTERNAL_DUMP("T2 = %u", T2) if (T2 && T2 < 3600) { peer->UEventTime::setTimeToExpire(T2); U_peer_flag |= U_PEER_TIMER_ACTIVE; UTimer::insert(peer); } sendNotify(); } goto end; } if (U_peer_permit) { U_SRV_LOG("request from OLD USER but it has status PERMIT"); goto end; } goto welcome; } // --------------------- // request from NEW user // --------------------- if (U_HTTP_URI_MEMEQ("/nodog_peer_allow.sh") || U_HTTP_URI_MEMEQ("/nodog_peer_delay.sh")) { U_SRV_LOG("/nodog_peer_(allow|delay).sh from NEW USER: %.*s", U_CLIENT_ADDRESS_TO_PARAM); goto end; } if (checkUrl(buffer, sizeof(buffer), sz, U_CONSTANT_TO_PARAM("NEW")) == 0) goto end; index_network = UIPAllow::find(UServer_Base::client_address, *vLocalNetworkMask); U_INTERNAL_DUMP("index_network = %u", index_network) if (index_network == U_NOT_FOUND) { U_SRV_LOG("WARNING: IP address for new peer %.*S not found in LocalNetworkMask %V", U_CLIENT_ADDRESS_TO_TRACE, localnet->rep); goto end; } U_NEW(UModNoDogPeer, peer, UModNoDogPeer); U_SRV_LOG("Start REQUEST_FROM_NEW_USER phase of plugin nodog: index_network = %u peer = %p", index_network, peer); pallow = vLocalNetworkMask->at((U_peer_index_network = index_network)); U_INTERNAL_ASSERT_POINTER(pallow) peer->addr = addr; (void) peer->ip.replace(U_CLIENT_ADDRESS_TO_PARAM); U_ASSERT_EQUALS(peer->ip, UIPAddress::toString(peer->addr)) if (setNewPeer() == false) { U_DELETE(peer) goto end; } log: sendLogin(); U_INTERNAL_DUMP("T1 = %u", T1) if (T1 == 0) { permit(U_peer_mac_from_dhcp_data_file ? *UString::str_without_mac : peer->mac); UHTTP::setRedirectResponse(UHTTP::NO_BODY, buffer, sz); } else { if (T1 < 3600) { peer->UEventTime::setTimeToExpire(T1); U_peer_flag |= U_PEER_TIMER_ACTIVE; UTimer::insert(peer); } welcome: x = UString::getUBuffer(); x.snprintf(U_CONSTANT_TO_PARAM("%v://%v/welcome?url="), auth_service->rep, auth_host->rep); Url::encode_add(buffer, sz, x); u_getXMAC(peer->mac.data(), buffer); x.snprintf_add(U_CONSTANT_TO_PARAM("&mac=%.12s&apid=%v&gateway=%v%%3A%u"), buffer, peer->label.rep, (bnetwork_interface ? pallow->host : *UServer_Base::IP_address).rep, UServer_Base::port); UHTTP::setRedirectResponse(UHTTP::NO_BODY, U_STRING_TO_PARAM(x)); } end: UClientImage_Base::setCloseConnection(); if (U_http_info.nResponseCode == HTTP_NO_CONTENT) UHTTP::setResponse(); U_RETURN(U_PLUGIN_HANDLER_PROCESSED); } U_RETURN(U_PLUGIN_HANDLER_OK); } // DEBUG #if defined(U_STDCPP_ENABLE) && defined(DEBUG) const char* UModNoDogPeer::dump(bool _reset) const { *UObjectIO::os << "addr " << addr << '\n' << "_ctime " << _ctime << '\n' << "ctraffic " << ctraffic << '\n' << "time_no_traffic " << time_no_traffic << '\n' << "ip (UString " << (void*)&ip << ")\n" << "mac (UString " << (void*)&mac << ")\n" << "label (UString " << (void*)&label << ')'; if (_reset) { UObjectIO::output(); return UObjectIO::buffer_output; } return U_NULLPTR; } const char* UNoDogPlugIn::dump(bool _reset) const { *UObjectIO::os << "fd_stderr " << fd_stderr << '\n' << "label (UString " << (void*)label << ")\n" << "extdev (UString " << (void*)extdev << ")\n" << "fw_cmd (UString " << (void*)fw_cmd << ")\n" << "fw_env (UString " << (void*)fw_env << ")\n" << "intdev (UString " << (void*)intdev << ")\n" << "hostname (UString " << (void*)hostname << ")\n" << "localnet (UString " << (void*)localnet << ")\n" << "auth_info (UString " << (void*)auth_info << ")\n" << "auth_login (UString " << (void*)auth_login << ")\n" << "allowed_members (UString " << (void*)allowed_members << ")\n" << "fw (UCommand " << (void*)fw << ")\n" << "ipt (UIptAccount " << (void*)ipt << ")\n" << "vInternalDevice (UVector " << (void*)vInternalDevice << ")\n" << "vLocalNetworkLabel (UVector " << (void*)vLocalNetworkLabel << ")\n" << "client (UHttpClient " << (void*)client << ")\n" << "peers (UHashMap " << (void*)peers << ')'; if (_reset) { UObjectIO::output(); return UObjectIO::buffer_output; } return U_NULLPTR; } #endif