/* Mis-connector - user-space router and NATP for misconfigured hosts on LAN.
Network utilities, ARP spoofer.
This file is part of mis-connector.
Copyright ⓒ 2022 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 <pcap.h>
#include <errno.h>
#include <sys/socket.h>
#include <features.h> /* for the glibc version number */
#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
#include <netpacket/packet.h>
#include <net/ethernet.h> /* the L2 protocols */
#else
#include <asm/types.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h> /* The L2 protocols */
#endif
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netinet/ip_icmp.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <netinet/igmp.h>
#include <arpa/nameser.h>
#include <error.h>
#include <glib.h>
#include <libnet.h>
//libnl: NLDBG=2 ./n/whack
#include <netlink/netlink.h>
#include <netlink/cache.h>
#include <netlink/route/link.h>
#include <netlink/socket.h>
#include <netlink/route/link.h>
#include <netlink/utils.h>
#include <netlink/route/route.h>
#include <netlink/route/nexthop.h>
#include <netlink/route/rtnl.h>
#include <netlink/cli/route.h>
#include <netlink/route/addr.h>
#include <linux/in_route.h>
#include "whackparam.h"
void route_add(struct nl_sock *, struct nl_addr *, int );
//3.2.2. Lookup Single Link (Direct Lookup)
//If only a single link is of interest, the link can be looked up directly without the use of a link cache using the function rtnl_link_get_kernel().
// int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name, struct rtnl_link **result);
/**
* Return error message for an error code
* @return error message
*/
//const char *nl_geterror(int error)
#define BUF_SIZE 256
void
route_init(struct nl_sock **sockp, struct nl_cache **cachep)
{
// struct nl_cache *cache;
// struct nl_sock
*sockp = nl_socket_alloc();
int err ;
if ((err = nl_connect(*sockp, NETLINK_ROUTE)) < 0)
error(1, errno, "Unable to connect socket ˝%s˝", nl_geterror(err));
if ((rtnl_link_alloc_cache(*sockp, AF_UNSPEC, cachep)) < 0)
error(0, errno, "rtnl_link_alloc_cache ˝%s˝", nl_geterror(err));
nl_socket_use_seq(*sockp);
}
void
route_finish(struct nl_sock *sock, struct nl_cache *cache)
{
nl_cache_put(cache);
nl_socket_free(sock);
}
void
route()
{
struct nl_sock *sock;
struct nl_cache *cache;
struct rtnl_link *link;
route_init(&sock, &cache );
if (!(link = rtnl_link_get_by_name(cache, wp->gw_dev)))
/* link does not exist */
error(1, errno, "link does not exist: ˝%s˝\n", wp->gw_dev);
/* do something with link */
int gw_idx = rtnl_link_get_ifindex(link);
uint8_t state = rtnl_link_get_operstate(link);
char buf[BUF_SIZE] ;
char *state_str = rtnl_link_operstate2str( state, buf, BUF_SIZE);
printf("Link %s[%d] is %s\n", wp->gw_dev, gw_idx, state_str );
unsigned int arptype = rtnl_link_get_arptype(link);
state_str = nl_llproto2str( arptype, buf, BUF_SIZE);
printf("Link %s[%d] ARP %s\n", wp->gw_dev, gw_idx, state_str );
unsigned int flags = rtnl_link_get_flags(link);
state_str= rtnl_link_flags2str( flags, buf, BUF_SIZE);
printf("Link %s[%d] flags %s\n", wp->gw_dev, gw_idx, state_str );
//
// addr
//
// struct rtnl_addr *raddr = rtnl_addr_alloc();
#if 0
struct rtnl_route *route = rtnl_route_alloc();
struct nl_addr *addr = nl_addr_alloc(16);
rtnl_route_set_iif(route, gw_idx );
int err = rtnl_route_add(sock, route, 0);
if ( err < 0 ) {
// nl_perror(err, "rtnl_route_add");
error(1, errno, "route add if :˝%s˝ - ˝%s˝", wp->gw_dev, nl_geterror(err));
}
#endif // 0
route_add(sock, wp->nl_nat_addr, gw_idx );
rtnl_link_put(link);
route_finish(sock, cache);
}
void
route_add(struct nl_sock *sock, struct nl_addr *nl_addr, int ifa)
{
struct rtnl_route *route;
// struct rtnl_nexthop *nh;
int ret;
route = rtnl_route_alloc();
if (!route)
error(1, errno,"Cannot allocate route");
ret = rtnl_route_set_dst(route, nl_addr);
if (ret < 0) {
rtnl_route_put(route);
error(1, errno, "Cannot set route destination - ˝%s˝", nl_geterror(ret));
}
rtnl_route_set_iif(route, ifa);
#if 0
nh = rtnl_route_nh_alloc();
if (!route) {
rtnl_route_put(route);
return TError(EError::Unknown, "Cannot allocate next hop");
}
rtnl_route_nh_set_ifindex(nh, GetIndex());
rtnl_route_add_nexthop(route, nh);
Dump("add", route);
#endif // 0
rtnl_route_guess_scope (route);
ret = rtnl_route_add(sock, route, NLM_F_CREATE | NLM_F_REPLACE);
rtnl_route_put(route);
if (ret < 0)
error(1, errno, "Cannot add direct route - ˝%s˝", nl_geterror(ret));
return ;
}