This linux kernel module acts like an icmp proxy for echo/echo-reply packets at kernel level, preventing icmp tunnels through firewalls or directly to the server it is installed on.
9fad32f633cbf5845c1c9aa19434551345fd747ac16e91b836ef8dfa81ef6435
/*
* mod_icmp module kernel
* by: Fryxar
* e-mail: fryxar@yahoo.com.ar
*
* This module acts like an icmp proxy for echo/echo-reply packets at kernel level,
* preventing icmp tunnels through firewalls or directly connections to a server.
*
* WARNNING:
* It doesn't support fragmented packet (at time...)
*
* Why do not use an userland icmp proxy?
* 1. You must disable icmp kernel handler to use it, so you need to patch the kernel anyway.
* 2. You don't need to modify ipchains and iptables politics
*
* TODO:
* Support fragmented packets
* Support another icmp messages
* Replace TRANSFORM algorithm
* Any other suggest?
*
* COMPILE & RUN:
* gcc -DMODULE -D__KERNEL__ -O -Wall -c mod_icmp.c -I/usr/src/linux/include
* insmod mod_icmp.o
*
*/
#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/icmp.h>
#include <linux/netdevice.h>
#include <linux/kernel.h>
#include <linux/if_ether.h>
#include <linux/time.h>
#define IP_MF 0x2000
#define IP_OFFMASK 0x1fff
//#define TRANSFORM(x) (~x) // Trivial transform
#define TRANSFORM(x,b) (x^b) // Yet another trivial transform :-)
struct packet_type icmp_proto;
unsigned char seed;
unsigned short icmp_cksum(unsigned short *ptr,int nbytes)
{
register long sum;
unsigned short oddbyte;
register unsigned short anwser;
sum = 0;
while(nbytes>1)
{
sum += *ptr++;
nbytes -= 2;
}
if(nbytes==1)
{
oddbyte = 0;
*((unsigned char *) & oddbyte) = *(unsigned char *)ptr;
sum += oddbyte;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
anwser = ~sum;
return(anwser);
}
/* Packet Handler Function */
int icmp_func(struct sk_buff *skb, struct device *dev, struct packet_type *pt) {
int i;
if(htons(skb->mac.ethernet->h_proto) != ETH_P_IP) goto bye;
skb->h.raw = skb->nh.raw + skb->nh.iph->ihl*4;
// Fragmented packet not supported
if(htons(skb->nh.iph->frag_off)&(IP_OFFMASK|IP_MF)) goto bye;
if(skb->nh.iph->protocol != IPPROTO_ICMP) goto bye;
if(skb->h.icmph->type != ICMP_ECHO &&
skb->h.icmph->type != ICMP_ECHOREPLY) goto bye;
// Process icmp packet
skb->len = htons(skb->nh.iph->tot_len) -
sizeof(struct iphdr) - sizeof(struct icmphdr);
skb->data = (skb->h.raw) + sizeof(struct icmphdr);
for(i = 0; i < skb->len; i++)
skb->data[i] = TRANSFORM(skb->data[i], seed);
// Calculate checksums again
skb->h.icmph->checksum = 0;
skb->h.icmph->checksum = icmp_cksum(skb->h.raw, skb->len
+ sizeof(struct icmphdr));
bye:
kfree_skb(skb);
return 0;
}
int init_module(void) {
seed = (unsigned char)get_cmos_time();
icmp_proto.dev = NULL;
icmp_proto.type = htons(ETH_P_ALL);
icmp_proto.func = icmp_func;
dev_add_pack(&icmp_proto);
return(0);
}
void cleanup_module(void) {
dev_remove_pack(&icmp_proto);
}