/* Mis-connector - user-space router and NATP for misconfigured hosts on LAN.
Data manglement.
This file is part of mis-connector.
Copyright ⓒ 2021 Petr Silhavy <petr.silhavy@yandex.com>
SPDX-License-Identifier: GPL-3.0-or-later
Mis-connector 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 3 of the
License, or (at your option) any later version.
Mis-connector 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 mis-connector. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <error.h>
#include <glib.h>
#include <netlink/addr.h>
#include "whackparam.h"
/*
============ ==============================================================
Event Chat
============ ==============================================================
new MAC ARPL->MULE MAC+inside IP
mule fills outside IP MULE->ARPL
MULE->BACKW
============ ==============================================================
*/
GSequence *by_IP, *by_MAC ;
#if 0
static int
compare_mac (gconstpointer a, gconstpointer b, gpointer userdata)
{
// unsigned long int ai, bi;
const struct hash_entry *ha = a ;
const struct hash_entry *hb = b ;
// ai = ( ha->mac[2] << 24 ) + ( ha->mac[3] << 16 ) + (ha->mac[4] << 8) + ha->mac[5] ;
// bi = ( hb->mac[2] << 24 ) + ( hb->mac[3] << 16 ) + (hb->mac[4] << 8) + hb->mac[5] ;
// return (ai > bi) - (ai < bi) ;
return memcmp(ha->mac, hb->mac, ETH_ALEN);
}
static int
compare_ip (gconstpointer a, gconstpointer b, gpointer userdata)
{
unsigned int ai, bi;
const struct hash_entry *ha = a ;
const struct hash_entry *hb = b ;
ai = ha->ip ;
bi = hb->ip ;
return (ai > bi) - (ai < bi) ;
}
#endif // 0
GList *
make_ip_pool(struct whack_param *w)
{
struct sockaddr_in6 sa ;
struct sockaddr_in *sa4 ;
int err ;
GList *ip_list = NULL ;
socklen_t sa_len = sizeof(sa) ;
if ( ( err = nl_addr_fill_sockaddr(w->nl_nat_addr, (void *)&sa, &sa_len )) != 0 )
error(1, errno, "nl_addr_fill_sockaddr: %s" , nl_geterror(err) );
sa4 = ( void *) &sa ;
if ( sa4->sin_family == AF_INET ) // IPv4
{
struct sockaddr_in *sa4 = (void *)&sa ;
uint32_t addr = sa4->sin_addr.s_addr ;
guint32 host_addr = ntohl(addr), net_addr , host_max_addr = ntohl(w->in_max);
guint32 i ;
for ( i = host_addr ; i < host_max_addr ; ++i )
{
net_addr = htonl(i);
ip_list = g_list_append( ip_list, GUINT_TO_POINTER (net_addr) );
}
}
else if ( sa.sin6_family == AF_INET6 )
{
// unsigned int prefix_len = nl_addr_get_prefixlen(w->nl_nat_addr);
// unsigned int suffix_len = ( __CHAR_BIT__ * w->in_nat_addr_size ) -
// nl_addr_get_prefixlen(w->nl_nat_addr);
guint32 net_addr = sa.sin6_addr.__in6_u.__u6_addr32[3] ;
for ( int i = 0 ; i < w->in_size ; ++i )
{
// for IPv6 only last part of sa.sin6_addr is on list
ip_list = g_list_append( ip_list, GUINT_TO_POINTER (htonl(net_addr)) );
net_addr++ ;
}
}
return ip_list ;
}
// returns net order addr
static GList *
ip_alloc(GList *l, guint32 *newip )
{
*newip = GPOINTER_TO_UINT(l->data);
return g_list_delete_link(l, l);
}
#if 0
static void
make_write_lock(GRWLock *lock)
{
const struct timespec ts = { .tv_sec = 0 , .tv_nsec = 1000 } ; // 1ms
while(1)
{
errno = 0 ;
g_rw_lock_writer_lock(lock);
//
// POSIX pthread_rwlock_wrlock error state :
//
if ( errno == EAGAIN || errno == EWOULDBLOCK )
{
g_rw_lock_writer_unlock(lock);
printf("Bug somewhere ? Maybe not locked ?\n");
nanosleep(&ts, NULL);
}
else
return ;
}
}
#endif // 0
void
new_hash_entry(struct ether_header *eh , char *sip /* src IP */,
char *tip /* gateway addr */)
{
GQuark key = mac_key(eh->ether_shost) ;
// unsigned char *sha = eh->ether_shost ;
struct hash_entry *he ;
// struct in_addr addr ;
// g_atomic_int_compare_and_exchange
// DEBUGP(stderr, "%s %s ->\n", ids[id], __func__ );
if ( ( he = g_datalist_id_get_data(&by_MAC_dl, key)) == NULL )
{
he = g_slice_new0(struct hash_entry);
memcpy(he->mac, eh->ether_shost, ETH_ALEN);
// if ( !inet_aton (sip, &addr))
// BUG("Malformed IP address «%s»\n", sip);
// else
memcpy(&he->in_ip , sip, sizeof (int));
memcpy(&he->gw_ip , tip, sizeof (int));
guint32 newip ;
ip_list = ip_alloc(ip_list, &newip);
he->ip = newip ; he->error = 0 ;
h_print(he, __func__, " LIAR: New MAC ");
lock_write(&by_MAC_lock);
g_datalist_id_set_data( &by_MAC_dl, key, he );
unlock_write(&by_MAC_lock);
GQuark ipkey = ip_key(newip);
// g_rw_lock_writer_lock(&by_IP_lock);
lock_write(&by_IP_lock);
g_datalist_id_set_data( &by_IP_dl, ipkey, he );
unlock_write(&by_IP_lock);
h_print(he, __func__, " LIAR: after ipalloc ");
printf("MAC key %u IP key %u\n", key, ipkey );
}
}
#if 0
void *
mule(void *arg)
{
struct whack_param *w = arg ;
struct hash_entry *h ;
by_IP = g_sequence_new(NULL);
by_MAC = g_sequence_new(NULL);
GList *ip_list = make_ip_pool(w);
while(1)
{
// char *errtxt = NULL ;
h = g_async_queue_pop(queue_to_mule);
// check in exists
GSequenceIter *si ;
if ( ( si = g_sequence_lookup ( by_MAC, h, compare_mac, NULL )) != NULL )
{
h_print(h, __func__, "Exist in MAC table" );
h->error = 1 ;
g_async_queue_push( queue_to_arpl, h );
continue ;
}
// new entry
guint32 newip ;
if ( ip_list )
{
ip_list = ip_alloc(ip_list, &newip);
h->ip = newip ; h->error = 0 ;
g_sequence_insert_sorted (by_MAC, h, compare_mac, h);
g_sequence_insert_sorted (by_IP, h, compare_ip, h );
g_async_queue_push( queue_to_arpl, h );
g_async_queue_push( queue_to_backwrt, h );
h_print(h, __func__, "Allocated" );
continue ;
}
error(0, errno, "Out of IP addressed");
h->error = 1 ;
g_async_queue_push( queue_to_arpl, h );
}
return NULL ;
}
#endif // 0