diff --git a/feeds/ucentral/natlog/Makefile b/feeds/ucentral/natlog/Makefile new file mode 100644 index 000000000..5b9875cde --- /dev/null +++ b/feeds/ucentral/natlog/Makefile @@ -0,0 +1,39 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=natlog +PKG_VERSION:=1.0 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=kmk + +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) + +include $(INCLUDE_DIR)/kernel.mk +include $(INCLUDE_DIR)/package.mk + +# Define dependencies +define KernelPackage/natlog + SUBMENU:=Netfilter Extensions + TITLE:=NFLOG NAT translation logger + FILES:=$(PKG_BUILD_DIR)/natlog.ko + DEPENDS:=+kmod-nf-conntrack +kmod-nf-ipt +endef + +define KernelPackage/natlog/description + Kernel module for logging NAT translations via NFLOG. +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Build/Compile + $(KERNEL_MAKE) M="$(PKG_BUILD_DIR)" modules +endef + +define KernelPackage/natlog/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call KernelPackage,natlog)) diff --git a/feeds/ucentral/natlog/files/etc/config/natlog b/feeds/ucentral/natlog/files/etc/config/natlog new file mode 100644 index 000000000..4428b3818 --- /dev/null +++ b/feeds/ucentral/natlog/files/etc/config/natlog @@ -0,0 +1,2 @@ +# config defaults +# option enabled '1' \ No newline at end of file diff --git a/feeds/ucentral/natlog/files/etc/init.d/natlog b/feeds/ucentral/natlog/files/etc/init.d/natlog new file mode 100755 index 000000000..4308cc1a9 --- /dev/null +++ b/feeds/ucentral/natlog/files/etc/init.d/natlog @@ -0,0 +1,35 @@ +#!/bin/sh /etc/rc.common +# OpenWrt init script for natlog kernel module + +START=15 +STOP=90 + +USE_PROCD=1 + +modfile="/lib/modules/$(uname -r)/natlog.ko" + +start_service() { + enabled=$(uci get natlog.@defaults[0].enabled 2>/dev/null) + + if [ "$enabled" = "1" ]; then + if [ -f "$modfile" ]; then + echo "Loading natlog kernel module..." + insmod "$modfile" || { + echo "Failed to load $modfile" + return 1 + } + else + echo "Kernel module not found: $modfile" + return 1 + fi + else + echo "natlog disabled in UCI config" + fi +} + +stop_service() { + if lsmod | grep -q "^natlog"; then + echo "Unloading natlog kernel module..." + rmmod natlog + fi +} \ No newline at end of file diff --git a/feeds/ucentral/natlog/src/Makefile b/feeds/ucentral/natlog/src/Makefile new file mode 100644 index 000000000..d0d30122b --- /dev/null +++ b/feeds/ucentral/natlog/src/Makefile @@ -0,0 +1 @@ +obj-m += natlog.o diff --git a/feeds/ucentral/natlog/src/natlog.c b/feeds/ucentral/natlog/src/natlog.c new file mode 100644 index 000000000..b092a12b2 --- /dev/null +++ b/feeds/ucentral/natlog/src/natlog.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("KMK"); +MODULE_DESCRIPTION("Kernel module to log client request SNAT and server response DNAT using nf_conntrack"); + +static struct nf_hook_ops nat_hook_ops_pre; +static struct nf_hook_ops nat_hook_ops_post; + +static void log_nat_info(struct nf_conn *ct, struct sk_buff *skb, unsigned int hooknum) +{ + struct nf_conntrack_tuple *orig_tuple, *reply_tuple; + char *proto_name; + __u16 sport, dport, nat_sport, nat_dport; + __u32 saddr, daddr, nat_saddr, nat_daddr; + unsigned char *mac_addr; + char mac_str[18]; + + if (!ct) + return; + + orig_tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + reply_tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; + + switch (orig_tuple->dst.protonum) { + case IPPROTO_TCP: + proto_name = "TCP"; + break; + case IPPROTO_UDP: + proto_name = "UDP"; + break; + default: + return; + } + + saddr = orig_tuple->src.u3.ip; + daddr = orig_tuple->dst.u3.ip; + sport = ntohs(orig_tuple->src.u.all); + dport = ntohs(orig_tuple->dst.u.all); + + nat_saddr = reply_tuple->dst.u3.ip; + nat_daddr = reply_tuple->src.u3.ip; + nat_sport = ntohs(reply_tuple->dst.u.all); + nat_dport = ntohs(reply_tuple->src.u.all); + + if (hooknum == NF_INET_POST_ROUTING && (ct->status & IPS_SRC_NAT)) { + if (!skb_mac_header_was_set(skb)) + return; + mac_addr = skb_mac_header(skb); + snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x", + mac_addr[6], mac_addr[7], mac_addr[8], mac_addr[9], mac_addr[10], mac_addr[11]); + printk(KERN_INFO "NAT_LOG: %s SRC MAC: %s; Original: %pI4:%u -> %pI4:%u, NAT: %pI4:%u -> %pI4:%u\n", + proto_name, mac_str, + &saddr, sport, &daddr, dport, + &nat_saddr, nat_sport, &daddr, dport); + } +} + +static unsigned int nat_hook_func(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct nf_conn *ct; + enum ip_conntrack_info ct_info; + + ct = nf_ct_get(skb, &ct_info); + if (!ct) { + printk(KERN_DEBUG "NAT_LOG: No conntrack info for packet\n"); + return NF_ACCEPT; + } + + if (ct->status & IPS_NAT_MASK) { + log_nat_info(ct, skb, state->hook); + } + + return NF_ACCEPT; +} + +static int __init nat_logger_init(void) +{ + int ret; + + nat_hook_ops_post.hook = nat_hook_func; + nat_hook_ops_post.pf = PF_INET; + nat_hook_ops_post.hooknum = NF_INET_POST_ROUTING; + nat_hook_ops_post.priority = NF_IP_PRI_NAT_SRC; + + ret = nf_register_net_hook(&init_net, &nat_hook_ops_post); + if (ret) { + printk(KERN_ERR "NAT_LOG: Failed to register POST_ROUTING hook: %d\n", ret); + nf_unregister_net_hook(&init_net, &nat_hook_ops_post); + return ret; + } + + printk(KERN_INFO "NAT_LOG: Module loaded successfully\n"); + return 0; +} + +static void __exit nat_logger_exit(void) +{ + nf_unregister_net_hook(&init_net, &nat_hook_ops_post); + printk(KERN_INFO "NAT_LOG: Module unloaded\n"); +} + +module_init(nat_logger_init); +module_exit(nat_logger_exit); diff --git a/profiles/ucentral-ap.yml b/profiles/ucentral-ap.yml index f7dfcf587..12d3bab08 100644 --- a/profiles/ucentral-ap.yml +++ b/profiles/ucentral-ap.yml @@ -68,6 +68,7 @@ packages: - wireless-regdb - wpad-openssl - cloud_discovery + - kmod-natlog diffconfig: | CONFIG_OPENSSL_ENGINE=y CONFIG_OPENSSL_PREFER_CHACHA_OVER_GCM=y