mirror of
https://github.com/stefanocasazza/ULib.git
synced 2025-09-28 19:05:55 +08:00
1571 lines
46 KiB
C++
1571 lines
46 KiB
C++
// ============================================================================
|
|
//
|
|
// = LIBRARY
|
|
// ULib - c++ library
|
|
//
|
|
// = FILENAME
|
|
// mod_nodog.cpp - this is a plugin nodog for userver
|
|
//
|
|
// = AUTHOR
|
|
// Stefano Casazza
|
|
//
|
|
// ============================================================================
|
|
|
|
#include <ulib/base/hash.h>
|
|
|
|
#include <ulib/date.h>
|
|
#include <ulib/file_config.h>
|
|
#include <ulib/utility/des3.h>
|
|
#include <ulib/utility/uhttp.h>
|
|
#include <ulib/net/udpsocket.h>
|
|
#include <ulib/net/ipt_ACCOUNT.h>
|
|
#include <ulib/utility/services.h>
|
|
#include <ulib/net/server/server.h>
|
|
#include <ulib/utility/string_ext.h>
|
|
#include <ulib/serialize/flatbuffers.h>
|
|
#include <ulib/net/server/client_image.h>
|
|
#include <ulib/net/server/plugin/mod_nodog.h>
|
|
|
|
#ifdef USE_LIBTDB
|
|
# include <ulib/db/tdb.h>
|
|
#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<UString>* UNoDogPlugIn::varp_cache;
|
|
UVector<UString>* UNoDogPlugIn::vInternalDevice;
|
|
UVector<UString>* UNoDogPlugIn::vLocalNetworkLabel;
|
|
UVector<UString>* UNoDogPlugIn::vLocalNetworkSpec;
|
|
UVector<UIPAllow*>* UNoDogPlugIn::vLocalNetworkMask;
|
|
UHttpClient<UTCPSocket>* UNoDogPlugIn::client;
|
|
UHashMap<UModNoDogPeer*>* 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<UString>, varp_cache, UVector<UString>);
|
|
U_NEW(UVector<UString>, vInternalDevice, UVector<UString>);
|
|
U_NEW(UVector<UString>, vLocalNetworkSpec, UVector<UString>);
|
|
U_NEW(UVector<UString>, vLocalNetworkLabel, UVector<UString>);
|
|
U_NEW(UVector<UIPAllow*>, vLocalNetworkMask, UVector<UIPAllow*>);
|
|
|
|
U_NEW(UHttpClient<UTCPSocket>, client, UHttpClient<UTCPSocket>(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<UModNoDogPeer*> uhashpeer;
|
|
|
|
# ifdef HAVE_ARCH64
|
|
char buffer_output[16U * 1024U];
|
|
# else
|
|
char buffer_output[ 1U * 1024U];
|
|
# endif
|
|
|
|
uint32_t buffer_output_len = UObject2String<uhashpeer>(*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<UModNoDogPeer*>, peers, UHashMap<UModNoDogPeer*>( 256, UHashMap<void*>::setIndexIntHash));
|
|
#else
|
|
U_NEW(UHashMap<UModNoDogPeer*>, peers, UHashMap<UModNoDogPeer*>(8192, UHashMap<void*>::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<UString> 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<uint64_t>(0);
|
|
# else
|
|
peer = (UModNoDogPeer*) (vec.AsVectorGet<uint64_t>(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<UString>(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<UString>(i+1);
|
|
apId = vec.AsVectorGet<UString>(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<UString> " << (void*)vInternalDevice << ")\n"
|
|
<< "vLocalNetworkLabel (UVector<UString> " << (void*)vLocalNetworkLabel << ")\n"
|
|
<< "client (UHttpClient<UTCPSocket> " << (void*)client << ")\n"
|
|
<< "peers (UHashMap<UModNoDogPeer*> " << (void*)peers << ')';
|
|
|
|
if (_reset)
|
|
{
|
|
UObjectIO::output();
|
|
|
|
return UObjectIO::buffer_output;
|
|
}
|
|
|
|
return U_NULLPTR;
|
|
}
|
|
#endif
|