/*
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/*
 *    Date: 27.10.2002
 */

/*
 *    Author : Boris Mikhailenko <stg34@ua.fm>
 */


#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <algorithm>
#include <functional>

#include "hostallow.h"
//-----------------------------------------------------------------------------
HOSTALLOW::HOSTALLOW()
{

}
//-----------------------------------------------------------------------------
int HOSTALLOW::ParseHosts(const char * str, int hostsType)
{
/*
ðÒÏÉÚ×ÏÄÉÍ ÒÁÚÂÏÒ ÓÔÒÏËÉ ×ÉÄÁ host host host ...
ÇÄÅ host ÍÏÖÅÔ ÉÍÅÔØ ×ÉÄ a.b.c.d ÉÌÉ a.b.c.d/e
ÉÌÉ all.
ÐÒÉÞÅÍ × ÓÌÕÞÁÅ ÓÅÔÉ ÍÁÓËÁ É ÁÄÒÅÓ ÄÏÌÖÎÙ ÂÙÔØ 
ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÍÉ ÄÒÕÇ ÄÒÕÇÕ.

òÅÚÕÌØÔÁÔÙ ÚÁÎÏÓÉÍ × ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ ÓÐÉÓÏË 
 * */

int len;
char *s;
char * tok;
uint32_t ip;
uint32_t mask;
//INETADDR inetAddr;

if (strcasecmp(str, "all") == 0)
    {
    if (hostsType == hostsAllow)
        hostAllowList.push_back(INETADDR());
    else
        hostDenyList.push_back(INETADDR());
    return 0;
    }
else
    {
    len = strlen(str);

    s = new char[len + 1];

    strcpy(s, str);

    tok = strtok(s, " ");

    while (tok)
        {
        if (ParseIPMask(tok, &ip, &mask) != 0)
            {
            return -1;
            delete[] s;
            }
        //printfd(__FILE__, "ParseHosts tok %s\n", tok);
        tok = strtok(NULL, " ");
        if (hostsType == hostsAllow)
            {
            //printfd(__FILE__, "ParseHosts APPEND allow %X %X\n", ip, mask);
            hostAllowList.push_back(INETADDR(ip, mask));
            }
        else
            {
            //printfd(__FILE__, "ParseHosts APPEND deny  %X %X\n", ip, mask);
            hostDenyList.push_back(INETADDR(ip, mask));
            }
        }
    }

delete[] s;
return 0;
}
//-----------------------------------------------------------------------------
int HOSTALLOW::ParseIPMask(const char * s, uint32_t * ip, uint32_t * mask)
{
/*
òÁÚÂÏÒ ÓÔÒÏËÉ ×ÉÄÁ a.b.c.d/e ÉÌÉ a.b.c.d

123.123.123.123/30
 * */
int len;
char * host;

int i = 0, msk;

len = strlen(s);
host = new char[len + 1];

while (s[i] != 0 && s[i] != '/')
    {
    host[i] = s[i];
    i++;
    }

host[i] = 0;

if (inet_addr(host) == INADDR_NONE)
    {
    delete[] host;
    sprintf(errMsg, "Icorrect IP address %s", host);
    return -1;
    }

*ip = inet_addr(host);

char *res;

if (s[i] == '/')
    {
    msk = strtol(&s[i+1], &res, 10);
    if (*res != 0)
        {
        sprintf(errMsg, "Icorrect mask %s", &s[i+1]);
        delete[] host;
        return -1;
        }

    if (msk < 0 || msk > 32)
        {
        sprintf(errMsg, "Icorrect mask %s", &s[i+1]);
        delete[] host;
        *mask = 0;
        return 0;
        }

    uint32_t m = 0;
    m = htonl(0xFFffFFff<<(32 - msk));

    *mask = m;
    }
else
    {
    *mask = 0xFFffFFff;
    }

if ((*ip & *mask) != *ip)
    {
    sprintf(errMsg, "Address does'n match mask.\n");
    delete[] host;
    return -1;
    }

delete[] host;
return 0;  
}
//-----------------------------------------------------------------------------
int HOSTALLOW::ParseOrder(const char * str)
{
/*
ÐÒÏÉÚ×ÏÄÉÍ ÒÁÚÂÏÒ ÓÔÒÏËÉ ×ÉÄÁ allow deny ÉÌÉ deny allow
 */

if (strcasecmp(str, "allow,deny") == 0)
    {
    order = orderAllow;
    return 0;
    }

if (strcasecmp(str, "deny,allow") == 0)
    {
    order = orderDeny;
    return 0;
    }

sprintf(errMsg, "Parameter \'order\' must be \'allow,deny\' or \'deny,allow\'");
return -1;
}
//-----------------------------------------------------------------------------
int HOSTALLOW::GetError()
{
/*
÷ÏÚ×ÒÁÝÁÅÍ ËÏÄ ÏÛÉÂËÉ É ÓÂÒÁÓÙ×ÁÅÍ ÅÅ.
 * */
return 0;
}
//-----------------------------------------------------------------------------
bool HOSTALLOW::HostAllowed(uint32_t ip)
{
/*
ðÒÏ×ÅÒÑÅÍ Ñ×ÌÑÅÔÓÑ ÌÉ éð ÒÁÚÒÅÛÅÎÎÙÍ ÉÌÉ ÎÅÔ
 * */

if (order == orderDeny)
    {
    if (IsHostInDeniedList(ip))
        {
        return false;
        }

    if (IsHostInAllowedList(ip))
        {
        return true;
        }
    }
else
    {
    if (IsHostInAllowedList(ip))
        {
        return true;
        }

    if (IsHostInDeniedList(ip))
        {
        return false;
        }
    }

return false;
}
//-----------------------------------------------------------------------------
int HOSTALLOW::IsIPInSubnet(uint32_t checkedIP, INETADDR &ia)
{
//uint32_t checkedIP;
if ((ia.mask & checkedIP) == (ia.ip))
    return true;
return false;
}
//-----------------------------------------------------------------------------
bool HOSTALLOW::IsHostInAllowedList(uint32_t ip)
{
/*
îÁÈÏÄÉÔÓÑ ÌÉ éð × ÓÐÉÓËÅ ÒÁÚÒÅÛÅÎÎÙÈ
 * */
list<INETADDR>::iterator li;

li = hostAllowList.begin();

while(li != hostAllowList.end())
    {
    if (IsIPInSubnet(ip, *li))
        return true;
    }

return false;
}
//-----------------------------------------------------------------------------
bool HOSTALLOW::IsHostInDeniedList(uint32_t ip)
{
/*
îÁÈÏÄÉÔÓÑ ÌÉ éð × ÓÐÉÓËÅ ÚÁÐÒÅÝÅÎÎÙÈ
 * */
list<INETADDR>::iterator li;

li = hostDenyList.begin();

while(li != hostDenyList.end())
    {
    if (IsIPInSubnet(ip, *li))
        return true;
    }

return false;
}
//-----------------------------------------------------------------------------
const char * HOSTALLOW::GetStrError()
{
/*
÷ÏÚ×ÒÁÝÁÅÍ ÔÅËÓÔÏ×ÏÅ ÏÐÉÓÁÎÉÅ ÏÛÉÂËÉ.
 * */
return errMsg;
}
//-----------------------------------------------------------------------------