/* Mis-connector - user-space router and NATP for misconfigured hosts on LAN.
Random tools.
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 <errno.h>
#include <libnet.h>
#include <glib.h>
#include <time.h>
#include "whackparam.h"
//extern GRWLock by_MAC_lock , by_IP_lock;
extern GData *by_MAC_dl , *by_IP_dl ;
// or g_bit_lock, g_bit_trylock, g_bit_unlock
enum
{
ALOCK_NONE = 0,
ALOCK_BIT_UPDATE = 1,
ALOCK_BIT_READ = 2,
ALOCK_BIT_WRITE = 3,
} ;
struct timespec ts = { .tv_sec = 0 , .tv_nsec = 1000000 } ; // 1ms
void
lock_read(struct MC_ALOCK *lck)
{
while( lck->lock & ALOCK_BIT_WRITE ) nanosleep(&ts, NULL);
g_bit_lock (&lck->lock, ALOCK_BIT_UPDATE );
lck->lock |= ALOCK_BIT_READ ;
++lck->read_count ;
g_bit_unlock (&lck->lock, ALOCK_BIT_UPDATE );
}
void
unlock_read(struct MC_ALOCK *lck)
{
if ( lck->lock & ALOCK_BIT_WRITE ) abort();
g_bit_lock (&lck->lock, ALOCK_BIT_UPDATE );
if ( --lck->read_count == 0 ) { lck->read_count = 0 ; lck->lock = 0 ; }
g_bit_unlock (&lck->lock, ALOCK_BIT_UPDATE );
}
void
lock_write(struct MC_ALOCK *lck)
{
while( lck->lock) nanosleep(&ts, NULL);
g_bit_lock (&lck->lock, ALOCK_BIT_UPDATE );
lck->lock |= ALOCK_BIT_WRITE ;
g_bit_unlock (&lck->lock, ALOCK_BIT_UPDATE );
// locked_by = gettid();
}
void
unlock_write(struct MC_ALOCK *lck)
{
if ( ! ( lck->lock & ALOCK_BIT_WRITE ) ) abort();
if ( lck->lock & ALOCK_BIT_READ ) abort();
g_bit_lock (&lck->lock, ALOCK_BIT_UPDATE );
lck->lock = 0 ;
g_bit_unlock (&lck->lock, ALOCK_BIT_UPDATE );
}
char *
addr2name4_r(uint32_t in)
{
uint8_t *p = (uint8_t *)∈
return g_strdup_printf( "%d.%d.%d.%d", (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255));
}
void
h_print(struct hash_entry *h, const char * const func, char *text)
{
char *ipi = addr2name4_r(h->in_ip);
char *ipnat = addr2name4_r(h->ip);
char *smac = mac2str(h->mac);
char *gwip = addr2name4_r(h->gw_ip);
fprintf(stderr, "[%s] ″%s″ NATIP: %s IP/GWIP/mac %s/%s/%s\n", func , text,
ipnat, ipi, gwip, smac );
g_free(ipi) ; g_free(ipnat) ; g_free(smac); g_free(gwip);
}
struct hash_entry *
ip_to_mac_ip(unsigned int netip)
{
struct hash_entry *he ;
#if 0
unsigned int ipkey = ipkey_get(netip);
he = sb->ip_to_mac[ipkey] ;
if ( he == NULL )
{
union conv c = { .u = netip } ;
WARNING("No IP entry for %u.%u.%u.%u\n",
c.c[0],
c.c[1],
c.c[2],
c.c[3]);
return NULL ;
}
#else
//
// new
//
GQuark ipkey = ip_key(netip);
lock_read(&by_IP_lock);
if ( ( he = g_datalist_id_get_data(&by_IP_dl, ipkey)) == NULL )
{
unlock_read(&by_IP_lock);
char * ips = addr2name4_r(netip) ;
error(0, errno, "No MAC+IP for net IP %s\n", ips);
g_free(ips);
}
unlock_read(&by_IP_lock);
#endif // 0
/* No collisions handling needed here , civilised IP is unique key */
return he ;
}
#if 0
static int
send_arp_query(struct ether_header *eh)
{
libnet_ptag_t t;
t = libnet_autobuild_arp(
ARPOP_REQUEST, /* operation type */
enet_src, /* sender hardware addr */
(uint8_t *)&i, /* sender protocol addr */
enet_dst, /* target hardware addr */
(uint8_t *)&i, /* target protocol addr */
l); /* libnet context */
if (t == -1)
{
fprintf(stderr, "Can't build ARP header: %s\n", libnet_geterror(l));
goto bad;
}
}
#endif // 0
/* return net order IP */
//unsigned int
struct hash_entry *
mac_to_ip(struct ether_header *eh )
{ /* */
GQuark key = mac_key(eh->ether_shost) ;
struct hash_entry *he ;
lock_read(&by_MAC_lock);
if ( ( he = g_datalist_id_get_data(&by_MAC_dl, key)) == NULL )
{
char * macs = mac2str(eh->ether_shost);
unlock_read(&by_MAC_lock);
error(0, 0, "No IP for MAC %s key %u\n", macs, key);
return 0 ;
}
unlock_read(&by_MAC_lock);
// DEBUGP(stderr,"%s Found IP %u.%u.%u.%u\n", ids[id],
// c.c[0],
// c.c[1],
// c.c[2],
// c.c[3]);
return he/* ->ip */ ;
// return he->ip ;
}
#if 0 ///////////////////////////////////////////////////
if ( sb->mac_to_ip[key] == NULL )
{
he = bm_alloc0(sb, sizeof *he, __func__ );
if ( he == NULL )
{
BUG("No new entry, bm_alloc returns NULL\n");
/* zap old entries, and try againg FIXME !!! or simple *CRASH* */
return ;
}
DEBUGP(stderr, "%s %s allocated -> new_entry\n", ids[id], __func__ );
goto new_entry ;
}
else
{
he = sb->mac_to_ip[key] ;
if ( he->next == NULL && ! memcmp(he->mac, sha, ETH_ALEN) ) /* entry exists */
{
DEBUGP(stderr,"Entry for MAC exists : ");
print_mac(sha);
DEBUGP(stderr,"\n");
return ;
}
/* handle collision */
if ( g_slist_find_mac(he, sha)) /* entry exists */
{
DEBUGP(stderr, "Entry for MAC exists in list : ");
print_mac(sha);
DEBUGP(stderr, "\n");
return ;
}
else
{
struct hash_entry *new = bm_alloc0(sb, sizeof *new, __func__ );
if ( new == NULL )
{
BUG("No new entry, bm_alloc returns NULL\n");
/* zap old entries, and try againg FIXME !!! or simple *CRASH* */
return ;
}
g_slist_append (he, new);
he = new ;
DEBUGP(stderr, "%s %s MAC doesn't exist -> new -> new_entry\n", ids[id], __func__ );
goto new_entry ;
}
}
return ;
new_entry:
memcpy(he->mac, sha, ETH_ALEN);
memcpy(&he->fool_ip, sip, sizeof he->fool_ip);
he->ip = htonl(ip_make(wp));
{
/* unsigned int ipkey = ntohl(ipkey_get(he->ip)); */
unsigned int ipkey = ipkey_get(he->ip);
DEBUGP(stderr, "%s %s ", ids[id], __func__);
print_mac(sha);
DEBUGP(stderr," Fool IP: %u.%u.%u.%u IPkey %d\n",
sip[0],
sip[1],
sip[2],
sip[3],
ipkey);
if ( ipkey > wp->fool_size )
BUG("IP key %u > hash size %d\n", ipkey, wp->fool_size );
else
DEBUGP(stderr,"%s IP key %u\n", __func__, ipkey );
sb->mac_to_ip[key] = he ;
sb->ip_to_mac[ ipkey ] = he ;
}
}
#endif // 0 //////////////////////////////////////////////////////////////////////////