Browse Source

added TS3INIT_SET_COOKIE

renamed ts3init_reset to TS3INIT_RESET

moved cookie seed spefic things to ts3init_cookie_seed.h
moved cache specific things to ts3init_cache
pull/1/head
Maximilian Münchow 8 years ago
parent
commit
1a334a2885
  1. 2
      src/Makefile
  2. 2
      src/Makefile.xtables
  3. 3
      src/libxt_TS3INIT_RESET.c
  4. 120
      src/libxt_TS3INIT_SET_COOKIE.c
  5. 1
      src/libxt_ts3init_get_cookie.c
  6. 24
      src/libxt_ts3init_get_puzzle.c
  7. 118
      src/ts3init_cache.c
  8. 10
      src/ts3init_cache.h
  9. 8
      src/ts3init_cookie.c
  10. 6
      src/ts3init_cookie.h
  11. 28
      src/ts3init_cookie_seed.h
  12. 79
      src/ts3init_match.c
  13. 4
      src/ts3init_match.h
  14. 394
      src/ts3init_target.c
  15. 23
      src/ts3init_target.h

2
src/Makefile

@ -3,7 +3,7 @@ MODULES_DIR := /lib/modules/$(shell uname -r) @@ -3,7 +3,7 @@ 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 ts3init_target.o siphash24.o
xt_ts3init-objs += ts3init_module.o ts3init_match.o ts3init_cookie.o ts3init_target.o ts3init_cache.o siphash24.o
all:
$(MAKE) -C ${KERNEL_DIR} M=$$PWD;

2
src/Makefile.xtables

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
CFLAGS = -O2 -Wall
LIBS = libxt_ts3init_get_cookie.so libxt_ts3init_get_puzzle.so libxt_ts3init_reset.so
LIBS = libxt_ts3init_get_cookie.so libxt_ts3init_get_puzzle.so libxt_TS3INIT_RESET.so libxt_TS3INIT_SET_COOKIE.so
all: $(LIBS)

3
src/libxt_ts3init_reset.c → src/libxt_TS3INIT_RESET.c

@ -14,10 +14,9 @@ @@ -14,10 +14,9 @@
#include <string.h>
#include <getopt.h>
#include <xtables.h>
#include "ts3init_cookie_seed.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");

120
src/libxt_TS3INIT_SET_COOKIE.c

@ -0,0 +1,120 @@ @@ -0,0 +1,120 @@
/*
* "ts3init_set_cookie" 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_cookie_seed.h"
#include "ts3init_target.h"
#define param_act(t, s, f) xtables_param_act((t), "ts3init_set_cookie", (s), (f))
static void ts3init_set_cookie_tg_help(void)
{
printf(
"ts3init_get_cookie match options:\n"
" --zero-random-sequence Always return 0 as random sequence.\n"
" --cookie-seed seed Seed is a 60 byte random number in lowecase\n"
" hex. A source could be /dev/random.\n");
}
static const struct option ts3init_set_cookie_tg_opts[] = {
{.name = "zero-random-sequence", .has_arg = false, .val = '1'},
{.name = "cookie-seed", .has_arg = true, .val = '2'},
{NULL},
};
static int ts3init_set_cookie_tg_parse(int c, char **argv,
int invert, unsigned int *flags, const void *entry,
struct xt_entry_target **target)
{
struct xt_ts3init_set_cookie_tginfo *info = (void *)(*target)->data;
switch (c) {
case '1':
param_act(XTF_ONLY_ONCE, "--zero-random-sequence", info->specific_options & TARGET_SET_COOKIE_ZERO_RANDOM_SEQUENCE);
param_act(XTF_NO_INVERT, "--check-time", invert);
info->specific_options |= TARGET_SET_COOKIE_ZERO_RANDOM_SEQUENCE;
return true;
case '2':
param_act(XTF_ONLY_ONCE, "--cookie-seed", info->specific_options & TARGET_SET_COOKIE_SEED);
param_act(XTF_NO_INVERT, "--cookie-seed", invert);
if (strlen(optarg) != (COOKIE_SEED_LEN * 2))
xtables_error(PARAMETER_PROBLEM,
"TS3INIT_SET_COOKIE: invalid cookie-seed length");
if (!hex2int_seed(optarg, info->cookie_seed))
xtables_error(PARAMETER_PROBLEM,
"TS3INIT_SET_COOKIE: invalid cookie-seed. (not lowercase hex)");
info->specific_options |= TARGET_SET_COOKIE_SEED;
*flags |= TARGET_SET_COOKIE_SEED;
return true;
default:
return false;
}
}
static void ts3init_set_cookie_tg_save(const void *ip, const struct xt_entry_target *target)
{
const struct xt_ts3init_set_cookie_tginfo *info = (const void *)target->data;
if (info->specific_options & TARGET_SET_COOKIE_ZERO_RANDOM_SEQUENCE)
{
printf("--zero-random-sequence ");
}
if (info->specific_options & TARGET_SET_COOKIE_SEED)
{
printf("--cookie-seed ");
for (int i = 0; i < COOKIE_SEED_LEN; i++)
{
printf("%02X", info->cookie_seed[i]);
}
printf(" ");
}
}
static void ts3init_set_cookie_tg_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
printf(" -j TS3INIT_SET_COOKIE ");
ts3init_set_cookie_tg_save(ip, target);
}
static void ts3init_set_cookie_tg_check(unsigned int flags)
{
if ((flags & TARGET_SET_COOKIE_SEED) == 0)
{
xtables_error(PARAMETER_PROBLEM,
"TS3INIT_SET_COOKIE: --cookie-seed must be specified");
}
}
/* register and init */
static struct xtables_target ts3init_set_cookie_tg_reg =
{
.name = "TS3INIT_SET_COOKIE",
.revision = 0,
.family = NFPROTO_UNSPEC,
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_ts3init_set_cookie_tginfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_ts3init_set_cookie_tginfo)),
.help = ts3init_set_cookie_tg_help,
.parse = ts3init_set_cookie_tg_parse,
.print = ts3init_set_cookie_tg_print,
.save = ts3init_set_cookie_tg_save,
.final_check = ts3init_set_cookie_tg_check,
.extra_opts = ts3init_set_cookie_tg_opts,
};
static __attribute__((constructor)) void ts3init_set_cookie_tg_ldr(void)
{
xtables_register_target(&ts3init_set_cookie_tg_reg);
}

1
src/libxt_ts3init_get_cookie.c

@ -14,6 +14,7 @@ @@ -14,6 +14,7 @@
#include <string.h>
#include <getopt.h>
#include <xtables.h>
#include "ts3init_cookie_seed.h"
#include "ts3init_match.h"
#define param_act(t, s, f) xtables_param_act((t), "ts3init_get_cookie", (s), (f))

24
src/libxt_ts3init_get_puzzle.c

@ -14,30 +14,12 @@ @@ -14,30 +14,12 @@
#include <string.h>
#include <getopt.h>
#include <xtables.h>
#include "ts3init_cookie_seed.h"
#include "ts3init_match.h"
#define param_act(t, s, f) xtables_param_act((t), "ts3init_get_puzzle", (s), (f))
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
static bool hex2int_seed(const char *src, __u8* dst)
{
for (int i = 0; i < 60; ++i)
{
int v = 0;
for (int j = 0; j < 2; ++j)
{
uint8_t byte = *src++;
if (byte >= '0' && byte <= '9') byte = byte - '0';
else if (byte >= 'a' && byte <='f') byte = byte - 'a' + 10;
else if (byte >= 'A' && byte <='F') byte = byte - 'A' + 10;
else return false;
v = (v << 4) | byte;
}
*dst++ = v;
}
return true;
}
static void ts3init_get_puzzle_help(void)
{
printf(
@ -76,7 +58,7 @@ static int ts3init_get_puzzle_parse(int c, char **argv, int invert, unsigned int @@ -76,7 +58,7 @@ static int ts3init_get_puzzle_parse(int c, char **argv, int invert, unsigned int
case '2':
param_act(XTF_ONLY_ONCE, "--check-cookie", info->specific_options & CHK_GET_PUZZLE_CHECK_COOKIE);
param_act(XTF_NO_INVERT, "--check-cookie", invert);
if (strlen(optarg) != 120)
if (strlen(optarg) != (COOKIE_SEED_LEN * 2))
xtables_error(PARAMETER_PROBLEM,
"ts3init_get_puzzle: invalid cookie-seed length");
if (!hex2int_seed(optarg, info->cookie_seed))
@ -100,7 +82,7 @@ static void ts3init_get_puzzle_save(const void *ip, const struct xt_entry_match @@ -100,7 +82,7 @@ static void ts3init_get_puzzle_save(const void *ip, const struct xt_entry_match
if (info->specific_options & CHK_GET_PUZZLE_CHECK_COOKIE)
{
printf("--check-cookie ");
for (int i = 0; i < 60; i++)
for (int i = 0; i < COOKIE_SEED_LEN; i++)
{
printf("%02X", info->cookie_seed[i]);
}

118
src/ts3init_cache.c

@ -0,0 +1,118 @@ @@ -0,0 +1,118 @@
/*
* "ts3init" extension for Xtables
*
* Description: A module to aid in ts3 spoof protection
* This is the "caching of cookies" related 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/skbuff.h>
#include <linux/netfilter/x_tables.h>
#include <linux/udp.h>
#include <linux/time.h>
#include <linux/jiffies.h>
#include <linux/percpu.h>
#include "ts3init_cookie.h"
#include "ts3init_cache.h"
struct ts3init_cache_t
{
unsigned long saved_jiffies;
time_t unix_time;
struct xt_ts3init_cookie_cache cookie_cache;
};
DEFINE_PER_CPU(struct ts3init_cache_t, ts3init_cache);
static inline void update_cache_time(unsigned long jifs,
struct ts3init_cache_t* cache)
{
if (((long)jifs - (long)cache->saved_jiffies) >= HZ)
{
/* it's been 1 second sinds last time update.
* Get the new unix time and cache it*/
struct timeval tv;
cache->saved_jiffies = jifs;
do_gettimeofday(&tv);
cache->unix_time = tv.tv_sec;
}
}
time_t get_cached_unix_time(void)
{
struct ts3init_cache_t* cache;
unsigned long jifs;
time_t current_unix_time;
jifs = jiffies;
cache = &get_cpu_var(ts3init_cache);
update_cache_time(jifs, cache);
current_unix_time = cache->unix_time;
put_cpu_var(ts3init_cache);
return current_unix_time;
}
bool get_cookie_for_package_index(u8 packet_index, const u8* seed, u64 (*cookie)[2])
{
struct ts3init_cache_t* cache;
u64* result;
unsigned long jifs;
time_t current_unix_time;
jifs = jiffies;
cache = &get_cpu_var(ts3init_cache);
update_cache_time(jifs, cache);
current_unix_time = cache->unix_time;
result = ts3init_get_cookie_seed(current_unix_time,
packet_index, &cache->cookie_cache, seed);
if (result)
{
(*cookie)[0] = result[0];
(*cookie)[1] = result[1];
}
put_cpu_var(ts3init_cache);
return result;
}
bool get_current_cookie(const u8* seed, u64 (*cookie)[2], u8 *packet_index)
{
struct ts3init_cache_t* cache;
u64* result;
unsigned long jifs;
time_t current_unix_time;
jifs = jiffies;
cache = &get_cpu_var(ts3init_cache);
update_cache_time(jifs, cache);
current_unix_time = cache->unix_time;
*packet_index = current_unix_time % 8;
result = ts3init_get_cookie_seed(current_unix_time,
*packet_index, &cache->cookie_cache, seed);
if (result)
{
(*cookie)[0] = result[0];
(*cookie)[1] = result[1];
}
put_cpu_var(ts3init_cache);
return result;
}

10
src/ts3init_cache.h

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
#ifndef _TS3INIT_CACHE_H
#define _TS3INIT_CACHE_H
time_t get_cached_unix_time(void);
bool get_cookie_for_package_index(u8 packet_index, const u8* seed, u64 (*cookie)[2]);
bool get_current_cookie(const u8* seed, u64 (*cookie)[2], u8 *packet_index);
#endif /* _TS3INIT_CACHE_H */

8
src/ts3init_cookie.c

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
#include <linux/netfilter/x_tables.h>
#include <linux/udp.h>
#include "siphash24.h"
#include "ts3init_cookie_seed.h"
#include "ts3init_cookie.h"
static void check_update_seed_cache(time_t time, __u8 index,
@ -33,10 +34,10 @@ static void check_update_seed_cache(time_t time, __u8 index, @@ -33,10 +34,10 @@ static void check_update_seed_cache(time_t time, __u8 index,
if (time == cache->time[index]) return;
/* We need to update the cache. */
/* seed = sha512(cookie_seed[60] + __le32 time) */
/* seed = sha512(cookie_seed[COOKIE_SEED_LEN] + __le32 time) */
seed_hash_time = cpu_to_le32( (__u32)time);
sg_init_table(sg, ARRAY_SIZE(sg));
sg_set_buf(&sg[0], cookie_seed, 60);
sg_set_buf(&sg[0], cookie_seed, COOKIE_SEED_LEN);
sg_set_buf(&sg[1], &seed_hash_time, 4);
desc.tfm = crypto_alloc_hash("sha512", 0, 0);
@ -93,7 +94,8 @@ __u64* ts3init_get_cookie_seed(time_t current_time, __u8 packet_index, @@ -93,7 +94,8 @@ __u64* ts3init_get_cookie_seed(time_t current_time, __u8 packet_index,
return cache->seed64 + ((SIP_KEY_SIZE/sizeof(__u64)) * packet_index );
}
int ts3init_calculate_cookie(const struct sk_buff *skb, struct xt_action_param *par, struct udphdr *udp, u64 k0, u64 k1, __u64* out)
int ts3init_calculate_cookie(const struct sk_buff *skb, const struct xt_action_param *par,
struct udphdr *udp, __u64 k0, __u64 k1, __u64* out)
{
int addr_offset;
int addr_len;

6
src/ts3init_cookie.h

@ -21,7 +21,7 @@ __u64* ts3init_get_cookie_seed(time_t current_time, __u8 packet_index, @@ -21,7 +21,7 @@ __u64* ts3init_get_cookie_seed(time_t current_time, __u8 packet_index,
const __u8* cookie_seed);
int ts3init_calculate_cookie(const struct sk_buff *skb,
struct xt_action_param *par, struct udphdr *udp,
u64 k0, u64 k1, __u64* out);
const struct xt_action_param *par, struct udphdr *udp,
__u64 k0, __u64 k1, __u64* out);
#endif /* _TS3INIT_COOKIE_H */

28
src/ts3init_cookie_seed.h

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
#ifndef _TS3INIT_COOKIE_SEED_H
#define _TS3INIT_COOKIE_SEED_H
enum {
COOKIE_SEED_LEN = 60
};
static inline bool hex2int_seed(const char *src, __u8* dst)
{
int i, j;
for (i = 0; i < 60; ++i)
{
int v = 0;
for ( j = 0; j < 2; ++j)
{
uint8_t byte = *src++;
if (byte >= '0' && byte <= '9') byte = byte - '0';
else if (byte >= 'a' && byte <='f') byte = byte - 'a' + 10;
else if (byte >= 'A' && byte <='F') byte = byte - 'A' + 10;
else return false;
v = (v << 4) | byte;
}
*dst++ = v;
}
return true;
}
#endif /* _TS3INIT_COOKIE_SEED_H */

79
src/ts3init_match.c

@ -16,19 +16,13 @@ @@ -16,19 +16,13 @@
#include <linux/netfilter/x_tables.h>
#include <linux/skbuff.h>
#include <linux/udp.h>
#include <linux/jiffies.h>
#include <linux/time.h>
#include <linux/percpu.h>
#include "ts3init_match.h"
#include "ts3init_cookie_seed.h"
#include "ts3init_cookie.h"
#include "ts3init_match.h"
#include "ts3init_header.h"
struct ts3init_cache_t
{
unsigned long saved_jiffies;
time_t unix_time;
struct xt_ts3init_cookie_cache cookie_cache;
};
#include "ts3init_cache.h"
static const struct ts3_init_header_tag ts3init_header_tag_signature =
{ .tag8 = {'T', 'S', '3', 'I', 'N', 'I', 'T', '1'} };
@ -36,8 +30,6 @@ static const struct ts3_init_header_tag ts3init_header_tag_signature = @@ -36,8 +30,6 @@ static const struct ts3_init_header_tag ts3init_header_tag_signature =
static const int header_size = 18;
static int ts3init_payload_sizes[] = { 16, 20, 20, 244, -1, 1 };
DEFINE_PER_CPU(struct ts3init_cache_t, ts3init_cache);
static bool check_header(const struct sk_buff *skb, const struct xt_action_param *par,
struct ts3_init_checked_header_data* header_data, __u32 min_client_version)
{
@ -88,20 +80,6 @@ static bool check_header(const struct sk_buff *skb, const struct xt_action_param @@ -88,20 +80,6 @@ static bool check_header(const struct sk_buff *skb, const struct xt_action_param
return true;
}
static inline void update_cache_time(unsigned long jifs,
struct ts3init_cache_t* cache)
{
if (((long)jifs - (long)cache->saved_jiffies) >= HZ)
{
/* it's been 1 second sinds last time update.
* Get the new unix time and cache it*/
struct timeval tv;
cache->saved_jiffies = jifs;
do_gettimeofday(&tv);
cache->unix_time = tv.tv_sec;
}
}
static bool
ts3init_get_cookie_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
@ -115,19 +93,9 @@ ts3init_get_cookie_mt(const struct sk_buff *skb, struct xt_action_param *par) @@ -115,19 +93,9 @@ ts3init_get_cookie_mt(const struct sk_buff *skb, struct xt_action_param *par)
if (info->specific_options & CHK_GET_COOKIE_CHECK_TIMESTAMP)
{
struct ts3init_cache_t* cache;
unsigned long jifs;
time_t current_unix_time, packet_unix_time;
jifs = jiffies;
cache = &get_cpu_var(ts3init_cache);
update_cache_time(jifs, cache);
current_unix_time = cache->unix_time;
put_cpu_var(ts3init_cache);
current_unix_time = get_cached_unix_time();
packet_unix_time =
header_data.ts3_header->payload[0] << 24 |
@ -179,39 +147,16 @@ ts3init_get_puzzle_mt(const struct sk_buff *skb, struct xt_action_param *par) @@ -179,39 +147,16 @@ ts3init_get_puzzle_mt(const struct sk_buff *skb, struct xt_action_param *par)
if (info->specific_options & CHK_GET_PUZZLE_CHECK_COOKIE)
{
struct ts3init_cache_t* cache;
struct ts3_init_header* ts3_header = header_data.ts3_header;
__u64* cookie_seed, cookie_seed0, cookie_seed1;
__u64 cookie_seed[2];
__u64 cookie, packet_cookie;
unsigned long jifs;
time_t current_unix_time;
jifs = jiffies;
cache = &get_cpu_var(ts3init_cache);
update_cache_time(jifs, cache);
current_unix_time = cache->unix_time;
cookie_seed = ts3init_get_cookie_seed(current_unix_time,
ts3_header->payload[8], &cache->cookie_cache,
info->cookie_seed);
if (!cookie_seed)
{
put_cpu_var(ts3init_cache);
if (get_cookie_for_package_index(ts3_header->payload[8], info->cookie_seed, &cookie_seed) == false)
return false;
}
cookie_seed0 = cookie_seed[0];
cookie_seed1 = cookie_seed[1];
put_cpu_var(ts3init_cache);
/* use cookie_seed and ipaddress and port to create a hash
* (cookie) for this connection */
if (ts3init_calculate_cookie(skb, par, header_data.udp, cookie_seed0, cookie_seed1, &cookie))
if (ts3init_calculate_cookie(skb, par, header_data.udp, cookie_seed[0], cookie_seed[1], &cookie))
return false; /*something went wrong*/
/* compare cookie with payload bytes 0-7. if equal, cookie
@ -245,7 +190,7 @@ static int ts3init_get_puzzle_mt_check(const struct xt_mtchk_param *par) @@ -245,7 +190,7 @@ static int ts3init_get_puzzle_mt_check(const struct xt_mtchk_param *par)
if (info->specific_options & ~(CHK_GET_PUZZLE_VALID_MASK))
{
printk(KERN_INFO KBUILD_MODNAME ": invalid (specific) options for get_cookie\n");
printk(KERN_INFO KBUILD_MODNAME ": invalid (specific) options for get_puzzle\n");
return -EINVAL;
}
@ -256,7 +201,7 @@ static int ts3init_get_puzzle_mt_check(const struct xt_mtchk_param *par) @@ -256,7 +201,7 @@ static int ts3init_get_puzzle_mt_check(const struct xt_mtchk_param *par)
static struct xt_match ts3init_mt_reg[] __read_mostly =
{
{
.name = "ts3init_get_cookie",
.name = "TS3INIT_GET_COOKIE",
.revision = 0,
.family = NFPROTO_IPV4,
.proto = IPPROTO_UDP,
@ -266,7 +211,7 @@ static struct xt_match ts3init_mt_reg[] __read_mostly = @@ -266,7 +211,7 @@ static struct xt_match ts3init_mt_reg[] __read_mostly =
.me = THIS_MODULE,
},
{
.name = "ts3init_get_cookie",
.name = "TS3INIT_GET_COOKIE",
.revision = 0,
.family = NFPROTO_IPV6,
.proto = IPPROTO_UDP,
@ -276,7 +221,7 @@ static struct xt_match ts3init_mt_reg[] __read_mostly = @@ -276,7 +221,7 @@ static struct xt_match ts3init_mt_reg[] __read_mostly =
.me = THIS_MODULE,
},
{
.name = "ts3init_get_puzzle",
.name = "TS3INIT_GET_PUZZLE",
.revision = 0,
.family = NFPROTO_IPV4,
.proto = IPPROTO_UDP,
@ -286,7 +231,7 @@ static struct xt_match ts3init_mt_reg[] __read_mostly = @@ -286,7 +231,7 @@ static struct xt_match ts3init_mt_reg[] __read_mostly =
.me = THIS_MODULE,
},
{
.name = "ts3init_get_puzzle",
.name = "TS3INIT_GET_PUZZLE",
.revision = 0,
.family = NFPROTO_IPV6,
.proto = IPPROTO_UDP,

4
src/ts3init_match.h

@ -32,8 +32,6 @@ enum @@ -32,8 +32,6 @@ enum
{
CHK_GET_PUZZLE_CHECK_COOKIE = 1 << 0,
CHK_GET_PUZZLE_VALID_MASK = (1 << 1) - 1,
SEED_LEN = 60
};
struct xt_ts3init_get_puzzle_mtinfo
@ -42,7 +40,7 @@ struct xt_ts3init_get_puzzle_mtinfo @@ -42,7 +40,7 @@ struct xt_ts3init_get_puzzle_mtinfo
__u8 specific_options;
__u16 reserved1;
__u32 min_client_version;
__u8 cookie_seed[SEED_LEN];
__u8 cookie_seed[COOKIE_SEED_LEN];
};
#endif /* _TS3INIT_MATCH_H */

394
src/ts3init_target.c

@ -26,22 +26,24 @@ @@ -26,22 +26,24 @@
#include <net/ip6_route.h>
#include <net/route.h>
#include "compat_xtables.h"
#include "ts3init_cookie_seed.h"
#include "ts3init_cookie.h"
#include "ts3init_target.h"
#include "ts3init_header.h"
#include "ts3init_cache.h"
bool
ts3init_send_ipv6(const struct sk_buff *oldskb, const struct xt_action_param *par, u8 command, const void *payload, const size_t payload_size)
static bool
ts3init_prepare_ipv6_reply(const struct sk_buff *oldskb, const struct xt_action_param *par,
const size_t payload_size, struct sk_buff **newskb, struct ipv6hdr **newip,
struct udphdr **newudp, u8 **payload)
{
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);
struct udphdr *udp, oldudp_buf;
struct ipv6hdr *ip;
struct sk_buff *skb;
oldip = ipv6_hdr(oldskb);
oldudp = skb_header_pointer(oldskb, par->thoff,
sizeof(*oldudp), &oldudp_buf);
@ -50,76 +52,91 @@ ts3init_send_ipv6(const struct sk_buff *oldskb, const struct xt_action_param *pa @@ -50,76 +52,91 @@ ts3init_send_ipv6(const struct sk_buff *oldskb, const struct xt_action_param *pa
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)
skb = alloc_skb(LL_MAX_HEADER + sizeof(*ip) +
sizeof(*udp) + payload_size, GFP_ATOMIC);
if (skb == 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);
skb_reserve(skb, LL_MAX_HEADER);
skb->protocol = oldskb->protocol;
skb_reset_network_header(skb);
ip = (void *)skb_put(skb, sizeof(*ip));
ip->version = oldip->version;
ip->priority = oldip->priority;
memcpy(ip->flow_lbl, oldip->flow_lbl, sizeof(ip->flow_lbl));
ip->nexthdr = par->target->proto;
ip->saddr = oldip->daddr;
ip->daddr = oldip->saddr;
skb_reset_transport_header(skb);
udp = (void *)skb_put(skb, sizeof(*udp));
udp->source = oldudp->dest;
udp->dest = oldudp->source;
udp->len = htons(sizeof(*udp) + payload_size);
*payload = skb_put(skb, payload_size);
ip->payload_len = htons(skb->len);
*newskb = skb;
*newip = ip;
*newudp = udp;
return true;
}
memcpy(skb_put(newskb, payload_size), payload, payload_size);
newip->payload_len = htons(newskb->len);
static bool
ts3init_send_ipv6_reply(struct sk_buff *oldskb, const struct xt_action_param *par,
struct sk_buff *skb, struct ipv6hdr *ip, struct udphdr *udp)
{
struct flowi6 fl;
struct dst_entry *dst = NULL;
struct net *net = dev_net((par->in != NULL) ? par->in : par->out);
newudp->check = 0;
newudp->check = csum_ipv6_magic(&newip->saddr, &newip->daddr,
ntohs(newudp->len), IPPROTO_UDP,
csum_partial(newudp, ntohs(newudp->len), 0));
udp->check = 0;
udp->check = csum_ipv6_magic(&ip->saddr, &ip->daddr,
ntohs(udp->len), IPPROTO_UDP,
csum_partial(udp, ntohs(udp->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;
fl.flowi6_proto = ip->nexthdr;
memcpy(&fl.saddr, &ip->saddr, sizeof(fl.saddr));
memcpy(&fl.daddr, &ip->daddr, sizeof(fl.daddr));
fl.fl6_sport = udp->source;
fl.fl6_dport = udp->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)
{
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;
skb_dst_set(skb, dst);
ip->hop_limit = ip6_dst_hoplimit(skb_dst(skb));
skb->ip_summed = CHECKSUM_NONE;
/* "Never happens" (?) */
if (newskb->len > dst_mtu(skb_dst(newskb)))
if (skb->len > dst_mtu(skb_dst(skb)))
goto free_nskb;
nf_ct_attach(newskb, oldskb);
ip6_local_out(par_net(par), newskb->sk, newskb);
nf_ct_attach(skb, oldskb);
ip6_local_out(par_net(par), skb->sk, skb);
return true;
free_nskb:
kfree_skb(newskb);
kfree_skb(skb);
return false;
}
bool
ts3init_send_ipv4(const struct sk_buff *oldskb, const struct xt_action_param *par, u8 command, const void *payload, const size_t payload_size)
static bool
ts3init_prepare_ipv4_reply(const struct sk_buff *oldskb, const struct xt_action_param *par,
const size_t payload_size, struct sk_buff **newskb, struct iphdr **newip,
struct udphdr **newudp, u8 **payload)
{
const struct udphdr *oldudp;
const struct iphdr *oldip;
struct udphdr *newudp, oldudp_buf;
struct iphdr *newip;
struct sk_buff *newskb;
struct udphdr *udp, oldudp_buf;
struct iphdr *ip;
struct sk_buff *skb;
oldip = ip_hdr(oldskb);
oldudp = skb_header_pointer(oldskb, par->thoff,
@ -129,96 +146,261 @@ ts3init_send_ipv4(const struct sk_buff *oldskb, const struct xt_action_param *pa @@ -129,96 +146,261 @@ ts3init_send_ipv4(const struct sk_buff *oldskb, const struct xt_action_param *pa
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)
skb = alloc_skb(LL_MAX_HEADER + sizeof(*ip) +
sizeof(*udp) + payload_size, GFP_ATOMIC);
if (skb == 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));
skb_reserve(skb, LL_MAX_HEADER);
skb->protocol = oldskb->protocol;
skb_reset_network_header(skb);
ip = (void *)skb_put(skb, sizeof(*ip));
ip->version = oldip->version;
ip->ihl = sizeof(*ip) / 4;
ip->tos = oldip->tos;
ip->id = oldip->id;
ip->frag_off = 0;
ip->protocol = oldip->protocol;
ip->check = 0;
ip->saddr = oldip->daddr;
ip->daddr = oldip->saddr;
skb_reset_transport_header(skb);
udp = (void *)skb_put(skb, sizeof(*udp));
udp->source = oldudp->dest;
udp->dest = oldudp->source;
udp->len = htons(sizeof(*udp) + payload_size);
*payload = skb_put(skb, payload_size);
ip->tot_len = htons(skb->len);
*newskb = skb;
*newip = ip;
*newudp = udp;
return true;
}
static bool
ts3init_send_ipv4_reply(struct sk_buff *oldskb, const struct xt_action_param *par,
struct sk_buff *skb, struct iphdr *ip, struct udphdr *udp)
{
udp->check = 0;
udp->check = csum_tcpudp_magic(ip->saddr, ip->daddr,
ntohs(udp->len), IPPROTO_UDP,
csum_partial(udp, ntohs(udp->len), 0));
/* ip_route_me_harder expects the skb's dst to be set */
skb_dst_set(newskb, dst_clone(skb_dst(oldskb)));
skb_dst_set(skb, dst_clone(skb_dst(oldskb)));
if (ip_route_me_harder(par_net(par), newskb, RTN_UNSPEC) != 0)
if (ip_route_me_harder(par_net(par), skb, RTN_UNSPEC) != 0)
goto free_nskb;
newip->ttl = ip4_dst_hoplimit(skb_dst(newskb));
newskb->ip_summed = CHECKSUM_NONE;
ip->ttl = ip4_dst_hoplimit(skb_dst(skb));
skb->ip_summed = CHECKSUM_NONE;
/* "Never happens" (?) */
if (newskb->len > dst_mtu(skb_dst(newskb)))
if (skb->len > dst_mtu(skb_dst(skb)))
goto free_nskb;
nf_ct_attach(newskb, oldskb);
ip_local_out(par_net(par), newskb->sk, newskb);
nf_ct_attach(skb, oldskb);
ip_local_out(par_net(par), skb->sk, skb);
return true;
free_nskb:
kfree_skb(newskb);
kfree_skb(skb);
return false;
}
static const char ts3init_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)
ts3init_reset_ipv4_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
struct sk_buff *newskb;
struct iphdr *newip;
struct udphdr *newudp;
u8 *payload;
if (ts3init_prepare_ipv4_reply(skb, par, sizeof(ts3init_reset_package), &newskb, &newip, &newudp, &payload))
{
memcpy(payload, ts3init_reset_package, sizeof(ts3init_reset_package));
ts3init_send_ipv4_reply(skb, par, newskb, newip, newudp);
}
return NF_DROP;
}
static unsigned int
ts3init_reset_ipv6_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
struct sk_buff *newskb;
struct ipv6hdr *newip;
struct udphdr *newudp;
u8 *payload;
if (ts3init_prepare_ipv6_reply(skb, par, sizeof(ts3init_reset_package), &newskb, &newip, &newudp, &payload))
{
memcpy(payload, ts3init_reset_package, sizeof(ts3init_reset_package));
ts3init_send_ipv6_reply(skb, par, newskb, newip, newudp);
}
return NF_DROP;
}
static const char set_cookie_package_header[12] = {'T', 'S', '3', 'I', 'N', 'I', 'T', '1', 0x65, 0, 0x88, COMMAND_SET_COOKIE };
static bool
ts3init_fill_set_cookie_payload(const struct sk_buff *skb, const struct xt_action_param *par,
struct sk_buff *newskb, struct udphdr *newudp, u8 *newpayload)
{
const struct xt_ts3init_set_cookie_tginfo *info = par->targinfo;
u8 *payload, payload_buf[34];
__u64 cookie[2];
u64 cookie_hash;
u8 packet_index;
if (get_current_cookie(info->cookie_seed, &cookie, &packet_index) == false)
return false;
if (ts3init_calculate_cookie(newskb, par, newudp, cookie[0], cookie[1], &cookie_hash))
return false;
memcpy(newpayload, set_cookie_package_header, sizeof(set_cookie_package_header));
newpayload[12] = (u8)cookie_hash;
newpayload[13] = (u8)(cookie_hash >> 8);
newpayload[14] = (u8)(cookie_hash >> 16);
newpayload[15] = (u8)(cookie_hash >> 24);
newpayload[16] = (u8)(cookie_hash >> 32);
newpayload[17] = (u8)(cookie_hash >> 40);
newpayload[18] = (u8)(cookie_hash >> 48);
newpayload[19] = (u8)(cookie_hash >> 56);
newpayload[20] = packet_index;
if (info->specific_options & TARGET_SET_COOKIE_ZERO_RANDOM_SEQUENCE)
{
memset(&newpayload[21], 0, 11);
}
else
{
memset(&newpayload[21], 0, 7);
payload = skb_header_pointer(skb, par->thoff + sizeof(struct udphdr),
sizeof(payload_buf), payload_buf);
if (payload == NULL)
{
printk(KERN_WARNING KBUILD_MODNAME ": was expecting a ts3init_get_cookie package. Use -m ts3init_get_cookie!\n");
return false;
}
newpayload[28] = payload[25];
newpayload[29] = payload[24];
newpayload[30] = payload[23];
newpayload[31] = payload[22];
}
return true;
}
static unsigned int
ts3init_set_cookie_ipv4_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
switch (par->family)
struct sk_buff *newskb;
struct iphdr *newip;
struct udphdr *newudp;
u8 *payload;
const int payload_size = sizeof(set_cookie_package_header) + 20;
if (ts3init_prepare_ipv4_reply(skb, par, payload_size, &newskb, &newip, &newudp, &payload))
{
case NFPROTO_IPV4:
ts3init_send_ipv4(skb, par, COMMAND_RESET_PUZZLE, ts3init_reset_package, sizeof(ts3init_reset_package));
break;
if (ts3init_fill_set_cookie_payload(skb, par, newskb, newudp, payload))
{
ts3init_send_ipv4_reply(skb, par, newskb, newip, newudp);
}
else
{
kfree_skb(newskb);
}
}
return NF_DROP;
}
case NFPROTO_IPV6:
ts3init_send_ipv6(skb, par, COMMAND_RESET_PUZZLE, ts3init_reset_package, sizeof(ts3init_reset_package));
break;
static unsigned int
ts3init_set_cookie_ipv6_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
struct sk_buff *newskb;
struct ipv6hdr *newip;
struct udphdr *newudp;
u8 *payload;
const int payload_size = sizeof(set_cookie_package_header) + 20;
if (ts3init_prepare_ipv6_reply(skb, par, payload_size, &newskb, &newip, &newudp, &payload))
{
if (ts3init_fill_set_cookie_payload(skb, par, newskb, newudp, payload))
{
ts3init_send_ipv6_reply(skb, par, newskb, newip, newudp);
}
else
{
kfree_skb(newskb);
}
}
return NF_DROP;
}
static struct xt_target ts3init_tg_reg[] __read_mostly =
static int ts3init_set_cookie_tg_check(const struct xt_tgchk_param *par)
{
struct xt_ts3init_set_cookie_tginfo *info = par->targinfo;
if (! (par->family == NFPROTO_IPV4 || par->family == NFPROTO_IPV6))
{
printk(KERN_INFO KBUILD_MODNAME ": invalid protocol (only ipv4 and ipv6) for TS3INIT_SET_COOKIE\n");
return -EINVAL;
}
if (info->common_options & ~(TARGET_COMMON_VALID_MASK))
{
printk(KERN_INFO KBUILD_MODNAME ": invalid (common) options for TS3INIT_SET_COOKIE\n");
return -EINVAL;
}
if (info->specific_options & ~(TARGET_SET_COOKIE_VALID_MASK))
{
printk(KERN_INFO KBUILD_MODNAME ": invalid (specific) options for TS3INIT_SET_COOKIE\n");
return -EINVAL;
}
return 0;
}
static struct xt_target ts3init_tg_reg[] __read_mostly = {
{
.name = "TS3INIT_RESET",
.revision = 0,
.family = NFPROTO_IPV4,
.proto = IPPROTO_UDP,
.target = ts3init_reset_ipv4_tg,
.me = THIS_MODULE,
},
{
.name = "TS3INIT_RESET",
.revision = 0,
.family = NFPROTO_IPV6,
.proto = IPPROTO_UDP,
.target = ts3init_reset_ipv6_tg,
.me = THIS_MODULE,
},
{
.name = "ts3init_reset",
.name = "TS3INIT_SET_COOKIE",
.revision = 0,
.family = NFPROTO_IPV4,
.proto = IPPROTO_UDP,
.target = ts3init_reset_tg,
.targetsize = sizeof(struct xt_ts3init_set_cookie_tginfo),
.target = ts3init_set_cookie_ipv4_tg,
.checkentry = ts3init_set_cookie_tg_check,
.me = THIS_MODULE,
},
{
.name = "ts3init_reset",
.name = "TS3INIT_SET_COOKIE",
.revision = 0,
.family = NFPROTO_IPV6,
.proto = IPPROTO_UDP,
.target = ts3init_reset_tg,
.targetsize = sizeof(struct xt_ts3init_set_cookie_tginfo),
.target = ts3init_set_cookie_ipv6_tg,
.checkentry = ts3init_set_cookie_tg_check,
.me = THIS_MODULE,
},
};

23
src/ts3init_target.h

@ -1,4 +1,27 @@ @@ -1,4 +1,27 @@
#ifndef _TS3INIT_TARGET_H
#define _TS3INIT_TARGET_H
/* Common Enums for targets */
enum
{
TARGET_COMMON_VALID_MASK = (1 << 0) -1
};
/* Enums and structs for set_cookie */
enum
{
TARGET_SET_COOKIE_ZERO_RANDOM_SEQUENCE = 1 << 0,
TARGET_SET_COOKIE_SEED = 1 << 1,
TARGET_SET_COOKIE_VALID_MASK = (1 << 2) - 1
};
struct xt_ts3init_set_cookie_tginfo
{
__u8 common_options;
__u8 specific_options;
__u16 reserved1;
__u8 cookie_seed[COOKIE_SEED_LEN];
};
#endif /* _TS3INIT_TARGET_H */

Loading…
Cancel
Save