Re: TCP port firewall controlled by UDP packets

From: Pavel Machek
Date: Thu Aug 25 2011 - 09:20:04 EST


No comments, variables named in czech.

Ok for me but...

But first thing would be description what it is good for...?

Pavel

On Fri 2011-08-12 01:42:52, Tonda wrote:
> If unsure, say N.
> +
> +config TCPFIREWALL
> + tristate "TCP Firewall controlled by UDP queries"
> + depends on m
> diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
> --- a/net/ipv4/Makefile
> +++ b/net/ipv4/Makefile
> @@ -51,3 +51,4 @@
>
> obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
> xfrm4_output.o
> +obj-$(CONFIG_TCPFIREWALL) += tcpfirewall/
> diff --git a/net/ipv4/tcpfirewall/Makefile b/net/ipv4/tcpfirewall/Makefile
> --- a/net/ipv4/tcpfirewall/Makefile
> +++ b/net/ipv4/tcpfirewall/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_TCPFIREWALL) += tcpfirewall.o
> diff --git a/net/ipv4/tcpfirewall/tcpfirewall.c b/net/ipv4/tcpfirewall/tcpfirewall.c
> --- a/net/ipv4/tcpfirewall/tcpfirewall.c
> +++ b/net/ipv4/tcpfirewall/tcpfirewall.c
> @@ -0,0 +1,451 @@
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/skbuff.h>
> +#include <linux/in.h>
> +#include <linux/if_packet.h>
> +#include <linux/tcp.h>
> +#include <linux/udp.h>
> +#include <net/tcp.h>
> +#include <net/udp.h>
> +
> +struct net_protocol {
> + int (*handler)(struct sk_buff *skb);
> + void (*err_handler)(struct sk_buff *skb, u32 info);
> + int (*gso_send_check)(struct sk_buff *skb);
> + struct sk_buff *(*gso_segment)(struct sk_buff *skb,
> + u32 features);
> + struct sk_buff **(*gro_receive)(struct sk_buff **head,
> + struct sk_buff *skb);
> + int (*gro_complete)(struct sk_buff *skb);
> + unsigned int no_policy:1,
> + netns_ok:1;
> +};
> +
> +MODULE_LICENSE("GPL");
> +
> +static unsigned long inet_protos = 0x01234567;
> +
> +struct net_protocol **_inet_protos;
> +
> +module_param(inet_protos, ulong, 0);
> +
> +static int *otviraky;
> +static int *zaviraky;
> +
> +static int pocetotviraku;
> +static int pocetzaviraku;
> +static int stav;
> +static int packetcounter;
> +static int tcpport;
> +static int open;
> +static int firewall;
> +
> +int (*tcpv4recv) (struct sk_buff *skb);
> +int (*udprecv) (struct sk_buff *skb);
> +
> +int udpcontroller(struct sk_buff *skb)
> +{
> + const struct udphdr *uh;
> +
> + if (skb->pkt_type != PACKET_HOST) {
> + kfree_skb(skb);
> + return 0;
> + }
> +
> + if (!pskb_may_pull(skb, sizeof(struct tcphdr))) {
> + kfree_skb(skb);
> + return 0;
> + }
> +
> + uh = udp_hdr(skb);
> +
> + if (pocetotviraku == 0)
> + return udprecv(skb);
> +
> + if (!open) {
> + if (uh->dest == otviraky[stav]) {
> + ++stav;
> + packetcounter = 0;
> +
> + if (stav == pocetotviraku) {
> + open = 1;
> + stav = 0;
> + }
> + } else {
> + if (packetcounter <= 16) {
> + ++packetcounter;
> + if (packetcounter > 16)
> + stav = 0;
> + }
> + }
> + } else {
> + if (uh->dest == zaviraky[stav]) {
> + ++stav;
> + packetcounter = 0;
> +
> + if (stav == pocetzaviraku) {
> + open = 0;
> + stav = 0;
> + }
> + } else {
> + if (packetcounter <= 16) {
> + ++packetcounter;
> + if (packetcounter > 16)
> + stav = 0;
> + }
> + }
> + }
> +
> +
> + return udprecv(skb);
> +}
> +
> +int tcpfirewall(struct sk_buff *skb)
> +{
> + const struct tcphdr *th;
> +
> + if (skb->pkt_type != PACKET_HOST) {
> + kfree_skb(skb);
> + return 0;
> + }
> +
> + if (!pskb_may_pull(skb, sizeof(struct tcphdr))) {
> + kfree_skb(skb);
> + return 0;
> + }
> +
> + th = tcp_hdr(skb);
> +
> + if (th->dest == tcpport) {
> + if (firewall == 1 && !open) {
> + /*tcpv4sendreset(NULL, skb);*/
> + kfree_skb(skb);
> + return 0;
> + }
> + }
> +
> + return tcpv4recv(skb);
> +}
> +
> +static struct net_protocol *zalohatcp;
> +static struct net_protocol *zalohaudp;
> +static struct net_protocol mytcp;
> +static struct net_protocol myudp;
> +
> +static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buffer)
> +{
> + if (!strcmp(attr->name, "firewall")) {
> + if (firewall)
> + buffer[0] = '1';
> + else
> + buffer[0] = '0';
> +
> + buffer[1] = '\n';
> + return 2;
> + }
> +
> + if (!strcmp(attr->name, "tcpport")) {
> + sprintf(buffer, "%d\n", ntohs(tcpport));
> + return strlen(buffer)+1;
> + }
> +
> + if (!strcmp(attr->name, "openers")) {
> + int i;
> + char *znak;
> + if (pocetotviraku == 0)
> + return 0;
> + buffer[0] = '\0';
> + znak = kmalloc(10, GFP_KERNEL);
> + for (i = 0; i < pocetotviraku; ++i) {
> + sprintf(znak, "%d ", ntohs(otviraky[i]));
> + strcat(buffer, znak);
> + }
> + kfree(znak);
> + buffer[strlen(buffer)-1] = '\n';
> + return strlen(buffer);
> + }
> +
> + if (!strcmp(attr->name, "closers")) {
> + int i;
> + char *znak;
> + if (pocetzaviraku == 0)
> + return 0;
> + buffer[0] = '\0';
> + znak = kmalloc(10, GFP_KERNEL);
> + for (i = 0; i < pocetzaviraku; ++i) {
> + sprintf(znak, "%d ", ntohs(zaviraky[i]));
> + strcat(buffer, znak);
> + }
> + kfree(znak);
> + buffer[strlen(buffer)-1] = '\n';
> + return strlen(buffer);
> + }
> +
> + if (!strcmp(attr->name, "open")) {
> + if (open)
> + buffer[0] = '1';
> + else
> + buffer[0] = '0';
> +
> + buffer[1] = '\n';
> + return 2;
> + }
> +
> + if (!strcmp(attr->name, "state")) {
> + sprintf(buffer, "%d\n", stav);
> + return strlen(buffer)+1;
> + }
> +
> + if (!strcmp(attr->name, "counter")) {
> + sprintf(buffer, "%d\n", packetcounter);
> + return strlen(buffer)+1;
> + }
> +
> + return 0;
> +}
> +
> +static ssize_t store(struct kobject *kobj, struct attribute *attr,
> + const char *buffer, size_t size)
> +{
> + int i;
> + char *cislo;
> + if (!strcmp(attr->name, "firewall")) {
> + if (size > 0 && buffer[0] == '1')
> + firewall = 1;
> + else
> + firewall = 0;
> + stav = 0;
> + return size;
> + }
> +
> + if (!strcmp(attr->name, "tcpport")) {
> + cislo = kmalloc(size+1, GFP_KERNEL);
> + for (i = 0; i < size; ++i)
> + cislo[i] = buffer[i];
> + cislo[size] = '\0';
> + if (kstrtoint(cislo, 10, &i) < 0)
> + i = -1;
> + if (i > 0 && i < 65536)
> + tcpport = htons(i);
> + kfree(cislo);
> + stav = 0;
> + return size;
> + }
> +
> + if (!strcmp(attr->name, "openers")) {
> + int udpport, i;
> + int *noveotviraky;
> + int *stareotviraky;
> + cislo = kmalloc(size+1, GFP_KERNEL);
> + for (i = 0; i < size; ++i)
> + cislo[i] = buffer[i];
> + cislo[size] = '\0';
> +
> + if (!strcmp(cislo, "reset") || !strcmp(cislo, "reset\n")) {
> + if (pocetotviraku)
> + kfree(otviraky);
> + pocetotviraku = 0;
> + }
> +
> + if (kstrtoint(cislo, 10, &i) < 0)
> + i = -1;
> + kfree(cislo);
> +
> + if (i > 0 && i < 65536 && (pocetotviraku == 0 ||
> + otviraky[pocetotviraku-1] != i))
> + udpport = htons(i);
> + else
> + return size;
> +
> + if (pocetotviraku < 10) {
> + noveotviraky = kmalloc((pocetotviraku+1)*sizeof(int),
> + GFP_KERNEL);
> +
> + for (i = 0; i < pocetotviraku; ++i)
> + noveotviraky[i] = otviraky[i];
> +
> + noveotviraky[pocetotviraku] = udpport;
> + stareotviraky = otviraky;
> + otviraky = noveotviraky;
> + if (pocetotviraku)
> + kfree(stareotviraky);
> +
> + ++pocetotviraku;
> + }
> + stav = 0;
> + return size;
> + }
> +
> + if (!strcmp(attr->name, "closers")) {
> + int udpport, i;
> + int *novezaviraky;
> + int *starezaviraky;
> + cislo = kmalloc(size+1, GFP_KERNEL);
> + for (i = 0; i < size; ++i)
> + cislo[i] = buffer[i];
> + cislo[size] = '\0';
> +
> + if (!strcmp(cislo, "reset") || !strcmp(cislo, "reset\n")) {
> + if (pocetzaviraku)
> + kfree(zaviraky);
> + pocetzaviraku = 0;
> + }
> +
> + if (kstrtoint(cislo, 10, &i) < 0)
> + i = -1;
> + kfree(cislo);
> +
> + if (i > 0 && i < 65536 && (pocetzaviraku == 0 ||
> + zaviraky[pocetzaviraku-1] != i))
> + udpport = htons(i);
> + else
> + return size;
> +
> + if (pocetzaviraku < 10) {
> + novezaviraky = kmalloc((pocetzaviraku+1)*sizeof(int),
> + GFP_KERNEL);
> +
> + for (i = 0; i < pocetzaviraku; ++i)
> + novezaviraky[i] = zaviraky[i];
> +
> + novezaviraky[pocetzaviraku] = udpport;
> + starezaviraky = zaviraky;
> + zaviraky = novezaviraky;
> + if (pocetzaviraku)
> + kfree(starezaviraky);
> +
> + ++pocetzaviraku;
> + }
> + stav = 0;
> + return size;
> + }
> +
> + if (!strcmp(attr->name, "open")) {
> + if (size > 0 && buffer[0] == '1')
> + open = 1;
> + else
> + open = 0;
> +
> + stav = 0;
> + return size;
> + }
> +
> + return 0;
> +}
> +
> +static const struct sysfs_ops so = {
> + .show = show,
> + .store = store,
> +};
> +
> +static struct kobj_type khid = {
> + .sysfs_ops = &so,
> +};
> +
> +static struct kobject kobj;
> +
> +static const struct attribute fw = {
> + .name = "firewall",
> + .mode = S_IRWXU,
> +};
> +
> +static const struct attribute opn = {
> + .name = "open",
> + .mode = S_IRWXU,
> +};
> +
> +static const struct attribute tcpp = {
> + .name = "tcpport",
> + .mode = S_IRWXU,
> +};
> +
> +static const struct attribute openers = {
> + .name = "openers",
> + .mode = S_IRWXU,
> +};
> +
> +static const struct attribute closers = {
> + .name = "closers",
> + .mode = S_IRWXU,
> +};
> +
> +static const struct attribute stat = {
> + .name = "state",
> + .mode = S_IRUSR,
> +};
> +
> +static const struct attribute counte = {
> + .name = "counter",
> + .mode = S_IRUSR,
> +};
> +
> +static int __init start(void)
> +{
> + if (inet_protos == 0x01234567) {
> + printk(KERN_WARNING "inet_protos parameter was not");
> + printk(KERN_WARNING " specified!\nread its value from");
> + printk(KERN_WARNING " System_map file file, and insert");
> + printk(KERN_WARNING " the module again!\n");
> + return -1;
> + }
> +
> + pocetotviraku = 0;
> + pocetzaviraku = 0;
> + stav = -1;
> + packetcounter = 0;
> + tcpport = 0;
> + open = 1;
> + firewall = 0;
> +
> + memset(&kobj, 0, sizeof(struct kobject));
> +
> + _inet_protos = (struct net_protocol **)inet_protos;
> +
> + kobject_init(&kobj, &khid);
> + if (kobject_add(&kobj, NULL, "tcpfirewall") < 0)
> + printk(KERN_ERR "kobject_add failed");
> +
> + if (sysfs_create_file(&kobj, &fw) < 0)
> + printk(KERN_ERR "sysfs_create_file failed");
> + if (sysfs_create_file(&kobj, &opn) < 0)
> + printk(KERN_ERR "sysfs_create_file failed");
> + if (sysfs_create_file(&kobj, &tcpp) < 0)
> + printk(KERN_ERR "sysfs_create_file failed");
> + if (sysfs_create_file(&kobj, &openers) < 0)
> + printk(KERN_ERR "sysfs_create_file failed");
> + if (sysfs_create_file(&kobj, &closers) < 0)
> + printk(KERN_ERR "sysfs_create_file failed");
> + if (sysfs_create_file(&kobj, &stat) < 0)
> + printk(KERN_ERR "sysfs_create_file failed");
> + if (sysfs_create_file(&kobj, &counte) < 0)
> + printk(KERN_ERR "sysfs_create_file failed");
> +
> + zalohatcp = _inet_protos[IPPROTO_TCP];
> + zalohaudp = _inet_protos[IPPROTO_UDP];
> + mytcp = *zalohatcp;
> + myudp = *zalohaudp;
> + tcpv4recv = mytcp.handler;
> + udprecv = myudp.handler;
> + mytcp.handler = tcpfirewall;
> + myudp.handler = udpcontroller;
> + _inet_protos[IPPROTO_TCP] = &mytcp;
> + _inet_protos[IPPROTO_UDP] = &myudp;
> + return 0;
> +}
> +
> +static void konec(void)
> +{
> + _inet_protos[IPPROTO_TCP] = zalohatcp;
> + _inet_protos[IPPROTO_UDP] = zalohaudp;
> +
> + if (pocetotviraku)
> + kfree(otviraky);
> + if (pocetzaviraku)
> + kfree(zaviraky);
> +
> + kobject_del(&kobj);
> +}
> +
> +module_init(start);
> +module_exit(konec);
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/