diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index e288e5d..8fa0858 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -229,6 +229,104 @@ jobs: path: /builder/youtubeUnblock*.ipk if-no-files-found: error + + build-openwrt-kmod: + needs: prepare + runs-on: ubuntu-latest + strategy: + matrix: + branch: + - openwrt-23.05 + - openwrt-22.03 + - openwrt-21.02 + - openwrt-19.07 + include: + - branch: openwrt-23.05 + wd_path: /builder + - branch: openwrt-22.03 + wd_path: /builder + - branch: openwrt-21.02 + wd_path: /builder + - branch: openwrt-19.07 + wd_path: /home/build/openwrt + arch: + - aarch64_cortex-a53 + - aarch64_cortex-a72 + - aarch64_generic + - arm_arm1176jzf-s_vfp + - arm_arm926ej-s + - arm_cortex-a15_neon-vfpv4 + - arm_cortex-a5_vfpv4 + - arm_cortex-a7 + - arm_cortex-a7_neon-vfpv4 + - arm_cortex-a7_vfpv4 + - arm_cortex-a8_vfpv3 + - arm_cortex-a9 + - arm_cortex-a9_neon + - arm_cortex-a9_vfpv3-d16 + - arm_fa526 + - arm_mpcore + - arm_xscale + - mips64_octeonplus + - mips_24kc + - mips_4kec + - mips_mips32 + - mipsel_24kc + - mipsel_24kc_24kf + - mipsel_74kc + - mipsel_mips32 + - ramips-mt76x8 + - x86_64 + exclude: + - branch: openwrt-19.07 + arch: arm_cortex-a7 + - branch: openwrt-19.07 + arch: mips_4kec + - branch: openwrt-19.07 + arch: ramips-mt76x8 + - branch: openwrt-19.07 + arch: arm_cortex-a7_vfpv4 + - branch: openwrt-21.02 + arch: arm_cortex-a7_vfpv4 + + container: + image: openwrt/sdk:${{ matrix.arch }}-${{ matrix.branch }} + options: --user root + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: 'openwrt' + + - name: Prepare build + env: + VERSION: ${{ needs.prepare.outputs.version }} + SHA: ${{ needs.prepare.outputs.sha }} + run: | + sed -i "s/PKG_REV:=.*$/PKG_REV:=$SHA/;s/PKG_VERSION:=.*$/PKG_VERSION:=$VERSION-$SHA/" kyoutubeUnblock/Makefile + - name: Build packages + id: build + env: + VERSION: ${{ needs.prepare.outputs.version }} + SHA: ${{ needs.prepare.outputs.sha }} + working-directory: ${{ matrix.wd_path }} + run: | + pwd + echo "src-link youtubeUnblock $GITHUB_WORKSPACE" >> feeds.conf + cat feeds.conf + ./scripts/feeds update youtubeUnblock + ./scripts/feeds install -a -p youtubeUnblock + make defconfig + make package/kyoutubeUnblock/compile V=s + cp $(find ./bin -type f -name 'kmod-youtubeUnblock*.ipk') ./ + - name: Upload packages + if: steps.build.outcome == 'success' + uses: actions/upload-artifact@v4 + with: + name: kmod-youtubeUnblock-${{ matrix.branch }}-${{ matrix.arch }} + path: ${{ matrix.wd_path }}/kmod-youtubeUnblock*.ipk + if-no-files-found: error + build-entware: needs: prepare runs-on: ubuntu-latest @@ -323,7 +421,7 @@ jobs: pre-release: if: github.event_name != 'pull_request' && github.ref_name == 'main' - needs: [build-static, build-static-cross, build-openwrt, build-entware] + needs: [build-static, build-static-cross, build-openwrt, build-entware, build-openwrt-kmod] permissions: contents: write runs-on: ubuntu-latest @@ -340,4 +438,5 @@ jobs: title: 'Development build' files: | ./**/youtubeUnblock*.ipk + ./**/kmod-youtubeUnblock*.ipk ./**/youtubeUnblock*.tar.gz diff --git a/Kbuild b/Kbuild index 28e0379..3962a79 100644 --- a/Kbuild +++ b/Kbuild @@ -1,3 +1,3 @@ obj-m := kyoutubeUnblock.o kyoutubeUnblock-objs := kytunblock.o mangle.o quic.o utils.o kmod_utils.o kargs.o -ccflags-y := -std=gnu11 -DKERNEL_SPACE -Wno-error -Wno-declaration-after-statement +ccflags-y := -std=gnu99 -DKERNEL_SPACE -Wno-error -Wno-declaration-after-statement diff --git a/kargs.c b/kargs.c index b355c6c..00ed9c0 100644 --- a/kargs.c +++ b/kargs.c @@ -89,7 +89,7 @@ static int inverse_boolean_get(char *buffer, const struct kernel_param *kp) { buffer[0] = '0'; } buffer[1] = '\0'; - return 0; + return strlen(buffer); } static const struct kernel_param_ops unumeric_parameter_ops = { @@ -212,4 +212,163 @@ static const struct kernel_param_ops verbose_trace_ops = { .set = verbose_trace_set, .get = param_get_int, }; + module_param_cb(trace, &verbose_trace_ops, &config.verbose, 0664); + +static int frag_strat_set(const char *val, const struct kernel_param *kp) { + size_t len; + + len = strnlen(val, STR_MAXLEN + 1); + if (len == STR_MAXLEN + 1) { + pr_err("%s: string parameter too long\n", kp->name); + return -ENOSPC; + } + + if (len >= 1 && val[len - 1] == '\n') { + len--; + } + + if (strncmp(val, "tcp", len) == 0) { + *(int *)kp->arg = FRAG_STRAT_TCP; + } else if (strncmp(val, "ip", len) == 0) { + *(int *)kp->arg = FRAG_STRAT_IP; + } else if (strncmp(val, "none", len) == 0) { + *(int *)kp->arg = FRAG_STRAT_NONE; + } else { + return -EINVAL; + } + + return 0; +} + +static int frag_strat_get(char *buffer, const struct kernel_param *kp) { + switch (*(int *)kp->arg) { + case FRAG_STRAT_TCP: + strcpy(buffer, "tcp\n"); + break; + case FRAG_STRAT_IP: + strcpy(buffer, "ip\n"); + break; + case FRAG_STRAT_NONE: + strcpy(buffer, "none\n"); + break; + default: + strcpy(buffer, "unknown\n"); + } + + return strlen(buffer); +} + +static const struct kernel_param_ops frag_strat_ops = { + .set = frag_strat_set, + .get = frag_strat_get, +}; + +module_param_cb(fragmentation_strategy, &frag_strat_ops, &config.fragmentation_strategy, 0664); + +static int fake_strat_set(const char *val, const struct kernel_param *kp) { + size_t len; + + len = strnlen(val, STR_MAXLEN + 1); + if (len == STR_MAXLEN + 1) { + pr_err("%s: string parameter too long\n", kp->name); + return -ENOSPC; + } + + if (len >= 1 && val[len - 1] == '\n') { + len--; + } + + if (strncmp(val, "randseq", len) == 0) { + *(int *)kp->arg = FAKE_STRAT_RAND_SEQ; + } else if (strncmp(val, "ttl", len) == 0) { + *(int *)kp->arg = FAKE_STRAT_TTL; + } else if (strncmp(val, "tcp_check", len) == 0) { + *(int *)kp->arg = FAKE_STRAT_TCP_CHECK; + } else if (strncmp(val, "pastseq", len) == 0) { + *(int *)kp->arg = FAKE_STRAT_PAST_SEQ; + } else if (strncmp(val, "md5sum", len) == 0) { + *(int *)kp->arg = FAKE_STRAT_TCP_MD5SUM; + } else { + return -EINVAL; + } + + return 0; +} + +static int fake_strat_get(char *buffer, const struct kernel_param *kp) { + switch (*(int *)kp->arg) { + case FAKE_STRAT_RAND_SEQ: + strcpy(buffer, "randseq\n"); + break; + case FAKE_STRAT_TTL: + strcpy(buffer, "ttl\n"); + break; + case FAKE_STRAT_TCP_CHECK: + strcpy(buffer, "tcp_check\n"); + break; + case FAKE_STRAT_PAST_SEQ: + strcpy(buffer, "pastseq\n"); + break; + case FAKE_STRAT_TCP_MD5SUM: + strcpy(buffer, "md5sum\n"); + break; + default: + strcpy(buffer, "unknown\n"); + } + + return strlen(buffer); +} + +static const struct kernel_param_ops fake_strat_ops = { + .set = fake_strat_set, + .get = fake_strat_get, +}; + +module_param_cb(faking_strategy, &fake_strat_ops, &config.faking_strategy, 0664); + +static int sni_detection_set(const char *val, const struct kernel_param *kp) { + size_t len; + + len = strnlen(val, STR_MAXLEN + 1); + if (len == STR_MAXLEN + 1) { + pr_err("%s: string parameter too long\n", kp->name); + return -ENOSPC; + } + + if (len >= 1 && val[len - 1] == '\n') { + len--; + } + + if (strncmp(val, "parse", len) == 0) { + *(int *)kp->arg = SNI_DETECTION_PARSE; + } else if (strncmp(val, "brute", len) == 0) { + *(int *)kp->arg = SNI_DETECTION_BRUTE; + } else { + return -EINVAL; + } + + return 0; +} + +static int sni_detection_get(char *buffer, const struct kernel_param *kp) { + switch (*(int *)kp->arg) { + case SNI_DETECTION_PARSE: + strcpy(buffer, "parse\n"); + break; + case SNI_DETECTION_BRUTE: + strcpy(buffer, "brute\n"); + break; + default: + strcpy(buffer, "unknown\n"); + } + + return strlen(buffer); +} + +static const struct kernel_param_ops sni_detection_ops = { + .set = sni_detection_set, + .get = sni_detection_get, +}; + +module_param_cb(sni_detection, &sni_detection_ops, &config.sni_detection, 0664); diff --git a/kmod_utils.c b/kmod_utils.c index 930f06d..2884e9a 100644 --- a/kmod_utils.c +++ b/kmod_utils.c @@ -32,8 +32,7 @@ int open_raw_socket(void) { rawsocket->sk->sk_mark=config.mark; return 0; -sr_err: - sock_release(rawsocket); + err: return ret; } @@ -63,9 +62,19 @@ static int send_raw_ipv4(const uint8_t *pkt, uint32_t pktlen) { struct msghdr msg; struct kvec iov; + + memset(&msg, 0, sizeof(msg)); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) iov.iov_base = (__u8 *)pkt; iov.iov_len = pktlen; iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, 1); +#else + iov.iov_base = (__u8 *)pkt; + iov.iov_len = pktlen; + // msg.msg_iov = (struct iovec *)&iov; + // msg.msg_iovlen = iov.iov_len; +#endif msg.msg_flags = 0; msg.msg_name = &daddr; @@ -73,6 +82,7 @@ static int send_raw_ipv4(const uint8_t *pkt, uint32_t pktlen) { msg.msg_control = NULL; msg.msg_controllen = 0; + ret = kernel_sendmsg(rawsocket, &msg, &iov, 1, pktlen); return ret; @@ -92,8 +102,7 @@ int open_raw6_socket(void) { raw6socket->sk->sk_mark=config.mark; return 0; -sr_err: - sock_release(raw6socket); + err: return ret; } @@ -120,11 +129,20 @@ int send_raw_ipv6(const uint8_t *pkt, uint32_t pktlen) { .sin6_addr = iph->ip6_dst }; - struct msghdr msg; struct kvec iov; + struct msghdr msg; + memset(&msg, 0, sizeof(msg)); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) iov.iov_base = (__u8 *)pkt; iov.iov_len = pktlen; iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, 1); +#else + iov.iov_base = (__u8 *)pkt; + iov.iov_len = pktlen; + // msg.msg_iov = (struct iovec *)&iov; + // msg.msg_iovlen = iov.iov_len; +#endif msg.msg_flags = 0; msg.msg_name = &daddr; diff --git a/kytunblock.c b/kytunblock.c index 2d6e8cf..b558ea7 100644 --- a/kytunblock.c +++ b/kytunblock.c @@ -1,3 +1,4 @@ +#include "nf_wrapper.h" #ifndef KERNEL_SPACE #error "You are trying to compile the kernel module not in the kernel space" #endif @@ -25,9 +26,7 @@ MODULE_VERSION("0.3.2"); MODULE_AUTHOR("Vadim Vetrov "); MODULE_DESCRIPTION("Linux kernel module for youtube unblock"); -static unsigned int ykb_nf_hook(void *priv, - struct sk_buff *skb, - const struct nf_hook_state *state) { +static NF_CALLBACK(ykb_nf_hook, skb) { int ret; if ((skb->mark & config.mark) == config.mark) diff --git a/nf_wrapper.h b/nf_wrapper.h new file mode 100644 index 0000000..2b4fc4b --- /dev/null +++ b/nf_wrapper.h @@ -0,0 +1,92 @@ +/** + * Thanks https://github.com/NICMx/Jool/blob/5f60dcda5944b01cc43c3be342aad26af8161bcb/include/nat64/mod/common/nf_wrapper.h for mapped kernel versions + */ +#ifndef _JOOL_MOD_NF_WRAPPER_H +#define _JOOL_MOD_NF_WRAPPER_H + +/** + * @file + * The kernel API is far from static. In particular, the Netfilter packet entry + * function keeps changing. nf_hook.c, the file where we declare our packet + * entry function, has been quite difficult to read for a while now. It's pretty + * amusing, because we don't even use any of the noisy arguments. + * + * This file declares a usable function header that abstracts away all those + * useless arguments. + */ + +#include + +/* If this is a Red Hat-based kernel (Red Hat, CentOS, Fedora, etc)... */ +#ifdef RHEL_RELEASE_CODE + +#if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7, 2) +#define NF_CALLBACK(name, skb) unsigned int name( \ + const struct nf_hook_ops *ops, \ + struct sk_buff *skb, \ + const struct net_device *in, \ + const struct net_device *out, \ + const struct nf_hook_state *state) \ + +#elif RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7, 0) +#define NF_CALLBACK(name, skb) unsigned int name( \ + const struct nf_hook_ops *ops, \ + struct sk_buff *skb, \ + const struct net_device *in, \ + const struct net_device *out, \ + int (*okfn)(struct sk_buff *)) + +#else + +/* + * Sorry, I don't have headers for RHEL 6 and below because I'm in a bit of a + * deadline right now. + * If this is causing you trouble, find `nf_hookfn` in your kernel headers + * (typically in include/linux/netfilter.h) and add your version of the + * NF_CALLBACK macro here. + * Also, kernel headers per version can be found here: http://vault.centos.org/ + */ +#error "Sorry; this version of RHEL is not supported because it's kind of old." + +#endif /* RHEL_RELEASE_CODE >= x */ + + +/* If this NOT a RedHat-based kernel (Ubuntu, Debian, SuSE, etc)... */ +#else + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) +#define NF_CALLBACK(name, skb) unsigned int name( \ + void *priv, \ + struct sk_buff *skb, \ + const struct nf_hook_state *state) + +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) +#define NF_CALLBACK(name, skb) unsigned int name( \ + const struct nf_hook_ops *ops, \ + struct sk_buff *skb, \ + const struct nf_hook_state *state) + +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) +#define NF_CALLBACK(name, skb) unsigned int name( \ + const struct nf_hook_ops *ops, \ + struct sk_buff *skb, \ + const struct net_device *in, \ + const struct net_device *out, \ + int (*okfn)(struct sk_buff *)) + +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) +#define NF_CALLBACK(name, skb) unsigned int name( \ + unsigned int hooknum, \ + struct sk_buff *skb, \ + const struct net_device *in, \ + const struct net_device *out, \ + int (*okfn)(struct sk_buff *)) + +#else +#error "Linux < 3.0 isn't supported at all." + +#endif /* LINUX_VERSION_CODE > n */ + +#endif /* RHEL or not RHEL */ + +#endif /* _JOOL_MOD_NF_WRAPPER_H */ diff --git a/utils.c b/utils.c index 8d16d63..19f14fa 100644 --- a/utils.c +++ b/utils.c @@ -506,8 +506,8 @@ int tcp_frag(const uint8_t *pkt, uint32_t buflen, uint32_t payload_offset, void z_function(const char *str, int *zbuf, size_t len) { zbuf[0] = len; - ssize_t lh = 0, rh = 1; - for (ssize_t i = 1; i < len; i++) { + int lh = 0, rh = 1; + for (int i = 1; i < (int)len; i++) { zbuf[i] = 0; if (i < rh) { zbuf[i] = min(zbuf[i - lh], rh - i);