diff --git a/iptk_YTUNBLOCK.c b/iptk_YTUNBLOCK.c index f14968f..6908732 100644 --- a/iptk_YTUNBLOCK.c +++ b/iptk_YTUNBLOCK.c @@ -66,10 +66,12 @@ MODULE_VERSION("0.3.2"); MODULE_AUTHOR("Vadim Vetrov "); MODULE_DESCRIPTION("Linux kernel module for youtube unblock"); -static int rsfd; static struct socket *rawsocket; DEFINE_MUTEX(rslock); +static struct socket *raw6socket; +DEFINE_MUTEX(rs6lock); + static int open_raw_socket(void) { int ret = 0; ret = sock_create(AF_INET, SOCK_RAW, IPPROTO_RAW, &rawsocket); @@ -144,6 +146,79 @@ static int send_raw_ipv4(const uint8_t *pkt, uint32_t pktlen) { return ret; } +static int open_raw6_socket(void) { + int ret = 0; + ret = sock_create(AF_INET6, SOCK_RAW, IPPROTO_RAW, &raw6socket); + + if (ret < 0) { + pr_alert("Unable to create raw socket\n"); + goto err; + } + + sockptr_t optval = { + .kernel = NULL, + .is_kernel = 1 + }; + + int mark = config.mark; + optval.kernel = &mark; + ret = sock_setsockopt(raw6socket, SOL_SOCKET, SO_MARK, optval, sizeof(mark)); + if (ret < 0) + { + pr_alert("setsockopt(SO_MARK, %d) failed\n", mark); + goto sr_err; + } + int one = 1; + optval.kernel = &one; + + return 0; +sr_err: + sock_release(raw6socket); +err: + return ret; +} + +static void close_raw6_socket(void) { + sock_release(raw6socket); +} + +static int send_raw_ipv6(const uint8_t *pkt, uint32_t pktlen) { + int ret = 0; + if (pktlen > AVAILABLE_MTU) return -ENOMEM; + + struct ip6_hdr *iph; + + if ((ret = ip6_payload_split( + (uint8_t *)pkt, pktlen, &iph, NULL, NULL, NULL)) < 0) { + return ret; + } + + struct sockaddr_in6 daddr = { + .sin6_family = AF_INET6, + /* Always 0 for raw socket */ + .sin6_port = 0, + .sin6_addr = iph->ip6_dst + }; + + struct msghdr msg; + struct kvec iov; + iov.iov_base = (__u8 *)pkt; + iov.iov_len = pktlen; + iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, 1); + + msg.msg_flags = 0; + msg.msg_name = &daddr; + msg.msg_namelen = sizeof(struct sockaddr_in6); + msg.msg_control = NULL; + msg.msg_controllen = 0; + + mutex_lock(&rs6lock); + ret = kernel_sendmsg(raw6socket, &msg, &iov, 1, pktlen); + mutex_unlock(&rs6lock); + + return ret; +} + static int send_raw_socket(const uint8_t *pkt, uint32_t pktlen) { int ret; @@ -213,8 +288,8 @@ erret_lc: if (ipvx == IP4VERSION) return send_raw_ipv4(pkt, pktlen); - // else if (ipvx == IP6VERSION) - // return send_raw_ipv6(pkt, pktlen); + else if (ipvx == IP6VERSION) + return send_raw_ipv6(pkt, pktlen); printf("proto version %d is unsupported\n", ipvx); return -EINVAL; @@ -286,17 +361,42 @@ static struct xt_target ykb_tg_reg __read_mostly = { .me = THIS_MODULE, }; +static struct xt_target ykb6_tg_reg __read_mostly = { + .name = "YTUNBLOCK", + .target = ykb_tg, + .table = "mangle", + .hooks = (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_FORWARD), + .targetsize = sizeof(struct xt_ytunblock_tginfo), + .proto = IPPROTO_TCP, + .family = NFPROTO_IPV6, + .checkentry = ykb_chk, + .me = THIS_MODULE, +}; + static int __init ykb_init(void) { int ret = 0; ret = open_raw_socket(); if (ret < 0) goto err; + if (config.use_ipv6) { + ret = open_raw6_socket(); + if (ret < 0) goto close_rawsocket; + + ret = xt_register_target(&ykb6_tg_reg); + if (ret < 0) goto close_raw6socket; + } + ret = xt_register_target(&ykb_tg_reg); - if (ret < 0) goto close_rawsocket; + if (ret < 0) goto close_xt6_target; pr_info("youtubeUnblock kernel module started.\n"); return 0; + +close_xt6_target: + if (config.use_ipv6) xt_unregister_target(&ykb6_tg_reg); +close_raw6socket: + if (config.use_ipv6) close_raw6_socket(); close_rawsocket: close_raw_socket(); err: @@ -305,6 +405,8 @@ err: static void __exit ykb_destroy(void) { xt_unregister_target(&ykb_tg_reg); + if (config.use_ipv6) xt_unregister_target(&ykb6_tg_reg); + if (config.use_ipv6) close_raw6_socket(); close_raw_socket(); pr_info("youtubeUnblock kernel module destroyed.\n"); } diff --git a/kmake.mk b/kmake.mk index 00e3f0f..8520c51 100644 --- a/kmake.mk +++ b/kmake.mk @@ -15,7 +15,7 @@ kmake: kmod xmod kmod: $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules -xmod: libipt_YTUNBLOCK.so +xmod: libipt_YTUNBLOCK.so libip6t_YTUNBLOCK.so libipt_YTUNBLOCK.so: libipt_YTUNBLOCK.o $(CCLD) -shared -fPIC ${IPT_CFLAGS} -o $@ $^; @@ -23,13 +23,21 @@ libipt_YTUNBLOCK.so: libipt_YTUNBLOCK.o libipt_YTUNBLOCK.o: libipt_YTUNBLOCK.c $(CC) ${IPT_CFLAGS} -D_INIT=lib$*_init -fPIC -c -o $@ $<; +libip6t_YTUNBLOCK.so: libip6t_YTUNBLOCK.o + $(CCLD) -shared -fPIC ${IPT_CFLAGS} -o $@ $^; + +libip6t_YTUNBLOCK.o: libip6t_YTUNBLOCK.c + $(CC) ${IPT_CFLAGS} -D_INIT=lib$*_init -fPIC -c -o $@ $<; + kload: insmod ipt_YTUNBLOCK.ko cp ./libipt_YTUNBLOCK.so /usr/lib/xtables/ + cp ./libip6t_YTUNBLOCK.so /usr/lib/xtables/ kunload: -rmmod ipt_YTUNBLOCK -/bin/rm /usr/lib/xtables/libipt_YTUNBLOCK.so + -/bin/rm /usr/lib/xtables/libip6t_YTUNBLOCK.so kreload: kunload kload diff --git a/libip6t_YTUNBLOCK.c b/libip6t_YTUNBLOCK.c new file mode 100644 index 0000000..f7d4d1d --- /dev/null +++ b/libip6t_YTUNBLOCK.c @@ -0,0 +1,26 @@ +// Used to register target in iptables +#include +#include + +#include +#include "ipt_YTUNBLOCK.h" + +#define _init __attribute__((constructor)) _INIT +#define __maybe_unused __attribute__((__unused__)) + +static void YTKB_help(void) { + printf("Youtube Unblock - bypass youtube slowdown DPI in Russia\n"); +} + +static struct xtables_target ykb6_tg_reg = { + .name = "YTUNBLOCK", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct xt_ytunblock_tginfo)), + .userspacesize = XT_ALIGN(sizeof(struct xt_ytunblock_tginfo)), + .help = YTKB_help, +}; + +void _init(void) { + xtables_register_target(&ykb6_tg_reg); +} diff --git a/utils.c b/utils.c index 8a2b2f8..1bbc6b2 100644 --- a/utils.c +++ b/utils.c @@ -37,7 +37,14 @@ void ip4_set_checksum(struct iphdr *iph) void tcp6_set_checksum(struct tcphdr *tcph, struct ip6_hdr *iph) { uint16_t old_check = ntohs(tcph->check); - // nfq_tcp_compute_checksum_ipv6(tcph, iph); +#ifdef KERNEL_SPACE + tcph->check = 0; + tcph->check = csum_ipv6_magic(&iph->saddr, &iph->daddr, + ntohs(iph->ip6_plen), IPPROTO_TCP, + csum_partial(tcph, ntohs(iph->ip6_plen), 0)); +#else + nfq_tcp_compute_checksum_ipv6(tcph, iph); +#endif } int set_ip_checksum(void *iph, uint32_t iphb_len) {