/* Mis-connector - user-space router and NATP for misconfigured hosts on LAN.
Configuration file /etc/whack.conf parser
Copyright (C) 2004,2021 Petr Silhavy <petr.silhavy@yandex.com>
SPDX-License-Identifier: GPL-3.0-or-later
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 3 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 mis-connector. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pcap.h>
#include <libnet.h>
#include <gio/gio.h>
#include <gio/gnetworking.h>
#include <error.h>
#include <errno.h>
#include "whackparam.h"
#define CONF "/etc/whack.conf"
char *delimiters = " \t=-" ;
//char *keys[] = { "Fool_dev", "GW_dev", "Fool_range", "Fool_net", "Decent_net",
//"DNS", NULL } ;
char *keys[] = { "In_dev", "GW_dev", "In_nat", "DHCP_net", "DNS",
//
"gw_ip", "gw_mac", NULL } ;
struct whack_param *
read_conf()
{
struct whack_param *wp = Malloc0(sizeof *wp);
char *buf = NULL ;
size_t size = 0 ;
FILE *FP ;
int n ;
char ipbuf[16] ;
// int dhcp_mask , in_mask ;
GInetAddressMask *iam ;
GError *ge = NULL ;
GInetAddress *addr;
guint len;
GSocketFamily *family ;
const guint8 *bytes;
gboolean any;
gboolean loopback;
gboolean link_local;
gboolean site_local;
gboolean multicast;
if ( ( FP = fopen(CONF,"r")) == NULL )
BUG("Can't open: %s\n", CONF);
while (1)
{
char *key , *v ;
int i ;
struct in_addr ina ;
if ( (n = getline(&buf, &size, FP )) == EOF )
break ;
if ( *buf == '#' ) continue ;
if ( (v = strchr(buf, '\n' ) ) != NULL )
*v = 0 ;
key = strtok(buf, delimiters);
for ( i = 0 ; keys[i] ; ++i )
if ( ! strcasecmp(keys[i], key) )
break ;
switch ( i )
{
case 0: /* "Fool_dev" */
wp->in_dev = strdup(strtok(NULL, delimiters));
break ;
case 1: /* "GW_dev" */
wp->gw_dev = strdup(strtok(NULL, delimiters));
break ;
case 2: /* "in_nat" */
v = strdup(strtok(NULL, delimiters));
if ( ( iam = g_inet_address_mask_new_from_string (v, &ge)) == NULL )
error(EXIT_FAILURE,errno, "Malformed in_nat «%s» - %s\n", v, ge->message );
// g_error_free (err);
g_object_get (iam,
"family", &family,
"address", &addr,
"length", &len,
NULL);
g_object_get (addr,
"family", &family,
"bytes", &bytes,
"is-any", &any,
"is-loopback", &loopback,
"is-link-local", &link_local,
"is-site-local", &site_local,
"is-multicast", &multicast, NULL );
{
const guint8 *bt = g_inet_address_to_bytes(addr) ;
memcpy(&wp->in_min, bt, sizeof (int) );
wp->in_nat = wp->in_min ;
}
// mask
{
int n = 32 - len ;
wp->in_len = len ;
wp->in_size = 1 << n ;
wp->in_mask = ntohl(0xffffffff << ( n )) ;
wp->in_max = wp->in_min | ~wp->in_mask ;
}
break ;
case 3: /* DHCP net */
v = strdup(strtok(NULL, delimiters));
if ( ( iam = g_inet_address_mask_new_from_string (v, &ge)) == NULL )
error(EXIT_FAILURE,errno, "Malformed %s «%s» - %s\n", key, v, ge->message );
// g_error_free (err);
g_object_get (iam,
"family", &family,
"address", &addr,
"length", &len,
NULL);
g_object_get (addr,
"family", &family,
"bytes", &bytes,
"is-any", &any,
"is-loopback", &loopback,
"is-link-local", &link_local,
"is-site-local", &site_local,
"is-multicast", &multicast, NULL );
{
const guint8 *bt = g_inet_address_to_bytes(addr) ;
memcpy(&wp->dhcp_net, bt, sizeof (int) );
}
// mask
{
int n = 32 - len ;
wp->dhcp_len = len ;
wp->dhcp_mask = ntohl(0xffffffff << ( n )) ;
}
break ;
case 4: /* DNS */
v = strdup(strtok(NULL, delimiters));
if ( !inet_aton (v, &ina))
BUG("Malformed IP address `%s'\n",v);
wp->dns = ina.s_addr ;
break ;
case 5:/* default gw */
v = strdup(strtok(NULL, delimiters));
wp->gw_ip = g_inet_address_new_from_string (v);
wp->gw_ip_size = g_inet_address_get_native_size (wp->gw_ip);
wp->gw_ip_bytes = g_slice_alloc0( wp->gw_ip_size );
memcpy( wp->gw_ip_bytes, g_inet_address_to_bytes(wp->gw_ip), wp->gw_ip_size);
break ;
case 6: /* default gw's MAC */
v = strdup(strtok(NULL, delimiters));
char **stra = g_strsplit(v, ":", 6);
for ( int i = 0 ; stra[i] && i < ETH_ALEN ; ++i )
{
wp->gw_mac[i] = strtoul( stra[i], NULL, 16 );
}
g_strfreev(stra);
break ;
default:
BUG("Unknow configuration option `%s'\n", key );
break ;
}
}
printf("%s %s\n", PACKAGE, VERSION);
printf("%s Libnet %s\n", pcap_lib_version() , LIBNET_VERSION);
printf("Internal interface : %s\n", wp->in_dev);
printf("Interface to gateway : %s\n", wp->gw_dev);
inet_ntop(AF_INET, &wp->in_min, ipbuf, sizeof ipbuf);
printf("IP range : %s-", ipbuf);
inet_ntop(AF_INET, &wp->in_max, ipbuf, sizeof ipbuf);
printf("%s\n",ipbuf);
inet_ntop(AF_INET, &wp->in_nat, ipbuf, sizeof ipbuf);
printf("Internal net : %s\n", ipbuf);
asprintf( &wp->gw_filter_app, "dst net %s/%d", ipbuf, wp->in_len );
inet_ntop(AF_INET, &wp->in_mask, ipbuf, sizeof ipbuf);
printf("Internal netmask : %s\n", ipbuf);
wp->in_size = htonl(wp->in_max) - htonl(wp->in_min) + 1 ;
printf("Free IP addresses : %u\n", wp->in_size);
inet_ntop(AF_INET, &wp->dhcp_net, ipbuf, sizeof ipbuf);
printf("DHCP's net : %s\n", ipbuf);
/* not dst OKNET ether dst */
asprintf( &wp->filter_app, "not src net %s/%d", ipbuf, wp->dhcp_len);
printf("Internal filter : %s\n", wp->filter_app);
printf("Gateway filter : %s\n", wp->gw_filter_app);
inet_ntop(AF_INET, &wp->dns, ipbuf, sizeof ipbuf);
printf("DNS : %s\n", ipbuf);
char *tmp_ip = g_inet_address_to_string(wp->gw_ip);
printf("Default gateway : %s\n", tmp_ip );
g_free(tmp_ip);
tmp_ip = mac2str( wp->gw_mac );
printf("Default gateway's MAC : %s\n", tmp_ip );
g_free(tmp_ip);
/* char filter_app[] = "not src net 192.168.100.0/23" */
/* "ether proto arp" */; /* The filter expression */
/* char gw_filter_app[] = "dst net 192.168.101.0/24" */
free(buf);
return wp ;
}