Browse Source

added ts3init_reset

pull/1/head
Maximilian Münchow 8 years ago
parent
commit
bf8594c03e
  1. 13
      src/Makefile
  2. 16
      src/compat_skbuff.h
  3. 12
      src/compat_user.h
  4. 92
      src/compat_xtables.h
  5. 67
      src/compat_xtnu.h
  6. 61
      src/libxt_ts3init_reset.c
  7. 13
      src/ts3init_module.c
  8. 232
      src/ts3init_target.c
  9. 4
      src/ts3init_target.h

13
src/Makefile

@ -3,17 +3,20 @@ MODULES_DIR := /lib/modules/$(shell uname -r) @@ -3,17 +3,20 @@ MODULES_DIR := /lib/modules/$(shell uname -r)
KERNEL_DIR := ${MODULES_DIR}/build
obj-m += xt_ts3init.o
xt_ts3init-objs += ts3init_module.o ts3init_match.o ts3init_cookie.o siphash24.o
xt_ts3init-objs += ts3init_module.o ts3init_match.o ts3init_cookie.o ts3init_target.o siphash24.o
so = libxt_ts3init_get_cookie.so libxt_ts3init_get_puzzle.so libxt_ts3init_reset.so
all:
make -C ${KERNEL_DIR} M=$$PWD;
$(MAKE) -C ${KERNEL_DIR} M=$$PWD;
$(MAKE) -f Makefile.xtables $(so)
modules:
make -C ${KERNEL_DIR} M=$$PWD $@;
$(MAKE) -C ${KERNEL_DIR} M=$$PWD $@;
modules_install:
make -C ${KERNEL_DIR} M=$$PWD $@;
$(MAKE) -C ${KERNEL_DIR} M=$$PWD $@;
clean:
make -C ${KERNEL_DIR} M=$$PWD $@;
$(MAKE) -C ${KERNEL_DIR} M=$$PWD $@;
rm $(so)

16
src/compat_skbuff.h

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
#ifndef COMPAT_SKBUFF_H
#define COMPAT_SKBUFF_H 1
struct tcphdr;
struct udphdr;
#define skb_ifindex(skb) (skb)->skb_iif
#define skb_nfmark(skb) (((struct sk_buff *)(skb))->mark)
#ifdef CONFIG_NETWORK_SECMARK
# define skb_secmark(skb) ((skb)->secmark)
#else
# define skb_secmark(skb) 0
#endif
#endif /* COMPAT_SKBUFF_H */

12
src/compat_user.h

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
/*
* Userspace-level compat hacks
*/
#ifndef _XTABLES_COMPAT_USER_H
#define _XTABLES_COMPAT_USER_H 1
/* linux-glibc-devel 2.6.34 header screwup */
#ifndef ALIGN
# define ALIGN(s, n) (((s) + ((n) - 1)) & ~((n) - 1))
#endif
#endif /* _XTABLES_COMPAT_USER_H */

92
src/compat_xtables.h

@ -0,0 +1,92 @@ @@ -0,0 +1,92 @@
#ifndef _XTABLES_COMPAT_H
#define _XTABLES_COMPAT_H 1
#include <linux/kernel.h>
#include <linux/version.h>
#include "compat_skbuff.h"
#include "compat_xtnu.h"
#define DEBUGP Use__pr_debug__instead
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
# warning Kernels below 3.7 not supported.
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
# define prandom_u32() random32()
#endif
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
# if !defined(CONFIG_NF_CONNTRACK_MARK)
# warning You have CONFIG_NF_CONNTRACK enabled, but CONFIG_NF_CONNTRACK_MARK is not (please enable).
# endif
# include <net/netfilter/nf_conntrack.h>
#else
# warning You need CONFIG_NF_CONNTRACK.
#endif
#if !defined(NIP6) && !defined(NIP6_FMT)
# define NIP6(addr) \
ntohs((addr).s6_addr16[0]), \
ntohs((addr).s6_addr16[1]), \
ntohs((addr).s6_addr16[2]), \
ntohs((addr).s6_addr16[3]), \
ntohs((addr).s6_addr16[4]), \
ntohs((addr).s6_addr16[5]), \
ntohs((addr).s6_addr16[6]), \
ntohs((addr).s6_addr16[7])
# define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
#endif
#if !defined(NIPQUAD) && !defined(NIPQUAD_FMT)
# define NIPQUAD(addr) \
((const unsigned char *)&addr)[0], \
((const unsigned char *)&addr)[1], \
((const unsigned char *)&addr)[2], \
((const unsigned char *)&addr)[3]
# define NIPQUAD_FMT "%u.%u.%u.%u"
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
static inline struct inode *file_inode(struct file *f)
{
return f->f_path.dentry->d_inode;
}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
static inline void proc_set_user(struct proc_dir_entry *de,
typeof(de->uid) uid, typeof(de->gid) gid)
{
de->uid = uid;
de->gid = gid;
}
static inline void *PDE_DATA(struct inode *inode)
{
return PDE(inode)->data;
}
static inline void proc_remove(struct proc_dir_entry *de)
{
if (de != NULL)
remove_proc_entry(de->name, de->parent);
}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)
# define ip6_local_out(xnet, xsk, xskb) ip6_local_out(xskb)
# define ip6_route_me_harder(xnet, xskb) ip6_route_me_harder(xskb)
# define ip_local_out(xnet, xsk, xskb) ip_local_out(xskb)
# define ip_route_me_harder(xnet, xskb, xaddrtype) ip_route_me_harder((xskb), (xaddrtype))
#endif
static inline struct net *par_net(const struct xt_action_param *par)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
return par->net;
#else
return dev_net((par->in != NULL) ? par->in : par->out);
#endif
}
#endif /* _XTABLES_COMPAT_H */

67
src/compat_xtnu.h

@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
#ifndef _COMPAT_XTNU_H
#define _COMPAT_XTNU_H 1
#include <linux/netfilter/x_tables.h>
struct module;
struct sk_buff;
struct xtnu_match {
/*
* Making it smaller by sizeof(void *) on purpose to catch
* lossy translation, if any.
*/
char name[sizeof(((struct xt_match *)NULL)->name) - 1 - sizeof(void *)];
uint8_t revision;
bool (*match)(const struct sk_buff *, struct xt_action_param *);
int (*checkentry)(const struct xt_mtchk_param *);
void (*destroy)(const struct xt_mtdtor_param *);
struct module *me;
const char *table;
unsigned int matchsize, hooks;
unsigned short proto, family;
void *__compat_match;
};
struct xtnu_target {
char name[sizeof(((struct xt_target *)NULL)->name) - 1 - sizeof(void *)];
uint8_t revision;
unsigned int (*target)(struct sk_buff **,
const struct xt_action_param *);
int (*checkentry)(const struct xt_tgchk_param *);
void (*destroy)(const struct xt_tgdtor_param *);
struct module *me;
const char *table;
unsigned int targetsize, hooks;
unsigned short proto, family;
void *__compat_target;
};
static inline struct xtnu_match *xtcompat_numatch(const struct xt_match *m)
{
void *q;
memcpy(&q, m->name + sizeof(m->name) - sizeof(void *), sizeof(void *));
return q;
}
static inline struct xtnu_target *xtcompat_nutarget(const struct xt_target *t)
{
void *q;
memcpy(&q, t->name + sizeof(t->name) - sizeof(void *), sizeof(void *));
return q;
}
extern int xtnu_register_match(struct xtnu_match *);
extern void xtnu_unregister_match(struct xtnu_match *);
extern int xtnu_register_matches(struct xtnu_match *, unsigned int);
extern void xtnu_unregister_matches(struct xtnu_match *, unsigned int);
extern int xtnu_register_target(struct xtnu_target *);
extern void xtnu_unregister_target(struct xtnu_target *);
extern int xtnu_register_targets(struct xtnu_target *, unsigned int);
extern void xtnu_unregister_targets(struct xtnu_target *, unsigned int);
extern void *HX_memmem(const void *, size_t, const void *, size_t);
#endif /* _COMPAT_XTNU_H */

61
src/libxt_ts3init_reset.c

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
/*
* "libxt_ts3init_reset" target extension for iptables
* Niels Werensteijn <niels werensteijn [at] teamspeak com>, 2016-10-03
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License; either version 2
* or 3 of the License, as published by the Free Software Foundation.
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <xtables.h>
#include "ts3init_target.h"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
static void ts3init_reset_help(void)
{
printf("ts3init_reset takes no options\n\n");
}
static int ts3init_reset_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **targetinfo)
{
return false;
}
/* register and init */
static struct xtables_target ts3init_tg_reg[] =
{
{
.name = "ts3init_reset",
.revision = 0,
.family = NFPROTO_IPV4,
.version = XTABLES_VERSION,
.size = 0,
.userspacesize = 0,
.help = ts3init_reset_help,
.parse = ts3init_reset_parse,
},
{
.name = "ts3init_reset",
.revision = 0,
.family = NFPROTO_IPV6,
.version = XTABLES_VERSION,
.size = 0,
.userspacesize = 0,
.help = ts3init_reset_help,
.parse = ts3init_reset_parse,
},
};
static __attribute__((constructor)) void ts3init_tg_ldr(void)
{
xtables_register_targets(ts3init_tg_reg, ARRAY_SIZE(ts3init_tg_reg));
}

13
src/ts3init_module.c

@ -20,6 +20,11 @@ @@ -20,6 +20,11 @@
int __init ts3init_match_init(void);
void __exit ts3init_match_exit(void);
/* defined in ts3init_target.c */
int __init ts3init_target_init(void);
void __exit ts3init_target_exit(void);
MODULE_AUTHOR("Niels Werensteijn <niels.werensteijn@teamspeak.com>");
MODULE_DESCRIPTION("A module to aid in ts3 spoof protection");
MODULE_LICENSE("GPL");
@ -28,12 +33,18 @@ MODULE_ALIAS("ip6t_ts3init"); @@ -28,12 +33,18 @@ MODULE_ALIAS("ip6t_ts3init");
static int __init ts3init_init(void)
{
return ts3init_match_init();
int error;
error = ts3init_match_init();
if (error)
return error;
error = ts3init_target_init();
return error;
}
static void __exit ts3init_exit(void)
{
ts3init_match_exit();
ts3init_target_exit();
}
module_init(ts3init_init);

232
src/ts3init_target.c

@ -0,0 +1,232 @@ @@ -0,0 +1,232 @@
/*
* "ts3init" extension for Xtables
*
* Description: A module to aid in ts3 spoof protection
* This is the "target" code
*
* Authors:
* Niels Werensteijn <niels werensteijn [at] teampseak com>, 2016-10-03
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License; either version 2
* or 3 of the License, as published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/ip.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/udp.h>
#include <linux/netfilter/x_tables.h>
#ifdef CONFIG_BRIDGE_NETFILTER
# include <linux/netfilter_bridge.h>
#endif
#include <net/ip.h>
#include <net/ip6_checksum.h>
#include <net/ip6_route.h>
#include <net/route.h>
#include "compat_xtables.h"
#include "ts3init_target.h"
#include "ts3init_header.h"
bool
send_ipv6(const struct sk_buff *oldskb, const struct xt_action_param *par, u8 command, const void *payload, const size_t payload_size)
{
const struct udphdr *oldudp;
const struct ipv6hdr *oldip;
struct udphdr *newudp, oldudp_buf;
struct ipv6hdr *newip;
struct sk_buff *newskb;
struct flowi6 fl;
struct dst_entry *dst = NULL;
struct net *net = dev_net((par->in != NULL) ? par->in : par->out);
oldip = ipv6_hdr(oldskb);
oldudp = skb_header_pointer(oldskb, par->thoff,
sizeof(*oldudp), &oldudp_buf);
if (oldudp == NULL)
return false;
if (ntohs(oldudp->len) <= sizeof(*oldudp))
return false;
newskb = alloc_skb(LL_MAX_HEADER + sizeof(*newip) +
sizeof(*newudp) + payload_size, GFP_ATOMIC);
if (newskb == NULL)
return false;
skb_reserve(newskb, LL_MAX_HEADER);
newskb->protocol = oldskb->protocol;
skb_reset_network_header(newskb);
newip = (void *)skb_put(newskb, sizeof(*newip));
newip->version = oldip->version;
newip->priority = oldip->priority;
memcpy(newip->flow_lbl, oldip->flow_lbl, sizeof(newip->flow_lbl));
newip->nexthdr = par->target->proto;
newip->saddr = oldip->daddr;
newip->daddr = oldip->saddr;
skb_reset_transport_header(newskb);
newudp = (void *)skb_put(newskb, sizeof(*newudp));
newudp->source = oldudp->dest;
newudp->dest = oldudp->source;
newudp->len = htons(sizeof(*newudp) + payload_size);
memcpy(skb_put(newskb, payload_size), payload, payload_size);
newip->payload_len = htons(newskb->len);
newudp->check = 0;
newudp->check = csum_ipv6_magic(&newip->saddr, &newip->daddr,
ntohs(newudp->len), IPPROTO_UDP,
csum_partial(newudp, ntohs(newudp->len), 0));
memset(&fl, 0, sizeof(fl));
fl.flowi6_proto = newip->nexthdr;
memcpy(&fl.saddr, &newip->saddr, sizeof(fl.saddr));
memcpy(&fl.daddr, &newip->daddr, sizeof(fl.daddr));
fl.fl6_sport = newudp->source;
fl.fl6_dport = newudp->dest;
security_skb_classify_flow((struct sk_buff *)oldskb, flowi6_to_flowi(&fl));
dst = ip6_route_output(net, NULL, &fl);
if (dst == NULL || dst->error != 0) {
dst_release(dst);
goto free_nskb;
}
skb_dst_set(newskb, dst);
newip->hop_limit = ip6_dst_hoplimit(skb_dst(newskb));
newskb->ip_summed = CHECKSUM_NONE;
/* "Never happens" (?) */
if (newskb->len > dst_mtu(skb_dst(newskb)))
goto free_nskb;
nf_ct_attach(newskb, oldskb);
ip6_local_out(par_net(par), newskb->sk, newskb);
return true;
free_nskb:
kfree_skb(newskb);
return false;
}
bool
send_ipv4(const struct sk_buff *oldskb, const struct xt_action_param *par, u8 command, const void *payload, const size_t payload_size)
{
const struct udphdr *oldudp;
const struct iphdr *oldip;
struct udphdr *newudp, oldudp_buf;
struct iphdr *newip;
struct sk_buff *newskb;
oldip = ip_hdr(oldskb);
oldudp = skb_header_pointer(oldskb, par->thoff,
sizeof(*oldudp), &oldudp_buf);
if (oldudp == NULL)
return false;
if (ntohs(oldudp->len) <= sizeof(*oldudp))
return false;
newskb = alloc_skb(LL_MAX_HEADER + sizeof(*newip) +
sizeof(*newudp) + payload_size, GFP_ATOMIC);
if (newskb == NULL)
return false;
skb_reserve(newskb, LL_MAX_HEADER);
newskb->protocol = oldskb->protocol;
skb_reset_network_header(newskb);
newip = (void *)skb_put(newskb, sizeof(*newip));
newip->version = oldip->version;
newip->ihl = sizeof(*newip) / 4;
newip->tos = oldip->tos;
newip->id = oldip->id;
newip->frag_off = 0;
newip->protocol = oldip->protocol;
newip->check = 0;
newip->saddr = oldip->daddr;
newip->daddr = oldip->saddr;
skb_reset_transport_header(newskb);
newudp = (void *)skb_put(newskb, sizeof(*newudp));
newudp->source = oldudp->dest;
newudp->dest = oldudp->source;
newudp->len = htons(sizeof(*newudp) + payload_size);
memcpy(skb_put(newskb, payload_size), payload, payload_size);
newip->tot_len = htons(newskb->len);
newudp->check = 0;
newudp->check = csum_tcpudp_magic(newip->saddr, newip->daddr,
ntohs(newudp->len), IPPROTO_UDP,
csum_partial(newudp, ntohs(newudp->len), 0));
/* ip_route_me_harder expects the skb's dst to be set */
skb_dst_set(newskb, dst_clone(skb_dst(oldskb)));
if (ip_route_me_harder(par_net(par), newskb, RTN_UNSPEC) != 0)
goto free_nskb;
newip->ttl = ip4_dst_hoplimit(skb_dst(newskb));
newskb->ip_summed = CHECKSUM_NONE;
/* "Never happens" (?) */
if (newskb->len > dst_mtu(skb_dst(newskb)))
goto free_nskb;
nf_ct_attach(newskb, oldskb);
ip_local_out(par_net(par), newskb->sk, newskb);
return true;
free_nskb:
kfree_skb(newskb);
return false;
}
static const char reset_package[] = {'T', 'S', '3', 'I', 'N', 'I', 'T', '1', 0x65, 0, 0x88, COMMAND_RESET_PUZZLE, 0 };
static unsigned int
ts3init_reset_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
switch (par->family)
{
case NFPROTO_IPV4:
send_ipv4(skb, par, COMMAND_RESET_PUZZLE, reset_package, sizeof(reset_package));
break;
case NFPROTO_IPV6:
send_ipv6(skb, par, COMMAND_RESET_PUZZLE, reset_package, sizeof(reset_package));
break;
}
return NF_DROP;
}
static struct xt_target ts3init_tg_reg[] __read_mostly = {
{
.name = "ts3init_reset",
.revision = 0,
.family = NFPROTO_IPV4,
.proto = IPPROTO_UDP,
.target = ts3init_reset_tg,
.me = THIS_MODULE,
},
{
.name = "ts3init_reset",
.revision = 0,
.family = NFPROTO_IPV6,
.proto = IPPROTO_UDP,
.target = ts3init_reset_tg,
.me = THIS_MODULE,
},
};
int __init ts3init_target_init(void)
{
return xt_register_targets(ts3init_tg_reg, ARRAY_SIZE(ts3init_tg_reg));
}
void __exit ts3init_target_exit(void)
{
xt_unregister_targets(ts3init_tg_reg, ARRAY_SIZE(ts3init_tg_reg));
}

4
src/ts3init_target.h

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
#ifndef _TS3INIT_TARGET_H
#define _TS3INIT_TARGET_H
#endif /* _TS3INIT_TARGET_H */
Loading…
Cancel
Save