├── test ├── .gitignore ├── Makefile ├── test_siphash.c ├── torture.py └── siphash24_ref.c ├── src ├── .gitignore ├── Makefile ├── ts3init_target.h ├── ts3init_cache.h ├── Makefile.xtables ├── compat_skbuff.h ├── ts3init_header.h ├── ts3init_cookie.h ├── siphash24.h ├── libxt_TS3INIT_RESET.c ├── libxt_TS3INIT_GET_COOKIE.c ├── ts3init_match.h ├── ts3init_module.c ├── ts3init_random_seed.h ├── compat_xtnu.h ├── compat_xtables.h ├── ts3init_cache.c ├── libxt_ts3init.c ├── libxt_ts3init_get_cookie.c ├── ts3init_cookie.c ├── siphash24.c ├── libxt_TS3INIT_SET_COOKIE.c ├── libxt_ts3init_get_puzzle.c ├── ts3init_match.c └── ts3init_target.c ├── Makefile ├── examples ├── simple │ ├── delete-fw.sh │ └── create-fw.sh ├── complex │ ├── delete-fw.sh │ └── create-fw.sh └── complex-forward │ ├── delete-fw.sh │ └── create-fw.sh ├── cookie.md ├── README.md └── LICENSE.md /test/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | /test_siphash 3 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.o.cmd 2 | *.ko.cmd 3 | *.o 4 | *.so 5 | *.S 6 | *.ko 7 | /xt_ts3init.mod.c 8 | *.symvers 9 | *.order 10 | /.tmp_versions 11 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | $(MAKE) -C src; 3 | $(MAKE) -C src -f Makefile.xtables; 4 | $(MAKE) -C test; 5 | 6 | clean: 7 | $(MAKE) -C src clean; 8 | $(MAKE) -C src -f Makefile.xtables clean; 9 | $(MAKE) -C test clean; 10 | 11 | install: 12 | $(MAKE) -C src modules_install; 13 | $(MAKE) -C src -f Makefile.xtables install; 14 | 15 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -g 3 | RM = rm -f 4 | 5 | 6 | default: all 7 | 8 | all: test_siphash 9 | 10 | %_test.o: %.c 11 | $(CC) -c $(CFLAGS) $< -o $@ 12 | 13 | test_siphash: test_siphash_test.o siphash24_ref_test.o ../src/siphash24_test.o 14 | $(CC) $(CFLAGS) -o $@ $^ 15 | 16 | clean veryclean: 17 | $(RM) test_siphash *.o ../src/siphash24_test.o 18 | 19 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # -*- Makefile -*- 2 | MODULES_DIR := /lib/modules/$(shell uname -r) 3 | KERNEL_DIR := ${MODULES_DIR}/build 4 | 5 | obj-m += xt_ts3init.o 6 | xt_ts3init-objs += ts3init_module.o ts3init_match.o ts3init_cookie.o ts3init_target.o ts3init_cache.o siphash24.o 7 | ccflags-$(CONFIG_CRYPTO_HASH_INFO) += -DHAS_CRYPTO_HASH_INFO=1 8 | 9 | all: 10 | $(MAKE) -C ${KERNEL_DIR} M=$$PWD; 11 | 12 | modules: 13 | $(MAKE) -C ${KERNEL_DIR} M=$$PWD $@; 14 | 15 | modules_install: 16 | $(MAKE) -C ${KERNEL_DIR} M=$$PWD $@; 17 | 18 | clean: 19 | $(MAKE) -C ${KERNEL_DIR} M=$$PWD $@; 20 | -------------------------------------------------------------------------------- /src/ts3init_target.h: -------------------------------------------------------------------------------- 1 | #ifndef _TS3INIT_TARGET_H 2 | #define _TS3INIT_TARGET_H 3 | 4 | /* Common Enums for targets */ 5 | enum 6 | { 7 | TARGET_COMMON_VALID_MASK = (1 << 0) -1 8 | }; 9 | 10 | /* Enums and structs for set_cookie */ 11 | enum 12 | { 13 | TARGET_SET_COOKIE_ZERO_RANDOM_SEQUENCE = 1 << 0, 14 | TARGET_SET_COOKIE_RANDOM_SEED_FROM_ARGUMENT = 1 << 1, 15 | TARGET_SET_COOKIE_RANDOM_SEED_FROM_FILE = 1 << 2, 16 | TARGET_SET_COOKIE_VALID_MASK = (1 << 3) - 1 17 | }; 18 | 19 | 20 | struct xt_ts3init_set_cookie_tginfo 21 | { 22 | __u8 common_options; 23 | __u8 specific_options; 24 | __u16 reserved1; 25 | __u8 random_seed[RANDOM_SEED_LEN]; 26 | char random_seed_path[RANDOM_SEED_PATH_MAX]; 27 | }; 28 | 29 | #endif /* _TS3INIT_TARGET_H */ 30 | -------------------------------------------------------------------------------- /src/ts3init_cache.h: -------------------------------------------------------------------------------- 1 | #ifndef _TS3INIT_CACHE_H 2 | #define _TS3INIT_CACHE_H 3 | 4 | /* 5 | * Returns the current unix_time from cache, updated once every second. 6 | */ 7 | time_t ts3init_get_cached_unix_time(void); 8 | 9 | 10 | /* 11 | * Returns the cookie seed for a packet_index. 12 | * If the cookie seed is not in the cache, it will be generated using the random seed. 13 | */ 14 | bool ts3init_get_cookie_seed_for_packet_index(u8 packet_index, const u8* random_seed, u64 (*cookie)[2]); 15 | 16 | /* 17 | * Returns the current cookie seed and packet_index. 18 | * If the cookie seed is not in the cache, it will be generated using the random seed. 19 | */ 20 | bool ts3init_get_current_cookie_seed(const u8* random_seed, u64 (*cookie)[2], u8 *packet_index); 21 | 22 | #endif /* _TS3INIT_CACHE_H */ 23 | -------------------------------------------------------------------------------- /src/Makefile.xtables: -------------------------------------------------------------------------------- 1 | CFLAGS = -O2 -Wall 2 | LIBS = libxt_ts3init.so libxt_ts3init_get_cookie.so libxt_ts3init_get_puzzle.so libxt_TS3INIT_RESET.so libxt_TS3INIT_SET_COOKIE.so libxt_TS3INIT_GET_COOKIE.so 3 | all: $(LIBS) 4 | 5 | clean: 6 | rm -f $(LIBS) 7 | 8 | install: 9 | if [ -d /lib/xtables ]; then \ 10 | install -g root -o root -m 644 $(LIBS) /lib/xtables/ ; \ 11 | elif [ -d /usr/lib/x86_64-linux-gnu/xtables ]; then \ 12 | install -g root -o root -m 644 $(LIBS) /usr/lib/x86_64-linux-gnu/xtables; \ 13 | elif [ -d /usr/lib/i386-linux-gnu/xtables ]; then \ 14 | install -g root -o root -m 644 $(LIBS) /usr/lib/i386-linux-gnu/xtables; \ 15 | else \ 16 | echo "Unable to find xtables modules path!"; \ 17 | exit 1; \ 18 | fi 19 | 20 | lib%.so: lib%.o 21 | gcc -shared -fPIC -o $@ $^; 22 | 23 | lib%.o: lib%.c 24 | gcc ${CFLAGS} -D_INIT=lib$*_init -fPIC -c -o $@ $<; 25 | 26 | -------------------------------------------------------------------------------- /examples/simple/delete-fw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" == "4" ] 4 | then 5 | IPTABLES=iptables 6 | FRAGMENT_FLAG="! -f " 7 | elif [ "$1" == "6" ] 8 | then 9 | IPTABLES=ip6tables 10 | FRAGMENT_FLAG="" 11 | else 12 | echo "specify either 4 or 6 as a parameter for ipv4 or ipv6"; 13 | exit -1 14 | fi 15 | 16 | #clear up ${IPTABLES} 17 | sudo ${IPTABLES} -t raw -D PREROUTING -p udp --dport 9987 -j CT --notrack 18 | sudo ${IPTABLES} -D INPUT -p udp --dport 9987 ${FRAGMENT_FLAG} -j TS3_UDP_TRAFFIC 19 | sudo ${IPTABLES} -D INPUT -p tcp --dport 30033 -j TS3_TCP_TRAFFIC 20 | 21 | sudo ${IPTABLES} -F TS3_UDP_TRAFFIC 22 | sudo ${IPTABLES} -F TS3_TCP_TRAFFIC 23 | sudo ${IPTABLES} -F TS3_ACCEPT_NEW 24 | sudo ${IPTABLES} -F TS3_UPDATE_AUTHORIZED 25 | 26 | sudo ${IPTABLES} -X TS3_UDP_TRAFFIC 27 | sudo ${IPTABLES} -X TS3_TCP_TRAFFIC 28 | sudo ${IPTABLES} -X TS3_ACCEPT_NEW 29 | sudo ${IPTABLES} -X TS3_UPDATE_AUTHORIZED 30 | 31 | #delete the ipset 32 | sudo ipset destroy ts3_authorized${1} 33 | -------------------------------------------------------------------------------- /src/compat_skbuff.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU General Public License; either 4 | * version 2 of the License, or any later version, as published by the 5 | * Free Software Foundation. 6 | */ 7 | 8 | #ifndef COMPAT_SKBUFF_H 9 | #define COMPAT_SKBUFF_H 1 10 | 11 | struct tcphdr; 12 | struct udphdr; 13 | 14 | #define skb_ifindex(skb) (skb)->skb_iif 15 | #define skb_nfmark(skb) (((struct sk_buff *)(skb))->mark) 16 | 17 | #ifdef CONFIG_NETWORK_SECMARK 18 | # define skb_secmark(skb) ((skb)->secmark) 19 | #else 20 | # define skb_secmark(skb) 0 21 | #endif 22 | 23 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) 24 | static inline int skb_put_padto(struct sk_buff *skb, unsigned int len) 25 | { 26 | unsigned int size = skb->len; 27 | 28 | if (unlikely(size < len)) { 29 | len -= size; 30 | if (skb_pad(skb, len)) return -ENOMEM; 31 | __skb_put(skb, len); 32 | } 33 | 34 | return 0; 35 | } 36 | #endif 37 | 38 | #endif /* COMPAT_SKBUFF_H */ 39 | -------------------------------------------------------------------------------- /src/ts3init_header.h: -------------------------------------------------------------------------------- 1 | #ifndef _TS3INIT_HEADER_H 2 | #define _TS3INIT_HEADER_H 3 | 4 | enum 5 | { 6 | TS3INIT_HEADER_CLIENT_LENGTH = 18, 7 | TS3INIT_HEADER_SERVER_LENGTH = 12, 8 | }; 9 | 10 | /* 11 | * Magic number of a TS3INIT packet. 12 | */ 13 | struct ts3_init_header_tag 14 | { 15 | union 16 | { 17 | char tag8[8]; 18 | __aligned_u64 tag64; 19 | }; 20 | }; 21 | 22 | /* 23 | * Header of a TS3INIT client packet. 24 | */ 25 | struct ts3_init_client_header 26 | { 27 | struct ts3_init_header_tag tag; 28 | __be16 packet_id; 29 | __be16 client_id; 30 | __u8 flags; 31 | __u8 client_version[4]; 32 | __u8 command; 33 | }; 34 | 35 | /* 36 | * Header of a TS3INIT server packet. 37 | */ 38 | struct ts3_init_server_header 39 | { 40 | struct ts3_init_header_tag tag; 41 | __be16 packet_id; 42 | __u8 flags; 43 | __u8 command; 44 | }; 45 | 46 | /* 47 | * The available TS3INIT commands, both client and server. 48 | */ 49 | enum 50 | { 51 | COMMAND_GET_COOKIE = 0, 52 | COMMAND_SET_COOKIE, 53 | COMMAND_GET_PUZZLE, 54 | COMMAND_SET_PUZZLE, 55 | COMMAND_SOLVE_PUZZLE, 56 | COMMAND_RESET_PUZZLE, 57 | COMMAND_MAX, 58 | COMMAND_RESET = 127 59 | }; 60 | 61 | #endif /* _TS3INIT_HEADER_H */ 62 | -------------------------------------------------------------------------------- /src/ts3init_cookie.h: -------------------------------------------------------------------------------- 1 | #ifndef _TS3INIT_COOKIE_H 2 | #define _TS3INIT_COOKIE_H 3 | 4 | enum 5 | { 6 | SHA512_SIZE = 64, 7 | SIP_KEY_SIZE = 16 8 | }; 9 | 10 | struct xt_ts3init_cookie_cache 11 | { 12 | time_t time[2]; 13 | union 14 | { 15 | __u8 seed8[SHA512_SIZE*2]; 16 | __u64 seed64[(SHA512_SIZE/sizeof(__u64))*2]; 17 | }; 18 | }; 19 | 20 | /* 21 | * Returns the cookie seed that fits current_time and packet_index. 22 | * If the cookie seed is missing in cache it will be generated using 23 | * random_seed and current_time 24 | */ 25 | __u64* ts3init_get_cookie_seed(time_t current_time, __u8 packet_index, 26 | struct xt_ts3init_cookie_cache* cache, 27 | const __u8* random_seed); 28 | 29 | /* 30 | * Returns a valid cookie. 31 | * The cookie is generated from a cookie seed and ip and port from the source 32 | * and destination. Ip and udp are the recieved headers from the client, 33 | * k0 and k1 are the cookie seed, and out is the resulting hash. 34 | */ 35 | int ts3init_calculate_cookie_ipv6(const struct ipv6hdr *ip, const struct udphdr *udp, 36 | __u64 k0, __u64 k1, __u64* out); 37 | int ts3init_calculate_cookie_ipv4(const struct iphdr *ip, const struct udphdr *udp, 38 | __u64 k0, __u64 k1, __u64* out); 39 | 40 | #endif /* _TS3INIT_COOKIE_H */ 41 | -------------------------------------------------------------------------------- /src/siphash24.h: -------------------------------------------------------------------------------- 1 | #ifndef _TS3INIT_SIPHASH_H 2 | #define _TS3INIT_SIPHASH_H 3 | 4 | /* 5 | SipHash reference C implementation 6 | Copyright (c) 2012-2014 Jean-Philippe Aumasson 7 | 8 | Copyright (c) 2012-2014 Daniel J. Bernstein 9 | Modified by TeamSpeak Systems for use in ts3init kernel module 10 | Copyright (c) 2016 Maximilian Muenchow 11 | Copyright (c) 2016 Niels Werensteijn 12 | To the extent possible under law, the author(s) have dedicated all copyright 13 | and related and neighboring rights to this software to the public domain 14 | worldwide. This software is distributed without any warranty. 15 | You should have received a copy of the CC0 Public Domain Dedication along 16 | with 17 | this software. If not, see 18 | . 19 | */ 20 | #ifndef __KERNEL__ 21 | #include 22 | #include 23 | #define u8 uint8_t 24 | #define u32 uint32_t 25 | #define u64 uint64_t 26 | #define printk printf 27 | #define le64_to_cpu(x) x 28 | #define cpu_to_le64(x) x 29 | #else 30 | #include 31 | #endif 32 | 33 | struct ts3init_siphash_state 34 | { 35 | u64 v0; 36 | u64 v1; 37 | u64 v2; 38 | u64 v3; 39 | u64 m; 40 | size_t len; 41 | }; 42 | 43 | void ts3init_siphash_setup(struct ts3init_siphash_state* state, u64 k0, u64 k1); 44 | void ts3init_siphash_update(struct ts3init_siphash_state* state, const u8 *in, size_t inlen); 45 | u64 ts3init_siphash_finalize(struct ts3init_siphash_state* state); 46 | 47 | #endif /*_TS3INIT_SIPHASH_H*/ 48 | -------------------------------------------------------------------------------- /src/libxt_TS3INIT_RESET.c: -------------------------------------------------------------------------------- 1 | /* 2 | * "libxt_ts3init_reset" target extension for iptables 3 | * Niels Werensteijn , 2016-10-03 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License; either version 2 7 | * or 3 of the License, as published by the Free Software Foundation. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "ts3init_random_seed.h" 21 | #include "ts3init_target.h" 22 | 23 | static void ts3init_reset_help(void) 24 | { 25 | printf("TS3INIT_RESET takes no options\n\n"); 26 | } 27 | 28 | static int ts3init_reset_parse(int c, char **argv, int invert, unsigned int *flags, 29 | const void *entry, struct xt_entry_target **target) 30 | { 31 | return false; 32 | } 33 | 34 | static void ts3init_reset_check(unsigned int flags) 35 | { 36 | } 37 | 38 | /* register and init */ 39 | static struct xtables_target ts3init_reset_tg_reg = 40 | { 41 | .name = "TS3INIT_RESET", 42 | .revision = 0, 43 | .family = NFPROTO_UNSPEC, 44 | .version = XTABLES_VERSION, 45 | .help = ts3init_reset_help, 46 | .parse = ts3init_reset_parse, 47 | .final_check = ts3init_reset_check, 48 | }; 49 | 50 | static __attribute__((constructor)) void ts3init_reset_tg_ldr(void) 51 | { 52 | xtables_register_target(&ts3init_reset_tg_reg); 53 | } 54 | -------------------------------------------------------------------------------- /examples/complex/delete-fw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" == "4" ] 4 | then 5 | IPTABLES=iptables 6 | FRAGMENT_FLAG="! -f " 7 | elif [ "$1" == "6" ] 8 | then 9 | IPTABLES=ip6tables 10 | FRAGMENT_FLAG="" 11 | else 12 | echo "specify either 4 or 6 as a parameter for ipv4 or ipv6"; 13 | exit -1 14 | fi 15 | 16 | #clear up ${IPTABLES} 17 | sudo ${IPTABLES} -t raw -D PREROUTING -p udp --dport 9987 -j CT --notrack 18 | sudo ${IPTABLES} -t raw -D OUTPUT -p udp --sport 9987 -j CT --notrack 19 | sudo ${IPTABLES} -D INPUT -p udp --dport 9987 ${FRAGMENT_FLAG} -j TS3_UDP_TRAFFIC 20 | sudo ${IPTABLES} -D INPUT -p tcp --dport 30033 -j TS3_TCP_TRAFFIC 21 | sudo ${IPTABLES} -D OUTPUT -p udp --sport 9987 ${FRAGMENT_FLAG} -j OUT_TS3 22 | 23 | sudo ${IPTABLES} -F TS3_UDP_TRAFFIC 24 | sudo ${IPTABLES} -F TS3_UDP_TRAFFIC_AUTHORIZING 25 | sudo ${IPTABLES} -F TS3_UDP_TRAFFIC_AUTHORIZED 26 | sudo ${IPTABLES} -F TS3_TCP_TRAFFIC 27 | sudo ${IPTABLES} -F TS3_ACCEPT_AUTHORIZING 28 | sudo ${IPTABLES} -F OUT_TS3 29 | sudo ${IPTABLES} -F OUT_TS3_AUTHORIZING 30 | sudo ${IPTABLES} -F OUT_TS3_AUTHORIZED 31 | sudo ${IPTABLES} -F OUT_TS3_ACCEPT_AUTHORIZED 32 | 33 | sudo ${IPTABLES} -X TS3_UDP_TRAFFIC 34 | sudo ${IPTABLES} -X TS3_UDP_TRAFFIC_AUTHORIZING 35 | sudo ${IPTABLES} -X TS3_UDP_TRAFFIC_AUTHORIZED 36 | sudo ${IPTABLES} -X TS3_TCP_TRAFFIC 37 | sudo ${IPTABLES} -X TS3_ACCEPT_AUTHORIZING 38 | sudo ${IPTABLES} -X OUT_TS3 39 | sudo ${IPTABLES} -X OUT_TS3_AUTHORIZING 40 | sudo ${IPTABLES} -X OUT_TS3_AUTHORIZED 41 | sudo ${IPTABLES} -X OUT_TS3_ACCEPT_AUTHORIZED 42 | 43 | #delete the ipset 44 | sudo ipset destroy ts3_authorized${1} 45 | sudo ipset destroy ts3_authorized_ft${1} 46 | sudo ipset destroy ts3_authorizing${1} 47 | -------------------------------------------------------------------------------- /src/libxt_TS3INIT_GET_COOKIE.c: -------------------------------------------------------------------------------- 1 | /* 2 | * "libxt_ts3init_reset" target extension for iptables 3 | * Niels Werensteijn , 2016-10-03 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License; either version 2 7 | * or 3 of the License, as published by the Free Software Foundation. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "ts3init_random_seed.h" 21 | #include "ts3init_target.h" 22 | 23 | static void ts3init_get_cookie_help(void) 24 | { 25 | printf("TS3INIT_GET_COOKIE takes no options\n\n"); 26 | } 27 | 28 | static int ts3init_get_cookie_parse(int c, char **argv, int invert, unsigned int *flags, 29 | const void *entry, struct xt_entry_target **target) 30 | { 31 | return false; 32 | } 33 | 34 | static void ts3init_get_cookie_check(unsigned int flags) 35 | { 36 | } 37 | 38 | /* register and init */ 39 | static struct xtables_target ts3init_get_cookie_tg_reg = 40 | { 41 | .name = "TS3INIT_GET_COOKIE", 42 | .revision = 0, 43 | .family = NFPROTO_UNSPEC, 44 | .version = XTABLES_VERSION, 45 | .help = ts3init_get_cookie_help, 46 | .parse = ts3init_get_cookie_parse, 47 | .final_check = ts3init_get_cookie_check, 48 | }; 49 | 50 | static __attribute__((constructor)) void ts3init_get_cookie_tg_ldr(void) 51 | { 52 | xtables_register_target(&ts3init_get_cookie_tg_reg); 53 | } -------------------------------------------------------------------------------- /src/ts3init_match.h: -------------------------------------------------------------------------------- 1 | #ifndef _TS3INIT_MATCH_H 2 | #define _TS3INIT_MATCH_H 3 | 4 | /* Enums for get_cookie and get_puzzle matches */ 5 | enum 6 | { 7 | CHK_COMMON_CLIENT_VERSION = 1 << 0, 8 | CHK_COMMON_VALID_MASK = (1 << 1) -1, 9 | 10 | CLIENT_VERSION_OFFSET = 1356998400 11 | }; 12 | 13 | /* Enums and structs for get_cookie */ 14 | enum 15 | { 16 | CHK_GET_COOKIE_CHECK_TIMESTAMP = 1 << 0, 17 | CHK_GET_COOKIE_VALID_MASK = (1 << 1) -1 18 | }; 19 | 20 | struct xt_ts3init_get_cookie_mtinfo 21 | { 22 | __u8 common_options; 23 | __u8 specific_options; 24 | __u16 reserved1; 25 | __u32 min_client_version; 26 | __u32 max_utc_offset; 27 | }; 28 | 29 | 30 | /* Enums and structs for get_puzzle */ 31 | enum 32 | { 33 | CHK_GET_PUZZLE_CHECK_COOKIE = 1 << 0, 34 | CHK_GET_PUZZLE_RANDOM_SEED_FROM_ARGUMENT = 1 << 1, 35 | CHK_GET_PUZZLE_RANDOM_SEED_FROM_FILE = 1 << 2, 36 | CHK_GET_PUZZLE_VALID_MASK = (1 << 3) - 1, 37 | }; 38 | 39 | struct xt_ts3init_get_puzzle_mtinfo 40 | { 41 | __u8 common_options; 42 | __u8 specific_options; 43 | __u16 reserved1; 44 | __u32 min_client_version; 45 | __u8 random_seed[RANDOM_SEED_LEN]; 46 | char random_seed_path[RANDOM_SEED_PATH_MAX]; 47 | }; 48 | 49 | /* Enums and structs for generic ts3init */ 50 | enum 51 | { 52 | CHK_TS3INIT_CLIENT = 1 << 0, 53 | CHK_TS3INIT_SERVER = 1 << 1, 54 | CHK_TS3INIT_COMMAND = 1 << 2, 55 | CHK_TS3INIT_VALID_MASK = (1 << 3) - 1, 56 | }; 57 | 58 | struct xt_ts3init_mtinfo 59 | { 60 | __u8 common_options; 61 | __u8 specific_options; 62 | __u16 reserved1; 63 | __u8 command; 64 | }; 65 | #endif /* _TS3INIT_MATCH_H */ 66 | -------------------------------------------------------------------------------- /src/ts3init_module.c: -------------------------------------------------------------------------------- 1 | /* 2 | * "ts3init" extension for Xtables 3 | * 4 | * Description: A module to aid in ts3 spoof protection 5 | * This file sets up the module load and remove functions 6 | * and module meta data. 7 | * 8 | * Authors: 9 | * Niels Werensteijn , 2016-10-03 10 | * 11 | * This program is free software; you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License; either version 2 13 | * or 3 of the License, as published by the Free Software Foundation. 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | /* defined in ts3init_match.c */ 21 | int ts3init_match_init(void) __init; 22 | void ts3init_match_exit(void); 23 | 24 | /* defined in ts3init_target.c */ 25 | int ts3init_target_init(void) __init; 26 | void ts3init_target_exit(void); 27 | 28 | /* defined in ts3init_cookie.c */ 29 | int ts3init_cookie_init(void) __init; 30 | void ts3init_cookie_exit(void); 31 | 32 | MODULE_AUTHOR("Niels Werensteijn "); 33 | MODULE_DESCRIPTION("A module to aid in ts3 spoof protection"); 34 | MODULE_LICENSE("GPL"); 35 | MODULE_ALIAS("ipt_ts3init"); 36 | MODULE_ALIAS("ip6t_ts3init"); 37 | 38 | static int __init ts3init_init(void) 39 | { 40 | int error; 41 | 42 | error = ts3init_cookie_init(); 43 | if (error) 44 | goto out1; 45 | 46 | error = ts3init_match_init(); 47 | if (error) 48 | goto out2; 49 | 50 | error = ts3init_target_init(); 51 | if (error) 52 | goto out3; 53 | 54 | return error; 55 | 56 | out3: 57 | ts3init_match_exit(); 58 | out2: 59 | ts3init_cookie_exit(); 60 | out1: 61 | return error; 62 | } 63 | 64 | static void __exit ts3init_exit(void) 65 | { 66 | ts3init_target_exit(); 67 | ts3init_match_exit(); 68 | ts3init_cookie_exit(); 69 | } 70 | 71 | module_init(ts3init_init); 72 | module_exit(ts3init_exit); 73 | -------------------------------------------------------------------------------- /examples/complex-forward/delete-fw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" == "4" ] 4 | then 5 | IPTABLES=iptables 6 | FRAGMENT_FLAG="! -f " 7 | elif [ "$1" == "6" ] 8 | then 9 | IPTABLES=ip6tables 10 | FRAGMENT_FLAG="" 11 | else 12 | echo "specify either 4 or 6 as a parameter for ipv4 or ipv6"; 13 | exit -1 14 | fi 15 | 16 | if [ "$2" == "" ] 17 | then 18 | echo "need the interface name where client packets will enter as 2nd parameter" 19 | exit -1 20 | fi 21 | CLIENT_SIDE_IF=$2 22 | 23 | if [ "$3" == "" ] 24 | then 25 | echo "need the interface name where server is located as 3rd parameter" 26 | exit -1 27 | fi 28 | SERVER_SIDE_IF=$3 29 | 30 | #clear up ${IPTABLES} 31 | sudo ${IPTABLES} -t raw -D PREROUTING -i $CLIENT_SIDE_IF -p udp --dport 9987 -j CT --notrack 32 | sudo ${IPTABLES} -t raw -D PREROUTING -i $SERVER_SIDE_IF -p udp --sport 9987 -j CT --notrack 33 | sudo ${IPTABLES} -D FORWARD -i $CLIENT_SIDE_IF -p udp --dport 9987 ${FRAGMENT_FLAG} -j TS3_UDP_TRAFFIC 34 | sudo ${IPTABLES} -D FORWARD -i $CLIENT_SIDE_IF -p tcp --dport 30033 -j TS3_TCP_TRAFFIC 35 | sudo ${IPTABLES} -D FORWARD -i $SERVER_SIDE_IF -p udp --sport 9987 ${FRAGMENT_FLAG} -j OUT_TS3 36 | 37 | sudo ${IPTABLES} -F TS3_UDP_TRAFFIC 38 | sudo ${IPTABLES} -F TS3_UDP_TRAFFIC_AUTHORIZING 39 | sudo ${IPTABLES} -F TS3_UDP_TRAFFIC_AUTHORIZED 40 | sudo ${IPTABLES} -F TS3_TCP_TRAFFIC 41 | sudo ${IPTABLES} -F TS3_ACCEPT_AUTHORIZING 42 | sudo ${IPTABLES} -F OUT_TS3 43 | sudo ${IPTABLES} -F OUT_TS3_AUTHORIZING 44 | sudo ${IPTABLES} -F OUT_TS3_AUTHORIZED 45 | sudo ${IPTABLES} -F OUT_TS3_ACCEPT_AUTHORIZED 46 | 47 | sudo ${IPTABLES} -X TS3_UDP_TRAFFIC 48 | sudo ${IPTABLES} -X TS3_UDP_TRAFFIC_AUTHORIZING 49 | sudo ${IPTABLES} -X TS3_UDP_TRAFFIC_AUTHORIZED 50 | sudo ${IPTABLES} -X TS3_TCP_TRAFFIC 51 | sudo ${IPTABLES} -X TS3_ACCEPT_AUTHORIZING 52 | sudo ${IPTABLES} -X OUT_TS3 53 | sudo ${IPTABLES} -X OUT_TS3_AUTHORIZING 54 | sudo ${IPTABLES} -X OUT_TS3_AUTHORIZED 55 | sudo ${IPTABLES} -X OUT_TS3_ACCEPT_AUTHORIZED 56 | 57 | #delete the ipset 58 | sudo ipset destroy ts3_authorized${1} 59 | sudo ipset destroy ts3_authorized_ft${1} 60 | sudo ipset destroy ts3_authorizing${1} 61 | -------------------------------------------------------------------------------- /src/ts3init_random_seed.h: -------------------------------------------------------------------------------- 1 | #ifndef _TS3INIT_COOKIE_SEED_H 2 | #define _TS3INIT_COOKIE_SEED_H 3 | 4 | enum { 5 | RANDOM_SEED_LEN = 60, 6 | RANDOM_SEED_PATH_MAX = 256, 7 | }; 8 | 9 | /* 10 | * Parses a hexstring into dest. 11 | * It is assumed that RANDOM_SEED_LEN bytes are to be parsed. 12 | */ 13 | static inline bool parse_random_seed(const char *src, __u8* dst) 14 | { 15 | int i, j; 16 | for (i = 0; i < RANDOM_SEED_LEN; ++i) 17 | { 18 | int v = 0; 19 | for ( j = 0; j < 2; ++j) 20 | { 21 | uint8_t byte = *src++; 22 | if (byte >= '0' && byte <= '9') byte = byte - '0'; 23 | else if (byte >= 'a' && byte <='f') byte = byte - 'a' + 10; 24 | else if (byte >= 'A' && byte <='F') byte = byte - 'A' + 10; 25 | else return false; 26 | v = (v << 4) | byte; 27 | } 28 | *dst++ = v; 29 | } 30 | return true; 31 | } 32 | 33 | #ifndef __KERNEL__ 34 | 35 | /* 36 | * Reads a cookie seed from a file. 37 | */ 38 | static inline bool read_random_seed_from_file(const char *module_name, const char *path, __u8* dst) 39 | { 40 | int n, fd; 41 | char text[RANDOM_SEED_LEN * 2], error_message[256]; 42 | if (strlen(path) > RANDOM_SEED_PATH_MAX) 43 | { 44 | xtables_error(PARAMETER_PROBLEM, "%s: path is too long.", module_name); 45 | return false; 46 | } 47 | 48 | fd = open(path, O_RDONLY); 49 | if (fd == -1) goto io_error; 50 | if (lseek(fd, 0, SEEK_END) == sizeof(text)) 51 | { 52 | xtables_error(PARAMETER_PROBLEM, "%s: %s must contain exactly %lu characters", module_name, path, sizeof(text)); 53 | return false; 54 | } 55 | if (lseek(fd, 0, SEEK_SET) == -1) goto io_error; 56 | 57 | n = read(fd, text, sizeof(text)); 58 | if (n == -1) goto io_error; 59 | else if (n != sizeof(text) || parse_random_seed(text, dst) == false) 60 | { 61 | xtables_error(PARAMETER_PROBLEM, "%s: %s must contain exactly %lu lowercase hex characters", module_name, path, sizeof(text)); 62 | return false; 63 | } 64 | return true; 65 | io_error: 66 | strerror_r(errno, error_message, sizeof(error_message)); 67 | xtables_error(PARAMETER_PROBLEM, "%s: %s.", 68 | module_name, 69 | error_message); 70 | return false; 71 | } 72 | 73 | #endif /* __KERNEL__ */ 74 | #endif /* _TS3INIT_COOKIE_SEED_H */ 75 | -------------------------------------------------------------------------------- /test/test_siphash.c: -------------------------------------------------------------------------------- 1 | /* 2 | * test to see if ts3init_siphash24 behaves like it should 3 | * 4 | * Authors: 5 | * Niels Werensteijn , 2016-10-03 6 | * 7 | * This program is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU General Public License; either version 2 9 | * or 3 of the License, as published by the Free Software Foundation. 10 | */ 11 | #include 12 | #include 13 | #include 14 | #include "../src/siphash24.h" 15 | 16 | int siphash(uint8_t *out, const uint8_t *in, uint64_t inlen, const uint8_t *k); 17 | 18 | int main() 19 | { 20 | uint64_t keys[8][2]; 21 | uint8_t data[40]; 22 | int i, j, k, l; 23 | 24 | union 25 | { 26 | uint8_t out1[8]; 27 | uint64_t out2; 28 | } o; 29 | 30 | uint64_t out64; 31 | 32 | struct ts3init_siphash_state state; 33 | 34 | /* initialize */ 35 | 36 | for (i=0; i<8; ++i) 37 | { 38 | keys[i][0] = 1 + i; 39 | keys[i][1] = 9 + i; 40 | } 41 | 42 | for (i=0; i < 40; ++i) 43 | data[i] = 100 + i; 44 | 45 | for (i=0; i < 8; ++i) 46 | { 47 | for (j = 0; j < 40; ++j) 48 | { 49 | siphash(o.out1, data, j, (uint8_t*)keys[i] ); 50 | 51 | ts3init_siphash_setup(&state, keys[i][0], keys[i][1]); 52 | ts3init_siphash_update(&state, data, j); 53 | out64 = ts3init_siphash_finalize(&state); 54 | 55 | if (out64 != o.out2) 56 | printf("failed i:%d j:%d 0x%" PRIx64 " 0x%" PRIx64 " \n", i, j, out64, o.out2); 57 | 58 | for(k=0; k < j; ++k) 59 | { 60 | for (l=k; l < j; ++l) 61 | { 62 | ts3init_siphash_setup(&state, keys[i][0], keys[i][1]); 63 | ts3init_siphash_update(&state, data, k); 64 | ts3init_siphash_update(&state, data+k, l-k); 65 | ts3init_siphash_update(&state, data+l, j-l); 66 | out64 = ts3init_siphash_finalize(&state); 67 | if (out64 != o.out2) 68 | printf("failed i:%d j:%d k:%d l:%d 0x%" PRIx64 " 0x%" PRIx64 " \n", i, j, k, l, out64, o.out2); 69 | } 70 | } 71 | } 72 | } 73 | 74 | printf("test complete\n"); 75 | } 76 | -------------------------------------------------------------------------------- /src/compat_xtnu.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU General Public License; either 4 | * version 2 of the License, or any later version, as published by the 5 | * Free Software Foundation. 6 | */ 7 | 8 | #ifndef _COMPAT_XTNU_H 9 | #define _COMPAT_XTNU_H 1 10 | 11 | #include 12 | 13 | struct module; 14 | struct sk_buff; 15 | 16 | struct xtnu_match { 17 | /* 18 | * Making it smaller by sizeof(void *) on purpose to catch 19 | * lossy translation, if any. 20 | */ 21 | char name[sizeof(((struct xt_match *)NULL)->name) - 1 - sizeof(void *)]; 22 | uint8_t revision; 23 | bool (*match)(const struct sk_buff *, struct xt_action_param *); 24 | int (*checkentry)(const struct xt_mtchk_param *); 25 | void (*destroy)(const struct xt_mtdtor_param *); 26 | struct module *me; 27 | const char *table; 28 | unsigned int matchsize, hooks; 29 | unsigned short proto, family; 30 | 31 | void *__compat_match; 32 | }; 33 | 34 | struct xtnu_target { 35 | char name[sizeof(((struct xt_target *)NULL)->name) - 1 - sizeof(void *)]; 36 | uint8_t revision; 37 | unsigned int (*target)(struct sk_buff **, 38 | const struct xt_action_param *); 39 | int (*checkentry)(const struct xt_tgchk_param *); 40 | void (*destroy)(const struct xt_tgdtor_param *); 41 | struct module *me; 42 | const char *table; 43 | unsigned int targetsize, hooks; 44 | unsigned short proto, family; 45 | 46 | void *__compat_target; 47 | }; 48 | 49 | static inline struct xtnu_match *xtcompat_numatch(const struct xt_match *m) 50 | { 51 | void *q; 52 | memcpy(&q, m->name + sizeof(m->name) - sizeof(void *), sizeof(void *)); 53 | return q; 54 | } 55 | 56 | static inline struct xtnu_target *xtcompat_nutarget(const struct xt_target *t) 57 | { 58 | void *q; 59 | memcpy(&q, t->name + sizeof(t->name) - sizeof(void *), sizeof(void *)); 60 | return q; 61 | } 62 | 63 | extern int xtnu_register_match(struct xtnu_match *); 64 | extern void xtnu_unregister_match(struct xtnu_match *); 65 | extern int xtnu_register_matches(struct xtnu_match *, unsigned int); 66 | extern void xtnu_unregister_matches(struct xtnu_match *, unsigned int); 67 | extern int xtnu_register_target(struct xtnu_target *); 68 | extern void xtnu_unregister_target(struct xtnu_target *); 69 | extern int xtnu_register_targets(struct xtnu_target *, unsigned int); 70 | extern void xtnu_unregister_targets(struct xtnu_target *, unsigned int); 71 | 72 | extern void *HX_memmem(const void *, size_t, const void *, size_t); 73 | 74 | #endif /* _COMPAT_XTNU_H */ 75 | -------------------------------------------------------------------------------- /examples/simple/create-fw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sudo modprobe xt_ts3init 3 | 4 | if [ "$1" == "4" ] 5 | then 6 | IPTABLES=iptables 7 | IPFAMILY=inet 8 | FRAGMENT_FLAG="! -f " 9 | elif [ "$1" == "6" ] 10 | then 11 | IPTABLES=ip6tables 12 | IPFAMILY=inet6 13 | FRAGMENT_FLAG="" 14 | else 15 | echo "specify either 4 or 6 as a parameter for ipv4 or ipv6"; 16 | exit -1 17 | fi 18 | 19 | #create an autorized ts3 client ip set. 20 | #perhaps create the set with more than the default 1024 entries 21 | sudo ipset create ts3_authorized${1} hash:ip family ${IPFAMILY} timeout 30 || { echo "ipset not installed or there is a problem with it"; exit -1; } 22 | 23 | #create new chain that handles ts3 24 | sudo ${IPTABLES} -N TS3_UDP_TRAFFIC 25 | sudo ${IPTABLES} -N TS3_TCP_TRAFFIC 26 | sudo ${IPTABLES} -N TS3_ACCEPT_NEW 27 | sudo ${IPTABLES} -N TS3_UPDATE_AUTHORIZED 28 | 29 | RANDOM_FILE_NAME=random.data 30 | if [ ! -f "${RANDOM_FILE_NAME}" ] 31 | then 32 | xxd -l 60 -c 60 -p /dev/urandom > "${RANDOM_FILE_NAME}" || { echo "could not use xxd to create random data"; exit -1; } 33 | fi 34 | 35 | RANDOM_FILE=`pwd`/${RANDOM_FILE_NAME} 36 | 37 | #disable connection tracking for ts3 server 38 | sudo ${IPTABLES} -t raw -A PREROUTING -p udp --dport 9987 -j CT --notrack 39 | 40 | #move ts3 traffic to TS3_TRAFFIC chain (do not allow fragments) 41 | sudo ${IPTABLES} -A INPUT -p udp --dport 9987 ${FRAGMENT_FLAG} -j TS3_UDP_TRAFFIC 42 | 43 | #move filetransfer to TCP chain 44 | sudo ${IPTABLES} -A INPUT -p tcp --dport 30033 -j TS3_TCP_TRAFFIC 45 | 46 | #Allow authorized clients on UDP 47 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC -m set --match-set ts3_authorized${1} src -j TS3_UPDATE_AUTHORIZED 48 | 49 | #Allow 3.0.19 and up clients 50 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC -p udp -m ts3init_get_cookie --min-client 1459504131 -j TS3INIT_SET_COOKIE --random-seed-file ${RANDOM_FILE} 51 | 52 | #add new connection if cookie is valid 53 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC -p udp -m ts3init_get_puzzle --check-cookie --random-seed-file ${RANDOM_FILE} -j TS3_ACCEPT_NEW 54 | 55 | #drop the rest 56 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC -j DROP 57 | 58 | #add new connection to authorized src 59 | sudo ${IPTABLES} -A TS3_ACCEPT_NEW -j SET --add-set ts3_authorized${1} src 60 | sudo ${IPTABLES} -A TS3_ACCEPT_NEW -p udp -j TS3INIT_GET_COOKIE 61 | 62 | 63 | #Allow authorized clients on TCP 64 | sudo ${IPTABLES} -A TS3_TCP_TRAFFIC -m set --match-set ts3_authorized${1} src -j ACCEPT 65 | sudo ${IPTABLES} -A TS3_TCP_TRAFFIC -j DROP 66 | 67 | #update timeout in set and allow traffic 68 | sudo ${IPTABLES} -A TS3_UPDATE_AUTHORIZED -j SET --add-set ts3_authorized${1} src --exist 69 | sudo ${IPTABLES} -A TS3_UPDATE_AUTHORIZED -j ACCEPT 70 | 71 | -------------------------------------------------------------------------------- /src/compat_xtables.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU General Public License; either 4 | * version 2 of the License, or any later version, as published by the 5 | * Free Software Foundation. 6 | */ 7 | 8 | #ifndef _XTABLES_COMPAT_H 9 | #define _XTABLES_COMPAT_H 1 10 | 11 | #include 12 | #include 13 | #include "compat_skbuff.h" 14 | #include "compat_xtnu.h" 15 | 16 | #define DEBUGP Use__pr_debug__instead 17 | 18 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0) 19 | # warning Kernels below 3.7 not supported. 20 | #endif 21 | 22 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) 23 | # define prandom_u32() random32() 24 | #endif 25 | 26 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) 27 | # if !defined(CONFIG_NF_CONNTRACK_MARK) 28 | # warning You have CONFIG_NF_CONNTRACK enabled, but CONFIG_NF_CONNTRACK_MARK is not (please enable). 29 | # endif 30 | # include 31 | #else 32 | # warning You need CONFIG_NF_CONNTRACK. 33 | #endif 34 | 35 | #if !defined(NIP6) && !defined(NIP6_FMT) 36 | # define NIP6(addr) \ 37 | ntohs((addr).s6_addr16[0]), \ 38 | ntohs((addr).s6_addr16[1]), \ 39 | ntohs((addr).s6_addr16[2]), \ 40 | ntohs((addr).s6_addr16[3]), \ 41 | ntohs((addr).s6_addr16[4]), \ 42 | ntohs((addr).s6_addr16[5]), \ 43 | ntohs((addr).s6_addr16[6]), \ 44 | ntohs((addr).s6_addr16[7]) 45 | # define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" 46 | #endif 47 | #if !defined(NIPQUAD) && !defined(NIPQUAD_FMT) 48 | # define NIPQUAD(addr) \ 49 | ((const unsigned char *)&addr)[0], \ 50 | ((const unsigned char *)&addr)[1], \ 51 | ((const unsigned char *)&addr)[2], \ 52 | ((const unsigned char *)&addr)[3] 53 | # define NIPQUAD_FMT "%u.%u.%u.%u" 54 | #endif 55 | 56 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0) 57 | static inline struct inode *file_inode(struct file *f) 58 | { 59 | return f->f_path.dentry->d_inode; 60 | } 61 | #endif 62 | 63 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) 64 | static inline void proc_set_user(struct proc_dir_entry *de, 65 | typeof(de->uid) uid, typeof(de->gid) gid) 66 | { 67 | de->uid = uid; 68 | de->gid = gid; 69 | } 70 | 71 | static inline void *PDE_DATA(struct inode *inode) 72 | { 73 | return PDE(inode)->data; 74 | } 75 | 76 | static inline void proc_remove(struct proc_dir_entry *de) 77 | { 78 | if (de != NULL) 79 | remove_proc_entry(de->name, de->parent); 80 | } 81 | #endif 82 | 83 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) 84 | # define ip6_local_out(xnet, xsk, xskb) ip6_local_out(xskb) 85 | # define ip6_route_me_harder(xnet, xskb) ip6_route_me_harder(xskb) 86 | # define ip_local_out(xnet, xsk, xskb) ip_local_out(xskb) 87 | # define ip_route_me_harder(xnet, xskb, xaddrtype) ip_route_me_harder((xskb), (xaddrtype)) 88 | #endif 89 | 90 | static inline struct net *par_net(const struct xt_action_param *par) 91 | { 92 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) 93 | return xt_net(par); 94 | #elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) 95 | return par->net; 96 | #else 97 | return dev_net((par->in != NULL) ? par->in : par->out); 98 | #endif 99 | } 100 | 101 | #endif /* _XTABLES_COMPAT_H */ 102 | -------------------------------------------------------------------------------- /src/ts3init_cache.c: -------------------------------------------------------------------------------- 1 | /* 2 | * "ts3init" extension for Xtables 3 | * 4 | * Description: A module to aid in ts3 spoof protection 5 | * This is the "caching of cookies" related code 6 | * 7 | * Authors: 8 | * Niels Werensteijn , 2016-10-03 9 | * 10 | * This program is free software; you can redistribute it and/or modify it 11 | * under the terms of the GNU General Public License; either version 2 12 | * or 3 of the License, as published by the Free Software Foundation. 13 | */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "ts3init_cookie.h" 24 | #include "ts3init_cache.h" 25 | 26 | struct ts3init_cache_t 27 | { 28 | unsigned long saved_jiffies; 29 | time_t unix_time; 30 | struct xt_ts3init_cookie_cache cookie_cache; 31 | }; 32 | 33 | DEFINE_PER_CPU(struct ts3init_cache_t, ts3init_cache); 34 | 35 | static inline void update_cache_time(unsigned long jifs, 36 | struct ts3init_cache_t* cache) 37 | { 38 | if (((long)jifs - (long)cache->saved_jiffies) >= HZ) 39 | { 40 | /* it's been 1 second sinds last time update. 41 | * Get the new unix time and cache it*/ 42 | struct timeval tv; 43 | cache->saved_jiffies = jifs; 44 | do_gettimeofday(&tv); 45 | cache->unix_time = tv.tv_sec; 46 | } 47 | } 48 | 49 | time_t ts3init_get_cached_unix_time(void) 50 | { 51 | struct ts3init_cache_t* cache; 52 | unsigned long jifs; 53 | time_t current_unix_time; 54 | 55 | jifs = jiffies; 56 | 57 | cache = &get_cpu_var(ts3init_cache); 58 | 59 | update_cache_time(jifs, cache); 60 | 61 | current_unix_time = cache->unix_time; 62 | 63 | put_cpu_var(ts3init_cache); 64 | 65 | return current_unix_time; 66 | } 67 | 68 | bool ts3init_get_cookie_seed_for_packet_index(u8 packet_index, const u8* random_seed, u64 (*cookie)[2]) 69 | { 70 | struct ts3init_cache_t* cache; 71 | u64* result; 72 | unsigned long jifs; 73 | time_t current_unix_time; 74 | 75 | jifs = jiffies; 76 | cache = &get_cpu_var(ts3init_cache); 77 | 78 | update_cache_time(jifs, cache); 79 | 80 | current_unix_time = cache->unix_time; 81 | 82 | result = ts3init_get_cookie_seed(current_unix_time, 83 | packet_index, &cache->cookie_cache, random_seed); 84 | 85 | if (result) 86 | { 87 | (*cookie)[0] = result[0]; 88 | (*cookie)[1] = result[1]; 89 | } 90 | put_cpu_var(ts3init_cache); 91 | return result != NULL; 92 | } 93 | 94 | bool ts3init_get_current_cookie_seed(const u8* random_seed, u64 (*cookie)[2], u8 *packet_index) 95 | { 96 | struct ts3init_cache_t* cache; 97 | u64* result; 98 | unsigned long jifs; 99 | time_t current_unix_time; 100 | 101 | jifs = jiffies; 102 | cache = &get_cpu_var(ts3init_cache); 103 | 104 | update_cache_time(jifs, cache); 105 | 106 | current_unix_time = cache->unix_time; 107 | 108 | *packet_index = current_unix_time % 8; 109 | 110 | result = ts3init_get_cookie_seed(current_unix_time, 111 | *packet_index, &cache->cookie_cache, random_seed); 112 | 113 | if (result) 114 | { 115 | (*cookie)[0] = result[0]; 116 | (*cookie)[1] = result[1]; 117 | } 118 | put_cpu_var(ts3init_cache); 119 | return result != NULL; 120 | } 121 | -------------------------------------------------------------------------------- /cookie.md: -------------------------------------------------------------------------------- 1 | What is the cookie 2 | ================== 3 | The cookie is used to prevent address spoofing, without the firewall having to remember the ip-address of the clients. 4 | It does this by forcing the client to send a cookie, it can only get from the server. The cookie is generated from the current time, the source and destination address and port, and a secret that only the server has. 5 | It works on the same principle that authenticators do. This method forces the client to reply with the same ip/port to the same server ip/port in order to continue. 6 | 7 | How is the cookie generated 8 | =========================== 9 | The cookie is the hashed `ClientIp`, `ServerIp`, `ClientPort` and `ServerPort` using `siphash24` and a key that is one quarter of a `cookie_seed`. Every second another quarter of the `cookie_seed` is used as key. 10 | The server generates a new `cookie_seed` every 4 seconds, and always keeps 2 `cookie_seeds`. That means a client has atleast 4 seconds, and atmost 8 seconds to reply before the cookie becomes invalid. ClientIp, ServerIp, ClientPort and ServerPort are in network order. 11 | 12 | ``` 13 | cookie_seed = sha512(random_seed << 32 | (unix_time & 0xffffffff)) 14 | cookie = siphash24(cookie_seed >> ((time & 3) * 128), Concat(ClientIp, ServerIp, ClientPort, ServerPort)) 15 | ``` 16 | 17 | What is the `Random-Seed` 18 | ======================== 19 | The server keeps a secret called `random-seed`. Should a attacker ever get hold of the `random-seed` a new `random-seed` must be used. Otherwise any protection that the cookie offers would be compromised. Since a cookie is only valid for atmost eight seconds, changing the `random-seed` would at the worst prevent users from logging into a Teamspeak-Server for atmost eight seconds, but the most common case would be no outage what so ever. 20 | 21 | How to generate a `Random-Seed` 22 | ------------------------------- 23 | ``` 24 | xxd -l 60 -c 60 -p /dev/urandom > random_seed 25 | ``` 26 | 27 | Format of `COMMAND_GET_COOKIE` 28 | ============================= 29 | 30 | ``` 31 | 0 1 2 3 32 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 33 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 34 | | 'T' | 'S' | '3' | 'I' | 35 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 36 | | 'N' | 'I' | 'T' | '1' | 37 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 38 | | PacketId | ClientId | 39 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 40 | | Type + Flags | Client Version -> 41 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 42 | | Command | Timestamp -> 43 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 44 | | Random Sequence -> 45 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 46 | | RESERVERD | 47 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 48 | | RESERVED | 49 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 50 | | RESERVERD | 51 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 52 | ``` 53 | * All fields are encoded in big endian, unless otherwise specified. 54 | * `PacketId` is always `101`. 55 | * `ClientId` is always `0`. 56 | * `Type + Flags` is always `0x88`. 57 | * `Client Version` is the build number of the client. 58 | * `Command` is always `0`. 59 | * `Timestamp` is the unixtime of the client maschine, encoded in big endian. 60 | * `Random Sequence` is a random value generated by the client. 61 | * Every `RESERVED` field must be zero. 62 | -------------------------------------------------------------------------------- /src/libxt_ts3init.c: -------------------------------------------------------------------------------- 1 | /* 2 | * "ts3init" match extension for iptables 3 | * Niels Werensteijn , 2016-10-03 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License; either version 2 7 | * or 3 of the License, as published by the Free Software Foundation. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "ts3init_random_seed.h" 21 | #include "ts3init_match.h" 22 | 23 | #define param_act(t, s, f) xtables_param_act((t), "ts3init", (s), (f)) 24 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) 25 | 26 | static void ts3init_help(void) 27 | { 28 | printf( 29 | "ts3init match options:\n" 30 | " --client Match ts3init client packets.\n" 31 | " --server Match ts3init server packets.\n" 32 | " --command Match packets with the specified command.\n" 33 | ); 34 | } 35 | 36 | static const struct option ts3init_opts[] = { 37 | {.name = "client", .has_arg = false, .val = '1'}, 38 | {.name = "server", .has_arg = false, .val = '2'}, 39 | {.name = "command", .has_arg = true, .val = '3'}, 40 | {NULL}, 41 | }; 42 | 43 | static int ts3init_parse(int c, char **argv, int invert, unsigned int *flags, 44 | const void *entry, struct xt_entry_match **match) 45 | { 46 | struct xt_ts3init_mtinfo *info = (void *)(*match)->data; 47 | int command; 48 | 49 | switch (c) { 50 | case '1': 51 | param_act(XTF_ONLY_ONCE, "--client", info->specific_options & CHK_TS3INIT_CLIENT); 52 | param_act(XTF_NO_INVERT, "--client", invert); 53 | info->specific_options |= CHK_TS3INIT_CLIENT; 54 | *flags |= CHK_TS3INIT_CLIENT; 55 | return true; 56 | 57 | case '2': 58 | param_act(XTF_ONLY_ONCE, "--server", info->specific_options & CHK_TS3INIT_SERVER); 59 | param_act(XTF_NO_INVERT, "--server", invert); 60 | info->specific_options |= CHK_TS3INIT_SERVER; 61 | *flags |= CHK_TS3INIT_SERVER; 62 | return true; 63 | 64 | case '3': 65 | param_act(XTF_ONLY_ONCE, "--command", info->specific_options & CHK_TS3INIT_COMMAND); 66 | param_act(XTF_NO_INVERT, "--command", invert); 67 | command = atoi(optarg); 68 | if (command < 0 || command > 255) 69 | xtables_error(PARAMETER_PROBLEM, 70 | "ts3init: invalid command number"); 71 | info->specific_options |= CHK_TS3INIT_COMMAND; 72 | info->command = (__u8)command; 73 | *flags |= CHK_TS3INIT_COMMAND; 74 | return true; 75 | 76 | default: 77 | return false; 78 | } 79 | } 80 | 81 | static void ts3init_save(const void *ip, const struct xt_entry_match *match) 82 | { 83 | const struct xt_ts3init_mtinfo *info = (const void *)match->data; 84 | if (info->specific_options & CHK_TS3INIT_CLIENT) 85 | { 86 | printf(" --client"); 87 | } 88 | if (info->specific_options & CHK_TS3INIT_SERVER) 89 | { 90 | printf(" --server"); 91 | } 92 | if (info->specific_options & CHK_TS3INIT_COMMAND) 93 | { 94 | printf(" --command %i", (int)info->command); 95 | } 96 | } 97 | 98 | static void ts3init_print(const void *ip, const struct xt_entry_match *match, 99 | int numeric) 100 | { 101 | printf(" -m ts3init"); 102 | ts3init_save(ip, match); 103 | } 104 | 105 | static void ts3init_check(unsigned int flags) 106 | { 107 | bool client = flags & CHK_TS3INIT_CLIENT; 108 | bool server = flags & CHK_TS3INIT_SERVER; 109 | if (client && server) 110 | { 111 | xtables_error(PARAMETER_PROBLEM, 112 | "ts3init_: --client and --server can not be specified at the same time"); 113 | } 114 | if (flags & CHK_TS3INIT_COMMAND) 115 | { 116 | if (!client && !server) 117 | { 118 | xtables_error(PARAMETER_PROBLEM, 119 | "ts3init: --command requires either --client or --server"); 120 | } 121 | } 122 | } 123 | 124 | /* register and init */ 125 | static struct xtables_match ts3init_mt_reg[] = 126 | { 127 | { 128 | .name = "ts3init", 129 | .revision = 0, 130 | .family = NFPROTO_UNSPEC, 131 | .version = XTABLES_VERSION, 132 | .size = XT_ALIGN(sizeof(struct xt_ts3init_mtinfo)), 133 | .userspacesize = XT_ALIGN(sizeof(struct xt_ts3init_mtinfo)), 134 | .help = ts3init_help, 135 | .parse = ts3init_parse, 136 | .print = ts3init_print, 137 | .save = ts3init_save, 138 | .extra_opts = ts3init_opts, 139 | .final_check = ts3init_check, 140 | }, 141 | }; 142 | 143 | static __attribute__((constructor)) void ts3init_mt_ldr(void) 144 | { 145 | xtables_register_matches(ts3init_mt_reg, ARRAY_SIZE(ts3init_mt_reg)); 146 | } 147 | -------------------------------------------------------------------------------- /src/libxt_ts3init_get_cookie.c: -------------------------------------------------------------------------------- 1 | /* 2 | * "ts3init_get_cookie and ts3init_get_puzzle" match extension for iptables 3 | * Niels Werensteijn , 2016-10-03 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License; either version 2 7 | * or 3 of the License, as published by the Free Software Foundation. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "ts3init_random_seed.h" 21 | #include "ts3init_match.h" 22 | 23 | #define param_act(t, s, f) xtables_param_act((t), "ts3init_get_cookie", (s), (f)) 24 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) 25 | 26 | static void ts3init_get_cookie_help(void) 27 | { 28 | printf( 29 | "ts3init_get_cookie match options:\n" 30 | " --min-client n The client needs to be at least version n.\n" 31 | " --check-time sec Check packet send time request.\n" 32 | " May be off by sec seconds.\n" 33 | ); 34 | } 35 | 36 | static const struct option ts3init_get_cookie_opts[] = { 37 | {.name = "min-client", .has_arg = true, .val = '1'}, 38 | {.name = "check-time", .has_arg = true, .val = '2'}, 39 | {NULL}, 40 | }; 41 | 42 | static int ts3init_get_cookie_parse(int c, char **argv, int invert, unsigned int *flags, 43 | const void *entry, struct xt_entry_match **match) 44 | { 45 | struct xt_ts3init_get_cookie_mtinfo *info = (void *)(*match)->data; 46 | int client_version; 47 | int time_offset; 48 | 49 | switch (c) { 50 | case '1': 51 | param_act(XTF_ONLY_ONCE, "--min-client", info->common_options & CHK_COMMON_CLIENT_VERSION); 52 | param_act(XTF_NO_INVERT, "--min-client", invert); 53 | client_version = atoi(optarg); 54 | if (client_version <= 0) 55 | xtables_error(PARAMETER_PROBLEM, 56 | "ts3init_get_cookie: invalid min-client version"); 57 | info->common_options |= CHK_COMMON_CLIENT_VERSION; 58 | info->min_client_version = client_version - CLIENT_VERSION_OFFSET; 59 | return true; 60 | 61 | case '2': 62 | param_act(XTF_ONLY_ONCE, "--check-time", info->specific_options & CHK_GET_COOKIE_CHECK_TIMESTAMP); 63 | param_act(XTF_NO_INVERT, "--check-time", invert); 64 | time_offset = atoi(optarg); 65 | if (time_offset <= 0) 66 | xtables_error(PARAMETER_PROBLEM, 67 | "ts3init_get_cookie: invalid time offset"); 68 | info->specific_options |= CHK_GET_COOKIE_CHECK_TIMESTAMP; 69 | info->max_utc_offset = time_offset; 70 | return true; 71 | 72 | default: 73 | return false; 74 | } 75 | } 76 | 77 | static void ts3init_get_cookie_save(const void *ip, const struct xt_entry_match *match) 78 | { 79 | const struct xt_ts3init_get_cookie_mtinfo *info = (const void *)match->data; 80 | if (info->common_options & CHK_COMMON_CLIENT_VERSION) 81 | { 82 | printf(" --min-client %u", info->min_client_version + CLIENT_VERSION_OFFSET); 83 | } 84 | if (info->specific_options & CHK_GET_COOKIE_CHECK_TIMESTAMP) 85 | { 86 | printf(" --check-time %u", info->max_utc_offset); 87 | } 88 | } 89 | 90 | static void ts3init_get_cookie_print(const void *ip, const struct xt_entry_match *match, 91 | int numeric) 92 | { 93 | printf(" -m ts3init_get_cookie"); 94 | ts3init_get_cookie_save(ip, match); 95 | } 96 | 97 | /* register and init */ 98 | static struct xtables_match ts3init_mt_reg[] = 99 | { 100 | { 101 | .name = "ts3init_get_cookie", 102 | .revision = 0, 103 | .family = NFPROTO_IPV4, 104 | .version = XTABLES_VERSION, 105 | .size = XT_ALIGN(sizeof(struct xt_ts3init_get_cookie_mtinfo)), 106 | .userspacesize = XT_ALIGN(sizeof(struct xt_ts3init_get_cookie_mtinfo)), 107 | .help = ts3init_get_cookie_help, 108 | .parse = ts3init_get_cookie_parse, 109 | .print = ts3init_get_cookie_print, 110 | .save = ts3init_get_cookie_save, 111 | .extra_opts = ts3init_get_cookie_opts, 112 | }, 113 | { 114 | .name = "ts3init_get_cookie", 115 | .revision = 0, 116 | .family = NFPROTO_IPV6, 117 | .version = XTABLES_VERSION, 118 | .size = XT_ALIGN(sizeof(struct xt_ts3init_get_cookie_mtinfo)), 119 | .userspacesize = XT_ALIGN(sizeof(struct xt_ts3init_get_cookie_mtinfo)), 120 | .help = ts3init_get_cookie_help, 121 | .parse = ts3init_get_cookie_parse, 122 | .print = ts3init_get_cookie_print, 123 | .save = ts3init_get_cookie_save, 124 | .extra_opts = ts3init_get_cookie_opts, 125 | }, 126 | }; 127 | 128 | static __attribute__((constructor)) void ts3init_mt_ldr(void) 129 | { 130 | xtables_register_matches(ts3init_mt_reg, ARRAY_SIZE(ts3init_mt_reg)); 131 | } 132 | -------------------------------------------------------------------------------- /src/ts3init_cookie.c: -------------------------------------------------------------------------------- 1 | /* 2 | * "ts3init" extension for Xtables 3 | * 4 | * Description: A module to aid in ts3 spoof protection 5 | * This is the "cookie" related code 6 | * 7 | * Authors: 8 | * Niels Werensteijn , 2016-10-03 9 | * 10 | * This program is free software; you can redistribute it and/or modify it 11 | * under the terms of the GNU General Public License; either version 2 12 | * or 3 of the License, as published by the Free Software Foundation. 13 | */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "siphash24.h" 26 | #include "ts3init_random_seed.h" 27 | #include "ts3init_cookie.h" 28 | 29 | #ifndef HAS_CRYPTO_HASH_INFO 30 | #define TS3_SHA_512_NAME "sha512" 31 | #else 32 | #include 33 | #define TS3_SHA_512_NAME hash_algo_name[HASH_ALGO_SHA512] 34 | #endif 35 | 36 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0) 37 | #define SHASH_DESC_ON_STACK(shash, ctx) \ 38 | char __##shash##_desc[sizeof(struct shash_desc) + \ 39 | crypto_shash_descsize(ctx)] CRYPTO_MINALIGN_ATTR; \ 40 | struct shash_desc *shash = (struct shash_desc *)__##shash##_desc 41 | #endif 42 | 43 | static struct crypto_shash *sha512_tfm; 44 | 45 | 46 | static void check_update_seed_cache(time_t time, __u8 index, 47 | struct xt_ts3init_cookie_cache* cache, 48 | const __u8* random_seed) 49 | { 50 | int ret; 51 | __le32 seed_hash_time; 52 | 53 | if (time == cache->time[index]) return; 54 | 55 | /* We need to update the cache. */ 56 | /* seed = sha512(random_seed[RANDOM_SEED_LEN] + __le32 time) */ 57 | seed_hash_time = cpu_to_le32( (__u32)time); 58 | { 59 | SHASH_DESC_ON_STACK(shash, sha512_tfm); 60 | shash->tfm = sha512_tfm; 61 | shash->flags = 0; 62 | 63 | ret = crypto_shash_init(shash); 64 | if (ret != 0) 65 | { 66 | printk(KERN_ERR KBUILD_MODNAME ": could not initalize sha512\n"); 67 | return; 68 | } 69 | 70 | ret = crypto_shash_update(shash, random_seed, RANDOM_SEED_LEN); 71 | if (ret != 0) 72 | { 73 | printk(KERN_ERR KBUILD_MODNAME ": could not update sha512\n"); 74 | return; 75 | } 76 | 77 | ret = crypto_shash_finup(shash, (u8*)&seed_hash_time, 4, 78 | cache->seed8 + index * SHA512_SIZE); 79 | if (ret != 0) 80 | { 81 | printk(KERN_ERR KBUILD_MODNAME ": could not finup sha512\n"); 82 | return; 83 | } 84 | 85 | cache->time[index] = time; 86 | } 87 | } 88 | 89 | __u64* ts3init_get_cookie_seed(time_t current_time, __u8 packet_index, 90 | struct xt_ts3init_cookie_cache* cache, 91 | const __u8* random_seed) 92 | { 93 | 94 | __u8 current_cache_index; 95 | __u8 packet_cache_index; 96 | time_t current_cache_time; 97 | time_t packet_cache_time; 98 | 99 | if (packet_index >= 8) return NULL; 100 | 101 | current_cache_index = (current_time % 8) / 4; 102 | packet_cache_index = packet_index / 4; 103 | 104 | /* get cache time of packet */ 105 | current_cache_time = current_time & ~((time_t)3); 106 | packet_cache_time = current_cache_time 107 | - ((current_cache_index ^ packet_cache_index)*4); 108 | 109 | /* make sure the cache is up-to-date */ 110 | check_update_seed_cache(packet_cache_time, packet_cache_index, cache, 111 | random_seed); 112 | 113 | /* return the proper seed */ 114 | return cache->seed64 + ((SIP_KEY_SIZE/sizeof(__u64)) * packet_index ); 115 | } 116 | 117 | int ts3init_calculate_cookie_ipv6(const struct ipv6hdr *ip, const struct udphdr *udp, 118 | __u64 k0, __u64 k1, __u64* out) 119 | { 120 | struct ts3init_siphash_state hash_state; 121 | 122 | ts3init_siphash_setup(&hash_state, k0, k1); 123 | ts3init_siphash_update(&hash_state, (u8 *)&ip->saddr, sizeof(ip->saddr) * 2); 124 | ts3init_siphash_update(&hash_state, (u8 *)&udp->source, 4); 125 | *out = ts3init_siphash_finalize(&hash_state); 126 | 127 | return 0; 128 | } 129 | 130 | int ts3init_calculate_cookie_ipv4(const struct iphdr *ip, const struct udphdr *udp, 131 | __u64 k0, __u64 k1, __u64* out) 132 | { 133 | struct ts3init_siphash_state hash_state; 134 | 135 | ts3init_siphash_setup(&hash_state, k0, k1); 136 | ts3init_siphash_update(&hash_state, (u8 *)&ip->saddr, sizeof(ip->saddr) * 2); 137 | ts3init_siphash_update(&hash_state, (u8 *)&udp->source, 4); 138 | *out = ts3init_siphash_finalize(&hash_state); 139 | 140 | return 0; 141 | } 142 | 143 | int __init ts3init_cookie_init(void) 144 | { 145 | sha512_tfm = crypto_alloc_shash(TS3_SHA_512_NAME, 0, 0); 146 | if (IS_ERR(sha512_tfm)) 147 | { 148 | printk(KERN_ERR KBUILD_MODNAME ": could not alloc sha512\n"); 149 | return (int) PTR_ERR(sha512_tfm); 150 | } 151 | return 0; 152 | } 153 | 154 | void ts3init_cookie_exit(void) 155 | { 156 | crypto_free_shash(sha512_tfm); 157 | } 158 | 159 | -------------------------------------------------------------------------------- /examples/complex/create-fw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #This example is a more complex. 4 | #The traffic will be split up into "unknown" / authorizing / authorized 5 | #We use packets from the ts3 server for extra state info 6 | #We also limit the concurrent connection to file transfer tcp port to 20/ip 7 | 8 | sudo modprobe xt_ts3init 9 | 10 | if [ "$1" == "4" ] 11 | then 12 | IPTABLES=iptables 13 | IPFAMILY=inet 14 | FRAGMENT_FLAG="! -f " 15 | elif [ "$1" == "6" ] 16 | then 17 | IPTABLES=ip6tables 18 | IPFAMILY=inet6 19 | FRAGMENT_FLAG="" 20 | else 21 | echo "specify either 4 or 6 as a parameter for ipv4 or ipv6"; 22 | exit -1 23 | fi 24 | 25 | #create an autorized ts3 client ip set. 26 | #perhaps create the set with more than the default 1024 entries 27 | sudo ipset create ts3_authorizing${1} hash:ip,port family ${IPFAMILY} timeout 8 || { echo "ipset not installed or there is a problem with it (1)"; exit -1; } 28 | sudo ipset create ts3_authorized${1} hash:ip,port family ${IPFAMILY} timeout 30 || { echo "ipset not installed or there is a problem with it (2)"; exit -1; } 29 | sudo ipset create ts3_authorized_ft${1} hash:ip family ${IPFAMILY} timeout 30 || { echo "ipset not installed or there is a problem with it (3)"; exit -1; } 30 | 31 | #create new chains that handles ts3 32 | sudo ${IPTABLES} -N TS3_UDP_TRAFFIC 33 | sudo ${IPTABLES} -N TS3_UDP_TRAFFIC_AUTHORIZING 34 | sudo ${IPTABLES} -N TS3_UDP_TRAFFIC_AUTHORIZED 35 | sudo ${IPTABLES} -N TS3_TCP_TRAFFIC 36 | sudo ${IPTABLES} -N TS3_ACCEPT_AUTHORIZING 37 | sudo ${IPTABLES} -N OUT_TS3 38 | sudo ${IPTABLES} -N OUT_TS3_AUTHORIZING 39 | sudo ${IPTABLES} -N OUT_TS3_AUTHORIZED 40 | sudo ${IPTABLES} -N OUT_TS3_ACCEPT_AUTHORIZED 41 | 42 | 43 | RANDOM_FILE_NAME=random.data 44 | if [ ! -f "${RANDOM_FILE_NAME}" ] 45 | then 46 | xxd -l 60 -c 60 -p /dev/urandom > "${RANDOM_FILE_NAME}" || { echo "could not use xxd to create random data"; exit -1; } 47 | fi 48 | 49 | RANDOM_FILE=`pwd`/${RANDOM_FILE_NAME} 50 | 51 | #disable connection tracking for ts3 client->server 52 | sudo ${IPTABLES} -t raw -A PREROUTING -p udp --dport 9987 -j CT --notrack 53 | 54 | #disable connection tracking for ts3 server->client 55 | sudo ${IPTABLES} -t raw -A OUTPUT -p udp --sport 9987 -j CT --notrack 56 | 57 | #move ts3 traffic to TS3_UDP_TRAFFIC chain (do not allow fragments) 58 | sudo ${IPTABLES} -A INPUT -p udp --dport 9987 ${FRAGMENT_FLAG} -j TS3_UDP_TRAFFIC 59 | 60 | #move filetransfer to TS3_TCP_TRAFFIC chain 61 | sudo ${IPTABLES} -A INPUT -p tcp --dport 30033 -j TS3_TCP_TRAFFIC 62 | 63 | #move authorized clients to TS3_UDP_TRAFFIC_AUTHORIZED chain 64 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC -m set --match-set ts3_authorized${1} src,src -j TS3_UDP_TRAFFIC_AUTHORIZED 65 | 66 | #move authorizing clients to TS3_UDP_TRAFFIC_AUTHORIZING chain 67 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC -m set --match-set ts3_authorizing${1} src,src -j TS3_UDP_TRAFFIC_AUTHORIZING 68 | 69 | #Allow 3.0.19 and up clients. If its get cookie, send back a cookie 70 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC -p udp -m ts3init_get_cookie --min-client 1459504131 -j TS3INIT_SET_COOKIE --random-seed-file ${RANDOM_FILE} 71 | 72 | #add new connection if cookie is valid 73 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC -p udp -m ts3init_get_puzzle --check-cookie --random-seed-file ${RANDOM_FILE} -j TS3_ACCEPT_AUTHORIZING 74 | 75 | #drop the rest 76 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC -j DROP 77 | 78 | #accept autorized/authorizing. Here is the time to rate limit per ip for autorized (connected) streams 79 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC_AUTHORIZED -j ACCEPT 80 | 81 | #accept autorized/authorizing. Here is the time to rate limit per ip for authorizing (ip checked, but not connected) 82 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC_AUTHORIZING -j ACCEPT 83 | 84 | #add new connection to authorizing src, and send the ts3 server a get cookie request 85 | sudo ${IPTABLES} -A TS3_ACCEPT_AUTHORIZING -j SET --add-set ts3_authorizing${1} src,src 86 | sudo ${IPTABLES} -A TS3_ACCEPT_AUTHORIZING -p udp -j TS3INIT_GET_COOKIE 87 | 88 | #Allow authorized clients on TCP only 89 | sudo ${IPTABLES} -A TS3_TCP_TRAFFIC -m set ! --match-set ts3_authorized_ft${1} src,src -j DROP 90 | 91 | #only allow 20 connections 92 | sudo ${IPTABLES} -A TS3_TCP_TRAFFIC -p tcp --syn -m connlimit --connlimit-above 20 -j REJECT --reject-with tcp-reset 93 | 94 | #accept 95 | sudo ${IPTABLES} -A TS3_TCP_TRAFFIC -j ACCEPT 96 | 97 | #watch server->client traffic 98 | sudo ${IPTABLES} -A OUTPUT -p udp --sport 9987 ${FRAGMENT_FLAG} -j OUT_TS3 99 | 100 | #Move clients in the authorized phase to the OUT_TS3_AUTHORIZED chain. 101 | sudo ${IPTABLES} -A OUT_TS3 -m set --match-set ts3_authorized${1} dst,dst -j OUT_TS3_AUTHORIZED 102 | #Move clients in the authorizing phase to the OUT_TS3_AUTHORIZING chain. 103 | sudo ${IPTABLES} -A OUT_TS3 -m set --match-set ts3_authorizing${1} dst,dst -j OUT_TS3_AUTHORIZING 104 | #These are packets from TS3INIT_SET_COOKIE 105 | sudo ${IPTABLES} -A OUT_TS3 -j ACCEPT 106 | 107 | #Is this still ts3init (not fully connected) 108 | sudo ${IPTABLES} -A OUT_TS3_AUTHORIZING -p udp -m ts3init --server -j ACCEPT 109 | #else this connection is accepeted(authorized) now. 110 | #Note that this is not really true. This only means the server accepted the client puzzle. 111 | #The conection request could still be rejected, because of a wrong password or other reasons. 112 | sudo ${IPTABLES} -A OUT_TS3_AUTHORIZING -j OUT_TS3_ACCEPT_AUTHORIZED 113 | 114 | #update/add timeout in set and allow traffic 115 | sudo ${IPTABLES} -A OUT_TS3_AUTHORIZED -j SET --add-set ts3_authorized${1} dst,dst --exist 116 | sudo ${IPTABLES} -A OUT_TS3_AUTHORIZED -j SET --add-set ts3_authorized_ft${1} dst --exist 117 | sudo ${IPTABLES} -A OUT_TS3_AUTHORIZED -j ACCEPT 118 | 119 | #accept connection as authorized. Remove from authorizing and treat as accepted 120 | sudo ${IPTABLES} -A OUT_TS3_ACCEPT_AUTHORIZED -j SET --del-set ts3_authorizing${1} dst,dst 121 | sudo ${IPTABLES} -A OUT_TS3_ACCEPT_AUTHORIZED -j OUT_TS3_AUTHORIZED 122 | -------------------------------------------------------------------------------- /test/torture.py: -------------------------------------------------------------------------------- 1 | """ 2 | Generates as fast as possible COMMAND_GET_COOKIE packets to see how well 3 | the TeamSpeak 3 Server can withstand a simple DOS attack. 4 | 5 | It has two modes: 6 | * a testing mode that checks that the server continues to reply with correct 7 | messages, even when under heavy load. 8 | * a spoofing mode, where answers are not expected or waited for, but the source 9 | ip and port are spoofed, in order to trick simple filtering. 10 | """ 11 | from socket import socket, getaddrinfo, IPPROTO_UDP, AF_INET, SOCK_RAW, IPPROTO_RAW, inet_aton 12 | from argparse import ArgumentParser 13 | from select import select 14 | from random import randint 15 | from itertools import repeat 16 | from struct import pack, unpack_from 17 | from time import time 18 | from sys import version_info, exit 19 | 20 | if version_info < (3,0): 21 | print('python3 required.') 22 | exit(1) 23 | 24 | parser = ArgumentParser(description='Tests if the ts3init module, can withstand heavy loads.') 25 | parser.add_argument('host', help='target host') 26 | parser.add_argument('--port', type=int, default=9987, help='target port') 27 | parser.add_argument('--count', type=int, default=100000, help='number of packets to send') 28 | parser.add_argument('--response', type=int, default=1, help='what command number is expected to be returned from the server') 29 | parser.add_argument('--spoof', action='store_const', const=True, default=False, help='should the source address be spoofed') 30 | parser.add_argument('--version', type=int, default=1459504131, help='version number send to the server') 31 | args = parser.parse_args() 32 | 33 | CLIENT_VERSION_OFFSET = 1356998400 34 | 35 | def generateSpoofedHeader(dest_address, dest_port, payload): 36 | # checksum functions needed for calculation checksum 37 | def checksum(msg): 38 | s = 0 39 | for i in range(0, len(msg), 2): 40 | w = msg[i+1] + (msg[i] << 8) 41 | s = s + w 42 | s = (s>>16) + (s & 0xffff); 43 | s = s + (s >> 16); 44 | s = ~s & 0xffff 45 | return s 46 | 47 | source_address = randint(0, (1 << 32) - 1) 48 | source_port = randint(0, (1 << 16) - 1) 49 | udp_length = 8 + len(payload) 50 | udp_checksum = checksum(pack('!I4sxBHHHH2x', 51 | source_address , dest_address, IPPROTO_UDP, udp_length, 52 | source_port, dest_port, udp_length) + payload) 53 | if udp_checksum == 0: 54 | udp_checksum = (1 << 16) - 1 55 | 56 | return pack('!BBHHHBBHI4sHHHH', 57 | (4 << 4) + 5, # Version, IHL 58 | 0, # TOS 59 | 0, # Total Length, kernel will fill the correct total length 60 | 0, # Identification 61 | 0, # Fragment Offset 62 | 255, # TTL 63 | IPPROTO_UDP, # Protocol 64 | 0, # Header checksum, kernel will fill the correct checksum 65 | source_address, # Source Address 66 | dest_address, # Destination Address 67 | source_port, # Source Port 68 | dest_port, # Destination Port 69 | udp_length, # UDP Length 70 | udp_checksum); # UDP Checksum 71 | 72 | def generatePayload(version): 73 | number = randint(0, (1 << 32) - 1) 74 | return pack('!8sHHBIBII8x', 75 | b'TS3INIT1', # Literal 76 | 101, # Packet ID 77 | 0, # Client ID 78 | 0x88, # Flags, 79 | version - CLIENT_VERSION_OFFSET, # Version 80 | 0, # Command 81 | int(time()), # Timestamp 82 | number); # Random-Sequence 83 | 84 | def validateResponse(answer, expectedCommand): 85 | (literal, packet_id, flags, command) = unpack_from('!8sHBB', answer) 86 | return (literal == 'TS3INIT1' 87 | and packet_id == 101 88 | and flags == 0x88 89 | and command == expectedCommand) 90 | 91 | target = getaddrinfo(args.host, args.port, 0, 0, IPPROTO_UDP)[0] 92 | print("Sending %i packets to %s:%i..." % (args.count, *target[4])) 93 | 94 | if not args.spoof: 95 | send = 0 96 | sendErrors = 0 97 | recieved = 0 98 | invalid = 0 99 | sock = socket(*target[0:3]) 100 | try: 101 | sock.connect(target[4]) 102 | sock.setblocking(False) 103 | finished_writing = False 104 | while True: 105 | (canRead, canWrite, _) = select([sock.fileno()], [sock.fileno()] if not args.spoof and send < args.count else [] , [], 1) 106 | if canRead: 107 | data = sock.recv(128) 108 | if not validateResponse(data, args.response): 109 | invalid += 1 110 | recieved += 1 111 | if canWrite: 112 | try: 113 | packet = generatePayload(args.version) 114 | sock.send(packet) 115 | send += 1 116 | except: 117 | sendErrors += 1 118 | if not canRead and not canWrite: 119 | break 120 | finally: 121 | sock.close() 122 | print("send: %i(errors: %i); recieved: %i; invalid: %i" % (send, sendErrors, recieved, invalid)) 123 | else: 124 | send = 0 125 | sendErrors = 0 126 | sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW) 127 | try: 128 | dest_address = inet_aton(target[4][0]) 129 | dest_port = target[4][1] 130 | 131 | for _ in repeat(None, args.count): 132 | try: 133 | payload = generatePayload(args.version) 134 | packet = generateSpoofedHeader(dest_address, dest_port, payload) + payload 135 | select([sock.fileno()], [] , [], 0) 136 | sock.sendto(packet, target[4]) 137 | send += 1 138 | except BaseException as e: 139 | print(e) 140 | sendErrors += 1 141 | finally: 142 | sock.close() 143 | print("send: %i(errors: %i);" % (send, sendErrors)) 144 | -------------------------------------------------------------------------------- /src/siphash24.c: -------------------------------------------------------------------------------- 1 | /* 2 | SipHash reference C implementation 3 | Copyright (c) 2012-2014 Jean-Philippe Aumasson 4 | 5 | Copyright (c) 2012-2014 Daniel J. Bernstein 6 | Modified by TeamSpeak Systems for use in ts3init kernel module 7 | Copyright (c) 2016 Maximilian Muenchow 8 | Copyright (c) 2016 Niels Werensteijn 9 | To the extent possible under law, the author(s) have dedicated all copyright 10 | and related and neighboring rights to this software to the public domain 11 | worldwide. This software is distributed without any warranty. 12 | You should have received a copy of the CC0 Public Domain Dedication along 13 | with 14 | this software. If not, see 15 | . 16 | */ 17 | 18 | #include "siphash24.h" 19 | 20 | 21 | /* default: SipHash-2-4 */ 22 | enum 23 | { 24 | ts3init_cROUNDS = 2, 25 | ts3init_dROUNDS = 4 26 | }; 27 | 28 | static inline u64 ts3init_ROTL(u64 x, int b) 29 | { 30 | return (x << b) | (x >> (64 - b)); 31 | } 32 | 33 | static inline u64 ts3init_U8TO64_LE(const u8* p) 34 | { 35 | return (((u64)(p[0])) | ((u64)(p[1]) << 8) | 36 | ((u64)(p[2]) << 16) | ((u64)(p[3]) << 24) | 37 | ((u64)(p[4]) << 32) | ((u64)(p[5]) << 40) | 38 | ((u64)(p[6]) << 48) | ((u64)(p[7]) << 56)); 39 | } 40 | 41 | static inline void ts3init_SIPROUND(u64* v0, u64* v1, u64* v2, u64* v3) 42 | { 43 | *v0 += *v1; 44 | *v1 = ts3init_ROTL(*v1, 13); 45 | *v1 ^= *v0; 46 | *v0 = ts3init_ROTL(*v0, 32); 47 | *v2 += *v3; 48 | *v3 = ts3init_ROTL(*v3, 16); 49 | *v3 ^= *v2; 50 | *v0 += *v3; 51 | *v3 = ts3init_ROTL(*v3, 21); 52 | *v3 ^= *v0; 53 | *v2 += *v1; 54 | *v1 = ts3init_ROTL(*v1, 17); 55 | *v1 ^= *v2; 56 | *v2 = ts3init_ROTL(*v2, 32); 57 | } 58 | 59 | 60 | static inline void ts3init_TRACE(u64 v0, u64 v1, u64 v2, u64 v3, size_t inlen) 61 | { 62 | #ifdef DEBUG 63 | printk("(%d) v0 %x %x\n", (int)inlen, (u32)(v0 >> 32), (u32)v0); 64 | printk("(%d) v1 %x %x\n", (int)inlen, (u32)(v1 >> 32), (u32)v1); 65 | printk("(%d) v2 %x %x\n", (int)inlen, (u32)(v2 >> 32), (u32)v2); 66 | printk("(%d) v3 %x %x\n", (int)inlen, (u32)(v3 >> 32), (u32)v3); 67 | #endif 68 | } 69 | 70 | void ts3init_siphash_setup(struct ts3init_siphash_state* state, u64 k0, u64 k1) 71 | { 72 | /* "somepseudorandomlygeneratedbytes" */ 73 | state->v0 = 0x736f6d6570736575ULL; 74 | state->v1 = 0x646f72616e646f6dULL; 75 | state->v2 = 0x6c7967656e657261ULL; 76 | state->v3 = 0x7465646279746573ULL; 77 | state->len= 0; 78 | k0 = le64_to_cpu(k0); 79 | k1 = le64_to_cpu(k1); 80 | state->v3 ^= k1; 81 | state->v2 ^= k0; 82 | state->v1 ^= k1; 83 | state->v0 ^= k0; 84 | } 85 | 86 | void ts3init_siphash_update(struct ts3init_siphash_state* state, const u8 *in, size_t inlen) 87 | { 88 | size_t next_byte = state->len % 8; 89 | size_t left; 90 | const u8* end = in + inlen; 91 | int i; 92 | u64 m, v0, v1, v2, v3; 93 | 94 | state->len += inlen; 95 | m = state->m; 96 | v0 = state->v0; 97 | v1 = state->v1; 98 | v2 = state->v2; 99 | v3 = state->v3; 100 | 101 | switch (next_byte) 102 | { 103 | case 1: 104 | if (in==end) goto __exit_update; 105 | m |= ((u64)(*in++)) << 8; 106 | case 2: 107 | if (in==end) goto __exit_update; 108 | m |= ((u64)(*in++)) << 16; 109 | case 3: 110 | if (in==end) goto __exit_update; 111 | m |= ((u64)(*in++)) << 24; 112 | case 4: 113 | if (in==end) goto __exit_update; 114 | m |= ((u64)(*in++)) << 32; 115 | case 5: 116 | if (in==end) goto __exit_update; 117 | m |= ((u64)(*in++)) << 40; 118 | case 6: 119 | if (in==end) goto __exit_update; 120 | m |= ((u64)(*in++)) << 48; 121 | case 7: 122 | if (in==end) goto __exit_update; 123 | m |= ((u64)(*in++)) << 56; 124 | 125 | v3 ^= m; 126 | 127 | ts3init_TRACE(v0, v1, v2, v3, inlen); 128 | for (i = 0; i < ts3init_cROUNDS; ++i) 129 | ts3init_SIPROUND(&v0, &v1, &v2, &v3); 130 | 131 | v0 ^= m; 132 | case 0: 133 | break; 134 | } 135 | 136 | left = (end-in) % 8; 137 | end -= left; 138 | 139 | for (; in != end; in += 8) 140 | { 141 | m = ts3init_U8TO64_LE(in); 142 | v3 ^= m; 143 | 144 | ts3init_TRACE(v0, v1, v2, v3, inlen); 145 | for (i = 0; i < ts3init_cROUNDS; ++i) 146 | ts3init_SIPROUND(&v0, &v1, &v2, &v3); 147 | 148 | v0 ^= m; 149 | } 150 | 151 | m=0; 152 | switch(left) 153 | { 154 | case 7: 155 | m |= ((u64)(in[6])) << 48; 156 | case 6: 157 | m |= ((u64)(in[5])) << 40; 158 | case 5: 159 | m |= ((u64)(in[4])) << 32; 160 | case 4: 161 | m |= ((u64)(in[3])) << 24; 162 | case 3: 163 | m |= ((u64)(in[2])) << 16; 164 | case 2: 165 | m |= ((u64)(in[1])) << 8; 166 | case 1: 167 | m |= ((u64)(in[0])); 168 | case 0: 169 | break; 170 | } 171 | 172 | __exit_update: 173 | state->m = m; 174 | state->v0 = v0; 175 | state->v1 = v1; 176 | state->v2 = v2; 177 | state->v3 = v3; 178 | } 179 | 180 | u64 ts3init_siphash_finalize(struct ts3init_siphash_state* state) 181 | { 182 | u64 b = state->len << 56; 183 | u64 v0, v1, v2, v3; 184 | int i; 185 | 186 | b |= state->m; 187 | 188 | 189 | v0 = state->v0; 190 | v1 = state->v1; 191 | v2 = state->v2; 192 | v3 = state->v3; 193 | 194 | v3 ^= b; 195 | 196 | ts3init_TRACE(v0, v1, v2, v3, state->len); 197 | for (i = 0; i < ts3init_cROUNDS; ++i) 198 | ts3init_SIPROUND(&v0, &v1, &v2, &v3); 199 | 200 | v0 ^= b; 201 | v2 ^= 0xff; 202 | 203 | ts3init_TRACE(v0, v1, v2, v3, state->len); 204 | for (i = 0; i < ts3init_dROUNDS; ++i) 205 | ts3init_SIPROUND(&v0, &v1, &v2, &v3); 206 | 207 | b = v0 ^ v1 ^ v2 ^ v3; 208 | return cpu_to_le64(b); 209 | } 210 | -------------------------------------------------------------------------------- /test/siphash24_ref.c: -------------------------------------------------------------------------------- 1 | /* 2 | SipHash reference C implementation 3 | 4 | Copyright (c) 2012-2014 Jean-Philippe Aumasson 5 | 6 | Copyright (c) 2012-2014 Daniel J. Bernstein 7 | 8 | To the extent possible under law, the author(s) have dedicated all copyright 9 | and related and neighboring rights to this software to the public domain 10 | worldwide. This software is distributed without any warranty. 11 | 12 | You should have received a copy of the CC0 Public Domain Dedication along 13 | with 14 | this software. If not, see 15 | . 16 | */ 17 | #include 18 | #include 19 | #include 20 | 21 | /* default: SipHash-2-4 */ 22 | #define cROUNDS 2 23 | #define dROUNDS 4 24 | 25 | #define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) 26 | 27 | #define U32TO8_LE(p, v) \ 28 | (p)[0] = (uint8_t)((v)); \ 29 | (p)[1] = (uint8_t)((v) >> 8); \ 30 | (p)[2] = (uint8_t)((v) >> 16); \ 31 | (p)[3] = (uint8_t)((v) >> 24); 32 | 33 | #define U64TO8_LE(p, v) \ 34 | U32TO8_LE((p), (uint32_t)((v))); \ 35 | U32TO8_LE((p) + 4, (uint32_t)((v) >> 32)); 36 | 37 | #define U8TO64_LE(p) \ 38 | (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \ 39 | ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \ 40 | ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \ 41 | ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) 42 | 43 | #define SIPROUND \ 44 | do { \ 45 | v0 += v1; \ 46 | v1 = ROTL(v1, 13); \ 47 | v1 ^= v0; \ 48 | v0 = ROTL(v0, 32); \ 49 | v2 += v3; \ 50 | v3 = ROTL(v3, 16); \ 51 | v3 ^= v2; \ 52 | v0 += v3; \ 53 | v3 = ROTL(v3, 21); \ 54 | v3 ^= v0; \ 55 | v2 += v1; \ 56 | v1 = ROTL(v1, 17); \ 57 | v1 ^= v2; \ 58 | v2 = ROTL(v2, 32); \ 59 | } while (0) 60 | 61 | #ifdef DEBUG 62 | #define TRACE \ 63 | do { \ 64 | printf("(%3d) v0 %08x %08x\n", (int)inlen, (uint32_t)(v0 >> 32), \ 65 | (uint32_t)v0); \ 66 | printf("(%3d) v1 %08x %08x\n", (int)inlen, (uint32_t)(v1 >> 32), \ 67 | (uint32_t)v1); \ 68 | printf("(%3d) v2 %08x %08x\n", (int)inlen, (uint32_t)(v2 >> 32), \ 69 | (uint32_t)v2); \ 70 | printf("(%3d) v3 %08x %08x\n", (int)inlen, (uint32_t)(v3 >> 32), \ 71 | (uint32_t)v3); \ 72 | } while (0) 73 | #else 74 | #define TRACE 75 | #endif 76 | 77 | int siphash(uint8_t *out, const uint8_t *in, uint64_t inlen, const uint8_t *k) { 78 | /* "somepseudorandomlygeneratedbytes" */ 79 | uint64_t v0 = 0x736f6d6570736575ULL; 80 | uint64_t v1 = 0x646f72616e646f6dULL; 81 | uint64_t v2 = 0x6c7967656e657261ULL; 82 | uint64_t v3 = 0x7465646279746573ULL; 83 | uint64_t b; 84 | uint64_t k0 = U8TO64_LE(k); 85 | uint64_t k1 = U8TO64_LE(k + 8); 86 | uint64_t m; 87 | int i; 88 | const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t)); 89 | const int left = inlen & 7; 90 | b = ((uint64_t)inlen) << 56; 91 | v3 ^= k1; 92 | v2 ^= k0; 93 | v1 ^= k1; 94 | v0 ^= k0; 95 | 96 | #ifdef DOUBLE 97 | v1 ^= 0xee; 98 | #endif 99 | 100 | for (; in != end; in += 8) { 101 | m = U8TO64_LE(in); 102 | v3 ^= m; 103 | 104 | TRACE; 105 | for (i = 0; i < cROUNDS; ++i) 106 | SIPROUND; 107 | 108 | v0 ^= m; 109 | } 110 | 111 | switch (left) { 112 | case 7: 113 | b |= ((uint64_t)in[6]) << 48; 114 | case 6: 115 | b |= ((uint64_t)in[5]) << 40; 116 | case 5: 117 | b |= ((uint64_t)in[4]) << 32; 118 | case 4: 119 | b |= ((uint64_t)in[3]) << 24; 120 | case 3: 121 | b |= ((uint64_t)in[2]) << 16; 122 | case 2: 123 | b |= ((uint64_t)in[1]) << 8; 124 | case 1: 125 | b |= ((uint64_t)in[0]); 126 | break; 127 | case 0: 128 | break; 129 | } 130 | 131 | v3 ^= b; 132 | 133 | TRACE; 134 | for (i = 0; i < cROUNDS; ++i) 135 | SIPROUND; 136 | 137 | v0 ^= b; 138 | 139 | #ifndef DOUBLE 140 | v2 ^= 0xff; 141 | #else 142 | v2 ^= 0xee; 143 | #endif 144 | 145 | TRACE; 146 | for (i = 0; i < dROUNDS; ++i) 147 | SIPROUND; 148 | 149 | b = v0 ^ v1 ^ v2 ^ v3; 150 | U64TO8_LE(out, b); 151 | 152 | #ifdef DOUBLE 153 | v1 ^= 0xdd; 154 | 155 | TRACE; 156 | for (i = 0; i < dROUNDS; ++i) 157 | SIPROUND; 158 | 159 | b = v0 ^ v1 ^ v2 ^ v3; 160 | U64TO8_LE(out + 8, b); 161 | #endif 162 | 163 | return 0; 164 | } 165 | 166 | -------------------------------------------------------------------------------- /src/libxt_TS3INIT_SET_COOKIE.c: -------------------------------------------------------------------------------- 1 | /* 2 | * "ts3init_set_cookie" target extension for iptables 3 | * Niels Werensteijn , 2016-10-03 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License; either version 2 7 | * or 3 of the License, as published by the Free Software Foundation. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "ts3init_random_seed.h" 21 | #include "ts3init_target.h" 22 | 23 | #define param_act(t, s, f) xtables_param_act((t), "TS3INIT_SET_COOKIE", (s), (f)) 24 | 25 | static void ts3init_set_cookie_tg_help(void) 26 | { 27 | printf( 28 | "TS3INIT_SET_COOKIE target options:\n" 29 | " --zero-random-sequence Always return 0 as random sequence.\n" 30 | " --random-seed Seed is a %i byte hex number in.\n" 31 | " A source could be /dev/random.\n" 32 | " --random-seed-file Read the seed from a file.\n", 33 | RANDOM_SEED_LEN); 34 | } 35 | 36 | static const struct option ts3init_set_cookie_tg_opts[] = { 37 | {.name = "zero-random-sequence", .has_arg = false, .val = '1'}, 38 | {.name = "random-seed", .has_arg = true, .val = '2'}, 39 | {.name = "random-seed-file", .has_arg = true, .val = '3'}, 40 | {NULL}, 41 | }; 42 | 43 | static int ts3init_set_cookie_tg_parse(int c, char **argv, 44 | int invert, unsigned int *flags, const void *entry, 45 | struct xt_entry_target **target) 46 | { 47 | struct xt_ts3init_set_cookie_tginfo *info = (void *)(*target)->data; 48 | switch (c) { 49 | case '1': 50 | param_act(XTF_ONLY_ONCE, "--zero-random-sequence", info->specific_options & TARGET_SET_COOKIE_ZERO_RANDOM_SEQUENCE); 51 | param_act(XTF_NO_INVERT, "--zero-random-sequence", invert); 52 | info->specific_options |= TARGET_SET_COOKIE_ZERO_RANDOM_SEQUENCE; 53 | return true; 54 | case '2': 55 | param_act(XTF_ONLY_ONCE, "--random-seed", *flags & TARGET_SET_COOKIE_RANDOM_SEED_FROM_ARGUMENT); 56 | param_act(XTF_NO_INVERT, "--random-seed", invert); 57 | if (strlen(optarg) != (RANDOM_SEED_LEN * 2)) 58 | xtables_error(PARAMETER_PROBLEM, 59 | "TS3INIT_SET_COOKIE: invalid random seed length"); 60 | if (!parse_random_seed(optarg, info->random_seed)) 61 | xtables_error(PARAMETER_PROBLEM, 62 | "TS3INIT_SET_COOKIE: invalid random seed. (not lowercase hex)"); 63 | info->specific_options |= TARGET_SET_COOKIE_RANDOM_SEED_FROM_ARGUMENT; 64 | *flags |= TARGET_SET_COOKIE_RANDOM_SEED_FROM_ARGUMENT; 65 | return true; 66 | 67 | case '3': 68 | param_act(XTF_ONLY_ONCE, "--random-seed-file", *flags & TARGET_SET_COOKIE_RANDOM_SEED_FROM_FILE); 69 | param_act(XTF_NO_INVERT, "--random-seed-file", invert); 70 | 71 | if (read_random_seed_from_file("TS3INIT_SET_COOKIE", optarg, info->random_seed)) 72 | memcpy(info->random_seed_path, optarg, strlen(optarg) + 1); 73 | info->specific_options |= TARGET_SET_COOKIE_RANDOM_SEED_FROM_FILE; 74 | *flags |= TARGET_SET_COOKIE_RANDOM_SEED_FROM_FILE; 75 | return true; 76 | 77 | default: 78 | return false; 79 | } 80 | } 81 | 82 | static void ts3init_set_cookie_tg_save(const void *ip, const struct xt_entry_target *target) 83 | { 84 | int i; 85 | const struct xt_ts3init_set_cookie_tginfo *info = (const void *)target->data; 86 | if (info->specific_options & TARGET_SET_COOKIE_ZERO_RANDOM_SEQUENCE) 87 | { 88 | printf(" --zero-random-sequence"); 89 | } 90 | if (info->specific_options & TARGET_SET_COOKIE_RANDOM_SEED_FROM_ARGUMENT) 91 | { 92 | printf(" --random-seed "); 93 | for (i = 0; i < RANDOM_SEED_LEN; i++) 94 | { 95 | printf("%02X", info->random_seed[i]); 96 | } 97 | } 98 | if (info->specific_options & TARGET_SET_COOKIE_RANDOM_SEED_FROM_FILE) 99 | { 100 | printf(" --random-seed-file \"%s\"", info->random_seed_path); 101 | } 102 | } 103 | 104 | static void ts3init_set_cookie_tg_print(const void *ip, const struct xt_entry_target *target, 105 | int numeric) 106 | { 107 | printf(" -j TS3INIT_SET_COOKIE"); 108 | ts3init_set_cookie_tg_save(ip, target); 109 | } 110 | 111 | static void ts3init_set_cookie_tg_check(unsigned int flags) 112 | { 113 | bool random_seed_from_argument = flags & TARGET_SET_COOKIE_RANDOM_SEED_FROM_ARGUMENT; 114 | bool random_seed_from_file = flags & TARGET_SET_COOKIE_RANDOM_SEED_FROM_FILE; 115 | if (random_seed_from_argument && random_seed_from_file) 116 | { 117 | xtables_error(PARAMETER_PROBLEM, 118 | "TS3INIT_SET_COOKIE: --random-seed and --random-seed-file " 119 | "can not be specified at the same time"); 120 | } 121 | if (!random_seed_from_argument && !random_seed_from_file) 122 | { 123 | xtables_error(PARAMETER_PROBLEM, 124 | "TS3INIT_SET_COOKIE: either --random-seed or --random-seed-file " 125 | "must be specified"); 126 | } 127 | } 128 | 129 | /* register and init */ 130 | static struct xtables_target ts3init_set_cookie_tg_reg = 131 | { 132 | .name = "TS3INIT_SET_COOKIE", 133 | .revision = 0, 134 | .family = NFPROTO_UNSPEC, 135 | .version = XTABLES_VERSION, 136 | .size = XT_ALIGN(sizeof(struct xt_ts3init_set_cookie_tginfo)), 137 | .userspacesize = XT_ALIGN(sizeof(struct xt_ts3init_set_cookie_tginfo)), 138 | .help = ts3init_set_cookie_tg_help, 139 | .parse = ts3init_set_cookie_tg_parse, 140 | .print = ts3init_set_cookie_tg_print, 141 | .save = ts3init_set_cookie_tg_save, 142 | .final_check = ts3init_set_cookie_tg_check, 143 | .extra_opts = ts3init_set_cookie_tg_opts, 144 | }; 145 | 146 | static __attribute__((constructor)) void ts3init_set_cookie_tg_ldr(void) 147 | { 148 | xtables_register_target(&ts3init_set_cookie_tg_reg); 149 | } 150 | -------------------------------------------------------------------------------- /examples/complex-forward/create-fw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #This example is meant as en example of using this module on a seperate 4 | #machine. That is, the ts3server is on a different machine 5 | #The traffic will be split up into "unknown" / authorizing / authorized 6 | #We use packets from the ts3 server for extra state info 7 | #We also limit the concurrent connection to file transfer tcp port to 20/ip 8 | 9 | sudo modprobe xt_ts3init 10 | 11 | if [ "$1" == "4" ] 12 | then 13 | IPTABLES=iptables 14 | IPFAMILY=inet 15 | FRAGMENT_FLAG="! -f " 16 | elif [ "$1" == "6" ] 17 | then 18 | IPTABLES=ip6tables 19 | IPFAMILY=inet6 20 | FRAGMENT_FLAG="" 21 | else 22 | echo "specify either 4 or 6 as a parameter for ipv4 or ipv6"; 23 | exit -1 24 | fi 25 | 26 | if [ "$2" == "" ] 27 | then 28 | echo "need the interface name where client packets will enter as 2nd parameter" 29 | exit -1 30 | fi 31 | CLIENT_SIDE_IF=$2 32 | 33 | if [ "$3" == "" ] 34 | then 35 | echo "need the interface name where server is located as 3rd parameter" 36 | exit -1 37 | fi 38 | SERVER_SIDE_IF=$3 39 | 40 | #create an autorized ts3 client ip set. 41 | #perhaps create the set with more than the default 1024 entries 42 | sudo ipset create ts3_authorizing${1} hash:ip,port family ${IPFAMILY} timeout 8 || { echo "ipset not installed or there is a problem with it (1)"; exit -1; } 43 | sudo ipset create ts3_authorized${1} hash:ip,port family ${IPFAMILY} timeout 30 || { echo "ipset not installed or there is a problem with it (2)"; exit -1; } 44 | sudo ipset create ts3_authorized_ft${1} hash:ip family ${IPFAMILY} timeout 30 || { echo "ipset not installed or there is a problem with it (3)"; exit -1; } 45 | 46 | #create new chains that handles ts3 47 | sudo ${IPTABLES} -N TS3_UDP_TRAFFIC 48 | sudo ${IPTABLES} -N TS3_UDP_TRAFFIC_AUTHORIZING 49 | sudo ${IPTABLES} -N TS3_UDP_TRAFFIC_AUTHORIZED 50 | sudo ${IPTABLES} -N TS3_TCP_TRAFFIC 51 | sudo ${IPTABLES} -N TS3_ACCEPT_AUTHORIZING 52 | sudo ${IPTABLES} -N OUT_TS3 53 | sudo ${IPTABLES} -N OUT_TS3_AUTHORIZING 54 | sudo ${IPTABLES} -N OUT_TS3_AUTHORIZED 55 | sudo ${IPTABLES} -N OUT_TS3_ACCEPT_AUTHORIZED 56 | 57 | 58 | RANDOM_FILE_NAME=random.data 59 | if [ ! -f "${RANDOM_FILE_NAME}" ] 60 | then 61 | xxd -l 60 -c 60 -p /dev/urandom > "${RANDOM_FILE_NAME}" || { echo "could not use xxd to create random data"; exit -1; } 62 | fi 63 | 64 | RANDOM_FILE=`pwd`/${RANDOM_FILE_NAME} 65 | 66 | #disable connection tracking for ts3 client->server 67 | sudo ${IPTABLES} -t raw -A PREROUTING -i $CLIENT_SIDE_IF -p udp --dport 9987 -j CT --notrack 68 | 69 | #disable connection tracking for ts3 server->client 70 | sudo ${IPTABLES} -t raw -A PREROUTING -i $SERVER_SIDE_IF -p udp --sport 9987 -j CT --notrack 71 | 72 | #move ts3 traffic to TS3_UDP_TRAFFIC chain (do not allow fragments) 73 | sudo ${IPTABLES} -A FORWARD -i $CLIENT_SIDE_IF -p udp --dport 9987 ${FRAGMENT_FLAG} -j TS3_UDP_TRAFFIC 74 | 75 | #move filetransfer to TS3_TCP_TRAFFIC chain 76 | sudo ${IPTABLES} -A FORWARD -i $CLIENT_SIDE_IF -p tcp --dport 30033 -j TS3_TCP_TRAFFIC 77 | 78 | #move authorized clients to TS3_UDP_TRAFFIC_AUTHORIZED chain 79 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC -m set --match-set ts3_authorized${1} src,src -j TS3_UDP_TRAFFIC_AUTHORIZED 80 | 81 | #move authorizing clients to TS3_UDP_TRAFFIC_AUTHORIZING chain 82 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC -m set --match-set ts3_authorizing${1} src,src -j TS3_UDP_TRAFFIC_AUTHORIZING 83 | 84 | #Allow 3.0.19 and up clients. If its get cookie, send back a cookie 85 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC -p udp -m ts3init_get_cookie --min-client 1459504131 -j TS3INIT_SET_COOKIE --random-seed-file ${RANDOM_FILE} 86 | 87 | #add new connection if cookie is valid 88 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC -p udp -m ts3init_get_puzzle --check-cookie --random-seed-file ${RANDOM_FILE} -j TS3_ACCEPT_AUTHORIZING 89 | 90 | #drop the rest 91 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC -j DROP 92 | 93 | #accept autorized/authorizing. Here is the time to rate limit per ip for autorized (connected) streams 94 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC_AUTHORIZED -j ACCEPT 95 | 96 | #accept autorized/authorizing. Here is the time to rate limit per ip for authorizing (ip checked, but not connected) 97 | sudo ${IPTABLES} -A TS3_UDP_TRAFFIC_AUTHORIZING -j ACCEPT 98 | 99 | #add new connection to authorizing src, and send the ts3 server a get cookie request 100 | sudo ${IPTABLES} -A TS3_ACCEPT_AUTHORIZING -j SET --add-set ts3_authorizing${1} src,src 101 | sudo ${IPTABLES} -A TS3_ACCEPT_AUTHORIZING -p udp -j TS3INIT_GET_COOKIE 102 | 103 | #Allow authorized clients on TCP only 104 | sudo ${IPTABLES} -A TS3_TCP_TRAFFIC -m set ! --match-set ts3_authorized_ft${1} src,src -j DROP 105 | 106 | #only allow 20 connections 107 | sudo ${IPTABLES} -A TS3_TCP_TRAFFIC -p tcp --syn -m connlimit --connlimit-above 20 -j REJECT --reject-with tcp-reset 108 | 109 | #accept 110 | sudo ${IPTABLES} -A TS3_TCP_TRAFFIC -j ACCEPT 111 | 112 | #watch server->client traffic 113 | sudo ${IPTABLES} -A FORWARD -i $SERVER_SIDE_IF -p udp --sport 9987 ${FRAGMENT_FLAG} -j OUT_TS3 114 | 115 | #Move clients in the authorized phase to the OUT_TS3_AUTHORIZED chain. 116 | sudo ${IPTABLES} -A OUT_TS3 -m set --match-set ts3_authorized${1} dst,dst -j OUT_TS3_AUTHORIZED 117 | #Move clients in the authorizing phase to the OUT_TS3_AUTHORIZING chain. 118 | sudo ${IPTABLES} -A OUT_TS3 -m set --match-set ts3_authorizing${1} dst,dst -j OUT_TS3_AUTHORIZING 119 | #These are packets from TS3INIT_SET_COOKIE 120 | sudo ${IPTABLES} -A OUT_TS3 -j ACCEPT 121 | 122 | #Is this still ts3init (not fully connected) 123 | sudo ${IPTABLES} -A OUT_TS3_AUTHORIZING -p udp -m ts3init --server -j ACCEPT 124 | #else this connection is accepeted(authorized) now. 125 | #Note that this is not really true. This only means the server accepted the client puzzle. 126 | #The conection request could still be rejected, because of a wrong password or other reasons. 127 | sudo ${IPTABLES} -A OUT_TS3_AUTHORIZING -j OUT_TS3_ACCEPT_AUTHORIZED 128 | 129 | #update/add timeout in set and allow traffic 130 | sudo ${IPTABLES} -A OUT_TS3_AUTHORIZED -j SET --add-set ts3_authorized${1} dst,dst --exist 131 | sudo ${IPTABLES} -A OUT_TS3_AUTHORIZED -j SET --add-set ts3_authorized_ft${1} dst --exist 132 | sudo ${IPTABLES} -A OUT_TS3_AUTHORIZED -j ACCEPT 133 | 134 | #accept connection as authorized. Remove from authorizing and treat as accepted 135 | sudo ${IPTABLES} -A OUT_TS3_ACCEPT_AUTHORIZED -j SET --del-set ts3_authorizing${1} dst,dst 136 | sudo ${IPTABLES} -A OUT_TS3_ACCEPT_AUTHORIZED -j OUT_TS3_AUTHORIZED 137 | -------------------------------------------------------------------------------- /src/libxt_ts3init_get_puzzle.c: -------------------------------------------------------------------------------- 1 | /* 2 | * "ts3init_get_cookie and ts3init_get_puzzle" match extension for iptables 3 | * Niels Werensteijn , 2016-10-03 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License; either version 2 7 | * or 3 of the License, as published by the Free Software Foundation. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "ts3init_random_seed.h" 21 | #include "ts3init_match.h" 22 | 23 | #define param_act(t, s, f) xtables_param_act((t), "ts3init_get_puzzle", (s), (f)) 24 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) 25 | 26 | static void ts3init_get_puzzle_help(void) 27 | { 28 | printf( 29 | "ts3init_get_puzzle match options:\n" 30 | " --min-client n The client needs to be at least version n.\n" 31 | " --check-cookie Check that the cookie was generated by same seed.\n" 32 | " --random-seed Seed is a %i byte hex number.\n" 33 | " A source could be /dev/random.\n" 34 | " --random-seed-file Read the seed from a file.\n", 35 | RANDOM_SEED_LEN 36 | ); 37 | } 38 | 39 | static const struct option ts3init_get_puzzle_opts[] = { 40 | {.name = "min-client", .has_arg = true, .val = '1'}, 41 | {.name = "check-cookie", .has_arg = false, .val = '2'}, 42 | {.name = "random-seed", .has_arg = true, .val = '3'}, 43 | {.name = "random-seed-file", .has_arg = true, .val = '4'}, 44 | {NULL}, 45 | }; 46 | 47 | static int ts3init_get_puzzle_parse(int c, char **argv, int invert, unsigned int *flags, 48 | const void *entry, struct xt_entry_match **match) 49 | { 50 | struct xt_ts3init_get_puzzle_mtinfo *info = (void *)(*match)->data; 51 | int client_version; 52 | 53 | switch (c) { 54 | case '1': 55 | param_act(XTF_ONLY_ONCE, "--min-client", info->common_options & CHK_COMMON_CLIENT_VERSION); 56 | param_act(XTF_NO_INVERT, "--min-client", invert); 57 | client_version = atoi(optarg); 58 | if (client_version <= 0) 59 | xtables_error(PARAMETER_PROBLEM, 60 | "ts3init_get_cookie: invalid min-client version"); 61 | info->common_options |= CHK_COMMON_CLIENT_VERSION; 62 | info->min_client_version = client_version - CLIENT_VERSION_OFFSET; 63 | return true; 64 | 65 | case '2': 66 | param_act(XTF_ONLY_ONCE, "--check-cookie", info->specific_options & CHK_GET_PUZZLE_CHECK_COOKIE); 67 | param_act(XTF_NO_INVERT, "--check-cookie", invert); 68 | info->specific_options |= CHK_GET_PUZZLE_CHECK_COOKIE; 69 | *flags |= CHK_GET_PUZZLE_CHECK_COOKIE; 70 | return true; 71 | 72 | case '3': 73 | param_act(XTF_ONLY_ONCE, "--random-seed", info->specific_options & CHK_GET_PUZZLE_RANDOM_SEED_FROM_ARGUMENT); 74 | param_act(XTF_NO_INVERT, "--random-seed", invert); 75 | if (strlen(optarg) != (RANDOM_SEED_LEN * 2)) 76 | xtables_error(PARAMETER_PROBLEM, 77 | "ts3init_get_puzzle: invalid random seed length"); 78 | if (!parse_random_seed(optarg, info->random_seed)) 79 | xtables_error(PARAMETER_PROBLEM, 80 | "ts3init_get_puzzle: invalid random seed. (not lowercase hex)"); 81 | info->specific_options |= CHK_GET_PUZZLE_RANDOM_SEED_FROM_ARGUMENT; 82 | *flags |= CHK_GET_PUZZLE_RANDOM_SEED_FROM_ARGUMENT; 83 | return true; 84 | 85 | case '4': 86 | param_act(XTF_ONLY_ONCE, "--random-seed-file", info->specific_options & CHK_GET_PUZZLE_RANDOM_SEED_FROM_FILE); 87 | param_act(XTF_NO_INVERT, "--random-seed-file", invert); 88 | 89 | if (read_random_seed_from_file("ts3init_get_puzzle", optarg, info->random_seed)) 90 | memcpy(info->random_seed_path, optarg, strlen(optarg) + 1); 91 | info->specific_options |= CHK_GET_PUZZLE_RANDOM_SEED_FROM_FILE; 92 | *flags |= CHK_GET_PUZZLE_RANDOM_SEED_FROM_FILE; 93 | return true; 94 | 95 | default: 96 | return false; 97 | } 98 | } 99 | 100 | static void ts3init_get_puzzle_save(const void *ip, const struct xt_entry_match *match) 101 | { 102 | int i; 103 | const struct xt_ts3init_get_puzzle_mtinfo *info = (const void *)match->data; 104 | if (info->common_options & CHK_COMMON_CLIENT_VERSION) 105 | { 106 | printf(" --min-client %u", info->min_client_version + CLIENT_VERSION_OFFSET); 107 | } 108 | if (info->specific_options & CHK_GET_PUZZLE_CHECK_COOKIE) 109 | { 110 | printf(" --check-cookie"); 111 | } 112 | if (info->specific_options & CHK_GET_PUZZLE_RANDOM_SEED_FROM_ARGUMENT) 113 | { 114 | printf(" --random-seed "); 115 | for (i = 0; i < RANDOM_SEED_LEN; i++) 116 | { 117 | printf("%02X", info->random_seed[i]); 118 | } 119 | } 120 | if (info->specific_options & CHK_GET_PUZZLE_RANDOM_SEED_FROM_FILE) 121 | { 122 | printf(" --random-seed-file \"%s\"", info->random_seed_path); 123 | } 124 | } 125 | 126 | static void ts3init_get_puzzle_print(const void *ip, const struct xt_entry_match *match, 127 | int numeric) 128 | { 129 | printf(" -m ts3init_get_puzzle"); 130 | ts3init_get_puzzle_save(ip, match); 131 | } 132 | 133 | static void ts3init_get_puzzle_check(unsigned int flags) 134 | { 135 | bool seed_from_argument = flags & CHK_GET_PUZZLE_RANDOM_SEED_FROM_ARGUMENT; 136 | bool seed_from_file = flags & CHK_GET_PUZZLE_RANDOM_SEED_FROM_FILE; 137 | if (seed_from_argument && seed_from_file) 138 | { 139 | xtables_error(PARAMETER_PROBLEM, 140 | "ts3init_get_puzzle: --random-seed and --random-seed-file " 141 | "can not be specified at the same time"); 142 | } 143 | if (flags & CHK_GET_PUZZLE_CHECK_COOKIE) 144 | { 145 | if (!seed_from_argument && !seed_from_file) 146 | { 147 | xtables_error(PARAMETER_PROBLEM, 148 | "ts3init_get_puzzle: --check-cookie requires either " 149 | "--random-seed or --random-seed-file"); 150 | } 151 | } 152 | } 153 | 154 | /* register and init */ 155 | static struct xtables_match ts3init_mt_reg[] = 156 | { 157 | { 158 | .name = "ts3init_get_puzzle", 159 | .revision = 0, 160 | .family = NFPROTO_IPV4, 161 | .version = XTABLES_VERSION, 162 | .size = XT_ALIGN(sizeof(struct xt_ts3init_get_puzzle_mtinfo)), 163 | .userspacesize = XT_ALIGN(sizeof(struct xt_ts3init_get_puzzle_mtinfo)), 164 | .help = ts3init_get_puzzle_help, 165 | .parse = ts3init_get_puzzle_parse, 166 | .print = ts3init_get_puzzle_print, 167 | .save = ts3init_get_puzzle_save, 168 | .extra_opts = ts3init_get_puzzle_opts, 169 | .final_check = ts3init_get_puzzle_check, 170 | }, 171 | { 172 | .name = "ts3init_get_puzzle", 173 | .revision = 0, 174 | .family = NFPROTO_IPV6, 175 | .version = XTABLES_VERSION, 176 | .size = XT_ALIGN(sizeof(struct xt_ts3init_get_puzzle_mtinfo)), 177 | .userspacesize = XT_ALIGN(sizeof(struct xt_ts3init_get_puzzle_mtinfo)), 178 | .help = ts3init_get_puzzle_help, 179 | .parse = ts3init_get_puzzle_parse, 180 | .print = ts3init_get_puzzle_print, 181 | .save = ts3init_get_puzzle_save, 182 | .extra_opts = ts3init_get_puzzle_opts, 183 | .final_check = ts3init_get_puzzle_check, 184 | } 185 | }; 186 | 187 | static __attribute__((constructor)) void ts3init_mt_ldr(void) 188 | { 189 | xtables_register_matches(ts3init_mt_reg, ARRAY_SIZE(ts3init_mt_reg)); 190 | } 191 | 192 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ts3init Linux netfilter module 2 | ============================== 3 | A Linux netfilter module to help filter ts3init floods on TeamSpeak 3 servers 4 | 5 | TeamSpeak 3 servers are a popular (D)Dos target. They are harder to protect than 6 | other servers because the TeamSpeak 3 protocol is based on UDP. A popular 7 | method, which is hard to mitigate by hosters is called *init floods*. This is 8 | where the attacker sends many connection request to the server, usually spoofing 9 | the source address, to make it harder to block them. The TeamSpeak 3 protocol 10 | has an anti spoof check as the first stage of the connection, but the server 11 | program can not keep up with the flood of packets. 12 | 13 | This set of plugins is designed to let the Linux kernel, or rather netfilter, 14 | handle the anti spoofing stages of a new TeamSpeak 3 connection. This could be 15 | done on a different machine than the one the TeamSpeak 3 server is executing 16 | on. 17 | 18 | Current version 19 | =============== 20 | The current release is version 0.1. This version is a beta and has by no means 21 | been tested in a production environment. At this stage this software is merely 22 | a proof of concept. We invite the TeamSpeak community and of course the Linux 23 | community to test this tool and to contribute improvements and new ideas. 24 | 25 | prerequisites 26 | ============= 27 | In order to compile and install this software you need the following things: 28 | * Linux kernel headers (version 2.6.35 or greater) 29 | * Iptables development headers 30 | * GCC (version 4.6.0 or greater) 31 | 32 | Usually these can be installed using your package manager (yum/apt-get/etc). 33 | Usually these packages resemble the names "Linux-header-<..>", "iptables-dev", 34 | "GCC" 35 | 36 | How to install 37 | ============== 38 | 39 | ``` 40 | make 41 | sudo make install 42 | sudo depmod -a 43 | sudo modprobe xt_ts3init 44 | ``` 45 | 46 | Protocol background and module description 47 | ========================================== 48 | When a TeamSpeak 3 client attempts to connect to a TeamSpeak 3 server, it sends 49 | out a *get cookie* packet. The server then replies with a *set cookie* packet. 50 | This packet has some secret information about the connection details. The client 51 | then response with a *get puzzle* packet. This packet includes the cookie that 52 | it got previously. The server now validates this cookie and if it is valid, the 53 | server continues with the rest of the connection packets. 54 | 55 | This software packages comes with two netfilter match extensions, and three 56 | netfilter target extensions which we will discuss next. Combined these 57 | extensions and some other netfilter modules, can handle the initial connection 58 | phase for a TeamSpeak 3 server. This prevents any packet, with a spoofed source 59 | ip address, to reach the TeamSpeak 3 server. 60 | 61 | Match extensions 62 | ================ 63 | 64 | ts3init_get_cookie 65 | ------------------ 66 | Matches if the packet in question is a valid TeamSpeak 3 *get cookie* packet 67 | from the client. 68 | There are additional parameters that can be set: 69 | ``` 70 | $ iptables -m ts3init_get_cookie -h 71 | <..> 72 | ts3init_get_cookie match options: 73 | --min-client n The client needs to be at least version n. 74 | --check-time sec Check packet send time request. 75 | May be off by sec seconds. 76 | ``` 77 | * `min-client` checks that the client version in the packet is at least the 78 | version specified. 79 | * `check-time` compares the unix-timestamp in the client packet to the unix-time 80 | on the server. If they differ too much, the packet is not matched. 81 | 82 | ts3init_get_puzzle 83 | ------------------ 84 | Matches if the packet in question is a valid TeamSpeak 3 *get puzzle* packet 85 | from the client. 86 | There are additional parameters that can be set: 87 | ``` 88 | $ iptables -m ts3init_get_puzzle -h 89 | <..> 90 | ts3init_get_puzzle match options: 91 | --min-client n The client needs to be at least version n. 92 | --check-cookie Check that the cookie was generated by same seed. 93 | --random-seed Seed is a 60 byte hex number. 94 | A source could be /dev/random. 95 | --random-seed-file Read the seed from a file. 96 | ``` 97 | * `min-client` checks that the client version in the packet is at least the 98 | version specified. 99 | * `check-cookie` matches if it matches the cookie that was generated in the 100 | netfilter target extension `TS3INIT_SET_COOKIE`. To match the seed needs to be 101 | exactly the same. It is possible to check cookies that were generated on a 102 | different machine, provided that those machines have the same date and time, 103 | and the same seed specified. In other words: The cookie is created in a 104 | deterministic way, depending only on the current time and the seed. If 105 | `check-cookie` is specified, either `random-seed` or `random-seed-file` needs 106 | to be specified too. 107 | 108 | ts3init 109 | ------- 110 | Matches a ts3init packet, by checking if the packet starts with the *TS3INIT1*. 111 | Additional header checks for client and server packets can be specified: 112 | ``` 113 | $ iptables -m ts3init -h 114 | <..> 115 | ts3init match options: 116 | --client Match ts3init client packets. 117 | --server Match ts3init server packets. 118 | --command Match packets with the specified command. 119 | ``` 120 | * `client` checks that the packet has a valid ts3init client header 121 | * `server` checks that the packet has a valid ts3init server header 122 | * `command` checks that the packet has the specified command in its header. 123 | Requires either --client or --server. 124 | 125 | Target extensions 126 | ================= 127 | 128 | TS3INIT_GET_COOKIE 129 | ------------------ 130 | Rewrites the packet into a *get_cookie* packet and then accepts it. 131 | It is assumed that the packet is a ts3init packet of any kind, any other packet 132 | may or may not result in a valid *get_cookie* packet. Used for pre 3.1 clients, 133 | as an alternative to `TS3INIT_RESET`. It takes no parameters. 134 | 135 | TS3INIT_SET_COOKIE 136 | ------------------ 137 | Generates a *set_cookie* packet to the matched *get_cookie* packet. The orginal 138 | *get_cookie* packet is dropped. It is assumed that the orginal packet is a 139 | *get_cookie* packet, no attempt is made to check if that is true. It should 140 | always be used with `ts3init_get_puzzle` match. 141 | 142 | ``` 143 | $ iptables -j TS3INIT_SET_COOKIE -h 144 | <..> 145 | TS3INIT_SET_COOKIE target options: 146 | --zero-random-sequence Always return 0 as random sequence. 147 | --random-seed Seed is a 60 byte hex number in. 148 | A source could be /dev/random. 149 | --random-seed-file Read the seed from a file. 150 | ``` 151 | 152 | * `zero-random-sequence` forces the returned *random-sequence* to be always 153 | zero. This allows the target to not look at the payload of the packet. 154 | * `random-seed` is used to generate the cookie returned in the *set-cookie* 155 | packet. *seed* must be a 120 character long hexstring. 156 | * `random-seed-file` read the `random-seed` from a file. The file must contain 157 | a 120 character long hexstring, without any newlines. 158 | 159 | TS3INIT_RESET 160 | ------------- 161 | Drops the packet and sends a *reset* packet back to the sender. The 162 | sender should always be the TeamSpeak 3 client. Starting with the TeamSpeak 3.1 163 | client, the client will react to the reset packet by resending the *get cookie* 164 | to the server. Older clients do not handle this packet. It takes no parameters. 165 | 166 | How to use 167 | ========== 168 | The idea for which these extensions were developed was to create a few iptables 169 | rules that do the anti spoofing phase for a TeamSpeak server. This can be done 170 | as follows: 171 | * [recommended] Disable connection tracking with the help of raw table 172 | * Create ipset: ts3_authorized with a timeout of 30 seconds 173 | * If a source ip address is in the ipset ts3_authorized, renew the entry in the 174 | set to update the timeout then accept the packet. 175 | * Use `ts3init_get_cookie` matches to get connection requests and reply with 176 | `TS3INIT_SET_COOKIE`. 177 | * Use `ts3init_get_puzzle` matches to get the cookie replies from the client. 178 | If they match, add the source ip address to the ts3_authorizing ipset and then 179 | reply with `TS3INIT_RESET` 180 | * Drop all other packets 181 | 182 | It is possible to make a more detailed firewall. 183 | 184 | Example iptables setup 185 | ====================== 186 | There are two examples included: _simple_ and _complex_. Both use ipset to 187 | create a set of whitelisted ip addresses that are allowed to send packets to the 188 | TeamSpeak3 server. The simple example does the bare minimum to do the ip 189 | addresss authentication on the firewall, and to protect the file transfer (tcp) 190 | port from traffic from unverified ip addresses. 191 | 192 | The complex example is a bit more advanced. It keeps three ipsets. Authorizing 193 | authorized and authorized_ft. 194 | 195 | The autorizing set stores ip addresses and ports for connections that have 196 | verified ip addresses, but did not yet complete the puzzle phase on the ts3 197 | server. 198 | 199 | The authorized set keeps ip addresses and ports that have completed the puzzle 200 | phase on the server and are assumed to be authorized. It is technically not 201 | true that the server has accepted this connection. It could still reject it 202 | because the password is wrong, or the server is full, or other reasons. But for 203 | this example, it is good enough. 204 | 205 | The authorized_ft set keeps a list of authorized ip addresses (not ports). Only 206 | these ip addresses are allowed to send traffic to the file transfer 207 | port. Since there is no way to know in advance what source port the TeamSpeak 3 208 | client is going to use for file transfer, this is the best we can do. 209 | 210 | -------------------------------------------------------------------------------- /src/ts3init_match.c: -------------------------------------------------------------------------------- 1 | /* 2 | * "ts3init" extension for Xtables 3 | * 4 | * Description: A module to aid in ts3 spoof protection 5 | * This is the "match" code 6 | * 7 | * Authors: 8 | * Niels Werensteijn , 2016-10-03 9 | * 10 | * This program is free software; you can redistribute it and/or modify it 11 | * under the terms of the GNU General Public License; either version 2 12 | * or 3 of the License, as published by the Free Software Foundation. 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "ts3init_random_seed.h" 27 | #include "ts3init_cookie.h" 28 | #include "ts3init_match.h" 29 | #include "ts3init_header.h" 30 | #include "ts3init_cache.h" 31 | 32 | /* Magic number of a TS3INIT packet. */ 33 | static const struct ts3_init_header_tag ts3init_header_tag_signature = 34 | {{ .tag8 = {'T', 'S', '3', 'I', 'N', 'I', 'T', '1'} }}; 35 | 36 | 37 | struct ts3_init_checked_client_header_data 38 | { 39 | struct udphdr *udp, udp_buf; 40 | struct ts3_init_client_header* ts3_header, ts3_header_buf; 41 | }; 42 | 43 | struct ts3_init_checked_server_header_data 44 | { 45 | struct udphdr *udp, udp_buf; 46 | struct ts3_init_server_header* ts3_header, ts3_header_buf; 47 | }; 48 | 49 | static const int ts3init_payload_sizes[] = { 16, 20, 20, 244, -1, 1 }; 50 | 51 | /* 52 | * Check that skb contains a valid TS3INIT client header. 53 | * Also initializes header_data, and checks client version. 54 | */ 55 | static bool check_client_header(const struct sk_buff *skb, const struct xt_action_param *par, 56 | struct ts3_init_checked_client_header_data* header_data, __u32 min_client_version) 57 | { 58 | unsigned int data_len; 59 | struct udphdr *udp; 60 | struct ts3_init_client_header* ts3_header; 61 | 62 | udp = skb_header_pointer(skb, par->thoff, sizeof(*udp), &header_data->udp_buf); 63 | data_len = be16_to_cpu(udp->len) - sizeof(*udp); 64 | 65 | if (data_len < TS3INIT_HEADER_CLIENT_LENGTH) 66 | return false; 67 | 68 | ts3_header = (struct ts3_init_client_header*) skb_header_pointer(skb, 69 | par->thoff + sizeof(*udp), TS3INIT_HEADER_CLIENT_LENGTH, 70 | &header_data->ts3_header_buf); 71 | 72 | if (!ts3_header) return false; 73 | 74 | if (ts3_header->tag.tag64 != ts3init_header_tag_signature.tag64) return false; 75 | if (ts3_header->packet_id != cpu_to_be16(101)) return false; 76 | if (ts3_header->client_id != 0) return false; 77 | if (ts3_header->flags != 0x88) return false; 78 | 79 | /* check min_client_version if needed */ 80 | if (min_client_version) 81 | { 82 | /* the client version is unaligned in the packet. 83 | * load it byte for byte. big endian*/ 84 | __u8* v = ts3_header->client_version; 85 | __u32 packet_min_client_version = 86 | ((__u32)v[0]) << 24 | ((__u32)v[1]) << 16 | 87 | ((__u32)v[1]) << 8 | ((__u32)v[3]); 88 | 89 | if (packet_min_client_version < min_client_version) 90 | return false; 91 | } 92 | 93 | header_data->udp = udp; 94 | header_data->ts3_header = ts3_header; 95 | return true; 96 | } 97 | 98 | /* 99 | * Check that skb contains a valid TS3INIT server header. 100 | */ 101 | static bool check_server_header(const struct sk_buff *skb, const struct xt_action_param *par, 102 | struct ts3_init_checked_server_header_data* header_data) 103 | { 104 | unsigned int data_len; 105 | struct udphdr *udp; 106 | struct ts3_init_server_header* ts3_header; 107 | 108 | udp = skb_header_pointer(skb, par->thoff, sizeof(*udp), &header_data->udp_buf); 109 | data_len = be16_to_cpu(udp->len) - sizeof(*udp); 110 | 111 | if (data_len < TS3INIT_HEADER_SERVER_LENGTH) return false; 112 | 113 | ts3_header = (struct ts3_init_server_header*) skb_header_pointer(skb, 114 | par->thoff + sizeof(*udp), TS3INIT_HEADER_SERVER_LENGTH, 115 | &header_data->ts3_header_buf); 116 | 117 | if (!ts3_header) return false; 118 | 119 | if (ts3_header->tag.tag64 != ts3init_header_tag_signature.tag64) return false; 120 | if (ts3_header->packet_id != cpu_to_be16(101)) return false; 121 | if (ts3_header->flags != 0x88) return false; 122 | 123 | header_data->udp = udp; 124 | header_data->ts3_header = ts3_header; 125 | return true; 126 | } 127 | 128 | static inline __u8* get_payload(const struct sk_buff *skb, const struct xt_action_param *par, 129 | const struct ts3_init_checked_client_header_data* header_data, 130 | __u8 *buf, size_t buf_size) 131 | { 132 | const int header_len = sizeof(*header_data->udp) + TS3INIT_HEADER_CLIENT_LENGTH; 133 | unsigned int data_len = be16_to_cpu(header_data->udp->len) - header_len; 134 | if (data_len < buf_size) 135 | return NULL; 136 | return skb_header_pointer(skb, par->thoff + header_len, buf_size, buf); 137 | } 138 | 139 | /* 140 | * Hashes the cookie with source/destination address/port. 141 | */ 142 | static int calculate_cookie(const struct sk_buff *skb, const struct xt_action_param *par, 143 | struct udphdr *udp, __u64 k0, __u64 k1, __u64* out) 144 | { 145 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) 146 | switch (xt_family(par)) 147 | #else 148 | switch (par->family) 149 | #endif 150 | { 151 | case NFPROTO_IPV4: 152 | { 153 | const struct iphdr *ip; 154 | 155 | ip = ip_hdr(skb); 156 | if (ip == NULL) 157 | { 158 | printk(KERN_ERR KBUILD_MODNAME ": could not load ipv4 addresses\n"); 159 | return -EINVAL; 160 | } 161 | 162 | return ts3init_calculate_cookie_ipv4(ip, udp, k0, k1, out); 163 | } 164 | 165 | case NFPROTO_IPV6: 166 | { 167 | const struct ipv6hdr *ip; 168 | 169 | ip = ipv6_hdr(skb); 170 | if (ip == NULL) 171 | { 172 | printk(KERN_ERR KBUILD_MODNAME ": could not load ipv6 addresses\n"); 173 | return -EINVAL; 174 | } 175 | 176 | return ts3init_calculate_cookie_ipv6(ip, udp, k0, k1, out); 177 | } 178 | default: 179 | printk(KERN_ERR KBUILD_MODNAME ": invalid family\n"); 180 | return -EINVAL; 181 | } 182 | } 183 | 184 | /* 185 | * The 'ts3init_get_cookie' match handler. 186 | * Checks that the packet is a valid COMMAND_GET_COOKIE. 187 | */ 188 | static bool 189 | ts3init_get_cookie_mt(const struct sk_buff *skb, struct xt_action_param *par) 190 | { 191 | const struct xt_ts3init_get_cookie_mtinfo *info = par->matchinfo; 192 | struct ts3_init_checked_client_header_data header_data; 193 | 194 | if (!check_client_header(skb, par, &header_data, info->min_client_version)) 195 | return false; 196 | 197 | if (header_data.ts3_header->command != COMMAND_GET_COOKIE) return false; 198 | 199 | if (info->specific_options & CHK_GET_COOKIE_CHECK_TIMESTAMP) 200 | { 201 | __u8 *payload, payload_buf[ts3init_payload_sizes[COMMAND_GET_COOKIE]]; 202 | time_t current_unix_time, packet_unix_time; 203 | 204 | payload = get_payload(skb, par, &header_data, payload_buf, sizeof(payload_buf)); 205 | if (!payload) 206 | return false; 207 | 208 | current_unix_time = ts3init_get_cached_unix_time(); 209 | 210 | packet_unix_time = 211 | payload[0] << 24 | 212 | payload[1] << 16 | 213 | payload[2] << 8 | 214 | payload[3]; 215 | 216 | if (abs(current_unix_time - packet_unix_time) > info->max_utc_offset) 217 | return false; 218 | } 219 | return true; 220 | } 221 | 222 | /* 223 | * Validates matchinfo recieved from userspace. 224 | */ 225 | static int ts3init_get_cookie_mt_check(const struct xt_mtchk_param *par) 226 | { 227 | struct xt_ts3init_get_cookie_mtinfo *info = par->matchinfo; 228 | 229 | if (! (par->family == NFPROTO_IPV4 || par->family == NFPROTO_IPV6)) 230 | { 231 | printk(KERN_INFO KBUILD_MODNAME ": invalid protocol (only ipv4 and ipv6) for get_cookie\n"); 232 | return -EINVAL; 233 | } 234 | 235 | if (info->common_options & ~(CHK_COMMON_VALID_MASK)) 236 | { 237 | printk(KERN_INFO KBUILD_MODNAME ": invalid (common) options for get_cookie\n"); 238 | return -EINVAL; 239 | } 240 | 241 | if (info->specific_options & ~(CHK_GET_COOKIE_VALID_MASK)) 242 | { 243 | printk(KERN_INFO KBUILD_MODNAME ": invalid (specific) options for get_cookie\n"); 244 | return -EINVAL; 245 | } 246 | 247 | return 0; 248 | } 249 | 250 | /* 251 | * The 'ts3init_get_cookie' match handler. 252 | * Checks that the packet is a valid COMMAND_GET_PUZZLE, and if the client 253 | * replied with the correct cookie. 254 | */ 255 | static bool ts3init_get_puzzle_mt(const struct sk_buff *skb, struct xt_action_param *par) 256 | { 257 | const struct xt_ts3init_get_puzzle_mtinfo *info = par->matchinfo; 258 | struct ts3_init_checked_client_header_data header_data; 259 | 260 | if (!check_client_header(skb, par, &header_data, info->min_client_version)) 261 | return false; 262 | 263 | if (header_data.ts3_header->command != COMMAND_GET_PUZZLE) return false; 264 | 265 | if (info->specific_options & CHK_GET_PUZZLE_CHECK_COOKIE) 266 | { 267 | __u8 *payload, payload_buf[ts3init_payload_sizes[COMMAND_GET_PUZZLE]]; 268 | __u64 cookie_seed[2]; 269 | __u64 cookie, packet_cookie; 270 | 271 | payload = get_payload(skb, par, &header_data, payload_buf, sizeof(payload_buf)); 272 | if (!payload) 273 | return false; 274 | 275 | if (ts3init_get_cookie_seed_for_packet_index(payload[8], info->random_seed, &cookie_seed) == false) 276 | return false; 277 | 278 | /* use cookie_seed and ipaddress and port to create a hash 279 | * (cookie) for this connection */ 280 | if (calculate_cookie(skb, par, header_data.udp, cookie_seed[0], cookie_seed[1], &cookie)) 281 | return false; /*something went wrong*/ 282 | 283 | /* compare cookie with payload bytes 0-7. if equal, cookie 284 | * is valid */ 285 | 286 | packet_cookie = (((u64)((payload)[0])) | ((u64)((payload)[1]) << 8) | 287 | ((u64)((payload)[2]) << 16) | ((u64)((payload)[3]) << 24) | 288 | ((u64)((payload)[4]) << 32) | ((u64)((payload)[5]) << 40) | 289 | ((u64)((payload)[6]) << 48) | ((u64)((payload)[7]) << 56)); 290 | 291 | if (packet_cookie != cookie) return false; 292 | } 293 | return true; 294 | } 295 | 296 | /* 297 | * Validates matchinfo recieved from userspace. 298 | */ 299 | static int ts3init_get_puzzle_mt_check(const struct xt_mtchk_param *par) 300 | { 301 | struct xt_ts3init_get_puzzle_mtinfo *info = par->matchinfo; 302 | 303 | if (! (par->family == NFPROTO_IPV4 || par->family == NFPROTO_IPV6)) 304 | { 305 | printk(KERN_INFO KBUILD_MODNAME ": invalid protocol (only ipv4 and ipv6) for get_puzzle\n"); 306 | return -EINVAL; 307 | } 308 | 309 | if (info->common_options & ~(CHK_COMMON_VALID_MASK)) 310 | { 311 | printk(KERN_INFO KBUILD_MODNAME ": invalid (common) options for get_puzzle\n"); 312 | return -EINVAL; 313 | } 314 | 315 | if (info->specific_options & ~(CHK_GET_PUZZLE_VALID_MASK)) 316 | { 317 | printk(KERN_INFO KBUILD_MODNAME ": invalid (specific) options for get_puzzle\n"); 318 | return -EINVAL; 319 | } 320 | 321 | return 0; 322 | } 323 | 324 | /* 325 | * The 'ts3init' match handler. 326 | * Checks that the packet is a valid ts3init packet 327 | */ 328 | static bool ts3init_mt(const struct sk_buff *skb, struct xt_action_param *par) 329 | { 330 | const struct xt_ts3init_mtinfo *info = par->matchinfo; 331 | 332 | if (info->specific_options & CHK_TS3INIT_CLIENT) 333 | { 334 | struct ts3_init_checked_client_header_data header_data; 335 | 336 | if (!check_client_header(skb, par, &header_data, 0)) 337 | return false; 338 | if (info->specific_options & CHK_TS3INIT_COMMAND) 339 | { 340 | if (header_data.ts3_header->command != info->command) 341 | return false; 342 | } 343 | } 344 | else if (info->specific_options & CHK_TS3INIT_SERVER) 345 | { 346 | struct ts3_init_checked_server_header_data header_data; 347 | 348 | if (!check_server_header(skb, par, &header_data)) 349 | return false; 350 | if (info->specific_options & CHK_TS3INIT_COMMAND) 351 | { 352 | if (header_data.ts3_header->command != info->command) 353 | return false; 354 | } 355 | } 356 | else 357 | { 358 | struct udphdr *udp, udp_buf; 359 | u64 *signature, signature_buf; 360 | 361 | udp = skb_header_pointer(skb, par->thoff, sizeof(udp_buf), &udp_buf); 362 | if (!udp) 363 | return false; 364 | signature = skb_header_pointer(skb, par->thoff + sizeof(*udp), 365 | sizeof(signature_buf), &signature_buf); 366 | 367 | if (!signature || *signature != ts3init_header_tag_signature.tag64) 368 | return false; 369 | } 370 | return true; 371 | } 372 | 373 | /* 374 | * Validates matchinfo recieved from userspace. 375 | */ 376 | static int ts3init_check(const struct xt_mtchk_param *par) 377 | { 378 | struct xt_ts3init_get_puzzle_mtinfo *info = par->matchinfo; 379 | 380 | if (info->common_options & ~(CHK_COMMON_VALID_MASK)) 381 | { 382 | printk(KERN_ERR KBUILD_MODNAME ": invalid (common) options for ts3init\n"); 383 | return -EINVAL; 384 | } 385 | 386 | if (info->specific_options & ~(CHK_TS3INIT_VALID_MASK)) 387 | { 388 | printk(KERN_ERR KBUILD_MODNAME ": invalid (specific) options for ts3init\n"); 389 | return -EINVAL; 390 | } 391 | 392 | return 0; 393 | } 394 | 395 | static struct xt_match ts3init_mt_reg[] __read_mostly = 396 | { 397 | { 398 | .name = "ts3init_get_cookie", 399 | .revision = 0, 400 | .family = NFPROTO_IPV4, 401 | .proto = IPPROTO_UDP, 402 | .matchsize = sizeof(struct xt_ts3init_get_cookie_mtinfo), 403 | .match = ts3init_get_cookie_mt, 404 | .checkentry = ts3init_get_cookie_mt_check, 405 | .me = THIS_MODULE, 406 | }, 407 | { 408 | .name = "ts3init_get_cookie", 409 | .revision = 0, 410 | .family = NFPROTO_IPV6, 411 | .proto = IPPROTO_UDP, 412 | .matchsize = sizeof(struct xt_ts3init_get_cookie_mtinfo), 413 | .match = ts3init_get_cookie_mt, 414 | .checkentry = ts3init_get_cookie_mt_check, 415 | .me = THIS_MODULE, 416 | }, 417 | { 418 | .name = "ts3init_get_puzzle", 419 | .revision = 0, 420 | .family = NFPROTO_IPV4, 421 | .proto = IPPROTO_UDP, 422 | .matchsize = sizeof(struct xt_ts3init_get_puzzle_mtinfo), 423 | .match = ts3init_get_puzzle_mt, 424 | .checkentry = ts3init_get_puzzle_mt_check, 425 | .me = THIS_MODULE, 426 | }, 427 | { 428 | .name = "ts3init_get_puzzle", 429 | .revision = 0, 430 | .family = NFPROTO_IPV6, 431 | .proto = IPPROTO_UDP, 432 | .matchsize = sizeof(struct xt_ts3init_get_puzzle_mtinfo), 433 | .match = ts3init_get_puzzle_mt, 434 | .checkentry = ts3init_get_puzzle_mt_check, 435 | .me = THIS_MODULE, 436 | }, 437 | { 438 | .name = "ts3init", 439 | .revision = 0, 440 | .family = NFPROTO_UNSPEC, 441 | .proto = IPPROTO_UDP, 442 | .matchsize = sizeof(struct xt_ts3init_mtinfo), 443 | .match = ts3init_mt, 444 | .checkentry = ts3init_check, 445 | .me = THIS_MODULE, 446 | }, 447 | }; 448 | 449 | int __init ts3init_match_init(void) 450 | { 451 | return xt_register_matches(ts3init_mt_reg, ARRAY_SIZE(ts3init_mt_reg)); 452 | } 453 | 454 | void ts3init_match_exit(void) 455 | { 456 | xt_unregister_matches(ts3init_mt_reg, ARRAY_SIZE(ts3init_mt_reg)); 457 | } 458 | -------------------------------------------------------------------------------- /src/ts3init_target.c: -------------------------------------------------------------------------------- 1 | /* 2 | * "ts3init" extension for Xtables 3 | * 4 | * Description: A module to aid in ts3 spoof protection 5 | * This is the "target" code 6 | * 7 | * Authors: 8 | * Niels Werensteijn , 2016-10-03 9 | * Maximilian Muenchow , 2016-10-03 10 | * This program is free software; you can redistribute it and/or modify it 11 | * under the terms of the GNU General Public License; either version 2 12 | * or 3 of the License, as published by the Free Software Foundation. 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #ifdef CONFIG_BRIDGE_NETFILTER 23 | # include 24 | #endif 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "compat_xtables.h" 31 | #include "ts3init_random_seed.h" 32 | #include "ts3init_cookie.h" 33 | #include "ts3init_target.h" 34 | #include "ts3init_header.h" 35 | #include "ts3init_cache.h" 36 | 37 | 38 | /* 39 | * Send a reply back to the client 40 | */ 41 | static bool 42 | ts3init_send_ipv6_reply(struct sk_buff *oldskb, const struct xt_action_param *par, 43 | const struct ipv6hdr *oldip, const struct udphdr *oldudp, 44 | const void* payload, const size_t payload_size) 45 | { 46 | struct sk_buff *skb; 47 | struct ipv6hdr *ip; 48 | struct udphdr *udp; 49 | struct flowi6 fl; 50 | struct dst_entry *dst = NULL; 51 | 52 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) 53 | struct net *net = dev_net((xt_in(par) != NULL) ? xt_in(par) : xt_out(par)); 54 | #else 55 | struct net *net = dev_net((par->in != NULL) ? par->in : par->out); 56 | #endif 57 | 58 | skb = alloc_skb(LL_MAX_HEADER + sizeof(*ip) + 59 | sizeof(*udp) + payload_size, GFP_ATOMIC); 60 | if (skb == NULL) 61 | return false; 62 | 63 | skb_reserve(skb, LL_MAX_HEADER); 64 | skb->protocol = oldskb->protocol; 65 | 66 | skb_reset_network_header(skb); 67 | ip = (void *)skb_put(skb, sizeof(*ip)); 68 | ip->version = oldip->version; 69 | ip->priority = oldip->priority; 70 | memcpy(ip->flow_lbl, oldip->flow_lbl, sizeof(ip->flow_lbl)); 71 | ip->nexthdr = par->target->proto; 72 | ip->saddr = oldip->daddr; 73 | ip->daddr = oldip->saddr; 74 | 75 | skb_reset_transport_header(skb); 76 | udp = (void *)skb_put(skb, sizeof(*udp)); 77 | udp->source = oldudp->dest; 78 | udp->dest = oldudp->source; 79 | udp->len = htons(sizeof(*udp) + payload_size); 80 | 81 | memcpy(skb_put(skb, payload_size), payload, payload_size); 82 | 83 | udp->check = 0; 84 | udp->check = csum_ipv6_magic(&ip->saddr, &ip->daddr, 85 | ntohs(udp->len), IPPROTO_UDP, 86 | csum_partial(udp, ntohs(udp->len), 0)); 87 | 88 | memset(&fl, 0, sizeof(fl)); 89 | fl.flowi6_proto = ip->nexthdr; 90 | memcpy(&fl.saddr, &ip->saddr, sizeof(fl.saddr)); 91 | memcpy(&fl.daddr, &ip->daddr, sizeof(fl.daddr)); 92 | fl.fl6_sport = udp->source; 93 | fl.fl6_dport = udp->dest; 94 | security_skb_classify_flow((struct sk_buff *)oldskb, flowi6_to_flowi(&fl)); 95 | dst = ip6_route_output(net, NULL, &fl); 96 | if (dst == NULL || dst->error != 0) { 97 | dst_release(dst); 98 | goto free_nskb; 99 | } 100 | 101 | skb_dst_set(skb, dst); 102 | ip->hop_limit = ip6_dst_hoplimit(skb_dst(skb)); 103 | skb->ip_summed = CHECKSUM_NONE; 104 | 105 | /* "Never happens" (?) */ 106 | if (skb->len > dst_mtu(skb_dst(skb))) 107 | goto free_nskb; 108 | 109 | nf_ct_attach(skb, oldskb); 110 | ip6_local_out(par_net(par), skb->sk, skb); 111 | return true; 112 | 113 | free_nskb: 114 | kfree_skb(skb); 115 | return false; 116 | } 117 | 118 | /* 119 | * Send a reply back to the client 120 | */ 121 | static bool 122 | ts3init_send_ipv4_reply(struct sk_buff *oldskb, const struct xt_action_param *par, 123 | const struct iphdr *oldip, const struct udphdr *oldudp, 124 | const void* payload, const size_t payload_size) 125 | { 126 | struct sk_buff *skb; 127 | struct iphdr *ip; 128 | struct udphdr *udp; 129 | 130 | skb = alloc_skb(LL_MAX_HEADER + sizeof(*ip) + 131 | sizeof(*udp) + payload_size, GFP_ATOMIC); 132 | if (skb == NULL) 133 | return false; 134 | 135 | skb_reserve(skb, LL_MAX_HEADER); 136 | skb->protocol = oldskb->protocol; 137 | 138 | skb_reset_network_header(skb); 139 | ip = (void *)skb_put(skb, sizeof(*ip)); 140 | ip->version = oldip->version; 141 | ip->ihl = sizeof(*ip) / 4; 142 | ip->tos = oldip->tos; 143 | ip->id = 0; 144 | ip->frag_off = htons(IP_DF); 145 | ip->protocol = oldip->protocol; 146 | ip->check = 0; 147 | ip->saddr = oldip->daddr; 148 | ip->daddr = oldip->saddr; 149 | 150 | skb_reset_transport_header(skb); 151 | udp = (void *)skb_put(skb, sizeof(*udp)); 152 | udp->source = oldudp->dest; 153 | udp->dest = oldudp->source; 154 | udp->len = htons(sizeof(*udp) + payload_size); 155 | 156 | memcpy(skb_put(skb, payload_size), payload, payload_size); 157 | 158 | udp->check = 0; 159 | udp->check = csum_tcpudp_magic(ip->saddr, ip->daddr, 160 | ntohs(udp->len), IPPROTO_UDP, 161 | csum_partial(udp, ntohs(udp->len), 0)); 162 | 163 | /* ip_route_me_harder expects the skb's dst to be set */ 164 | skb_dst_set(skb, dst_clone(skb_dst(oldskb))); 165 | 166 | if (ip_route_me_harder(par_net(par), skb, RTN_UNSPEC) != 0) 167 | goto free_nskb; 168 | 169 | ip->ttl = ip4_dst_hoplimit(skb_dst(skb)); 170 | skb->ip_summed = CHECKSUM_NONE; 171 | 172 | /* "Never happens" (?) */ 173 | if (skb->len > dst_mtu(skb_dst(skb))) 174 | goto free_nskb; 175 | 176 | nf_ct_attach(skb, oldskb); 177 | ip_local_out(par_net(par), skb->sk, skb); 178 | return true; 179 | 180 | free_nskb: 181 | kfree_skb(skb); 182 | return false; 183 | } 184 | 185 | /* The payload replied by TS3INIT_RESET. */ 186 | static const char ts3init_reset_packet[] = {'T', 'S', '3', 'I', 'N', 'I', 'T', '1', 0, 0x65, 0x88, COMMAND_RESET, 0 }; 187 | 188 | /* 189 | * The 'TS3INIT_RESET' target handler. 190 | * Always replies with COMMAND_RESET and drops the packet 191 | */ 192 | static unsigned int 193 | ts3init_reset_ipv4_tg(struct sk_buff *skb, const struct xt_action_param *par) 194 | { 195 | struct iphdr *ip; 196 | struct udphdr *udp, udp_buf; 197 | ip = ip_hdr(skb); 198 | udp = skb_header_pointer(skb, par->thoff, sizeof(*udp), &udp_buf); 199 | if (udp == NULL || ntohs(udp->len) <= sizeof(*udp)) 200 | return NF_DROP; 201 | 202 | ts3init_send_ipv4_reply(skb, par, ip, udp, ts3init_reset_packet, sizeof(ts3init_reset_packet)); 203 | return NF_DROP; 204 | } 205 | 206 | /* 207 | * The 'TS3INIT_RESET' target handler. 208 | * Always replies with COMMAND_RESET and drops the packet. 209 | */ 210 | static unsigned int 211 | ts3init_reset_ipv6_tg(struct sk_buff *skb, const struct xt_action_param *par) 212 | { 213 | struct ipv6hdr *ip; 214 | struct udphdr *udp, udp_buf; 215 | ip = ipv6_hdr(skb); 216 | udp = skb_header_pointer(skb, par->thoff, sizeof(*udp), &udp_buf); 217 | if (udp == NULL || ntohs(udp->len) <= sizeof(*udp)) 218 | return NF_DROP; 219 | 220 | ts3init_send_ipv6_reply(skb, par, ip, udp, ts3init_reset_packet, sizeof(ts3init_reset_packet)); 221 | return NF_DROP; 222 | } 223 | 224 | /* The header replied by TS3INIT_SET_COOKIE. */ 225 | static const char ts3init_set_cookie_packet_header[TS3INIT_HEADER_SERVER_LENGTH] = {'T', 'S', '3', 'I', 'N', 'I', 'T', '1', 0, 0x65, 0x88, COMMAND_SET_COOKIE }; 226 | 227 | /* 228 | * Returns the current cookie. 229 | */ 230 | static bool 231 | ts3init_generate_cookie_ipv4(const struct xt_action_param *par, 232 | const struct iphdr *ip, const struct udphdr *udp, 233 | u64 *cookie, u8 *packet_index) 234 | { 235 | const struct xt_ts3init_set_cookie_tginfo *info = par->targinfo; 236 | __u64 cookie_seed[2]; 237 | 238 | if (ts3init_get_current_cookie_seed(info->random_seed, &cookie_seed, packet_index) == false) 239 | return false; 240 | if (ts3init_calculate_cookie_ipv4(ip, udp, cookie_seed[0], cookie_seed[1], cookie)) 241 | return false; 242 | return true; 243 | } 244 | 245 | /* 246 | * Returns the current cookie. 247 | */ 248 | static bool 249 | ts3init_generate_cookie_ipv6(const struct xt_action_param *par, 250 | const struct ipv6hdr *ip, const struct udphdr *udp, 251 | u64 *cookie, u8 *packet_index) 252 | { 253 | const struct xt_ts3init_set_cookie_tginfo *info = par->targinfo; 254 | __u64 cookie_seed[2]; 255 | 256 | if (ts3init_get_current_cookie_seed(info->random_seed, &cookie_seed, packet_index) == false) 257 | return false; 258 | if (ts3init_calculate_cookie_ipv6(ip, udp, cookie_seed[0], cookie_seed[1], cookie)) 259 | return false; 260 | return true; 261 | } 262 | 263 | /* 264 | * Fills 'newpayload' with a TS3INIT_SET_COOKIE packet. 265 | */ 266 | static bool 267 | ts3init_fill_set_cookie_payload(const struct sk_buff *skb, 268 | const struct xt_action_param *par, 269 | const u64 cookie, const u8 packet_index, 270 | u8 *newpayload) 271 | { 272 | const struct xt_ts3init_set_cookie_tginfo *info = par->targinfo; 273 | u8 *payload, payload_buf[34]; 274 | 275 | memcpy(newpayload, ts3init_set_cookie_packet_header, sizeof(ts3init_set_cookie_packet_header)); 276 | newpayload[12] = (u8)cookie; 277 | newpayload[13] = (u8)(cookie >> 8); 278 | newpayload[14] = (u8)(cookie >> 16); 279 | newpayload[15] = (u8)(cookie >> 24); 280 | newpayload[16] = (u8)(cookie >> 32); 281 | newpayload[17] = (u8)(cookie >> 40); 282 | newpayload[18] = (u8)(cookie >> 48); 283 | newpayload[19] = (u8)(cookie >> 56); 284 | newpayload[20] = packet_index; 285 | if (info->specific_options & TARGET_SET_COOKIE_ZERO_RANDOM_SEQUENCE) 286 | { 287 | memset(&newpayload[21], 0, 11); 288 | } 289 | else 290 | { 291 | memset(&newpayload[21], 0, 7); 292 | payload = skb_header_pointer(skb, par->thoff + sizeof(struct udphdr), 293 | sizeof(payload_buf), payload_buf); 294 | if (payload == NULL) 295 | { 296 | printk(KERN_WARNING KBUILD_MODNAME ": was expecting a ts3init_get_cookie packet. Use -m ts3init_get_cookie!\n"); 297 | return false; 298 | } 299 | newpayload[28] = payload[25]; 300 | newpayload[29] = payload[24]; 301 | newpayload[30] = payload[23]; 302 | newpayload[31] = payload[22]; 303 | } 304 | return true; 305 | } 306 | 307 | /* 308 | * The 'TS3INIT_SET_COOKIE' target handler. 309 | * Always replies with TS3INIT_SET_COOKIE and drops the packet. 310 | */ 311 | static unsigned int 312 | ts3init_set_cookie_ipv4_tg(struct sk_buff *skb, const struct xt_action_param *par) 313 | { 314 | struct iphdr *ip; 315 | struct udphdr *udp, udp_buf; 316 | u64 cookie; 317 | u8 packet_index; 318 | u8 payload[sizeof(ts3init_set_cookie_packet_header) + 20]; 319 | 320 | ip = ip_hdr(skb); 321 | udp = skb_header_pointer(skb, par->thoff, sizeof(*udp), &udp_buf); 322 | if (udp == NULL || ntohs(udp->len) <= sizeof(*udp)) 323 | return NF_DROP; 324 | 325 | if (ts3init_generate_cookie_ipv4(par, ip, udp, &cookie, &packet_index) && 326 | ts3init_fill_set_cookie_payload(skb, par, cookie, packet_index, payload)) 327 | { 328 | ts3init_send_ipv4_reply(skb, par, ip, udp, payload, sizeof(payload)); 329 | } 330 | return NF_DROP; 331 | } 332 | 333 | /* 334 | * The 'TS3INIT_SET_COOKIE' target handler. 335 | * Always replies with TS3INIT_SET_COOKIE and drops the packet. 336 | */ 337 | static unsigned int 338 | ts3init_set_cookie_ipv6_tg(struct sk_buff *skb, const struct xt_action_param *par) 339 | { 340 | struct ipv6hdr *ip; 341 | struct udphdr *udp, udp_buf; 342 | u64 cookie; 343 | u8 packet_index; 344 | u8 payload[sizeof(ts3init_set_cookie_packet_header) + 20]; 345 | 346 | ip = ipv6_hdr(skb); 347 | udp = skb_header_pointer(skb, par->thoff, sizeof(*udp), &udp_buf); 348 | if (udp == NULL || ntohs(udp->len) <= sizeof(*udp)) 349 | return NF_DROP; 350 | 351 | if (ts3init_generate_cookie_ipv6(par, ip, udp, &cookie, &packet_index) && 352 | ts3init_fill_set_cookie_payload(skb, par, cookie, packet_index, payload)) 353 | { 354 | ts3init_send_ipv6_reply(skb, par, ip, udp, payload, sizeof(payload)); 355 | } 356 | return NF_DROP; 357 | } 358 | 359 | /* 360 | * Validates targinfo recieved from userspace. 361 | */ 362 | static int ts3init_set_cookie_tg_check(const struct xt_tgchk_param *par) 363 | { 364 | struct xt_ts3init_set_cookie_tginfo *info = par->targinfo; 365 | 366 | if (! (par->family == NFPROTO_IPV4 || par->family == NFPROTO_IPV6)) 367 | { 368 | printk(KERN_INFO KBUILD_MODNAME ": invalid protocol (only ipv4 and ipv6) for TS3INIT_SET_COOKIE\n"); 369 | return -EINVAL; 370 | } 371 | 372 | if (info->common_options & ~(TARGET_COMMON_VALID_MASK)) 373 | { 374 | printk(KERN_INFO KBUILD_MODNAME ": invalid (common) options for TS3INIT_SET_COOKIE\n"); 375 | return -EINVAL; 376 | } 377 | 378 | if (info->specific_options & ~(TARGET_SET_COOKIE_VALID_MASK)) 379 | { 380 | printk(KERN_INFO KBUILD_MODNAME ": invalid (specific) options for TS3INIT_SET_COOKIE\n"); 381 | return -EINVAL; 382 | } 383 | 384 | return 0; 385 | } 386 | 387 | static inline void 388 | ts3init_fill_get_cookie_payload(u8 *payload) 389 | { 390 | time_t current_unix_time = ts3init_get_cached_unix_time(); 391 | payload[TS3INIT_HEADER_CLIENT_LENGTH - 1] = COMMAND_GET_COOKIE; 392 | payload[TS3INIT_HEADER_CLIENT_LENGTH + 0] = current_unix_time >> 24; 393 | payload[TS3INIT_HEADER_CLIENT_LENGTH + 1] = current_unix_time >> 16; 394 | payload[TS3INIT_HEADER_CLIENT_LENGTH + 2] = current_unix_time >> 8; 395 | payload[TS3INIT_HEADER_CLIENT_LENGTH + 3] = current_unix_time; 396 | get_random_bytes(&payload[TS3INIT_HEADER_CLIENT_LENGTH + 4], 4); 397 | memset(&payload[TS3INIT_HEADER_CLIENT_LENGTH + 8], 0, 8); 398 | } 399 | 400 | /* 401 | * The 'TS3INIT_GET_COOKIE' target handler. 402 | * Morphes the incomming packet into a TS3INIT_GET_COOKIE 403 | */ 404 | static unsigned int 405 | ts3init_get_cookie_ipv4_tg(struct sk_buff *skb, const struct xt_action_param *par) 406 | { 407 | struct iphdr *ip; 408 | struct udphdr *udp, udp_buf; 409 | u8 *payload, payload_buf[TS3INIT_HEADER_CLIENT_LENGTH + 16]; 410 | int delta; 411 | int new_udp_len; 412 | 413 | ip = ip_hdr(skb); 414 | udp = skb_header_pointer(skb, par->thoff, sizeof(udp_buf), &udp_buf); 415 | if (udp == NULL) 416 | return NF_DROP; 417 | if (ip->frag_off & htons(IP_OFFSET)) 418 | return NF_DROP; 419 | 420 | new_udp_len = sizeof(*udp) + sizeof(payload_buf); 421 | delta = new_udp_len - ntohs(udp->len); 422 | if (delta < 0) 423 | { 424 | skb_trim(skb, skb->len + delta); 425 | } 426 | else 427 | { 428 | if (skb_put_padto(skb, skb->len + delta)) 429 | return NF_STOLEN; 430 | } 431 | if (!skb_make_writable(skb, skb->len)) 432 | return NF_DROP; 433 | 434 | payload = skb_header_pointer(skb, par->thoff + sizeof(*udp), sizeof(payload_buf), payload_buf); 435 | ts3init_fill_get_cookie_payload(payload); 436 | 437 | udp->len = htons(new_udp_len); 438 | udp->check = 0; 439 | udp->check = csum_tcpudp_magic(ip->saddr, ip->daddr, 440 | new_udp_len, IPPROTO_UDP, 441 | csum_partial(udp, new_udp_len, 0)); 442 | ip->tot_len = htons( ntohs(ip->tot_len) + delta ); 443 | ip_send_check(ip); 444 | 445 | if (skb->len > dst_mtu(skb_dst(skb))) 446 | return NF_DROP; 447 | 448 | return NF_ACCEPT; 449 | } 450 | 451 | /* 452 | * The 'TS3INIT_GET_COOKIE' target handler. 453 | * Morphes the incomming packet into a TS3INIT_GET_COOKIE 454 | */ 455 | static unsigned int 456 | ts3init_get_cookie_ipv6_tg(struct sk_buff *skb, const struct xt_action_param *par) 457 | { 458 | struct ipv6hdr *ip; 459 | struct udphdr *udp, udp_buf; 460 | u8 *payload, payload_buf[TS3INIT_HEADER_CLIENT_LENGTH + 16]; 461 | int delta; 462 | int new_udp_len; 463 | 464 | ip = ipv6_hdr(skb); 465 | udp = skb_header_pointer(skb, par->thoff, sizeof(udp_buf), &udp_buf); 466 | if (udp == NULL) 467 | return NF_DROP; 468 | 469 | new_udp_len = sizeof(*udp) + sizeof(payload_buf); 470 | delta = new_udp_len - ntohs(udp->len); 471 | 472 | if (delta < 0) 473 | { 474 | skb_trim(skb, skb->len + delta); 475 | } 476 | else 477 | { 478 | if (skb_put_padto(skb, skb->len + delta)) 479 | return NF_STOLEN; 480 | } 481 | if (!skb_make_writable(skb, skb->len)) 482 | return NF_DROP; 483 | 484 | payload = skb_header_pointer(skb, par->thoff + sizeof(*udp), sizeof(payload_buf), payload_buf); 485 | ts3init_fill_get_cookie_payload(payload); 486 | 487 | udp->len = htons(new_udp_len); 488 | udp->check = 0; 489 | udp->check = csum_ipv6_magic(&ip->saddr, &ip->daddr, 490 | new_udp_len, IPPROTO_UDP, 491 | csum_partial(udp, new_udp_len, 0)); 492 | ip->payload_len = htons( ntohs(ip->payload_len) + delta ); 493 | 494 | if (skb->len > dst_mtu(skb_dst(skb))) 495 | return NF_DROP; 496 | 497 | return NF_ACCEPT; 498 | } 499 | 500 | static struct xt_target ts3init_tg_reg[] __read_mostly = { 501 | { 502 | .name = "TS3INIT_RESET", 503 | .revision = 0, 504 | .family = NFPROTO_IPV4, 505 | .proto = IPPROTO_UDP, 506 | .target = ts3init_reset_ipv4_tg, 507 | .me = THIS_MODULE, 508 | }, 509 | { 510 | .name = "TS3INIT_RESET", 511 | .revision = 0, 512 | .family = NFPROTO_IPV6, 513 | .proto = IPPROTO_UDP, 514 | .target = ts3init_reset_ipv6_tg, 515 | .me = THIS_MODULE, 516 | }, 517 | { 518 | .name = "TS3INIT_SET_COOKIE", 519 | .revision = 0, 520 | .family = NFPROTO_IPV4, 521 | .proto = IPPROTO_UDP, 522 | .targetsize = sizeof(struct xt_ts3init_set_cookie_tginfo), 523 | .target = ts3init_set_cookie_ipv4_tg, 524 | .checkentry = ts3init_set_cookie_tg_check, 525 | .me = THIS_MODULE, 526 | }, 527 | { 528 | .name = "TS3INIT_SET_COOKIE", 529 | .revision = 0, 530 | .family = NFPROTO_IPV6, 531 | .proto = IPPROTO_UDP, 532 | .targetsize = sizeof(struct xt_ts3init_set_cookie_tginfo), 533 | .target = ts3init_set_cookie_ipv6_tg, 534 | .checkentry = ts3init_set_cookie_tg_check, 535 | .me = THIS_MODULE, 536 | }, 537 | { 538 | .name = "TS3INIT_GET_COOKIE", 539 | .revision = 0, 540 | .family = NFPROTO_IPV4, 541 | .proto = IPPROTO_UDP, 542 | .target = ts3init_get_cookie_ipv4_tg, 543 | .me = THIS_MODULE, 544 | }, 545 | { 546 | .name = "TS3INIT_GET_COOKIE", 547 | .revision = 0, 548 | .family = NFPROTO_IPV6, 549 | .proto = IPPROTO_UDP, 550 | .target = ts3init_get_cookie_ipv6_tg, 551 | .me = THIS_MODULE, 552 | }, 553 | }; 554 | 555 | int __init ts3init_target_init(void) 556 | { 557 | return xt_register_targets(ts3init_tg_reg, ARRAY_SIZE(ts3init_tg_reg)); 558 | } 559 | 560 | void ts3init_target_exit(void) 561 | { 562 | xt_unregister_targets(ts3init_tg_reg, ARRAY_SIZE(ts3init_tg_reg)); 563 | } 564 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 [Free Software Foundation, Inc.](http://fsf.org/) 5 | 6 | Everyone is permitted to copy and distribute verbatim copies of this license 7 | document, but changing it is not allowed. 8 | 9 | ## Preamble 10 | 11 | The GNU General Public License is a free, copyleft license for software and 12 | other kinds of works. 13 | 14 | The licenses for most software and other practical works are designed to take 15 | away your freedom to share and change the works. By contrast, the GNU General 16 | Public License is intended to guarantee your freedom to share and change all 17 | versions of a program--to make sure it remains free software for all its users. 18 | We, the Free Software Foundation, use the GNU General Public License for most 19 | of our software; it applies also to any other work released this way by its 20 | authors. You can apply it to your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not price. Our 23 | General Public Licenses are designed to make sure that you have the freedom to 24 | distribute copies of free software (and charge for them if you wish), that you 25 | receive source code or can get it if you want it, that you can change the 26 | software or use pieces of it in new free programs, and that you know you can do 27 | these things. 28 | 29 | To protect your rights, we need to prevent others from denying you these rights 30 | or asking you to surrender the rights. Therefore, you have certain 31 | responsibilities if you distribute copies of the software, or if you modify it: 32 | responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether gratis or for 35 | a fee, you must pass on to the recipients the same freedoms that you received. 36 | You must make sure that they, too, receive or can get the source code. And you 37 | must show them these terms so they know their rights. 38 | 39 | Developers that use the GNU GPL protect your rights with two steps: 40 | 41 | 1. assert copyright on the software, and 42 | 2. offer you this License giving you legal permission to copy, distribute 43 | and/or modify it. 44 | 45 | For the developers' and authors' protection, the GPL clearly explains that 46 | there is no warranty for this free software. For both users' and authors' sake, 47 | the GPL requires that modified versions be marked as changed, so that their 48 | problems will not be attributed erroneously to authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run modified 51 | versions of the software inside them, although the manufacturer can do so. This 52 | is fundamentally incompatible with the aim of protecting users' freedom to 53 | change the software. The systematic pattern of such abuse occurs in the area of 54 | products for individuals to use, which is precisely where it is most 55 | unacceptable. Therefore, we have designed this version of the GPL to prohibit 56 | the practice for those products. If such problems arise substantially in other 57 | domains, we stand ready to extend this provision to those domains in future 58 | versions of the GPL, as needed to protect the freedom of users. 59 | 60 | Finally, every program is threatened constantly by software patents. States 61 | should not allow patents to restrict development and use of software on 62 | general-purpose computers, but in those that do, we wish to avoid the special 63 | danger that patents applied to a free program could make it effectively 64 | proprietary. To prevent this, the GPL assures that patents cannot be used to 65 | render the program non-free. 66 | 67 | The precise terms and conditions for copying, distribution and modification 68 | follow. 69 | 70 | ## TERMS AND CONDITIONS 71 | 72 | ### 0. Definitions. 73 | 74 | *This License* refers to version 3 of the GNU General Public License. 75 | 76 | *Copyright* also means copyright-like laws that apply to other kinds of works, 77 | such as semiconductor masks. 78 | 79 | *The Program* refers to any copyrightable work licensed under this License. 80 | Each licensee is addressed as *you*. *Licensees* and *recipients* may be 81 | individuals or organizations. 82 | 83 | To *modify* a work means to copy from or adapt all or part of the work in a 84 | fashion requiring copyright permission, other than the making of an exact copy. 85 | The resulting work is called a *modified version* of the earlier work or a work 86 | *based on* the earlier work. 87 | 88 | A *covered work* means either the unmodified Program or a work based on the 89 | Program. 90 | 91 | To *propagate* a work means to do anything with it that, without permission, 92 | would make you directly or secondarily liable for infringement under applicable 93 | copyright law, except executing it on a computer or modifying a private copy. 94 | Propagation includes copying, distribution (with or without modification), 95 | making available to the public, and in some countries other activities as well. 96 | 97 | To *convey* a work means any kind of propagation that enables other parties to 98 | make or receive copies. Mere interaction with a user through a computer 99 | network, with no transfer of a copy, is not conveying. 100 | 101 | An interactive user interface displays *Appropriate Legal Notices* to the 102 | extent that it includes a convenient and prominently visible feature that 103 | 104 | 1. displays an appropriate copyright notice, and 105 | 2. tells the user that there is no warranty for the work (except to the 106 | extent that warranties are provided), that licensees may convey the work 107 | under this License, and how to view a copy of this License. 108 | 109 | If the interface presents a list of user commands or options, such as a menu, a 110 | prominent item in the list meets this criterion. 111 | 112 | ### 1. Source Code. 113 | 114 | The *source code* for a work means the preferred form of the work for making 115 | modifications to it. *Object code* means any non-source form of a work. 116 | 117 | A *Standard Interface* means an interface that either is an official standard 118 | defined by a recognized standards body, or, in the case of interfaces specified 119 | for a particular programming language, one that is widely used among developers 120 | working in that language. 121 | 122 | The *System Libraries* of an executable work include anything, other than the 123 | work as a whole, that (a) is included in the normal form of packaging a Major 124 | Component, but which is not part of that Major Component, and (b) serves only 125 | to enable use of the work with that Major Component, or to implement a Standard 126 | Interface for which an implementation is available to the public in source code 127 | form. A *Major Component*, in this context, means a major essential component 128 | (kernel, window system, and so on) of the specific operating system (if any) on 129 | which the executable work runs, or a compiler used to produce the work, or an 130 | object code interpreter used to run it. 131 | 132 | The *Corresponding Source* for a work in object code form means all the source 133 | code needed to generate, install, and (for an executable work) run the object 134 | code and to modify the work, including scripts to control those activities. 135 | However, it does not include the work's System Libraries, or general-purpose 136 | tools or generally available free programs which are used unmodified in 137 | performing those activities but which are not part of the work. For example, 138 | Corresponding Source includes interface definition files associated with source 139 | files for the work, and the source code for shared libraries and dynamically 140 | linked subprograms that the work is specifically designed to require, such as 141 | by intimate data communication or control flow between those subprograms and 142 | other parts of the work. 143 | 144 | The Corresponding Source need not include anything that users can regenerate 145 | automatically from other parts of the Corresponding Source. 146 | 147 | The Corresponding Source for a work in source code form is that same work. 148 | 149 | ### 2. Basic Permissions. 150 | 151 | All rights granted under this License are granted for the term of copyright on 152 | the Program, and are irrevocable provided the stated conditions are met. This 153 | License explicitly affirms your unlimited permission to run the unmodified 154 | Program. The output from running a covered work is covered by this License only 155 | if the output, given its content, constitutes a covered work. This License 156 | acknowledges your rights of fair use or other equivalent, as provided by 157 | copyright law. 158 | 159 | You may make, run and propagate covered works that you do not convey, without 160 | conditions so long as your license otherwise remains in force. You may convey 161 | covered works to others for the sole purpose of having them make modifications 162 | exclusively for you, or provide you with facilities for running those works, 163 | provided that you comply with the terms of this License in conveying all 164 | material for which you do not control copyright. Those thus making or running 165 | the covered works for you must do so exclusively on your behalf, under your 166 | direction and control, on terms that prohibit them from making any copies of 167 | your copyrighted material outside their relationship with you. 168 | 169 | Conveying under any other circumstances is permitted solely under the 170 | conditions stated below. Sublicensing is not allowed; section 10 makes it 171 | unnecessary. 172 | 173 | ### 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 174 | 175 | No covered work shall be deemed part of an effective technological measure 176 | under any applicable law fulfilling obligations under article 11 of the WIPO 177 | copyright treaty adopted on 20 December 1996, or similar laws prohibiting or 178 | restricting circumvention of such measures. 179 | 180 | When you convey a covered work, you waive any legal power to forbid 181 | circumvention of technological measures to the extent such circumvention is 182 | effected by exercising rights under this License with respect to the covered 183 | work, and you disclaim any intention to limit operation or modification of the 184 | work as a means of enforcing, against the work's users, your or third parties' 185 | legal rights to forbid circumvention of technological measures. 186 | 187 | ### 4. Conveying Verbatim Copies. 188 | 189 | You may convey verbatim copies of the Program's source code as you receive it, 190 | in any medium, provided that you conspicuously and appropriately publish on 191 | each copy an appropriate copyright notice; keep intact all notices stating that 192 | this License and any non-permissive terms added in accord with section 7 apply 193 | to the code; keep intact all notices of the absence of any warranty; and give 194 | all recipients a copy of this License along with the Program. 195 | 196 | You may charge any price or no price for each copy that you convey, and you may 197 | offer support or warranty protection for a fee. 198 | 199 | ### 5. Conveying Modified Source Versions. 200 | 201 | You may convey a work based on the Program, or the modifications to produce it 202 | from the Program, in the form of source code under the terms of section 4, 203 | provided that you also meet all of these conditions: 204 | 205 | - a) The work must carry prominent notices stating that you modified it, and 206 | giving a relevant date. 207 | - b) The work must carry prominent notices stating that it is released under 208 | this License and any conditions added under section 7. This requirement 209 | modifies the requirement in section 4 to *keep intact all notices*. 210 | - c) You must license the entire work, as a whole, under this License to 211 | anyone who comes into possession of a copy. This License will therefore 212 | apply, along with any applicable section 7 additional terms, to the whole 213 | of the work, and all its parts, regardless of how they are packaged. This 214 | License gives no permission to license the work in any other way, but it 215 | does not invalidate such permission if you have separately received it. 216 | - d) If the work has interactive user interfaces, each must display 217 | Appropriate Legal Notices; however, if the Program has interactive 218 | interfaces that do not display Appropriate Legal Notices, your work need 219 | not make them do so. 220 | 221 | A compilation of a covered work with other separate and independent works, 222 | which are not by their nature extensions of the covered work, and which are not 223 | combined with it such as to form a larger program, in or on a volume of a 224 | storage or distribution medium, is called an *aggregate* if the compilation and 225 | its resulting copyright are not used to limit the access or legal rights of the 226 | compilation's users beyond what the individual works permit. Inclusion of a 227 | covered work in an aggregate does not cause this License to apply to the other 228 | parts of the aggregate. 229 | 230 | ### 6. Conveying Non-Source Forms. 231 | 232 | You may convey a covered work in object code form under the terms of sections 4 233 | and 5, provided that you also convey the machine-readable Corresponding Source 234 | under the terms of this License, in one of these ways: 235 | 236 | - a) Convey the object code in, or embodied in, a physical product (including 237 | a physical distribution medium), accompanied by the Corresponding Source 238 | fixed on a durable physical medium customarily used for software 239 | interchange. 240 | - b) Convey the object code in, or embodied in, a physical product (including 241 | a physical distribution medium), accompanied by a written offer, valid for 242 | at least three years and valid for as long as you offer spare parts or 243 | customer support for that product model, to give anyone who possesses the 244 | object code either 245 | 1. a copy of the Corresponding Source for all the software in the product 246 | that is covered by this License, on a durable physical medium 247 | customarily used for software interchange, for a price no more than your 248 | reasonable cost of physically performing this conveying of source, or 249 | 2. access to copy the Corresponding Source from a network server at no 250 | charge. 251 | - c) Convey individual copies of the object code with a copy of the written 252 | offer to provide the Corresponding Source. This alternative is allowed only 253 | occasionally and noncommercially, and only if you received the object code 254 | with such an offer, in accord with subsection 6b. 255 | - d) Convey the object code by offering access from a designated place 256 | (gratis or for a charge), and offer equivalent access to the Corresponding 257 | Source in the same way through the same place at no further charge. You 258 | need not require recipients to copy the Corresponding Source along with the 259 | object code. If the place to copy the object code is a network server, the 260 | Corresponding Source may be on a different server operated by you or a 261 | third party) that supports equivalent copying facilities, provided you 262 | maintain clear directions next to the object code saying where to find the 263 | Corresponding Source. Regardless of what server hosts the Corresponding 264 | Source, you remain obligated to ensure that it is available for as long as 265 | needed to satisfy these requirements. 266 | - e) Convey the object code using peer-to-peer transmission, provided you 267 | inform other peers where the object code and Corresponding Source of the 268 | work are being offered to the general public at no charge under subsection 269 | 6d. 270 | 271 | A separable portion of the object code, whose source code is excluded from the 272 | Corresponding Source as a System Library, need not be included in conveying the 273 | object code work. 274 | 275 | A *User Product* is either 276 | 277 | 1. a *consumer product*, which means any tangible personal property which is 278 | normally used for personal, family, or household purposes, or 279 | 2. anything designed or sold for incorporation into a dwelling. 280 | 281 | In determining whether a product is a consumer product, doubtful cases shall be 282 | resolved in favor of coverage. For a particular product received by a 283 | particular user, *normally used* refers to a typical or common use of that 284 | class of product, regardless of the status of the particular user or of the way 285 | in which the particular user actually uses, or expects or is expected to use, 286 | the product. A product is a consumer product regardless of whether the product 287 | has substantial commercial, industrial or non-consumer uses, unless such uses 288 | represent the only significant mode of use of the product. 289 | 290 | *Installation Information* for a User Product means any methods, procedures, 291 | authorization keys, or other information required to install and execute 292 | modified versions of a covered work in that User Product from a modified 293 | version of its Corresponding Source. The information must suffice to ensure 294 | that the continued functioning of the modified object code is in no case 295 | prevented or interfered with solely because modification has been made. 296 | 297 | If you convey an object code work under this section in, or with, or 298 | specifically for use in, a User Product, and the conveying occurs as part of a 299 | transaction in which the right of possession and use of the User Product is 300 | transferred to the recipient in perpetuity or for a fixed term (regardless of 301 | how the transaction is characterized), the Corresponding Source conveyed under 302 | this section must be accompanied by the Installation Information. But this 303 | requirement does not apply if neither you nor any third party retains the 304 | ability to install modified object code on the User Product (for example, the 305 | work has been installed in ROM). 306 | 307 | The requirement to provide Installation Information does not include a 308 | requirement to continue to provide support service, warranty, or updates for a 309 | work that has been modified or installed by the recipient, or for the User 310 | Product in which it has been modified or installed. Access to a network may be 311 | denied when the modification itself materially and adversely affects the 312 | operation of the network or violates the rules and protocols for communication 313 | across the network. 314 | 315 | Corresponding Source conveyed, and Installation Information provided, in accord 316 | with this section must be in a format that is publicly documented (and with an 317 | implementation available to the public in source code form), and must require 318 | no special password or key for unpacking, reading or copying. 319 | 320 | ### 7. Additional Terms. 321 | 322 | *Additional permissions* are terms that supplement the terms of this License by 323 | making exceptions from one or more of its conditions. Additional permissions 324 | that are applicable to the entire Program shall be treated as though they were 325 | included in this License, to the extent that they are valid under applicable 326 | law. If additional permissions apply only to part of the Program, that part may 327 | be used separately under those permissions, but the entire Program remains 328 | governed by this License without regard to the additional permissions. 329 | 330 | When you convey a copy of a covered work, you may at your option remove any 331 | additional permissions from that copy, or from any part of it. (Additional 332 | permissions may be written to require their own removal in certain cases when 333 | you modify the work.) You may place additional permissions on material, added 334 | by you to a covered work, for which you have or can give appropriate copyright 335 | permission. 336 | 337 | Notwithstanding any other provision of this License, for material you add to a 338 | covered work, you may (if authorized by the copyright holders of that material) 339 | supplement the terms of this License with terms: 340 | 341 | - a) Disclaiming warranty or limiting liability differently from the terms of 342 | sections 15 and 16 of this License; or 343 | - b) Requiring preservation of specified reasonable legal notices or author 344 | attributions in that material or in the Appropriate Legal Notices displayed 345 | by works containing it; or 346 | - c) Prohibiting misrepresentation of the origin of that material, or 347 | requiring that modified versions of such material be marked in reasonable 348 | ways as different from the original version; or 349 | - d) Limiting the use for publicity purposes of names of licensors or authors 350 | of the material; or 351 | - e) Declining to grant rights under trademark law for use of some trade 352 | names, trademarks, or service marks; or 353 | - f) Requiring indemnification of licensors and authors of that material by 354 | anyone who conveys the material (or modified versions of it) with 355 | contractual assumptions of liability to the recipient, for any liability 356 | that these contractual assumptions directly impose on those licensors and 357 | authors. 358 | 359 | All other non-permissive additional terms are considered *further restrictions* 360 | within the meaning of section 10. If the Program as you received it, or any 361 | part of it, contains a notice stating that it is governed by this License along 362 | with a term that is a further restriction, you may remove that term. If a 363 | license document contains a further restriction but permits relicensing or 364 | conveying under this License, you may add to a covered work material governed 365 | by the terms of that license document, provided that the further restriction 366 | does not survive such relicensing or conveying. 367 | 368 | If you add terms to a covered work in accord with this section, you must place, 369 | in the relevant source files, a statement of the additional terms that apply to 370 | those files, or a notice indicating where to find the applicable terms. 371 | 372 | Additional terms, permissive or non-permissive, may be stated in the form of a 373 | separately written license, or stated as exceptions; the above requirements 374 | apply either way. 375 | 376 | ### 8. Termination. 377 | 378 | You may not propagate or modify a covered work except as expressly provided 379 | under this License. Any attempt otherwise to propagate or modify it is void, 380 | and will automatically terminate your rights under this License (including any 381 | patent licenses granted under the third paragraph of section 11). 382 | 383 | However, if you cease all violation of this License, then your license from a 384 | particular copyright holder is reinstated 385 | 386 | - a) provisionally, unless and until the copyright holder explicitly and 387 | finally terminates your license, and 388 | - b) permanently, if the copyright holder fails to notify you of the 389 | violation by some reasonable means prior to 60 days after the cessation. 390 | 391 | Moreover, your license from a particular copyright holder is reinstated 392 | permanently if the copyright holder notifies you of the violation by some 393 | reasonable means, this is the first time you have received notice of violation 394 | of this License (for any work) from that copyright holder, and you cure the 395 | violation prior to 30 days after your receipt of the notice. 396 | 397 | Termination of your rights under this section does not terminate the licenses 398 | of parties who have received copies or rights from you under this License. If 399 | your rights have been terminated and not permanently reinstated, you do not 400 | qualify to receive new licenses for the same material under section 10. 401 | 402 | ### 9. Acceptance Not Required for Having Copies. 403 | 404 | You are not required to accept this License in order to receive or run a copy 405 | of the Program. Ancillary propagation of a covered work occurring solely as a 406 | consequence of using peer-to-peer transmission to receive a copy likewise does 407 | not require acceptance. However, nothing other than this License grants you 408 | permission to propagate or modify any covered work. These actions infringe 409 | copyright if you do not accept this License. Therefore, by modifying or 410 | propagating a covered work, you indicate your acceptance of this License to do 411 | so. 412 | 413 | ### 10. Automatic Licensing of Downstream Recipients. 414 | 415 | Each time you convey a covered work, the recipient automatically receives a 416 | license from the original licensors, to run, modify and propagate that work, 417 | subject to this License. You are not responsible for enforcing compliance by 418 | third parties with this License. 419 | 420 | An *entity transaction* is a transaction transferring control of an 421 | organization, or substantially all assets of one, or subdividing an 422 | organization, or merging organizations. If propagation of a covered work 423 | results from an entity transaction, each party to that transaction who receives 424 | a copy of the work also receives whatever licenses to the work the party's 425 | predecessor in interest had or could give under the previous paragraph, plus a 426 | right to possession of the Corresponding Source of the work from the 427 | predecessor in interest, if the predecessor has it or can get it with 428 | reasonable efforts. 429 | 430 | You may not impose any further restrictions on the exercise of the rights 431 | granted or affirmed under this License. For example, you may not impose a 432 | license fee, royalty, or other charge for exercise of rights granted under this 433 | License, and you may not initiate litigation (including a cross-claim or 434 | counterclaim in a lawsuit) alleging that any patent claim is infringed by 435 | making, using, selling, offering for sale, or importing the Program or any 436 | portion of it. 437 | 438 | ### 11. Patents. 439 | 440 | A *contributor* is a copyright holder who authorizes use under this License of 441 | the Program or a work on which the Program is based. The work thus licensed is 442 | called the contributor's *contributor version*. 443 | 444 | A contributor's *essential patent claims* are all patent claims owned or 445 | controlled by the contributor, whether already acquired or hereafter acquired, 446 | that would be infringed by some manner, permitted by this License, of making, 447 | using, or selling its contributor version, but do not include claims that would 448 | be infringed only as a consequence of further modification of the contributor 449 | version. For purposes of this definition, *control* includes the right to grant 450 | patent sublicenses in a manner consistent with the requirements of this 451 | License. 452 | 453 | Each contributor grants you a non-exclusive, worldwide, royalty-free patent 454 | license under the contributor's essential patent claims, to make, use, sell, 455 | offer for sale, import and otherwise run, modify and propagate the contents of 456 | its contributor version. 457 | 458 | In the following three paragraphs, a *patent license* is any express agreement 459 | or commitment, however denominated, not to enforce a patent (such as an express 460 | permission to practice a patent or covenant not to sue for patent 461 | infringement). To *grant* such a patent license to a party means to make such 462 | an agreement or commitment not to enforce a patent against the party. 463 | 464 | If you convey a covered work, knowingly relying on a patent license, and the 465 | Corresponding Source of the work is not available for anyone to copy, free of 466 | charge and under the terms of this License, through a publicly available 467 | network server or other readily accessible means, then you must either 468 | 469 | 1. cause the Corresponding Source to be so available, or 470 | 2. arrange to deprive yourself of the benefit of the patent license for this 471 | particular work, or 472 | 3. arrange, in a manner consistent with the requirements of this License, to 473 | extend the patent license to downstream recipients. 474 | 475 | *Knowingly relying* means you have actual knowledge that, but for the patent 476 | license, your conveying the covered work in a country, or your recipient's use 477 | of the covered work in a country, would infringe one or more identifiable 478 | patents in that country that you have reason to believe are valid. 479 | 480 | If, pursuant to or in connection with a single transaction or arrangement, you 481 | convey, or propagate by procuring conveyance of, a covered work, and grant a 482 | patent license to some of the parties receiving the covered work authorizing 483 | them to use, propagate, modify or convey a specific copy of the covered work, 484 | then the patent license you grant is automatically extended to all recipients 485 | of the covered work and works based on it. 486 | 487 | A patent license is *discriminatory* if it does not include within the scope of 488 | its coverage, prohibits the exercise of, or is conditioned on the non-exercise 489 | of one or more of the rights that are specifically granted under this License. 490 | You may not convey a covered work if you are a party to an arrangement with a 491 | third party that is in the business of distributing software, under which you 492 | make payment to the third party based on the extent of your activity of 493 | conveying the work, and under which the third party grants, to any of the 494 | parties who would receive the covered work from you, a discriminatory patent 495 | license 496 | 497 | - a) in connection with copies of the covered work conveyed by you (or copies 498 | made from those copies), or 499 | - b) primarily for and in connection with specific products or compilations 500 | that contain the covered work, unless you entered into that arrangement, or 501 | that patent license was granted, prior to 28 March 2007. 502 | 503 | Nothing in this License shall be construed as excluding or limiting any implied 504 | license or other defenses to infringement that may otherwise be available to 505 | you under applicable patent law. 506 | 507 | ### 12. No Surrender of Others' Freedom. 508 | 509 | If conditions are imposed on you (whether by court order, agreement or 510 | otherwise) that contradict the conditions of this License, they do not excuse 511 | you from the conditions of this License. If you cannot convey a covered work so 512 | as to satisfy simultaneously your obligations under this License and any other 513 | pertinent obligations, then as a consequence you may not convey it at all. For 514 | example, if you agree to terms that obligate you to collect a royalty for 515 | further conveying from those to whom you convey the Program, the only way you 516 | could satisfy both those terms and this License would be to refrain entirely 517 | from conveying the Program. 518 | 519 | ### 13. Use with the GNU Affero General Public License. 520 | 521 | Notwithstanding any other provision of this License, you have permission to 522 | link or combine any covered work with a work licensed under version 3 of the 523 | GNU Affero General Public License into a single combined work, and to convey 524 | the resulting work. The terms of this License will continue to apply to the 525 | part which is the covered work, but the special requirements of the GNU Affero 526 | General Public License, section 13, concerning interaction through a network 527 | will apply to the combination as such. 528 | 529 | ### 14. Revised Versions of this License. 530 | 531 | The Free Software Foundation may publish revised and/or new versions of the GNU 532 | General Public License from time to time. Such new versions will be similar in 533 | spirit to the present version, but may differ in detail to address new problems 534 | or concerns. 535 | 536 | Each version is given a distinguishing version number. If the Program specifies 537 | that a certain numbered version of the GNU General Public License *or any later 538 | version* applies to it, you have the option of following the terms and 539 | conditions either of that numbered version or of any later version published by 540 | the Free Software Foundation. If the Program does not specify a version number 541 | of the GNU General Public License, you may choose any version ever published by 542 | the Free Software Foundation. 543 | 544 | If the Program specifies that a proxy can decide which future versions of the 545 | GNU General Public License can be used, that proxy's public statement of 546 | acceptance of a version permanently authorizes you to choose that version for 547 | the Program. 548 | 549 | Later license versions may give you additional or different permissions. 550 | However, no additional obligations are imposed on any author or copyright 551 | holder as a result of your choosing to follow a later version. 552 | 553 | ### 15. Disclaimer of Warranty. 554 | 555 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE 556 | LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER 557 | PARTIES PROVIDE THE PROGRAM *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER 558 | EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 559 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE 560 | QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE 561 | DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR 562 | CORRECTION. 563 | 564 | ### 16. Limitation of Liability. 565 | 566 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY 567 | COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS 568 | PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, 569 | INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE 570 | THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED 571 | INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE 572 | PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY 573 | HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 574 | 575 | ### 17. Interpretation of Sections 15 and 16. 576 | 577 | If the disclaimer of warranty and limitation of liability provided above cannot 578 | be given local legal effect according to their terms, reviewing courts shall 579 | apply local law that most closely approximates an absolute waiver of all civil 580 | liability in connection with the Program, unless a warranty or assumption of 581 | liability accompanies a copy of the Program in return for a fee. 582 | 583 | ## END OF TERMS AND CONDITIONS ### 584 | 585 | ### How to Apply These Terms to Your New Programs 586 | 587 | If you develop a new program, and you want it to be of the greatest possible 588 | use to the public, the best way to achieve this is to make it free software 589 | which everyone can redistribute and change under these terms. 590 | 591 | To do so, attach the following notices to the program. It is safest to attach 592 | them to the start of each source file to most effectively state the exclusion 593 | of warranty; and each file should have at least the *copyright* line and a 594 | pointer to where the full notice is found. 595 | 596 | 597 | Copyright (C) 598 | 599 | This program is free software: you can redistribute it and/or modify 600 | it under the terms of the GNU General Public License as published by 601 | the Free Software Foundation, either version 3 of the License, or 602 | (at your option) any later version. 603 | 604 | This program is distributed in the hope that it will be useful, 605 | but WITHOUT ANY WARRANTY; without even the implied warranty of 606 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 607 | GNU General Public License for more details. 608 | 609 | You should have received a copy of the GNU General Public License 610 | along with this program. If not, see . 611 | 612 | Also add information on how to contact you by electronic and paper mail. 613 | 614 | If the program does terminal interaction, make it output a short notice like 615 | this when it starts in an interactive mode: 616 | 617 | Copyright (C) 618 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 619 | This is free software, and you are welcome to redistribute it 620 | under certain conditions; type `show c' for details. 621 | 622 | The hypothetical commands `show w` and `show c` should show the appropriate 623 | parts of the General Public License. Of course, your program's commands might 624 | be different; for a GUI interface, you would use an *about box*. 625 | 626 | You should also get your employer (if you work as a programmer) or school, if 627 | any, to sign a *copyright disclaimer* for the program, if necessary. For more 628 | information on this, and how to apply and follow the GNU GPL, see 629 | [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/). 630 | 631 | The GNU General Public License does not permit incorporating your program into 632 | proprietary programs. If your program is a subroutine library, you may consider 633 | it more useful to permit linking proprietary applications with the library. If 634 | this is what you want to do, use the GNU Lesser General Public License instead 635 | of this License. But first, please read 636 | [http://www.gnu.org/philosophy/why-not-lgpl.html](http://www.gnu.org/philosophy/why-not-lgpl.html). 637 | --------------------------------------------------------------------------------