This commit is contained in:
github-actions[bot] 2021-03-24 10:33:12 +00:00
parent b045da7985
commit 1d42fd874d
275 changed files with 37797 additions and 39 deletions

View File

@ -0,0 +1,63 @@
#
# Copyright (C) 2014-2015 KyleRicardo
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=mentohust
PKG_VERSION:=0.3.1
PKG_RELEASE:=1
PKG_FIXUP:=autoreconf
PKG_INSTALL:=1
include $(INCLUDE_DIR)/package.mk
define Package/mentohust
SECTION:=net
CATEGORY:=Network
DEPENDS:=+libpcap
TITLE:=A Ruijie Client Daemon
URL:=https://github.com/KyleRicardo/MentoHUST-OpenWrt-ipk.git
SUBMENU:=Ruijie
endef
define Package/mentohust/description
A Ruijie Client Daemon,
Most usually used in China collages.
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
$(SED) 's/dhclient/udhcpc -i/g' $(PKG_BUILD_DIR)/myconfig.c
endef
define Package/mentohust/conffiles
/etc/mentohust.conf
endef
define Build/Compile
#$(Build/Compile/$(PKG_NAME))
$(MAKE) -C $(PKG_BUILD_DIR)/ \
$(TARGET_CONFIGURE_OPTS) \
CFLAGS="$(TARGET_CFLAGS)" \
CPPFLAGS="$(TARGET_CPPFLAGS)" \
LDFLAGS="$(TARGET_LDFLAGS) -ldl"
endef
define Package/mentohust/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/mentohust $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/etc
$(INSTALL_CONF) $(PKG_BUILD_DIR)/mentohust.conf $(1)/etc/mentohust.conf
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@ -0,0 +1,276 @@
# MentoHUST-OpenWrt-ipk
这是一个积累了很长时间的项目。从2014年起就陆续在折腾这些东西期间还自己写了一个基于OpenWrt的神州数码客户端[802.1X Evasi0n](https://github.com/KyleRicardo/802.1X-Evasi0n)服役了大半年的时间表现良好内存占用小工作效率高。后来学校所有神州数码服务器全部换成了锐捷导致我的项目失去了光彩我又翻出了大名鼎鼎的MentoHUST在反复折腾交叉编译和功能性修补过程中有了这样一个版本。该版本非常适合于在OpenWrt的SDK环境下编译出MentoHUST的ipk包。
## 特点
- 修复了原MentoHUST在shell下由于libiconv库编译或工作不正常导致的反馈信息乱码问题
- 去除了libiconv库的依赖加入了轻量级的strnormalize库GBK to UTF-8转换良好
- 去除configure等冗余文件仅保留核心src源码文件
- ./src/Makefile中使用通配符`*`指代libpcap版本通用性更强
- 无需手动配置环境变量无需使用automake和configure生成所需Makefile
- 重新完全手动编写./和./src/目录下的Makefile保证编译的有效性
- 无`--disable-notify --disable-encodepass`等配置,保证原汁原味
- 无手动`#define NO_DYLOAD`补丁使用动态加载库函数ipk包更小并且更容易编译
## PreOperation
### 预备知识
> 这里的编译是指交叉编译。所谓交叉编译,简单地说,就是在一个平台上生成另一个平台上的可执行代码。这里需要注意的是所谓 平台实际上包含两个概念体系结构Architecture、操作系统Operating System。同一个体系结构可以运行不同的操作系统同样同一个操作系统也可以在不同的体系结构上运行。
> 交叉编译通常是不得已而为之,有时是因为目的平台上不允许或不能够安装我们所需要的编译器,而我们又需要这个编译器的某些特征;有时是因为目的平台上的资源贫乏,无法运行我们所需要编译器;有时又是因为目的平台还没有建立,连操作系统都没有,根本谈不上运行什么编译器。
> OpenWrt系统是基于Linux平台的操作系统故我们需要用到Linux的操作系统平台进行交叉编译。但由于种种原因我们的电脑不可能使用Linux操作系统但又要交叉编译怎么办呢这时候就需要用到虚拟机了。
### 需要的工具
- VMWare Workstation虚拟机工具
- 一个Ubuntu Linux镜像版本无所谓笔者用的是15.04版本 x86
- OpenWrt SDK**不建议**自行从网上下载建议直接在Ubuntu中用git clone
- 本项目的源码
### 虚拟机的安装Tips
关于虚拟机在这里不多赘述仅提供一些Tips。如果对虚拟机完全不了解建议不要继续观看本教程先找百度谷歌充充电。
- 推荐新手使用**Ubuntu**
> 虚拟机的Linux系统推荐使用Ubuntu对于我们新手来说这无疑是最适合于我们的系统图形化的界面很贴心基本操作上和Windows相差不大可以较快的熟悉起来。
- 务必安装VMWare Tools工具
> 使用VMWare Workstation装Ubuntu的时候千万不要选择简易安装这样在后面安装VMware Tools会非常麻烦。先建立一个空虚拟机然后再用镜像引导安装这样就比较好系统安装好了之后再安装上VMWare Tools你会发现这个Tools有多么方便。其中最大的好处有二系统分辨率的自动调整和剪贴板的无缝连接。就是说不管文字或者文件你在windows里面使用Ctrl+C复制后可以直接在Ubuntu里面粘贴反之亦然。这在后面将给我们提供非常大的方便。所以VMWare Tools必须安装切记。
- 务必关闭Ubuntu系统屏保
> 还有一点需要提醒的是安装好后在右上角“系统”菜单的“首选项”中选择“屏幕保护程序”然后去掉左下角的“计算机空闲时激活屏幕保护程序”然后按“关闭”这个窗口是没有“应用”或“确定”之类的直接关闭它就会保存。用惯了WINDOWS的用户注意了。为什么要做这步呢因为整个编译过程中有些步骤要等一段时间的老是自动启用屏幕保护程序然后还要重新输密码才能退出也是麻烦事。开始的时候我忘了设置这一步后来有一次把黑屏状态的虚拟机唤醒的时候显卡瞬间崩溃了虚拟机直接死机然后编译了好久的数据丢失了白白浪费了几个小时。这个教训也希望大家引起重视。
## PreCompile
现在进入正题了首先要做的是配置好SDK的交叉编译环境。
### 获取OpenWrt SDK
首先安装 subversion 和 git两个应用广泛的源代码管理方案在此需要这两个工具下载源代码也就是`svn`和`git`命令。其方法如下:
使用`Ctrl+Alt+T`组合快捷键打开终端然后在左侧的Dock中右键单击将其锁定方便以后打开。如下图
![terminal](https://ws1.sinaimg.cn/large/8832d37agy1fxkp9lt8qbj215p0q8adn.jpg)打开终端后,在其中输入如下命令:
```
$ sudo apt-get update
$ sudo apt-get install git
```
其中,`sudo`是linux系统管理指令是允许系统管理员让普通用户执行一些或者全部的root命令的一个工具如`halt``reboot``su`等等。这样不仅减少了root用户的登录和管理时间同样也提高了安全性。sudo不是对shell的一个代替它是面向每个命令的。
`apt-get`是一条linux命令适用于deb包管理式的操作系统主要用于自动从互联网的软件仓库中搜索、安装、升级、卸载软件或操作系统。其简写为`apt`。
这两条命令执行后,我们就可以用`git`命令获取所需要的源代码了。
但是,编译源代码还有一些必须的工具和依赖,在这里我们一并安上,这种东西不怕安多了,就怕安少了。执行如下命令:
```bash
$ sudo apt install curl build-essential libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc libxml-parser-perl mercurial bzr ecj cvs unzip
```
下面就是来获取trunk版本的SDK了执行命令
```bash
$ git clone https://git.openwrt.org/openwrt/openwrt.git
```
cd到我们的SDK目录下这就是OpenWrt开发环境的根目录。后面几乎所有的操作都是在这个目录下进行
```bash
$ cd openwrt/
```
可以利用Ubuntu的自动填充就是输入`cd op`然后按一下Tab键就会自动填充为上面的命令。记住这一点以后会经常用到熟练使用自动填充会节约不少时间。
### 更新feeds
Feeds也就是软件包列表是在OpenWrt中共用位置的包的集合。运行以下命令即可更新内置软件包列表并链接到编译工具中
```
$ ./scripts/feeds update
$ ./scripts/feeds install
```
如果网速不快可能需要等待一段时间。静待其完成后我们的feeds就被更新了。
从github上下载我已经开源的evasi0n软件包。
将我们的evasi0n文件夹直接放入trunk/package/目录下即可。
### 添加需要编译的第三方软件包也就是我们的MentoHUST-OpenWrt-ipk指定目标架构
首先要在GitHub上clone此repo至package/mentohust目录下。执行命令
```bash
$ git clone https://github.com/KyleRicardo/MentoHUST-OpenWrt-ipk.git package/mentohust
```
这里说一下我的Makefile。
一个工程中的源文件不计其数其按类型、功能、模块分别放在若干个目录中Makefile定义了一系列的规则来指定哪些文件需要先编译哪些文件需要后编译哪些文件需要重新编译甚至于进行更复杂的功能操作因为 Makefile就像一个Shell脚本一样其中也可以执行操作系统的命令。
Makefile的语法规则并不算复杂但是新手研究起来也很头大也不能静下心来去花时间学习Makefile的写法。我虽然起初不会写Makefile但是折腾了这么久之后对于一个Makefile已经不算什么了。于是github上包含了我写的Makefile同学们可以直接编译。下个版本可能会发布自动从网上下载源码并编译的Makefile。
原始的mentohust编码转换是使用的libiconv库这个库问题特别多效率低不方便编译受802.1X Evasi0n项目的启发我干脆摒弃了libiconv库使用了strnormalize这个文件代替了它一次性解决了编码转换问题。所以现在Makefile里面再也找不到iconv的依赖了现在mentohust唯一依赖的库就是libpcap编译起来也是相当轻松了。
Makefile既然已经包括在源码中那么我们可以开始配置我们的编译器了。使用命令
```
$ make menuconfig
```
这个命令会启用图形化的选项,我们在其中进行调节即可。
我们一共要调整三个选项:
> Target System
> Subtarget
> Target Profile
对于极壹,调整好后应该如下图所示:
![HiWiFi](https://ws1.sinaimg.cn/large/8832d37agy1fxkpauo1zyj215p0q8wk7.jpg)
对于小米Mini调整好应该如下图所示
![XiaoMi Mini](https://wx4.sinaimg.cn/large/8832d37agy1fxkpbdkdezj215p0q8teh.jpg)
下面一步,就是把我们要编译的软件包含进去。
在Makefile里面我们已经知道这个软件包是属于Network里的Ruijie所以我们在主菜单中找到Network回车进入然后找到Ruijie这一项
![Ruijie](https://ws3.sinaimg.cn/large/8832d37agy1fxkpcgym9xj215p0q8afx.jpg)
然后到这里
![mentohust](https://ws2.sinaimg.cn/large/8832d37agy1fxkpcox4yvj215p0q8tcv.jpg)
这里不要按Y选中Y选中是将其编译到固件中去我们在这里不是要编译固件而是要神州数码单独作为一个软件编译出来。所以我们按M键选中将其编译为一个组件模块(Module)。
用M键选中后我们用光标键右几次选中Save保存后再多次Exit最终退出这个界面。
### 更新编译必需工具与工具链(编译依赖)
这一步是从官网上获取我们编译所需的工具(如编译器、链接器等),十分关键。不过,命令却十分简单:
```
$ make tools/install
```
即可编译并安装好我们所需的工具。
```
$ make toolchain/install
```
即可编译并安装好我们所需的工具链。
为了显示编译过程我们可以在命令后面加上一个选项V=s。即
```
$ make tools/install V=s
$ make toolchain/install V=s
```
注意V一定要大写。
不幸的是我发现Tools和Toolchain的编译十分漫长等待过程十分痛苦。这是因为需要从网上下载大量的文件而这些镜像源都不是特别好。为了减少等待的时间不妨给大家分享一个小技巧。通过研究编译的过程我发现所需的文件是下载并保存到openwrt目录的dl文件夹下的。通过实验我发现这个dl文件夹可以移植只要我们的OpenWrt SDK的版本是差不多的我们可以直接将已经弄好的dl文件夹放在openwrt目录中这样可以节省大量时间。编译所需的dl文件夹我均已打包上传请自行下载。
[------------百度网盘------------](https://pan.baidu.com/s/1acyd1aAr-QLtWQmy58eZ-g)
下载后提取压缩包到openwrt 目录,然后可以删掉该压缩包。
同样地不建议直接将形如http://downloads.openwrt.org/snapshots/trunk/ramips/OpenWrt-Toolchain-ramips-for-mipsel_24kec%2bdsp-gcc-4.8-linaro_uClibc-0.9.33.2.tar.bz2的这种文件解压后直接应用于我们的toolchain因为省略了编译安装过程后面可能会发生意想不到的错误。dl文件夹我已经提供给大家Toolchain的编译已经不需要太长时间。不要因小失大。
## Compile
```bash
$ make package/mentohust/compile V=s
```
如果顺利,编译完成之后就能在`openwrt/bin/packages/YourArchitecture/base`中找到你的ipk包了。还包含其依赖的libpcap.ipk。如果你的路由器默认没有安装libpcap包可以一并安装。
![compiled-ipk](https://wx1.sinaimg.cn/large/8832d37agy1fxksnqln5bj215p0q8n5j.jpg)
## Install
将上面拷贝出来的mentohust及libpcap的ipk用上面的方法利用WinSCP上传到路由器的tmp目录。这个操作很简单这里不再赘述。
使用快捷键`Ctrl+P`打开PuTTY输入密码(默认是admin)回车后,来到如下界面:
![pandorabox](https://ws3.sinaimg.cn/large/8832d37agy1fxkpeg7eg2j20ir0btjrj.jpg)
然后我们先`cd /tmp/`
然后用`opkg`命令安装我们所需的软件包:
```
opkg install libpcap_1.7.4-1_ramips_24kec.ipk
opkg install mentohust_0.3.1-1_ramips_24kec.ipk
```
这时有可能会出现这种情况:
![arch-mismatch](https://ws4.sinaimg.cn/large/8832d37agy1fxkpfctgj9j20ir0btmxg.jpg)
遇到这种错误,需要修改/etc/opkg.conf文件对于小米Mini需要在其尾部追加
```
arch all 1
arch ralink 200
arch ramips_24kec 100
```
这样就能正确地安装了:
![libpcap](https://wx3.sinaimg.cn/large/8832d37agy1fxkpfyu41kj20ua0jgdgv.jpg)
当然mentohust也可以了
![mentohust](https://ws4.sinaimg.cn/large/8832d37agy1fxkpg99g6zj20ir0btmxg.jpg)
在有些比较老的路由器固件中安装,会有类似这样的错误:
> //usr/lib/opkg/info/mentohust: line 4: default_postinst: not found
> Collected errors:
>
> pkg_run_script: package "mentohust" postinst script returned status 127.
> opkg_configure: dnsmasq-full.postinst returned 127.
上述错误原因如下:
因为evasi0n是基于 trunk 代码编译所以目前编译出的ipk 包默认带有
Package/postinst 脚本
```
#!/bin/sh
[ "${IPKG_NO_SCRIPT}" = "1" ] && exit 0
. ${IPKG_INSTROOT}/lib/functions.sh
default_postinst$0 $@
```
Package/prerm 脚本
```
#!/bin/sh
. ${IPKG_INSTROOT}/lib/functions.sh
default_prerm $0$@
```
而若不是最新编译的固件, /lib/functions.sh 中是没有 default_postinst default_prerm函数的所以会造成 127错误。
临时解决办法:
在PuTTY中键入如下命令并回车
`echo -e "\ndefault_postinst() {\n\treturn0\n}\ndefault_prerm() {\n\treturn 0\n}" >> /lib/functions.sh`
注意这是一条命令是用echo命令将这段空函数追加到functions.sh文件尾部。
上述错误解决之后终于可以愉快地安装mentohust了。
## Usage
安装好后可以立即使用,配置文件在`/etc/mentohust.conf`,可以自行编辑。
关于mentohust的用法想必不用我多说吧。我都已经帮忙帮到这一步了。这里提一下mentohust未能智能识别路由器WAN口对应的网卡请手动在mentohust.conf的末尾DHCP脚本中添加自己WAN口对应的网卡。最终脚本类似`udhcpc -i eth1`。
最后可以将mentohust添加到开机启动怎么弄不用我多说了吧。
## 已知问题
- mentohust未能智能识别路由器WAN口对应的网卡请手动在mentohust.conf的末尾DHCP脚本中添加自己WAN口对应的网卡。最终脚本类似`udhcpc -i eth1`
- 暂未加入init.d目录的mentohust脚本可能下个版本加入。
- 后续可能加入只有一个Makefile通过自动从git下载源码进行编译的版本

View File

@ -0,0 +1,46 @@
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/package.mk
CC = mips-openwrt-linux-gcc
CFLAGS = -Wall -g -O2
INC_DIR= $(STAGING_DIR)/usr/include -I$(BUILD_DIR)/libpcap-*/ipkg-install/usr/include
LINK_DIR= $(STAGING_DIR)/usr/lib -L$(BUILD_DIR)/libpcap-*/ipkg-install/usr/lib
LIBS= $(BUILD_DIR)/libpcap-*/ipkg-install/usr/lib/libpcap.a
OBJ = mentohust.o dlfunc.o md5.o mycheck.o myconfig.o myfunc.o strnormalize.o myini.o mystate.o
.PHONY: all
all: mentohust
mentohust: $(OBJ)
$(CC) $(CFLAGS) -o $@ $(OBJ) $(LIBS) -I$(INC_DIR) -L$(LINK_DIR) $(LDFLAGS)
mentohust.o : mentohust.c
$(CC) $(CFLAGS) -c $< -I$(INC_DIR)
dlfunc.o : dlfunc.c
$(CC) $(CFLAGS) -c $< -I$(INC_DIR)
md5.o : md5.c md5.h
$(CC) $(CFLAGS) -c $< -I$(INC_DIR)
strnormalize.o: strnormalize.c strnormalize.h
$(CC) $(CFLAGS) -c $< -I$(INC_DIR)
mycheck.o : mycheck.c
$(CC) $(CFLAGS) -c $< -I$(INC_DIR)
myconfig.o : myconfig.c
$(CC) $(CFLAGS) -c $< -I$(INC_DIR)
myfunc.o : myfunc.c
$(CC) $(CFLAGS) -c $< -I$(INC_DIR)
myini.o : myini.c
$(CC) $(CFLAGS) -c $< -I$(INC_DIR)
mystate.o : mystate.c
$(CC) $(CFLAGS) -c $< -I$(INC_DIR)
clean :
rm -v $(OBJ) mentohust

View File

@ -0,0 +1,153 @@
/* -*- Mode: C; tab-width: 4; -*- */
/*
* Copyright (C) 2009, HustMoon Studio
*
* dlfunc.c
*
* HustMoon@BYHH
* www.ehust@gmail.com
* 2009.11.11
*/
#include "dlfunc.h"
#ifndef NO_DYLOAD
#include <dlfcn.h>
int (*pcap_findalldevs)(pcap_if_t **, char *);
void (*pcap_freealldevs)(pcap_if_t *);
pcap_t *(*pcap_open_live)(const char *, int, int, int, char *);
int (*pcap_compile)(pcap_t *, struct bpf_program *, const char *, int, bpf_u_int32);
int (*pcap_setfilter)(pcap_t *, struct bpf_program *);
char *(*pcap_geterr)(pcap_t *);
void (*pcap_freecode)(struct bpf_program *);
int (*pcap_loop)(pcap_t *, int, pcap_handler, unsigned char *);
void (*pcap_close)(pcap_t *);
void (*pcap_breakloop)(pcap_t *);
int (*pcap_sendpacket)(pcap_t *, const unsigned char *, int);
static void *libpcap = NULL;
int load_libpcap(void) {
char *error;
#ifdef MAC_OS
char *file[] = {"libpcap.dylib", "libpcap.A.dylib"};
int i, count = 2;
#else
char *file[] = {"libpcap.so", "libpcap.so.1", "libpcap.so.1.0", "libpcap.so.0.9", "libpcap.so.0.8"};
int i, count = 5;
#endif
for (i=0; i<count && !libpcap; i++) {
libpcap = dlopen(file[i], RTLD_LAZY);
error = dlerror();
}
if (libpcap == NULL) {
printf("!! 打开libpcap失败请检查是否已安装该库文件。\n");
return -1;
}
if ((pcap_findalldevs = dlsym(libpcap, "pcap_findalldevs"), error = dlerror()) != NULL
|| (pcap_freealldevs = dlsym(libpcap, "pcap_freealldevs"), error = dlerror()) != NULL
|| (pcap_open_live = dlsym(libpcap, "pcap_open_live"), error = dlerror()) != NULL
|| (pcap_compile = dlsym(libpcap, "pcap_compile"), error = dlerror()) != NULL
|| (pcap_setfilter = dlsym(libpcap, "pcap_setfilter"), error = dlerror()) != NULL
|| (pcap_geterr = dlsym(libpcap, "pcap_geterr"), error = dlerror()) != NULL
|| (pcap_freecode = dlsym(libpcap, "pcap_freecode"), error = dlerror()) != NULL
|| (pcap_loop = dlsym(libpcap, "pcap_loop"), error = dlerror()) != NULL
|| (pcap_close = dlsym(libpcap, "pcap_close"), error = dlerror()) != NULL
|| (pcap_breakloop = dlsym(libpcap, "pcap_breakloop"), error = dlerror()) != NULL
|| (pcap_sendpacket = dlsym(libpcap, "pcap_sendpacket"), error = dlerror()) != NULL) {
printf("!! 从libpcap获取函数失败: %s\n", error);
free_libpcap();
return -1;
}
return 0;
}
void free_libpcap(void) {
if (libpcap) {
dlclose(libpcap);
dlerror();
libpcap = NULL;
}
}
#endif /* NO_DYLOAD */
#ifndef NO_NOTIFY
#include <dlfcn.h>
typedef void NotifyNotification, GtkWidget, GError;
typedef char gchar;
typedef int gint, gboolean;
static gboolean (*notify_notification_update)(NotifyNotification *, const gchar *,
const gchar *, const gchar *);
static void (*notify_notification_set_timeout)(NotifyNotification *, gint);
static gboolean (*notify_notification_show)(NotifyNotification *, GError **);
static void *libnotify = NULL;
static NotifyNotification *notify = NULL;
int load_libnotify(void) {
char *error;
gboolean (*notify_init)(const char *);
NotifyNotification *(*notify_notification_new)(const gchar *, const gchar *,
const gchar *, GtkWidget *);
#ifdef MAC_OS
char *file[] = {"libnotify.dylib", "libnotify.1.dylib"};
int i, count = 2;
#else
char *file[] = {"libnotify.so", "libnotify.so.1"};
int i, count = 2;
#endif
for (i=0; i<count && !libnotify; i++) {
libnotify = dlopen(file[i], RTLD_LAZY);
error = dlerror();
}
if (libnotify == NULL) {
printf("!! 打开libnotify失败请检查是否已安装该库文件。\n");
return -1;
}
if ((notify_init = dlsym(libnotify, "notify_init"), error = dlerror()) != NULL
|| (notify_notification_new = dlsym(libnotify, "notify_notification_new"), error = dlerror()) != NULL
|| (notify_notification_show = dlsym(libnotify, "notify_notification_show"), error = dlerror()) != NULL
|| (notify_notification_update = dlsym(libnotify, "notify_notification_update"), error = dlerror()) != NULL
|| (notify_notification_set_timeout = dlsym(libnotify, "notify_notification_set_timeout"), error = dlerror()) != NULL) {
printf("!! 从libnotify获取函数失败: %s\n", error);
free_libnotify();
return -1;
}
if (!notify_init("mentohust")) {
printf("!! 初始化libnotify失败。\n");
free_libnotify();
return -1;
}
notify = notify_notification_new("MentoHUST", NULL, NULL, NULL);
return 0;
}
void free_libnotify(void) {
void (*notify_uninit)(void);
if (notify) {
notify_uninit = dlsym(libnotify, "notify_uninit");
if (!dlerror())
notify_uninit();
notify = NULL;
}
if (libnotify) {
dlclose(libnotify);
dlerror();
libnotify = NULL;
}
}
void set_timeout(int timeout) {
notify_notification_set_timeout(notify, timeout);
}
void show_notify(const char *summary, char *body) {
notify_notification_update(notify, summary, body, NULL);
notify_notification_show(notify, NULL);
}
#endif /* NO_NOTIFY */

View File

@ -0,0 +1,77 @@
/* -*- Mode: C; tab-width: 4; -*- */
/*
* dlfunc.h
*
*/
#ifndef HUSTMOON_DLFUNC_H
#define HUSTMOON_DLFUNC_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <sys/time.h>
#define PCAP_ERRBUF_SIZE 256
#define PCAP_IF_LOOPBACK 0x00000001
typedef unsigned int bpf_u_int32;
typedef void pcap_t;
typedef struct pcap_if {
struct pcap_if *next;
char *name;
char *description;
void *addresses;
bpf_u_int32 flags;
}pcap_if_t;
struct bpf_program {
unsigned int bf_len;
void *bf_insns;
};
struct pcap_pkthdr {
struct timeval ts;
bpf_u_int32 caplen;
bpf_u_int32 len;
};
typedef void (*pcap_handler)(unsigned char *, const struct pcap_pkthdr *, const unsigned char *);
#ifdef NO_DYLOAD
int pcap_findalldevs(pcap_if_t **, char *);
void pcap_freealldevs(pcap_if_t *);
pcap_t *pcap_open_live(const char *, int, int, int, char *);
int pcap_compile(pcap_t *, struct bpf_program *, const char *, int, bpf_u_int32);
int pcap_setfilter(pcap_t *, struct bpf_program *);
char *pcap_geterr(pcap_t *);
void pcap_freecode(struct bpf_program *);
int pcap_loop(pcap_t *, int, pcap_handler, unsigned char *);
void pcap_close(pcap_t *);
void pcap_breakloop(pcap_t *);
int pcap_sendpacket(pcap_t *, const unsigned char *, int);
#else
extern int (*pcap_findalldevs)(pcap_if_t **, char *);
extern void (*pcap_freealldevs)(pcap_if_t *);
extern pcap_t *(*pcap_open_live)(const char *, int, int, int, char *);
extern int (*pcap_compile)(pcap_t *, struct bpf_program *, const char *, int, bpf_u_int32);
extern int (*pcap_setfilter)(pcap_t *, struct bpf_program *);
extern char *(*pcap_geterr)(pcap_t *);
extern void (*pcap_freecode)(struct bpf_program *);
extern int (*pcap_loop)(pcap_t *, int, pcap_handler, unsigned char *);
extern void (*pcap_close)(pcap_t *);
extern void (*pcap_breakloop)(pcap_t *);
extern int (*pcap_sendpacket)(pcap_t *, const unsigned char *, int);
int load_libpcap(void); /* 载入libpcap.so */
void free_libpcap(void); /* 释放libpcap.so */
#endif /* NO_DYLOAD */
#ifndef NO_NOTIFY
int load_libnotify(void); /* 载入libnotify.so */
void free_libnotify(void); /* 释放libnotify.so */
void set_timeout(int timeout); /* 设置超时间隔 */
void show_notify(const char *summary, char *body); /* 显示通知:概要、正文 */
#endif /* NO_NOTIFY */
#endif /* HUSTMOON_DLFUNC_H */

View File

@ -0,0 +1,297 @@
/* MD5.c - an implementation of md5 algorithm */
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#include "md5.h"
#include <string.h>
/* Constants for MD5Transform routine. */
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
static void MD5Transform(UINT4 [4], UCHAR [64]);
static void Encode(UCHAR *, UINT4 *, UINT4);
static void Decode(UINT4 *, UCHAR *, UINT4);
static UCHAR PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
void MD5Init (MD5_CTX * context)
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/* MD5 block update operation. Continues an MD5 message-digest
operation, processing another message block, and updating the
context.
*/
void MD5Update (MD5_CTX *context, UCHAR *input, UINT4 inputLen)
{
UINT4 i, index, partLen;
/* Compute number of bytes mod 64 */
index = (UINT4)((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UINT4)inputLen << 3))
< ((UINT4)inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible.
*/
if (inputLen >= partLen) {
memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);
MD5Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (context->state, &input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
memcpy((POINTER)&context->buffer[index], (POINTER)&input[i],inputLen-i);
}
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
void MD5Final (UCHAR digest[16], MD5_CTX *context)
{
UCHAR bits[8];
UINT4 index, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/* Pad out to 56 mod 64.
*/
index = (UINT4)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update (context, PADDING, padLen);
/* Append length (before padding) */
MD5Update (context, bits, 8);
/* Store state in digest */
Encode (digest, context->state, 16);
/* Zeroize sensitive information.
*/
memset ((POINTER)context, 0, sizeof (*context));
}
/* MD5 basic transformation. Transforms state based on block.
*/
static void MD5Transform (UINT4 state[4],UCHAR block[64])
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information.
*/
memset ((POINTER)x, 0, sizeof (x));
}
/* Encodes input (UINT4) into output (UCHAR). Assumes len is
a multiple of 4.
*/
static void Encode (UCHAR *output, UINT4 *input, UINT4 len)
{
UINT4 i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (UCHAR)(input[i] & 0xff);
output[j+1] = (UCHAR)((input[i] >> 8) & 0xff);
output[j+2] = (UCHAR)((input[i] >> 16) & 0xff);
output[j+3] = (UCHAR)((input[i] >> 24) & 0xff);
}
}
/* Decodes input (UCHAR) into output (UINT4). Assumes len is
a multiple of 4.
*/
static void Decode (UINT4 *output, UCHAR *input, UINT4 len)
{
UINT4 i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}
/*Compute the md5sum (return static-local-variable),whose length is 16 bytes.*/
UCHAR* ComputeHash(UCHAR* src, UINT4 len)
{
MD5_CTX context;
static UCHAR digest[16];
MD5Init(&context);
MD5Update(&context, src, len);
MD5Final(digest, &context);
return digest;
}

View File

@ -0,0 +1,43 @@
/* MD5.H - header file for MD5.C */
/*
Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.*/
#ifndef MD5_H
#define MD5_H
#include "types.h"
/* MD5 context. */
typedef struct
{
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
UCHAR buffer[64]; /* input buffer */
} MD5_CTX;
void MD5Init(MD5_CTX * context);
void MD5Update(MD5_CTX *context, UCHAR *input, UINT4 inputLen);
void MD5Final(UCHAR digest[16], MD5_CTX *context);
UCHAR* ComputeHash(UCHAR *src, UINT4 len);
#endif /* MD5_H */

View File

@ -0,0 +1,278 @@
/* -*- Mode: C; tab-width: 4; -*- */
/*
* Copyright (C) 2009, HustMoon Studio
*
* mentohust.c
* MentoHUST主函数
* HustMoon@BYHH
* www.ehust@gmail.com
*/
#include "strnormalize.h"
#include "myconfig.h"
#include "mystate.h"
#include "myfunc.h"
#include "dlfunc.h"
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <unistd.h>
extern pcap_t *hPcap;
extern volatile int state;
extern u_char *fillBuf;
extern const u_char *capBuf;
extern unsigned startMode, dhcpMode, maxFail;
extern u_char destMAC[];
extern int lockfd;
#ifndef NO_NOTIFY
extern int showNotify;
#endif
#ifndef NO_ARP
extern u_int32_t rip, gateway;
extern u_char gateMAC[];
#endif
static void exit_handle(void); /* 退出回调 */
static void sig_handle(int sig); /* 信号回调 */
static void pcap_handle(u_char *user, const struct pcap_pkthdr *h, const u_char *buf); /* pcap_loop回调 */
static void showRuijieMsg(const u_char *buf, unsigned bufLen); /* 显示锐捷服务器提示信息 */
static void showCernetMsg(const u_char *buf); /* 显示赛尔服务器提示信息 */
int main(int argc, char **argv)
{
atexit(exit_handle);
initConfig(argc, argv);
signal(SIGALRM, sig_handle); /* 定时器 */
signal(SIGHUP, sig_handle); /* 注销时 */
signal(SIGINT, sig_handle); /* Ctrl+C */
signal(SIGQUIT, sig_handle); /* Ctrl+\ */
signal(SIGTSTP, sig_handle); /* Ctrl+Z */
signal(SIGTERM, sig_handle); /* 被结束时 */
if (dhcpMode == 3) /* 认证前DHCP */
switchState(ID_DHCP);
else
switchState(ID_START); /* 开始认证 */
if (-1 == pcap_loop(hPcap, -1, pcap_handle, NULL)) { /* 开始捕获数据包 */
printf("!! 捕获数据包失败,请检查网络连接!\n");
#ifndef NO_NOTIFY
if (showNotify)
show_notify("MentoHUST - 错误提示", "捕获数据包失败,请检查网络连接!");
#endif
}
exit(EXIT_FAILURE);
}
static void exit_handle(void)
{
if (state != ID_DISCONNECT)
switchState(ID_DISCONNECT);
if (hPcap != NULL)
pcap_close(hPcap);
if (fillBuf != NULL)
free(fillBuf);
if (lockfd > -1)
close(lockfd);
#ifndef NO_NOTIFY
free_libnotify();
#endif
#ifndef NO_DYLOAD
free_libpcap();
#endif
printf(">> 认证已退出。\n");
}
static void sig_handle(int sig)
{
if (sig == SIGALRM) /* 定时器 */
{
if (-1 == switchState(state))
{
pcap_breakloop(hPcap);
printf("!! 发送数据包失败, 请检查网络连接!\n");
#ifndef NO_NOTIFY
if (showNotify)
show_notify("MentoHUST - 错误提示", "发送数据包失败, 请检查网络连接!");
#endif
exit(EXIT_FAILURE);
}
}
else /* 退出 */
{
pcap_breakloop(hPcap);
exit(EXIT_SUCCESS);
}
}
static void pcap_handle(u_char *user, const struct pcap_pkthdr *h, const u_char *buf)
{
static unsigned failCount = 0;
#ifndef NO_ARP
if (buf[0x0c]==0x88 && buf[0x0d]==0x8e) {
#endif
if (memcmp(destMAC, buf+6, 6)!=0 && startMode>2) /* 服务器MAC地址不符 */
return;
capBuf = buf;
if (buf[0x0F]==0x00 && buf[0x12]==0x01 && buf[0x16]==0x01) { /* 验证用户名 */
if (startMode < 3) {
memcpy(destMAC, buf+6, 6);
printf("** 认证MAC:\t%s\n", formatHex(destMAC, 6));
startMode += 3; /* 标记为已获取 */
}
if (startMode==3 && memcmp(buf+0x17, "User name", 9)==0) /* 塞尔 */
startMode = 5;
switchState(ID_IDENTITY);
}
else if (buf[0x0F]==0x00 && buf[0x12]==0x01 && buf[0x16]==0x04) /* 验证密码 */
switchState(ID_CHALLENGE);
else if (buf[0x0F]==0x00 && buf[0x12]==0x03) { /* 认证成功 */
printf(">> 认证成功!\n");
failCount = 0;
if (!(startMode%3 == 2)) {
getEchoKey(buf);
showRuijieMsg(buf, h->caplen);
}
if (dhcpMode==1 || dhcpMode==2) /* 二次认证第一次或者认证后 */
switchState(ID_DHCP);
else if (startMode%3 == 2)
switchState(ID_WAITECHO);
else
switchState(ID_ECHO);
}
else if (buf[0x0F]==0x00 && buf[0x12]==0x01 && buf[0x16]==0x02) /* 显示赛尔提示信息 */
showCernetMsg(buf);
else if (buf[0x0F] == 0x05) /* (赛尔)响应在线 */
switchState(ID_ECHO);
else if (buf[0x0F]==0x00 && buf[0x12]==0x04) { /* 认证失败或被踢下线 */
if (state==ID_WAITECHO || state==ID_ECHO) {
printf(">> 认证掉线,开始重连!\n");
switchState(ID_START);
}
else if (buf[0x1b]!=0 || startMode%3==2) {
printf(">> 认证失败!\n");
if (startMode%3 != 2)
showRuijieMsg(buf, h->caplen);
if (maxFail && ++failCount>=maxFail) {
printf(">> 连续认证失败%u次退出认证。\n", maxFail);
exit(EXIT_SUCCESS);
}
restart();
}
else
switchState(ID_START);
}
#ifndef NO_ARP
} else if (gateMAC[0]!=0xFE && buf[0x0c]==0x08 && buf[0x0d]==0x06) {
if (*(u_int32_t *)(buf+0x1c) == gateway) {
char str[50];
if (gateMAC[0] == 0xFF) {
memcpy(gateMAC, buf+0x16, 6);
printf("** 网关MAC:\t%s\n", formatHex(gateMAC, 6));
fflush(stdout);
sprintf(str, "arp -s %s %s", formatIP(gateway), formatHex(gateMAC, 6));
system(str);
} else if (buf[0x15]==0x02 && *(u_int32_t *)(buf+0x26)==rip
&& memcmp(gateMAC, buf+0x16, 6)!=0) {
printf("** ARP欺骗:\t%s\n", formatHex(buf+0x16, 6));
fflush(stdout);
#ifndef NO_NOTIFY
if (showNotify) {
sprintf(str, "欺骗源: %s", formatHex(buf+0x16, 6));
show_notify("MentoHUST - ARP提示", str);
}
#endif
}
}
}
#endif
}
#ifndef MAC_OS
static char *gbk2utf(char *gbksrc, size_t gbklen) /* GBK转UTF8 */
#else
static char *gbk2utf(const char *gbksrc, size_t gbklen) /* GBK转UTF8 */
#endif
{
/* GBK一汉字俩字节UTF-8一汉字3字节二者ASCII字符均一字节
*/
str_normalize_init();
size_t utf8len = gbklen * 3 + 1;
char *utf8dst = (char *)malloc(utf8len);
memset(utf8dst,0,utf8len);
char *temp=(char *)malloc(gbklen+5);
memset(temp, 0, gbklen+5);
memcpy(temp,gbksrc,gbklen);
gbksrc = temp;
gbklen = strlen(gbksrc);
gbk_to_utf8(gbksrc, gbklen, &utf8dst, &utf8len);
free(temp);
return utf8dst;
}
static void showRuijieMsg(const u_char *buf, unsigned bufLen)
{
char *serverMsg;
int length = buf[0x1b];
if (length > 0)
{
for (serverMsg=(char *)(buf+0x1c); *serverMsg=='\r'||*serverMsg=='\n'; serverMsg++,length--); /* 跳过开头的换行符 */
if (strlen(serverMsg) < length)
length = strlen(serverMsg);
if (length>0 && (serverMsg=gbk2utf(serverMsg, length))!=NULL)
{
printf("$$ 系统提示:\t%s\n", serverMsg);
#ifndef NO_NOTIFY
if (showNotify)
show_notify("MentoHUST - 系统提示", serverMsg);
#endif
free(serverMsg);
}
}
if ((length=0x1c+buf[0x1b]+0x69+39) < bufLen)
{
serverMsg=(char *)(buf+length);
if (buf[length-1]-2 > bufLen-length)
length = bufLen - length;
else
length = buf[length-1]-2;
for (; *serverMsg=='\r'||*serverMsg=='\n'; serverMsg++,length--);
if (length>0 && (serverMsg=gbk2utf(serverMsg, length))!=NULL)
{
printf("$$ 计费提示:\t%s\n", serverMsg);
#ifndef NO_NOTIFY
if (showNotify)
show_notify("MentoHUST - 计费提示", serverMsg);
#endif
free(serverMsg);
}
}
fflush(stdout);
}
static void showCernetMsg(const u_char *buf)
{
char *serverMsg = (char *)(buf+0x17);
int length = ntohs(*(u_int16_t *)(buf+0x14)) - 5;
if (strlen(serverMsg) < length)
length = strlen(serverMsg);
if (length>0 && (serverMsg=gbk2utf(serverMsg, length))!=NULL)
{
printf("$$ 系统提示:\t%s\n", serverMsg);
#ifndef NO_NOTIFY
if (showNotify)
show_notify("MentoHUST - 系统提示", serverMsg);
#endif
free(serverMsg);
}
fflush(stdout);
}

View File

@ -0,0 +1,46 @@
# MentoHUST for Linux By HustMoon Studio
#
# 配置文件名称必须是小写/etc/mentohust.conf编码格式建议是UTF-8
# 配置文件中一行开头的空格和Tab会被忽略其他的会视为参数一部分
# 配置文件中Section与Key不区分大小写以#或;开头的行视为注释
# 同一个参数若在命令行参数和配置文件中均有设置,使用命令行参数
# 命令行中使用参数-h或-?可查看详细参数信息,建议通过命令行设置参数
# 命令行中使用参数-w可将配置更新到/etc/mentohust.conf
[MentoHUST]
;用户名长度不超过64
Username=
;密码(简单加密)
EncodePass=
;网卡
Nic=
;静态IP用户可以使用非本机IP
IP=
;掩码,无关紧要
Mask=
;网关如果指定了就会监视网关ARP信息
Gateway=
;DNS服务器无关紧要
DNS=
;Ping主机用于掉线检测0.0.0.0表示关闭该功能
PingHost=
;每次发包超时时间(秒)
Timeout=
;发送Echo包的间隔
EchoInterval=
;失败等待认证失败后等待RestartWait秒或者服务器请求后重启认证
RestartWait=
;寻找服务器时的组播地址类型 0标准 1锐捷 2将MentoHUST用于赛尔认证
StartMode=
;DHCP方式 0(不使用) 1(二次认证) 2(认证后) 3(认证前)
DhcpMode=
;是否后台运行: 0(否) 1(是,关闭输出) 2(是,保留输出) 3(是,输出到文件/tmp/mentohust.log)
DaemonMode=
;是否显示通知: 0(否) 1~20(是)
ShowNotify=
;客户端版本号如果未开启客户端校验但对版本号有要求可以在此指定形如3.30
Version=
;认证数据文件,如果需要校验客户端,就需要正确设置
DataFile=
;进行DHCP的脚本
DhcpScript=

View File

@ -0,0 +1,189 @@
/* -*- Mode: C; tab-width: 4; -*- */
/*
* Copyright (C) 2009, HustMoon Studio
*
* mycheck.c
*
* kkHAIKE & HustMoon
*/
#include "mycheck.h"
#include "md5.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static BYTE *bin_8021x = NULL;
static DWORD size_8021x;
static BYTE hex[][17]={"0123456789ABCDEF", "0123456789abcdef"};
#ifdef WORDS_BIGENDIAN
WORD ltobs(WORD x) {
return ((x & 0xff) << 8) | ((x & 0xff00) >> 8);
}
DWORD ltobl(DWORD x) {
return ((x & 0xff) << 24) |\
((x & 0xff00) << 8) |\
((x & 0xff0000) >> 8) |\
((x & 0xff000000) >> 24);
}
#endif
void hex_to_str(const BYTE *a, char *b, int hexsize, int upper) {
BYTE *q = (BYTE *)b;
int i;
for (i=0; i<hexsize; i++) {
*q = hex[upper][a[i]>>4]; q++;
*q = hex[upper][a[i]&0xf]; q++;
}
*q = 0;
}
BYTE *ReadCode(const char *file, DWORD *size) {
BYTE *data = NULL;
int i;
FILE *fp;
PPE_HEADER_MAP hpe;
if ((fp=fopen(file, "rb")) == NULL)
goto fileError;
data = (BYTE *)malloc(0x1000);
if (fread(data, 0x1000, 1, fp) < 1)
goto fileError;
hpe = (PPE_HEADER_MAP)(data + LTOBL(((PIMAGE_DOS_HEADER)data)->e_lfanew));
for (i=0; i<LTOBS(hpe->_head.NumberOfSections); i++) {
if (LTOBL(hpe->section_header[i].Characteristics) & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE)) {
fseek(fp, LTOBL(hpe->section_header[i].PointerToRawData), SEEK_SET);
*size = LTOBL(hpe->section_header[i].SizeOfRawData);
free(data);
data = (BYTE *)malloc(*size);
if (fread(data, *size, 1, fp) < 1)
goto fileError;
fclose(fp);
return data;
}
}
fileError:
if (fp != NULL)
fclose(fp);
if (data != NULL)
free(data);
return NULL;
}
BYTE *ReadCode2(const char *dataFile, DWORD *size) {
BYTE Buf[16], *buf=Buf;
FILE *fp = NULL;
if ((fp=fopen(dataFile, "rb")) == NULL
|| fread(buf, 16, 1, fp ) < 1)
goto fileError;
*size = LTOBL(*(UINT4 *)buf ^ *(UINT4 *)(buf + 4));
if ((int)*size <= 0)
goto fileError;
buf = (BYTE *)malloc(*size+0x100);
if (fread(buf, *size, 1, fp) < 1) {
free(buf);
goto fileError;
}
fclose(fp);
return buf;
fileError:
if (fp != NULL)
fclose(fp);
return NULL;
}
void check_free() {
if (bin_8021x) {
free(bin_8021x);
bin_8021x = NULL;
}
}
int check_init(const char *dataFile) {
char name[0x100];
char *p;
check_free();
strcpy(name, dataFile);
if ((p=strrchr(name, '/')+1) == (void *)1)
p = name;
strcpy(p, "8021x.exe");
if ((bin_8021x=ReadCode(name, &size_8021x)) == NULL
&& (bin_8021x=ReadCode2(dataFile, &size_8021x)) == NULL)
return -1;
return 0;
}
void V2_check(const BYTE *seed, char *final_str) {
int i, size = size_8021x / 8;
BYTE table[144], *md5Dig, *b8021x = (BYTE *)malloc(size+16);
memcpy(b8021x, seed, 16);
for (i=0; i<8; i++) {
memcpy(b8021x+16, bin_8021x+size*i, size);
md5Dig = ComputeHash(b8021x, size+16);
table[18*i] = seed[2*i];
memcpy(table+18*i+1, md5Dig, 16);
table[18*i+17] = seed[2*i+1];
}
free(b8021x);
md5Dig = ComputeHash(table, 144);
hex_to_str(md5Dig, final_str, 16, 1);
}
DWORD getVer(const char *file) {
FILE *fp;
BYTE *data = NULL;
int i, j;
DWORD size, VirtualAddress;
PPE_HEADER_MAP hpe;
PIMAGE_RESOURCE_DIRECTORY prd;
PIMAGE_RESOURCE_DATA_ENTRY prde;
PVS_VERSIONINFO pvs;
if ((fp=fopen(file, "rb")) == NULL)
goto fileError;
data = (BYTE *)malloc(0x1000);
if (fread(data, 0x1000, 1, fp) < 1)
goto fileError;
hpe = (PPE_HEADER_MAP)(data + LTOBL(((PIMAGE_DOS_HEADER)data)->e_lfanew));
for (i=LTOBS(hpe->_head.NumberOfSections)-1; i>=0; i--) {
if (strcmp(hpe->section_header[i].Name, ".rsrc") == 0) {
fseek(fp, LTOBL(hpe->section_header[i].PointerToRawData), SEEK_SET);
size = LTOBL(hpe->section_header[i].SizeOfRawData);
VirtualAddress = LTOBL(hpe->section_header[i].VirtualAddress);
free(data);
data = (BYTE *)malloc(size);
if (fread(data, size, 1, fp) < 1)
goto fileError;
prd = (PIMAGE_RESOURCE_DIRECTORY)data;
for (j=0; j<LTOBS(prd->NumberOfIdEntries); j++) {
prd->DirectoryEntries[j].Name = LTOBL(prd->DirectoryEntries[j].Name);
if (prd->DirectoryEntries[j].Id==16 && prd->DirectoryEntries[j].NameIsString==0) {
prd->DirectoryEntries[j].OffsetToData = LTOBL(prd->DirectoryEntries[j].OffsetToData);
prd = (PIMAGE_RESOURCE_DIRECTORY)(data+prd->DirectoryEntries[j].OffsetToDirectory);
prd->DirectoryEntries[0].OffsetToData = LTOBL(prd->DirectoryEntries[0].OffsetToData);
prd = (PIMAGE_RESOURCE_DIRECTORY)(data+prd->DirectoryEntries[0].OffsetToDirectory);
prde = (PIMAGE_RESOURCE_DATA_ENTRY)(data+LTOBL(prd->DirectoryEntries[0].OffsetToData));
pvs = (PVS_VERSIONINFO)(data+LTOBL(prde->OffsetToData)-VirtualAddress);
size = pvs->Value.dwFileVersionMS;
fclose(fp);
free(data);
return size;
}
}
goto fileError;
}
}
fileError:
if (fp != NULL)
fclose(fp);
if (data != NULL)
free(data);
return -1;
}

View File

@ -0,0 +1,219 @@
/* -*- Mode: C; tab-width: 4; -*- */
/*
* Copyright (C) 2009, HustMoon Studio
*
* mycheck.h
*
* kkHAIKE
*/
#ifndef MYCHECK_H
#define MYCHECK_H
#include "types.h"
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
WORD e_magic; // Magic number
WORD e_cblp; // Bytes on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Initial SP value
WORD e_csum; // Checksum
WORD e_ip; // Initial IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[10]; // Reserved words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
//
// NT additional fields.
//
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;
#define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_SECTION_HEADER {
char Name[IMAGE_SIZEOF_SHORT_NAME];
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
typedef struct _PE_HEADER_MAP
{
DWORD signature;
IMAGE_FILE_HEADER _head;
IMAGE_OPTIONAL_HEADER opt_head;
IMAGE_SECTION_HEADER section_header[8];
}PE_HEADER_MAP,*PPE_HEADER_MAP;
typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
#ifdef WORDS_BIGENDIAN
union {
struct {
DWORD NameIsString:1;
DWORD NameOffset:31;
};
DWORD Name;
struct {
WORD Id_unuse;
WORD Id;
};
};
union {
DWORD OffsetToData;
struct {
DWORD DataIsDirectory:1;
DWORD OffsetToDirectory:31;
};
};
#else
union {
struct {
DWORD NameOffset:31;
DWORD NameIsString:1;
};
DWORD Name;
WORD Id;
};
union {
DWORD OffsetToData;
struct {
DWORD OffsetToDirectory:31;
DWORD DataIsDirectory:1;
};
};
#endif
} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;
typedef struct _IMAGE_RESOURCE_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
WORD NumberOfNamedEntries;
WORD NumberOfIdEntries;
IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;
typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
DWORD OffsetToData;
DWORD Size;
DWORD CodePage;
DWORD Reserved;
} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;
typedef struct tagVS_FIXEDFILEINFO {
DWORD dwSignature; /* e.g. 0xfeef04bd */
DWORD dwStrucVersion; /* e.g. 0x00000042 = "0.42" */
DWORD dwFileVersionMS; /* e.g. 0x00030075 = "3.75" */
DWORD dwFileVersionLS; /* e.g. 0x00000031 = "0.31" */
DWORD dwProductVersionMS; /* e.g. 0x00030010 = "3.10" */
DWORD dwProductVersionLS; /* e.g. 0x00000031 = "0.31" */
DWORD dwFileFlagsMask; /* = 0x3F for version "0.42" */
DWORD dwFileFlags; /* e.g. VFF_DEBUG | VFF_PRERELEASE */
DWORD dwFileOS; /* e.g. VOS_DOS_WINDOWS16 */
DWORD dwFileType; /* e.g. VFT_DRIVER */
DWORD dwFileSubtype; /* e.g. VFT2_DRV_KEYBOARD */
DWORD dwFileDateMS; /* e.g. 0 */
DWORD dwFileDateLS; /* e.g. 0 */
} VS_FIXEDFILEINFO;
typedef struct _VS_VERSIONINFO {
WORD wLength;
WORD wValueLength;
WORD wType;
WORD szKey[16];
WORD Padding1[1];
VS_FIXEDFILEINFO Value;
} VS_VERSIONINFO, *PVS_VERSIONINFO;
#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code
#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable
#ifdef WORDS_BIGENDIAN
#define LTOBS(x) ltobs(x)
#define LTOBL(x) ltobl(x)
WORD ltobs(WORD x);
DWORD ltobl(DWORD x);
#else
#define LTOBS(x) (x)
#define LTOBL(x) (x)
#endif
int check_init(const char *dataFile);
void V2_check(const BYTE *seed, char *final_str);
void check_free();
DWORD getVer(const char *file);
#endif

View File

@ -0,0 +1,592 @@
/* -*- Mode: C; tab-width: 4; -*- */
/*
* Copyright (C) 2009, HustMoon Studio
*
* myconfig.c
*
* HustMoon@BYHH
* www.ehust@gmail.com
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#else
static const char *VERSION = "0.3.1";
static const char *PACKAGE_BUGREPORT = "http://code.google.com/p/mentohust/issues/list";
#endif
#include "myconfig.h"
#include "myini.h"
#include "myfunc.h"
#include "dlfunc.h"
#include <string.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <sys/stat.h>
#define ACCOUNT_SIZE 65 /* 用户名密码长度*/
#define NIC_SIZE 16 /* 网卡名最大长度 */
#define MAX_PATH 255 /* FILENAME_MAX */
#define D_TIMEOUT 8 /* 默认超时间隔 */
#define D_ECHOINTERVAL 30 /* 默认心跳间隔 */
#define D_RESTARTWAIT 15 /* 默认重连间隔 */
#define D_STARTMODE 0 /* 默认组播模式 */
#define D_DHCPMODE 0 /* 默认DHCP模式 */
#define D_DAEMONMODE 0 /* 默认daemon模式 */
#define D_MAXFAIL 0 /* 默认允许失败次数 */
static const char *D_DHCPSCRIPT = "dhclient"; /* 默认DHCP脚本 */
static const char *CFG_FILE = "/etc/mentohust.conf"; /* 配置文件 */
static const char *LOG_FILE = "/tmp/mentohust.log"; /* 日志文件 */
static const char *LOCK_FILE = "/tmp/mentohust.pid"; /* 锁文件 */
#define LOCKMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) /* 创建掩码 */
#ifndef NO_NOTIFY
#define D_SHOWNOTIFY 5 /* 默认Show Notify模式 */
int showNotify = D_SHOWNOTIFY; /* 显示通知 */
#endif
extern int bufType; /*0内置xrgsu 1内置Win 2仅文件 3文件+校验*/
extern u_char version[]; /* 版本 */
char userName[ACCOUNT_SIZE] = ""; /* 用户名 */
char password[ACCOUNT_SIZE] = ""; /* 密码 */
char nic[NIC_SIZE] = ""; /* 网卡名 */
char dataFile[MAX_PATH] = ""; /* 数据文件 */
char dhcpScript[MAX_PATH] = ""; /* DHCP脚本 */
u_int32_t ip = 0; /* 本机IP */
u_int32_t mask = 0; /* 子网掩码 */
u_int32_t gateway = 0; /* 网关 */
u_int32_t dns = 0; /* DNS */
u_int32_t pingHost = 0; /* ping */
u_char localMAC[6]; /* 本机MAC */
u_char destMAC[6]; /* 服务器MAC */
unsigned timeout = D_TIMEOUT; /* 超时间隔 */
unsigned echoInterval = D_ECHOINTERVAL; /* 心跳间隔 */
unsigned restartWait = D_RESTARTWAIT; /* 失败等待 */
unsigned startMode = D_STARTMODE; /* 组播模式 */
unsigned dhcpMode = D_DHCPMODE; /* DHCP模式 */
unsigned maxFail = D_MAXFAIL; /* 允许失败次数 */
pcap_t *hPcap = NULL; /* Pcap句柄 */
int lockfd = -1; /* 锁文件描述符 */
static int readFile(int *daemonMode); /* 读取配置文件来初始化 */
static void readArg(char argc, char **argv, int *saveFlag, int *exitFlag, int *daemonMode); /* 读取命令行参数来初始化 */
static void showHelp(const char *fileName); /* 显示帮助信息 */
static int getAdapter(); /* 查找网卡名 */
static void printConfig(); /* 显示初始化后的认证参数 */
static int openPcap(); /* 初始化pcap、设置过滤器 */
static void saveConfig(int daemonMode); /* 保存参数 */
static void checkRunning(int exitFlag, int daemonMode); /* 检测是否已运行 */
#ifndef NO_ENCODE_PASS
static const unsigned char base64Tab[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"};
static const char xorRuijie[] = {"~!:?$*<(qw2e5o7i8x12c6m67s98w43d2l45we82q3iuu1z4xle23rt4oxclle34e54u6r8m"};
static int encodePass(char *dst, const char *osrc) {
unsigned char in[3], buf[70];
unsigned char *src = buf;
int sz = strlen(osrc);
int i, len;
if (sizeof(xorRuijie) < sz)
return -1;
for(i=0; i<sz; i++)
src[i] = osrc[i] ^ xorRuijie[i];
while (sz > 0) {
for (len=0, i=0; i<3; i++, sz--) {
if (sz > 0) {
len++;
in[i] = src[i];
} else in[i] = 0;
}
src += 3;
if (len) {
dst[0] = base64Tab[ in[0] >> 2 ];
dst[1] = base64Tab[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
dst[2] = len > 1 ? base64Tab[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=';
dst[3] = len > 2 ? base64Tab[ in[2] & 0x3f ] : '=';
dst += 4;
}
}
*dst = '\0';
return 0;
}
static int decodePass(char *dst, const char *src) {
unsigned esi = 0, idx = 0;
int i=0, j=0, equal=0;
for(; src[i]!='\0'; i++) {
if (src[i] == '=') {
if (++equal > 2)
return -1;
} else {
for(idx=0; base64Tab[idx]!='\0'; idx++) {
if(base64Tab[idx] == src[i])
break;
}
if (idx == 64)
return -1;
esi += idx;
}
if(i%4 == 3) {
dst[j++] = (char)(esi>>16);
if(equal < 2)
dst[j++] = (char)(esi>>8);
if(equal < 1)
dst[j++] = (char)esi;
esi = 0;
equal = 0;
}
esi <<= 6;
}
if (i%4!=0 || sizeof(xorRuijie)<j)
return -1;
for(i=0; i<j; i++)
dst[i] ^= xorRuijie[i];
dst[j] = '\0';
return 0;
}
#endif
void initConfig(int argc, char **argv)
{
int saveFlag = 0; /* 是否需要保存参数 */
int exitFlag = 0; /* 0Nothing 1退出 2重启 */
int daemonMode = D_DAEMONMODE; /* 是否后台运行 */
printf("\n欢迎使用MentoHUST\t版本: %s\n"
"Copyright (C) 2009-2010 HustMoon Studio\n"
"人到华中大,有甜亦有辣。明德厚学地,求是创新家。\n"
"Bug report to %s\n\n", VERSION, PACKAGE_BUGREPORT);
saveFlag = (readFile(&daemonMode)==0 ? 0 : 1);
readArg(argc, argv, &saveFlag, &exitFlag, &daemonMode);
#ifndef NO_NOTIFY
if (showNotify) {
seteuid(getuid());
if (load_libnotify() == -1)
showNotify = 0;
else
set_timeout(1000 * showNotify);
seteuid(0);
}
#endif
#ifndef NO_DYLOAD
if (load_libpcap() == -1) {
#ifndef NO_NOTIFY
if (showNotify)
show_notify("MentoHUST - 错误提示", "载入libpcap失败, 请检查该库文件!");
#endif
exit(EXIT_FAILURE);
}
#endif
if (nic[0] == '\0')
{
saveFlag = 1;
if (getAdapter() == -1) { /* 找不到(第一块)网卡? */
#ifndef NO_NOTIFY
if (showNotify)
show_notify("MentoHUST - 错误提示", "找不到网卡!");
#endif
exit(EXIT_FAILURE);
}
}
if (userName[0]=='\0' || password[0]=='\0') /* 未写用户名密码? */
{
saveFlag = 1;
printf("?? 请输入用户名: ");
scanf("%s", userName);
printf("?? 请输入密码: ");
scanf("%s", password);
printf("?? 请选择组播地址(0标准 1锐捷私有 2赛尔): ");
scanf("%u", &startMode);
startMode %= 3;
printf("?? 请选择DHCP方式(0不使用 1二次认证 2认证后 3认证前): ");
scanf("%u", &dhcpMode);
dhcpMode %= 4;
}
checkRunning(exitFlag, daemonMode);
if (startMode%3==2 && gateway==0) /* 赛尔且未填写网关地址 */
{
gateway = ip; /* 据说赛尔的网关是ip前三字节后一字节是2 */
((u_char *)&gateway)[3] = 0x02;
}
if (dhcpScript[0] == '\0') /* 未填写DHCP脚本 */
strcpy(dhcpScript, D_DHCPSCRIPT);
newBuffer();
printConfig();
if (fillHeader()==-1 || openPcap()==-1) { /* 获取IP、MAC打开网卡 */
#ifndef NO_NOTIFY
if (showNotify)
show_notify("MentoHUST - 错误提示", "获取MAC地址或打开网卡失败");
#endif
exit(EXIT_FAILURE);
}
if (saveFlag)
saveConfig(daemonMode);
}
static int readFile(int *daemonMode)
{
char tmp[16];
char *buf = loadFile(CFG_FILE);
if (buf == NULL)
return -1;
getString(buf, "MentoHUST", "Username", "", userName, sizeof(userName));
getString(buf, "MentoHUST", "Password", "", password, sizeof(password));
#ifndef NO_ENCODE_PASS
char pass[ACCOUNT_SIZE*4/3];
if (password[0] == '\0') {
getString(buf, "MentoHUST", "EncodePass", "", pass, sizeof(pass));
decodePass(password, pass);
} else {
encodePass(pass, password);
setString(&buf, "MentoHUST", "Password", NULL);
setString(&buf, "MentoHUST", "EncodePass", pass);
saveFile(buf, CFG_FILE);
}
#endif
getString(buf, "MentoHUST", "Nic", "", nic, sizeof(nic));
getString(buf, "MentoHUST", "Datafile", "", dataFile, sizeof(dataFile));
getString(buf, "MentoHUST", "DhcpScript", "", dhcpScript, sizeof(dhcpScript));
getString(buf, "MentoHUST", "Version", "", tmp, sizeof(tmp));
if (strlen(tmp) >= 3) {
unsigned ver[2];
if (sscanf(tmp, "%u.%u", ver, ver+1)!=EOF && ver[0]!=0) {
version[0] = ver[0];
version[1] = ver[1];
bufType = 1;
}
}
getString(buf, "MentoHUST", "IP", "255.255.255.255", tmp, sizeof(tmp));
ip = inet_addr(tmp);
getString(buf, "MentoHUST", "Mask", "255.255.255.255", tmp, sizeof(tmp));
mask = inet_addr(tmp);
getString(buf, "MentoHUST", "Gateway", "0.0.0.0", tmp, sizeof(tmp));
gateway = inet_addr(tmp);
getString(buf, "MentoHUST", "DNS", "0.0.0.0", tmp, sizeof(tmp));
dns = inet_addr(tmp);
getString(buf, "MentoHUST", "PingHost", "0.0.0.0", tmp, sizeof(tmp));
pingHost = inet_addr(tmp);
timeout = getInt(buf, "MentoHUST", "Timeout", D_TIMEOUT) % 100;
echoInterval = getInt(buf, "MentoHUST", "EchoInterval", D_ECHOINTERVAL) % 1000;
restartWait = getInt(buf, "MentoHUST", "RestartWait", D_RESTARTWAIT) % 100;
startMode = getInt(buf, "MentoHUST", "StartMode", D_STARTMODE) % 3;
dhcpMode = getInt(buf, "MentoHUST", "DhcpMode", D_DHCPMODE) % 4;
#ifndef NO_NOTIFY
showNotify = getInt(buf, "MentoHUST", "ShowNotify", D_SHOWNOTIFY) % 21;
#endif
*daemonMode = getInt(buf, "MentoHUST", "DaemonMode", D_DAEMONMODE) % 4;
maxFail = getInt(buf, "MentoHUST", "MaxFail", D_MAXFAIL);
free(buf);
return 0;
}
static void readArg(char argc, char **argv, int *saveFlag, int *exitFlag, int *daemonMode)
{
char *str, c;
int i;
for (i=1; i<argc; i++)
{
str = argv[i];
if (str[0]!='-' && str[0]!='/')
continue;
c = str[1];
if (c=='h' || c=='?' || strcmp(str, "--help")==0)
showHelp(argv[0]);
else if (c == 'w')
*saveFlag = 1;
else if (c == 'k') {
if (strlen(str) > 2)
*exitFlag = 2;
else {
*exitFlag = 1;
return;
}
} else if (strlen(str) > 2) {
if (c == 'u')
strncpy(userName, str+2, sizeof(userName)-1);
else if (c == 'p')
strncpy(password, str+2, sizeof(password)-1);
else if (c == 'n')
strncpy(nic, str+2, sizeof(nic)-1);
else if (c == 'f')
strncpy(dataFile, str+2, sizeof(dataFile)-1);
else if (c == 'c')
strncpy(dhcpScript, str+2, sizeof(dhcpScript)-1);
else if (c=='v' && strlen(str+2)>=3) {
unsigned ver[2];
if (sscanf(str+2, "%u.%u", ver, ver+1) != EOF) {
if (ver[0] == 0)
bufType = 0;
else {
version[0] = ver[0];
version[1] = ver[1];
bufType = 1;
}
}
}
else if (c == 'i')
ip = inet_addr(str+2);
else if (c == 'm')
mask = inet_addr(str+2);
else if (c == 'g')
gateway = inet_addr(str+2);
else if (c == 's')
dns = inet_addr(str+2);
else if (c == 'o')
pingHost = inet_addr(str+2);
else if (c == 't')
timeout = atoi(str+2) % 100;
else if (c == 'e')
echoInterval = atoi(str+2) % 1000;
else if (c == 'r')
restartWait = atoi(str+2) % 100;
else if (c == 'a')
startMode = atoi(str+2) % 3;
else if (c == 'd')
dhcpMode = atoi(str+2) % 4;
#ifndef NO_NOTIFY
else if (c == 'y')
showNotify = atoi(str+2) % 21;
#endif
else if (c == 'b')
*daemonMode = atoi(str+2) % 4;
else if (c == 'l')
maxFail = atoi(str+2);
}
}
}
static void showHelp(const char *fileName)
{
char *helpString =
"用法:\t%s [-选项][参数]\n"
"选项:\t-h 显示本帮助信息\n"
"\t-k -k(退出程序) 其他(重启程序)\n"
"\t-w 保存参数到配置文件\n"
"\t-u 用户名\n"
"\t-p 密码\n"
"\t-n 网卡名\n"
"\t-i IP[默认本机IP]\n"
"\t-m 子网掩码[默认本机掩码]\n"
"\t-g 网关[默认0.0.0.0]\n"
"\t-s DNS[默认0.0.0.0]\n"
"\t-o Ping主机[默认0.0.0.0,表示关闭该功能]\n"
"\t-t 认证超时(秒)[默认8]\n"
"\t-e 响应间隔(秒)[默认30]\n"
"\t-r 失败等待(秒)[默认15]\n"
"\t-l 允许失败次数[默认0表示无限制]\n"
"\t-a 组播地址: 0(标准) 1(锐捷) 2(赛尔) [默认0]\n"
"\t-d DHCP方式: 0(不使用) 1(二次认证) 2(认证后) 3(认证前) [默认0]\n"
"\t-b 是否后台运行: 0(否) 1(是,关闭输出) 2(是,保留输出) 3(是,输出到文件) [默认0]\n"
#ifndef NO_NOTIFY
"\t-y 是否显示通知: 0(否) 1~20(是) [默认5]\n"
#endif
"\t-v 客户端版本号[默认0.00表示兼容xrgsu]\n"
"\t-f 自定义数据文件[默认不使用]\n"
"\t-c DHCP脚本[默认dhclient]\n"
"例如:\t%s -uusername -ppassword -neth0 -i192.168.0.1 -m255.255.255.0 -g0.0.0.0 -s0.0.0.0 -o0.0.0.0 -t8 -e30 -r15 -a0 -d1 -b0 -v4.10 -fdefault.mpf -cdhclient\n"
"注意使用时请确保是以root权限运行\n\n";
printf(helpString, fileName, fileName);
exit(EXIT_SUCCESS);
}
static int getAdapter()
{
pcap_if_t *alldevs, *d;
int num = 0, avail = 0, i;
char errbuf[PCAP_ERRBUF_SIZE];
if (pcap_findalldevs(&alldevs, errbuf)==-1 || alldevs==NULL)
{
printf("!! 查找网卡失败: %s\n", errbuf);
return -1;
}
for (d=alldevs; d!=NULL; d=d->next)
{
num++;
if (!(d->flags & PCAP_IF_LOOPBACK) && strcmp(d->name, "any")!=0)
{
printf("** 网卡[%d]:\t%s\n", num, d->name);
avail++;
i = num;
}
}
if (avail == 0)
{
pcap_freealldevs(alldevs);
printf("!! 找不到网卡!\n");
return -1;
}
if (avail > 1)
{
printf("?? 请选择网卡[1-%d]: ", num);
scanf("%d", &i);
if (i < 1)
i = 1;
else if (i > num)
i = num;
}
printf("** 您选择了第[%d]块网卡。\n", i);
for (d=alldevs; i>1; d=d->next, i--);
strncpy(nic, d->name, sizeof(nic)-1);
pcap_freealldevs(alldevs);
return 0;
}
static void printConfig()
{
char *addr[] = {"标准", "锐捷", "赛尔"};
char *dhcp[] = {"不使用", "二次认证", "认证后", "认证前"};
printf("** 用户名:\t%s\n", userName);
/* printf("** 密码:\t%s\n", password); */
printf("** 网卡: \t%s\n", nic);
if (gateway)
printf("** 网关地址:\t%s\n", formatIP(gateway));
if (dns)
printf("** DNS地址:\t%s\n", formatIP(dns));
if (pingHost)
printf("** 智能重连:\t%s\n", formatIP(pingHost));
printf("** 认证超时:\t%u秒\n", timeout);
printf("** 响应间隔:\t%u秒\n", echoInterval);
printf("** 失败等待:\t%u秒\n", restartWait);
printf("** 允许失败:\t%u次\n", maxFail);
printf("** 组播地址:\t%s\n", addr[startMode]);
printf("** DHCP方式:\t%s\n", dhcp[dhcpMode]);
#ifndef NO_NOTIFY
if (showNotify)
printf("** 通知超时:\t%d秒\n", showNotify);
#endif
if (bufType >= 2)
printf("** 数据文件:\t%s\n", dataFile);
if (dhcpMode != 0)
printf("** DHCP脚本:\t%s\n", dhcpScript);
}
static int openPcap()
{
char buf[PCAP_ERRBUF_SIZE], *fmt;
struct bpf_program fcode;
if ((hPcap = pcap_open_live(nic, 2048, 1, 1000, buf)) == NULL)
{
printf("!! 打开网卡%s失败: %s\n", nic, buf);
return -1;
}
fmt = formatHex(localMAC, 6);
#ifndef NO_ARP
sprintf(buf, "((ether proto 0x888e and (ether dst %s or ether dst 01:80:c2:00:00:03)) "
"or ether proto 0x0806) and not ether src %s", fmt, fmt);
#else
sprintf(buf, "ether proto 0x888e and (ether dst %s or ether dst 01:80:c2:00:00:03) "
"and not ether src %s", fmt, fmt);
#endif
if (pcap_compile(hPcap, &fcode, buf, 0, 0xffffffff) == -1
|| pcap_setfilter(hPcap, &fcode) == -1)
{
printf("!! 设置pcap过滤器失败: %s\n", pcap_geterr(hPcap));
return -1;
}
pcap_freecode(&fcode);
return 0;
}
static void saveConfig(int daemonMode)
{
char *buf = loadFile(CFG_FILE);
if (buf == NULL) {
buf = (char *)malloc(1);
buf[0] = '\0';
}
setString(&buf, "MentoHUST", "DhcpScript", dhcpScript);
setString(&buf, "MentoHUST", "DataFile", dataFile);
if (bufType != 0) {
char ver[10];
sprintf(ver, "%u.%u", version[0], version[1]);
setString(&buf, "MentoHUST", "Version", ver);
} else
setString(&buf, "MentoHUST", "Version", "0.00");
#ifndef NO_NOTIFY
setInt(&buf, "MentoHUST", "ShowNotify", showNotify);
#endif
setInt(&buf, "MentoHUST", "DaemonMode", daemonMode);
setInt(&buf, "MentoHUST", "DhcpMode", dhcpMode);
setInt(&buf, "MentoHUST", "StartMode", startMode);
setInt(&buf, "MentoHUST", "MaxFail", maxFail);
setInt(&buf, "MentoHUST", "RestartWait", restartWait);
setInt(&buf, "MentoHUST", "EchoInterval", echoInterval);
setInt(&buf, "MentoHUST", "Timeout", timeout);
setString(&buf, "MentoHUST", "PingHost", formatIP(pingHost));
setString(&buf, "MentoHUST", "DNS", formatIP(dns));
setString(&buf, "MentoHUST", "Gateway", formatIP(gateway));
setString(&buf, "MentoHUST", "Mask", formatIP(mask));
setString(&buf, "MentoHUST", "IP", formatIP(ip));
setString(&buf, "MentoHUST", "Nic", nic);
#ifdef NO_ENCODE_PASS
setString(&buf, "MentoHUST", "Password", password);
#else
char pass[ACCOUNT_SIZE*4/3];
encodePass(pass, password);
setString(&buf, "MentoHUST", "EncodePass", pass);
#endif
setString(&buf, "MentoHUST", "Username", userName);
if (saveFile(buf, CFG_FILE) != 0)
printf("!! 保存认证参数到%s失败\n", CFG_FILE);
else
printf("** 认证参数已成功保存到%s.\n", CFG_FILE);
free(buf);
}
static void checkRunning(int exitFlag, int daemonMode)
{
struct flock fl;
lockfd = open (LOCK_FILE, O_RDWR|O_CREAT, LOCKMODE);
if (lockfd < 0) {
perror("!! 打开锁文件失败"); /* perror真的很好啊以前没用它真是太亏了 */
goto error_exit;
}
fl.l_start = 0;
fl.l_whence = SEEK_SET;
fl.l_len = 0;
fl.l_type = F_WRLCK;
if (fcntl(lockfd, F_GETLK, &fl) < 0) {
perror("!! 获取文件锁失败");
goto error_exit;
}
if (exitFlag) {
if (fl.l_type != F_UNLCK) {
printf(">> 已发送退出信号给MentoHUST进程(PID=%d).\n", fl.l_pid);
if (kill(fl.l_pid, SIGINT) == -1)
perror("!! 结束进程失败");
}
else
printf("!! 没有MentoHUST正在运行\n");
if (exitFlag == 1)
exit(EXIT_SUCCESS);
}
else if (fl.l_type != F_UNLCK) {
printf("!! MentoHUST已经运行(PID=%d)!\n", fl.l_pid);
exit(EXIT_FAILURE);
}
if (daemonMode) { /* 貌似我过早进入后台模式了,就给个选项保留输出或者输出到文件吧 */
printf(">> 进入后台运行模式,使用参数-k可退出认证。\n");
if (daemon(0, (daemonMode+1)%2))
perror("!! 后台运行失败");
else if (daemonMode == 3) {
freopen(LOG_FILE, "w", stdout);
freopen(LOG_FILE, "a", stderr);
}
}
fl.l_type = F_WRLCK;
fl.l_pid = getpid();
if (fcntl(lockfd, F_SETLKW, &fl) < 0) {
perror("!! 加锁失败");
goto error_exit;
}
return;
error_exit:
#ifndef NO_NOTIFY
if (showNotify)
show_notify("MentoHUST - 错误提示", "操作锁文件失败请检查是否为root权限");
#endif
exit(EXIT_FAILURE);
}

View File

@ -0,0 +1,13 @@
/*
* Copyright (C) 2009, HustMoon Studio
*
* myconfig.h
*
* HustMoon@BYHH
*/
#ifndef HUSTMOON_MYCONFIG_H
#define HUSTMOON_MYCONFIG_H
void initConfig(int argc, char **argv); /* 初始化配置 */
#endif

View File

@ -0,0 +1,522 @@
/* -*- Mode: C; tab-width: 4; -*- */
/*
* Copyright (C) 2009, HustMoon Studio
*
* myfunc.c
*
* HustMoon@BYHH
*/
#include "myfunc.h"
#include "md5.h"
#include "mycheck.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
#ifndef SIOCGIFHWADDR /* BSD、MacOS */
#include <net/if_dl.h>
#include <ifaddrs.h>
#endif
#include <sys/poll.h>
const u_char STANDARD_ADDR[] = {0x01,0x80,0xC2,0x00,0x00,0x03};
const u_char RUIJIE_ADDR[] = {0x01,0xD0,0xF8,0x00,0x00,0x03};
static const char *DATAFILE = "/etc/mentohust/"; /* 默认数据文件(目录) */
static int dataOffset; /* 抓包偏移 */
static u_int32_t echoKey = 0, echoNo = 0; /* Echo阶段所需 */
u_char *fillBuf = NULL; /* 填充包地址 */
int fillSize = 0; /* 填充包大小 */
int bufType = 0; /*0内置xrgsu 1内置Win 2仅文件 3文件+校验*/
u_char version[2]; /* 版本 */
#ifndef NO_ARP
u_int32_t rip = 0; /* 实际IP */
u_char gateMAC[6]; /* 网关MAC */
#endif
extern char password[];
extern char nic[];
extern char dataFile[];
extern u_int32_t ip, mask, gateway, dns, pingHost;
extern u_char localMAC[], destMAC[];
extern unsigned startMode, dhcpMode;
static int checkFile(); /* 检查数据文件 */
static int getVersion(); /* 获取8021x.exe版本号 */
static int getAddress(); /* 获取网络地址 */
static u_char encode(u_char base); /* 锐捷算法颠倒一个字节的8位 */
static void checkSum(u_char *buf); /* 锐捷算法,计算两个字节的检验值 */
static int setProperty(u_char type, const u_char *value, int length); /* 设置指定属性 */
static int readPacket(int type); /* 读取数据 */
static int Check(const u_char *md5Seed); /* 校验算法 */
char *formatIP(u_int32_t ip)
{
static char tmp[16];
u_char *p = (u_char *)(&ip);
sprintf(tmp, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
return tmp;
}
char *formatHex(const void *buf, int length)
{
static char hex[385];
u_char *p = (u_char *)buf;
int i;
if (length > 128)
length = 128;
for (i=0; i<length; i++)
sprintf(hex+3*i,"%02x:", p[i]);
hex[3*length-1] = '\0';
return hex;
}
static int checkFile() {
u_char Buf[16], *buf=Buf;
FILE *fp = NULL;
if ((fp=fopen(dataFile, "rb")) == NULL)
goto fileError;
if (fread(buf, 16, 1, fp)<1 || memcmp(buf, "HUST", 4)!=0) {
fclose(fp);
goto fileError;
}
dataOffset = (int)LTOBL(*(u_int32_t *)buf ^ *(u_int32_t *)(buf + 8)) + 16;
fseek(fp, 0, SEEK_END);
fillSize = ftell(fp);
fclose(fp);
if (dataOffset < 16)
goto fileError;
fillSize = (fillSize - dataOffset) / 2 + 0x17;
if (fillSize<0x80 || fillSize>0x397)
goto fileError;
return 0;
fileError:
if (dataFile[strlen(dataFile)-1] != '/')
printf("!! 所选文件%s无效改用内置数据认证。\n", dataFile);
return -1;
}
static int getVersion() {
char file[0x100], *p;
DWORD ver;
strcpy(file, dataFile);
if ((p=strrchr(file, '/')+1) == (void *)1)
p = file;
strcpy(p, "8021x.exe");
if ((ver=getVer(file)) == (DWORD)-1)
return -1;
p = (char *)&ver;
version[0] = p[2];
version[1] = p[0];
bufType = 1;
return 0;
}
void newBuffer()
{
if (dataFile[0] == '\0')
strcpy(dataFile, DATAFILE);
getVersion();
if (checkFile() == 0)
bufType += 2;
else fillSize = (bufType==0 ? 0x80 : 0x1d7);
fillBuf = (u_char *)malloc(fillSize);
}
static int getAddress()
{
struct ifreq ifr;
#ifndef SIOCGIFHWADDR /* BSD、MacOS */
struct ifaddrs *ifap, *p = NULL;
struct sockaddr_dl *sdl;
#endif
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
{
printf("!! 创建套接字失败!\n");
return -1;
}
strcpy(ifr.ifr_name, nic);
#ifdef SIOCGIFHWADDR
if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
goto getMACError;
memcpy(localMAC, ifr.ifr_hwaddr.sa_data, 6);
#else
if (getifaddrs(&ifap) == 0)
{
for (p=ifap; p; p=p->ifa_next)
{
if (p->ifa_name && strcmp(p->ifa_name, nic)==0)
{
sdl = (struct sockaddr_dl *)p->ifa_addr;
memcpy(localMAC, sdl->sdl_data + sdl->sdl_nlen, 6);
break;
}
}
freeifaddrs(ifap);
}
if (p == NULL)
goto getMACError;
#endif
if (startMode == 0)
memcpy(destMAC, STANDARD_ADDR, 6);
else if (startMode == 1)
memcpy(destMAC, RUIJIE_ADDR, 6);
#ifndef NO_ARP
gateMAC[0] = 0xFE;
if (ioctl(sock, SIOCGIFADDR, &ifr) < 0)
printf("!! 在网卡%s上获取IP失败!\n", nic);
else {
rip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
if (gateway!=0 && (startMode%3!=2 || ((u_char *)&gateway)[3]!=0x02))
gateMAC[0] = 0xFF;
}
if (dhcpMode!=0 || ip==-1)
ip = rip;
#else
if (dhcpMode!=0 || ip==-1) {
if (ioctl(sock, SIOCGIFADDR, &ifr) < 0)
printf("!! 在网卡%s上获取IP失败!\n", nic);
else
ip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
}
#endif
if (dhcpMode!=0 || mask==-1) {
if (ioctl(sock, SIOCGIFNETMASK, &ifr) < 0)
printf("!! 在网卡%s上获取子网掩码失败!\n", nic);
else
mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
}
close(sock);
printf("** 本机MAC:\t%s\n", formatHex(localMAC, 6));
printf("** 使用IP:\t%s\n", formatIP(ip));
printf("** 子网掩码:\t%s\n", formatIP(mask));
return 0;
getMACError:
close(sock);
printf("!! 在网卡%s上获取MAC失败!\n", nic);
return -1;
}
static u_char encode(u_char base) /* 算法将一个字节的8位颠倒并取反 */
{
u_char result = 0;
int i;
for (i=0; i<8; i++)
{
result <<= 1;
result |= base&0x01;
base >>= 1;
}
return ~result;
}
static void checkSum(u_char *buf) /* 算法计算两个字节的checksum */
{
u_char table[] =
{
0x00,0x00,0x21,0x10,0x42,0x20,0x63,0x30,0x84,0x40,0xA5,0x50,0xC6,0x60,0xE7,0x70,
0x08,0x81,0x29,0x91,0x4A,0xA1,0x6B,0xB1,0x8C,0xC1,0xAD,0xD1,0xCE,0xE1,0xEF,0xF1,
0x31,0x12,0x10,0x02,0x73,0x32,0x52,0x22,0xB5,0x52,0x94,0x42,0xF7,0x72,0xD6,0x62,
0x39,0x93,0x18,0x83,0x7B,0xB3,0x5A,0xA3,0xBD,0xD3,0x9C,0xC3,0xFF,0xF3,0xDE,0xE3,
0x62,0x24,0x43,0x34,0x20,0x04,0x01,0x14,0xE6,0x64,0xC7,0x74,0xA4,0x44,0x85,0x54,
0x6A,0xA5,0x4B,0xB5,0x28,0x85,0x09,0x95,0xEE,0xE5,0xCF,0xF5,0xAC,0xC5,0x8D,0xD5,
0x53,0x36,0x72,0x26,0x11,0x16,0x30,0x06,0xD7,0x76,0xF6,0x66,0x95,0x56,0xB4,0x46,
0x5B,0xB7,0x7A,0xA7,0x19,0x97,0x38,0x87,0xDF,0xF7,0xFE,0xE7,0x9D,0xD7,0xBC,0xC7,
0xC4,0x48,0xE5,0x58,0x86,0x68,0xA7,0x78,0x40,0x08,0x61,0x18,0x02,0x28,0x23,0x38,
0xCC,0xC9,0xED,0xD9,0x8E,0xE9,0xAF,0xF9,0x48,0x89,0x69,0x99,0x0A,0xA9,0x2B,0xB9,
0xF5,0x5A,0xD4,0x4A,0xB7,0x7A,0x96,0x6A,0x71,0x1A,0x50,0x0A,0x33,0x3A,0x12,0x2A,
0xFD,0xDB,0xDC,0xCB,0xBF,0xFB,0x9E,0xEB,0x79,0x9B,0x58,0x8B,0x3B,0xBB,0x1A,0xAB,
0xA6,0x6C,0x87,0x7C,0xE4,0x4C,0xC5,0x5C,0x22,0x2C,0x03,0x3C,0x60,0x0C,0x41,0x1C,
0xAE,0xED,0x8F,0xFD,0xEC,0xCD,0xCD,0xDD,0x2A,0xAD,0x0B,0xBD,0x68,0x8D,0x49,0x9D,
0x97,0x7E,0xB6,0x6E,0xD5,0x5E,0xF4,0x4E,0x13,0x3E,0x32,0x2E,0x51,0x1E,0x70,0x0E,
0x9F,0xFF,0xBE,0xEF,0xDD,0xDF,0xFC,0xCF,0x1B,0xBF,0x3A,0xAF,0x59,0x9F,0x78,0x8F,
0x88,0x91,0xA9,0x81,0xCA,0xB1,0xEB,0xA1,0x0C,0xD1,0x2D,0xC1,0x4E,0xF1,0x6F,0xE1,
0x80,0x10,0xA1,0x00,0xC2,0x30,0xE3,0x20,0x04,0x50,0x25,0x40,0x46,0x70,0x67,0x60,
0xB9,0x83,0x98,0x93,0xFB,0xA3,0xDA,0xB3,0x3D,0xC3,0x1C,0xD3,0x7F,0xE3,0x5E,0xF3,
0xB1,0x02,0x90,0x12,0xF3,0x22,0xD2,0x32,0x35,0x42,0x14,0x52,0x77,0x62,0x56,0x72,
0xEA,0xB5,0xCB,0xA5,0xA8,0x95,0x89,0x85,0x6E,0xF5,0x4F,0xE5,0x2C,0xD5,0x0D,0xC5,
0xE2,0x34,0xC3,0x24,0xA0,0x14,0x81,0x04,0x66,0x74,0x47,0x64,0x24,0x54,0x05,0x44,
0xDB,0xA7,0xFA,0xB7,0x99,0x87,0xB8,0x97,0x5F,0xE7,0x7E,0xF7,0x1D,0xC7,0x3C,0xD7,
0xD3,0x26,0xF2,0x36,0x91,0x06,0xB0,0x16,0x57,0x66,0x76,0x76,0x15,0x46,0x34,0x56,
0x4C,0xD9,0x6D,0xC9,0x0E,0xF9,0x2F,0xE9,0xC8,0x99,0xE9,0x89,0x8A,0xB9,0xAB,0xA9,
0x44,0x58,0x65,0x48,0x06,0x78,0x27,0x68,0xC0,0x18,0xE1,0x08,0x82,0x38,0xA3,0x28,
0x7D,0xCB,0x5C,0xDB,0x3F,0xEB,0x1E,0xFB,0xF9,0x8B,0xD8,0x9B,0xBB,0xAB,0x9A,0xBB,
0x75,0x4A,0x54,0x5A,0x37,0x6A,0x16,0x7A,0xF1,0x0A,0xD0,0x1A,0xB3,0x2A,0x92,0x3A,
0x2E,0xFD,0x0F,0xED,0x6C,0xDD,0x4D,0xCD,0xAA,0xBD,0x8B,0xAD,0xE8,0x9D,0xC9,0x8D,
0x26,0x7C,0x07,0x6C,0x64,0x5C,0x45,0x4C,0xA2,0x3C,0x83,0x2C,0xE0,0x1C,0xC1,0x0C,
0x1F,0xEF,0x3E,0xFF,0x5D,0xCF,0x7C,0xDF,0x9B,0xAF,0xBA,0xBF,0xD9,0x8F,0xF8,0x9F,
0x17,0x6E,0x36,0x7E,0x55,0x4E,0x74,0x5E,0x93,0x2E,0xB2,0x3E,0xD1,0x0E,0xF0,0x1E
};
u_char *checkSum = buf + 0x15;
int i, index;
for (i=0; i<0x15; i++)
{
index = checkSum[0] ^ buf[i];
checkSum[0] = checkSum[1] ^ table[index*2+1];
checkSum[1] = table[index*2];
}
for (i=0; i<0x17; i++)
buf[i] = encode(buf[i]);
}
int fillHeader()
{
if (getAddress() == -1)
return -1;
memset(fillBuf, 0, fillSize);
fillBuf[0x02] = 0x13;
fillBuf[0x03] = 0x11;
if (dhcpMode != 0)
fillBuf[0x04] = 0x01; /* DHCP位使用1、不使用0 */
memcpy(fillBuf+0x05, &ip, 4);
memcpy(fillBuf+0x09, &mask, 4);
memcpy(fillBuf+0x0D, &gateway, 4);
memcpy(fillBuf+0x11, &dns, 4);
checkSum(fillBuf);
return 0;
}
static int setProperty(u_char type, const u_char *value, int length)
{
u_char *p = fillBuf+0x46, *end = fillBuf+fillSize-length-8; /* 形如1a 28 00 00 13 11 17 22至少8个字节 */
while (p < end)
{
if (*p == 0x1a) /* 有些老版本没有前两个字节包括xrgsu */
p += 2;
if (p[4] == type)
{
memcpy(p+4+p[5]-length, value, length);
return 0;
}
p += p[5] + 4;
}
return -1;
}
static int readPacket(int type)
{
u_char dhcp[] = {0x00};
FILE *fp = fopen(dataFile, "rb");
if (fp == NULL)
goto fileError;
type %= 2; /* 偶数读Start包奇数读Md5包 */
fseek(fp, dataOffset+(fillSize-0x17)*type, SEEK_SET);
if (fread(fillBuf+0x17, fillSize-0x17, 1, fp) < 1) /* 前0x17字节是地址及校验值 */
{
fclose(fp);
goto fileError;
}
fclose(fp);
if (dhcpMode == 1) /* 二次认证第一次 */
dhcp[0] = 0x01;
setProperty(0x18, dhcp, 1);
setProperty(0x2D, localMAC, 6);
if (bufType == 3)
memcpy(fillBuf+0x3b, version, 2);
return 0;
fileError:
printf("!! 所选文件%s无效改用内置数据认证。\n", dataFile);
bufType -= 2;
if (bufType==1 && fillSize<0x1d7) {
free(fillBuf);
fillSize = 0x1d7;
fillBuf = (u_char *)malloc(fillSize);
}
return -1;
}
void fillStartPacket()
{
if (bufType <= 1) { /* 使用xrgsu */
const u_char packet0[] = {
0x00,0x00,0x13,0x11,0x38,0x30,0x32,0x31,0x78,0x2e,0x65,0x78,0x65,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x13,0x11,0x00,0x28,0x1a,
0x28,0x00,0x00,0x13,0x11,0x17,0x22,0x91,0x66,0x64,0x93,0x67,0x60,0x65,0x62,0x62,
0x94,0x61,0x69,0x67,0x63,0x91,0x93,0x92,0x68,0x66,0x93,0x91,0x66,0x95,0x65,0xaa,
0xdc,0x64,0x98,0x96,0x6a,0x9d,0x66,0x00,0x00,0x13,0x11,0x18,0x06,0x02,0x00,0x00
};
const u_char packet1[] = {
0x00,0x00,0x13,0x11,0x38,0x30,0x32,0x31,0x78,0x2e,0x65,0x78,0x65,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x04,0x0a,0x00,0x02,0x00,0x00,0x00,0x13,0x11,0x01,0x8c,0x1a,
0x28,0x00,0x00,0x13,0x11,0x17,0x22,0x36,0x38,0x44,0x43,0x31,0x32,0x33,0x42,0x37,
0x45,0x42,0x32,0x33,0x39,0x46,0x32,0x33,0x41,0x38,0x43,0x30,0x30,0x30,0x33,0x38,
0x38,0x34,0x39,0x38,0x36,0x33,0x39,0x1a,0x0c,0x00,0x00,0x13,0x11,0x18,0x06,0x00,
0x00,0x00,0x00,0x1a,0x0e,0x00,0x00,0x13,0x11,0x2d,0x08,0x00,0x00,0x00,0x00,0x00,
0x00,0x1a,0x08,0x00,0x00,0x13,0x11,0x2f,0x02,0x1a,0x09,0x00,0x00,0x13,0x11,0x35,
0x03,0x01,0x1a,0x18,0x00,0x00,0x13,0x11,0x36,0x12,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0x18,0x00,0x00,0x13,0x11,
0x38,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x86,
0x13,0x4c,0x1a,0x88,0x00,0x00,0x13,0x11,0x4d,0x82,0x36,0x38,0x64,0x63,0x31,0x32,
0x33,0x62,0x30,0x37,0x65,0x62,0x32,0x33,0x39,0x66,0x32,0x33,0x61,0x38,0x30,0x64,
0x63,0x66,0x32,0x35,0x38,0x37,0x35,0x64,0x30,0x35,0x37,0x37,0x30,0x63,0x37,0x32,
0x31,0x65,0x34,0x35,0x36,0x34,0x35,0x65,0x35,0x33,0x37,0x61,0x62,0x33,0x35,0x31,
0x62,0x62,0x36,0x33,0x31,0x35,0x35,0x61,0x65,0x31,0x36,0x32,0x36,0x31,0x36,0x37,
0x65,0x62,0x30,0x39,0x32,0x32,0x33,0x65,0x32,0x61,0x30,0x61,0x37,0x38,0x30,0x33,
0x31,0x31,0x36,0x31,0x61,0x63,0x30,0x39,0x64,0x61,0x32,0x64,0x63,0x30,0x37,0x33,
0x36,0x39,0x33,0x61,0x34,0x66,0x35,0x61,0x32,0x39,0x32,0x38,0x36,0x37,0x35,0x31,
0x66,0x39,0x37,0x66,0x34,0x64,0x30,0x34,0x36,0x38,0x1a,0x28,0x00,0x00,0x13,0x11,
0x39,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x1a,0x48,0x00,0x00,0x13,0x11,0x54,0x42,0x48,0x55,0x53,0x54,0x4d,0x4f,
0x4f,0x4e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0x08,0x00,0x00,0x13,0x11,
0x55,0x02,0x1a,0x09,0x00,0x00,0x13,0x11,0x62,0x03,0x00,0x00,0x00,0x00,0x00,0x00
};
u_char dhcp[] = {0x00};
if (dhcpMode == 1) /* 二次认证第一次 */
dhcp[0] = 0x01;
if (bufType == 1) {
memcpy(fillBuf+0x17, packet1, sizeof(packet1));
memcpy(fillBuf+0x3b, version, 2);
} else
memcpy(fillBuf+0x17, packet0, sizeof(packet0));
setProperty(0x18, dhcp, 1);
setProperty(0x2D, localMAC, 6);
}
else if (readPacket(0) == -1) /* 读取数据失败就用默认的填充 */
fillStartPacket();
}
void fillMd5Packet(const u_char *md5Seed)
{
if (bufType <= 1) { /* 不使用数据包? */
/* xrgsu的Md5包与Start包只有一个字节的差异若以其他版本为基础可进一步区别对待 */
fillStartPacket();
if (bufType == 1)
Check(md5Seed);
} else {
if (readPacket(1) == -1)
fillMd5Packet(md5Seed);
else
Check(md5Seed);
}
echoNo = 0x0000102B; /* 初始化echoNo */
}
static int Check(const u_char *md5Seed) /* 客户端校验 */
{
char final_str[129];
int value;
printf("** 客户端版本:\t%d.%d\n", fillBuf[0x3B], fillBuf[0x3C]);
printf("** MD5种子:\t%s\n", formatHex(md5Seed, 16));
value = check_init(dataFile);
if (value == -1) {
printf("!! 缺少8021x.exe信息客户端校验无法继续\n");
return 1;
}
V2_check(md5Seed, final_str);
printf("** V2校验值:\t%s\n", final_str);
setProperty(0x17, (u_char *)final_str, 32);
check_free();
return 0;
}
void fillEchoPacket(u_char *echoBuf)
{
int i;
u_int32_t dd1=htonl(echoKey + echoNo), dd2=htonl(echoNo);
u_char *bt1=(u_char *)&dd1, *bt2=(u_char *)&dd2;
echoNo++;
for (i=0; i<4; i++)
{
echoBuf[0x18+i] = encode(bt1[i]);
echoBuf[0x22+i] = encode(bt2[i]);
}
}
void getEchoKey(const u_char *capBuf)
{
int i, offset = 0x1c+capBuf[0x1b]+0x69+24; /* 通过比较了大量抓包,通用的提取点就是这样的 */
u_char *base;
echoKey = ntohl(*(u_int32_t *)(capBuf+offset));
base = (u_char *)(&echoKey);
for (i=0; i<4; i++)
base[i] = encode(base[i]);
}
u_char *checkPass(u_char id, const u_char *md5Seed, int seedLen)
{
u_char md5Src[80];
int md5Len = strlen(password);
md5Src[0] = id;
memcpy(md5Src+1, password, md5Len);
md5Len++;
if (startMode % 3 == 2) /* 赛尔? */
{
memcpy(md5Src+md5Len, "xxghlmxhzb", 10);
md5Len += 10;
}
memcpy(md5Src+md5Len, md5Seed, seedLen);
md5Len += seedLen;
return ComputeHash(md5Src, md5Len);
}
void fillCernetAddr(u_char *buf)
{
memcpy(buf+0x18, &ip, 4);
memcpy(buf+0x1C, &mask, 4);
memcpy(buf+0x20, &gateway, 4);
memset(buf+0x24, 0, 4); /* memcpy(buf+0x24, &dns, 4); */
}
int isOnline()
{
u_char echoPacket[] =
{
0x08,0x00,0x61,0xb2,0x02,0x00,0x01,0x00,0x57,0x65,0x6C,0x63,0x6F,0x6D,0x65,0x20,
0x74,0x6F,0x20,0x4D,0x65,0x6E,0x74,0x6F,0x48,0x55,0x53,0x54,0x21,0x0A,0x43,0x6F,
0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x39,
0x20,0x48,0x75,0x73,0x74,0x4D,0x6F,0x6F,0x6E,0x20,0x53,0x74,0x75,0x64,0x69,0x6F
};
int sock=-1, rtVal, t;
struct pollfd pfd;
struct sockaddr_in dest;
if (pingHost == 0)
return 0;
memset(&dest, 0, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = pingHost;
if ((sock=socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
goto pingError;
pfd.fd = sock;
pfd.events = POLLIN;
for (t=1; t<=3; t++) {
if (sendto(sock, echoPacket, sizeof(echoPacket), 0,
(struct sockaddr *)&dest, sizeof(dest)) < 0)
goto pingError;
rtVal = poll(&pfd, 1, t*1000);
if (rtVal == -1)
goto pingError;
if (rtVal > 0) {
close(sock);
return 0;
}
}
close(sock);
return -1;
pingError:
perror("!! Ping主机出错关闭该功能");
if (sock != -1)
close(sock);
pingHost = 0;
return 0;
}

View File

@ -0,0 +1,26 @@
/*
* Copyright (C) 2009, HustMoon Studio
*
* myfunc.h
*
* HustMoon@BYHH
*/
#ifndef HUSTMOON_MYFUNC_H
#define HUSTMOON_MYFUNC_H
#include <sys/types.h>
char *formatIP(u_int32_t ip); /* 格式化IP */
char *formatHex(const void *buf, int length); /* 格式化成十六进制形式 */
void newBuffer(); /* 检测数据文件有效性并分配内存 */
int fillHeader(); /* 填充网络地址及校验值部分 */
void fillStartPacket(); /* 填充Start包 */
void fillMd5Packet(const u_char *md5Seed); /* 填充Md5包 */
void fillEchoPacket(u_char *buf); /* 填充Echo包 */
void getEchoKey(const u_char *capBuf); /* 获取EchoKey */
u_char *checkPass(u_char id, const u_char *md5Seed, int seedLen); /* 计算密码的md5 */
void fillCernetAddr(u_char *buf); /* 填充赛尔网络地址 */
int isOnline(); /* ping主机判断是否掉线 */
#endif

View File

@ -0,0 +1,203 @@
/* -*- Mode: C; tab-width: 4; -*- */
/*
* Copyright (C) 2009, HustMoon Studio
*
* myini.c
* ini文件+ini文件
* HustMoon@BYHH
* 2009.10.8
*/
#include "myini.h"
#include <stdio.h>
#include <string.h>
#define NOT_COMMENT(c) (c!=';' && c!='#') /* 不是注释行 */
#ifndef strnicmp
#define strnicmp strncasecmp
#endif
static void getLine(const char *buf, int inStart, int *lineStart, int *lineEnd);
static int findKey(const char *buf, const char *section, const char *key,
int *sectionStart, int *valueStart, unsigned long *valueSize);
static int getSection(const char *buf, int inStart);
char *loadFile(const char *fileName)
{
FILE *fp = NULL;
long size = 0;
char *buf = NULL;
if ((fp=fopen(fileName, "rb")) == NULL)
return NULL;
fseek(fp, 0, SEEK_END);
size = ftell(fp);
rewind(fp);
buf = (char *)malloc(size+1);
buf[size] = '\0';
if (fread(buf, size, 1, fp) < 1)
{
free(buf);
buf = NULL;
}
fclose(fp);
return buf;
}
static void getLine(const char *buf, int inStart, int *lineStart, int *lineEnd)
{
int start, end;
for (start=inStart; buf[start]==' ' || buf[start]=='\t' || buf[start]=='\r' || buf[start]=='\n'; start++);
for (end=start; buf[end]!='\r' && buf[end]!='\n' && buf[end]!='\0'; end++);
*lineStart = start;
*lineEnd = end;
}
static int findKey(const char *buf, const char *section, const char *key,
int *sectionStart, int *valueStart, unsigned long *valueSize)
{
int lineStart, lineEnd, i;
for (*sectionStart=-1, lineEnd=0; buf[lineEnd]!='\0'; )
{
getLine(buf, lineEnd, &lineStart, &lineEnd);
if (buf[lineStart] == '[')
{
for (i=++lineStart; i<lineEnd && buf[i]!=']'; i++);
if (i<lineEnd && strnicmp(buf+lineStart, section, i-lineStart)==0) /* 找到Section */
{
*sectionStart = lineStart-1;
if (key == NULL)
return -1;
}
else if (*sectionStart != -1) /* 找到Section但未找到Key */
return -1;
}
else if (*sectionStart!=-1 && NOT_COMMENT(buf[lineStart])) /* 找到Section且该行不是注释 */
{
for (i=lineStart+1; i<lineEnd && buf[i]!='='; i++);
if (i<lineEnd && strnicmp(buf+lineStart, key, i-lineStart)==0) /* 找到Key */
{
*valueStart = i + 1;
*valueSize = lineEnd - *valueStart;
return 0;
}
}
}
return -1;
}
int getString(const char *buf, const char *section, const char *key,
const char *defaultValue, char *value, unsigned long size)
{
int sectionStart, valueStart;
unsigned long valueSize;
if (findKey(buf, section, key, &sectionStart, &valueStart, &valueSize)!=0 || valueSize==0) /* 未找到? */
{
strncpy(value, defaultValue, size);
return -1;
}
if (size-1 < valueSize) /* 找到但太长? */
valueSize = size - 1;
memset(value, 0, size);
strncpy(value, buf+valueStart, valueSize);
return 0;
}
int getInt(const char *buf, const char *section, const char *key, int defaultValue)
{
char value[21] = {0};
getString(buf, section, key, "", value, sizeof(value));
if (value[0] == '\0') /* 找不到或找到但为空? */
return defaultValue;
return atoi(value);
}
void setString(char **buf, const char *section, const char *key, const char *value)
{
int sectionStart, valueStart;
unsigned long valueSize;
char *newBuf = NULL;
if (findKey(*buf, section, key, &sectionStart, &valueStart, &valueSize) == 0) /* 找到key */
{
if (value == NULL) /* 删除key? */
memmove(*buf+valueStart-strlen(key)-1, *buf+valueStart+valueSize,
strlen(*buf)+1-valueStart-valueSize);
else /* 修改key */
{
newBuf = (char *)malloc(strlen(*buf)-valueSize+strlen(value)+1);
memcpy(newBuf, *buf, valueStart);
strcpy(newBuf+valueStart, value);
strcpy(newBuf+valueStart+strlen(value), *buf+valueStart+valueSize);
free(*buf);
*buf = newBuf;
}
}
else if (sectionStart != -1) /* 找到section找不到key */
{
if (key == NULL) /* 删除section? */
{
valueStart = getSection(*buf, sectionStart+3);
if (valueStart <= sectionStart) /* 后面没有section */
(*buf)[sectionStart] = '\0';
else
memmove(*buf+sectionStart, *buf+valueStart, strlen(*buf)+1-valueStart);
}
else if (value != NULL) /* 不是要删除key */
{
newBuf = (char *)malloc(strlen(*buf)+strlen(key)+strlen(value)+4);
valueSize = sectionStart+strlen(section)+2;
memcpy(newBuf, *buf, valueSize);
sprintf(newBuf+valueSize, "\n%s=%s", key, value);
strcpy(newBuf+strlen(newBuf), *buf+valueSize);
free(*buf);
*buf = newBuf;
}
}
else /* 找不到section? */
{
if (key!=NULL && value!=NULL)
{
newBuf = (char *)malloc(strlen(*buf)+strlen(section)+strlen(key)+strlen(value)+8);
strcpy(newBuf, *buf);
sprintf(newBuf+strlen(newBuf), "\n[%s]\n%s=%s", section, key, value);
free(*buf);
*buf = newBuf;
}
}
}
static int getSection(const char *buf, int inStart)
{
int lineStart, lineEnd, i;
for (lineEnd=inStart; buf[lineEnd]!='\0'; )
{
getLine(buf, lineEnd, &lineStart, &lineEnd);
if (buf[lineStart] == '[')
{
for (i=lineStart+1; i<lineEnd && buf[i]!=']'; i++);
if (i < lineEnd)
return lineStart;
}
}
return -1;
}
void setInt(char **buf, const char *section, const char *key, int value)
{
char svalue[21];
sprintf(svalue, "%d", value);
setString(buf, section, key, svalue);
}
int saveFile(const char *buf, const char *fileName)
{
FILE *fp;
int result;
if ((fp=fopen(fileName, "wb")) == NULL)
return -1;
result = fwrite(buf, strlen(buf), 1, fp)<1 ? -1 : 0;
fclose(fp);
return result;
}

View File

@ -0,0 +1,32 @@
/* -*- Mode: C; tab-width: 4; -*- */
/*
* Copyright (C) 2009, HustMoon Studio
*
* myini.h
* ini文件+ini文件
* HustMoon@BYHH
* 2009.10.8
*/
#ifndef HUSTMOON_MYINI_H
#define HUSTMOON_MYINI_H
#include <stdlib.h> /* for free() */
#ifdef __cplusplus
extern "C"
{
#endif
char *loadFile(const char *fileName); /* 读取文件 */
int getString(const char *buf, const char *section, const char *key,
const char *defaultValue, char *value, unsigned long size); /* 读取字符串 */
int getInt(const char *buf, const char *section, const char *key, int defaultValue); /* 读取整数 */
void setString(char **buf, const char *section, const char *key, const char *value); /* 设置字符串value=NULL则删除keykey=NULL则删除section */
void setInt(char **buf, const char *section, const char *key, int value); /* 设置整数 */
int saveFile(const char *buf, const char *fileName); /* 写入文件 */
#ifdef __cplusplus
};
#endif
#endif

View File

@ -0,0 +1,331 @@
/* -*- Mode: C; tab-width: 4; -*- */
/*
* Copyright (C) 2009, HustMoon Studio
*
* mystate.c
*
* HustMoon@BYHH
* www.ehust@gmail.com
*/
#include "mystate.h"
#include "myfunc.h"
#include "dlfunc.h"
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
#define MAX_SEND_COUNT 3 /* 最大超时次数 */
volatile int state = ID_DISCONNECT; /* 认证状态 */
const u_char *capBuf = NULL; /* 抓到的包 */
static u_char sendPacket[0x3E8]; /* 用来发送的包 */
static int sendCount = 0; /* 同一阶段发包计数 */
extern const u_char STANDARD_ADDR[];
extern char userName[];
extern unsigned startMode;
extern unsigned dhcpMode;
extern u_char localMAC[], destMAC[];
extern unsigned timeout;
extern unsigned echoInterval;
extern unsigned restartWait;
extern char dhcpScript[];
extern pcap_t *hPcap;
extern u_char *fillBuf;
extern unsigned fillSize;
extern u_int32_t pingHost;
#ifndef NO_ARP
extern u_int32_t rip, gateway;
extern u_char gateMAC[];
static void sendArpPacket(); /* ARP监视 */
#endif
static void setTimer(unsigned interval); /* 设置定时器 */
static int renewIP(); /* 更新IP */
static void fillEtherAddr(u_int32_t protocol); /* 填充MAC地址和协议 */
static int sendStartPacket(); /* 发送Start包 */
static int sendIdentityPacket(); /* 发送Identity包 */
static int sendChallengePacket(); /* 发送Md5 Challenge包 */
static int sendEchoPacket(); /* 发送心跳包 */
static int sendLogoffPacket(); /* 发送退出包 */
static int waitEchoPacket(); /* 等候响应包 */
static void setTimer(unsigned interval) /* 设置定时器 */
{
struct itimerval timer;
timer.it_value.tv_sec = interval;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = interval;
timer.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &timer, NULL);
}
int switchState(int type)
{
if (state == type) /* 跟上次是同一状态? */
sendCount++;
else
{
state = type;
sendCount = 0;
}
if (sendCount>=MAX_SEND_COUNT && type!=ID_ECHO) /* 超时太多次? */
{
switch (type)
{
case ID_START:
printf(">> 找不到服务器,重启认证!\n");
break;
case ID_IDENTITY:
printf(">> 发送用户名超时,重启认证!\n");
break;
case ID_CHALLENGE:
printf(">> 发送密码超时,重启认证!\n");
break;
case ID_WAITECHO:
printf(">> 等候响应包超时,自行响应!\n");
return switchState(ID_ECHO);
}
return restart();
}
switch (type)
{
case ID_DHCP:
return renewIP();
case ID_START:
return sendStartPacket();
case ID_IDENTITY:
return sendIdentityPacket();
case ID_CHALLENGE:
return sendChallengePacket();
case ID_WAITECHO: /* 塞尔的就不ping了不好计时 */
return waitEchoPacket();
case ID_ECHO:
if (pingHost && sendCount*echoInterval > 60) { /* 1分钟左右 */
if (isOnline() == -1) {
printf(">> 认证掉线,开始重连!\n");
return switchState(ID_START);
}
sendCount = 1;
}
#ifndef NO_ARP
if (gateMAC[0] != 0xFE)
sendArpPacket();
#endif
return sendEchoPacket();
case ID_DISCONNECT:
return sendLogoffPacket();
}
return 0;
}
int restart()
{
if (startMode >= 3) /* 标记服务器地址为未获取 */
startMode -= 3;
state = ID_START;
sendCount = -1;
setTimer(restartWait); /* restartWait秒后或者服务器请求后重启认证 */
return 0;
}
static int renewIP()
{
setTimer(0); /* 取消定时器 */
printf(">> 正在获取IP...\n");
system(dhcpScript);
printf(">> 操作结束。\n");
dhcpMode += 3; /* 标记为已获取123变为4565不需再认证*/
if (fillHeader() == -1)
exit(EXIT_FAILURE);
if (dhcpMode == 5)
return switchState(ID_ECHO);
return switchState(ID_START);
}
static void fillEtherAddr(u_int32_t protocol)
{
memset(sendPacket, 0, 0x3E8);
memcpy(sendPacket, destMAC, 6);
memcpy(sendPacket+0x06, localMAC, 6);
*(u_int32_t *)(sendPacket+0x0C) = htonl(protocol);
}
static int sendStartPacket()
{
if (startMode%3 == 2) /* 赛尔 */
{
if (sendCount == 0)
{
printf(">> 寻找服务器...\n");
memcpy(sendPacket, STANDARD_ADDR, 6);
memcpy(sendPacket+0x06, localMAC, 6);
*(u_int32_t *)(sendPacket+0x0C) = htonl(0x888E0101);
*(u_int16_t *)(sendPacket+0x10) = 0;
memset(sendPacket+0x12, 0xa5, 42);
setTimer(timeout);
}
return pcap_sendpacket(hPcap, sendPacket, 60);
}
if (sendCount == 0)
{
printf(">> 寻找服务器...\n");
fillStartPacket();
fillEtherAddr(0x888E0101);
memcpy(sendPacket+0x12, fillBuf, fillSize);
setTimer(timeout);
}
return pcap_sendpacket(hPcap, sendPacket, 0x3E8);
}
static int sendIdentityPacket()
{
int nameLen = strlen(userName);
if (startMode%3 == 2) /* 赛尔 */
{
if (sendCount == 0)
{
printf(">> 发送用户名...\n");
*(u_int16_t *)(sendPacket+0x0E) = htons(0x0100);
*(u_int16_t *)(sendPacket+0x10) = *(u_int16_t *)(sendPacket+0x14) = htons(nameLen+30);
sendPacket[0x12] = 0x02;
sendPacket[0x16] = 0x01;
sendPacket[0x17] = 0x01;
fillCernetAddr(sendPacket);
memcpy(sendPacket+0x28, "03.02.05", 8);
memcpy(sendPacket+0x30, userName, nameLen);
setTimer(timeout);
}
sendPacket[0x13] = capBuf[0x13];
return pcap_sendpacket(hPcap, sendPacket, nameLen+48);
}
if (sendCount == 0)
{
printf(">> 发送用户名...\n");
fillEtherAddr(0x888E0100);
nameLen = strlen(userName);
*(u_int16_t *)(sendPacket+0x14) = *(u_int16_t *)(sendPacket+0x10) = htons(nameLen+5);
sendPacket[0x12] = 0x02;
sendPacket[0x13] = capBuf[0x13];
sendPacket[0x16] = 0x01;
memcpy(sendPacket+0x17, userName, nameLen);
memcpy(sendPacket+0x17+nameLen, fillBuf, fillSize);
setTimer(timeout);
}
return pcap_sendpacket(hPcap, sendPacket, 0x3E8);
}
static int sendChallengePacket()
{
int nameLen = strlen(userName);
if (startMode%3 == 2) /* 赛尔 */
{
if (sendCount == 0)
{
printf(">> 发送密码...\n");
*(u_int16_t *)(sendPacket+0x0E) = htons(0x0100);
*(u_int16_t *)(sendPacket+0x10) = *(u_int16_t *)(sendPacket+0x14) = htons(nameLen+22);
sendPacket[0x12] = 0x02;
sendPacket[0x13] = capBuf[0x13];
sendPacket[0x16] = 0x04;
sendPacket[0x17] = 16;
memcpy(sendPacket+0x18, checkPass(capBuf[0x13], capBuf+0x18, capBuf[0x17]), 16);
memcpy(sendPacket+0x28, userName, nameLen);
setTimer(timeout);
}
return pcap_sendpacket(hPcap, sendPacket, nameLen+40);
}
if (sendCount == 0)
{
printf(">> 发送密码...\n");
fillMd5Packet(capBuf+0x18);
fillEtherAddr(0x888E0100);
*(u_int16_t *)(sendPacket+0x14) = *(u_int16_t *)(sendPacket+0x10) = htons(nameLen+22);
sendPacket[0x12] = 0x02;
sendPacket[0x13] = capBuf[0x13];
sendPacket[0x16] = 0x04;
sendPacket[0x17] = 16;
memcpy(sendPacket+0x18, checkPass(capBuf[0x13], capBuf+0x18, capBuf[0x17]), 16);
memcpy(sendPacket+0x28, userName, nameLen);
memcpy(sendPacket+0x28+nameLen, fillBuf, fillSize);
setTimer(timeout);
}
return pcap_sendpacket(hPcap, sendPacket, 0x3E8);
}
static int sendEchoPacket()
{
if (startMode%3 == 2) /* 赛尔 */
{
*(u_int16_t *)(sendPacket+0x0E) = htons(0x0106);
*(u_int16_t *)(sendPacket+0x10) = 0;
memset(sendPacket+0x12, 0xa5, 42);
switchState(ID_WAITECHO); /* 继续等待 */
return pcap_sendpacket(hPcap, sendPacket, 60);
}
if (sendCount == 0)
{
u_char echo[] =
{
0x00,0x1E,0xFF,0xFF,0x37,0x77,0x7F,0x9F,0xFF,0xFF,0xD9,0x13,0xFF,0xFF,0x37,0x77,
0x7F,0x9F,0xFF,0xFF,0xF7,0x2B,0xFF,0xFF,0x37,0x77,0x7F,0x3F,0xFF
};
printf(">> 发送心跳包以保持在线...\n");
fillEtherAddr(0x888E01BF);
memcpy(sendPacket+0x10, echo, sizeof(echo));
setTimer(echoInterval);
}
fillEchoPacket(sendPacket);
return pcap_sendpacket(hPcap, sendPacket, 0x2D);
}
static int sendLogoffPacket()
{
setTimer(0); /* 取消定时器 */
if (startMode%3 == 2) /* 赛尔 */
{
*(u_int16_t *)(sendPacket+0x0E) = htons(0x0102);
*(u_int16_t *)(sendPacket+0x10) = 0;
memset(sendPacket+0x12, 0xa5, 42);
return pcap_sendpacket(hPcap, sendPacket, 60);
}
fillStartPacket(); /* 锐捷的退出包与Start包类似不过其实不这样也是没问题的 */
fillEtherAddr(0x888E0102);
memcpy(sendPacket+0x12, fillBuf, fillSize);
return pcap_sendpacket(hPcap, sendPacket, 0x3E8);
}
static int waitEchoPacket()
{
if (sendCount == 0)
setTimer(echoInterval);
return 0;
}
#ifndef NO_ARP
static void sendArpPacket()
{
u_char arpPacket[0x3C] = {
0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x06,0x00,0x01,
0x08,0x00,0x06,0x04,0x00};
if (gateMAC[0] != 0xFF) {
memcpy(arpPacket, gateMAC, 6);
memcpy(arpPacket+0x06, localMAC, 6);
arpPacket[0x15]=0x02;
memcpy(arpPacket+0x16, localMAC, 6);
memcpy(arpPacket+0x1c, &rip, 4);
memcpy(arpPacket+0x20, gateMAC, 6);
memcpy(arpPacket+0x26, &gateway, 4);
pcap_sendpacket(hPcap, arpPacket, 0x3C);
}
memset(arpPacket, 0xFF, 6);
memcpy(arpPacket+0x06, localMAC, 6);
arpPacket[0x15]=0x01;
memcpy(arpPacket+0x16, localMAC, 6);
memcpy(arpPacket+0x1c, &rip, 4);
memset(arpPacket+0x20, 0, 6);
memcpy(arpPacket+0x26, &gateway, 4);
pcap_sendpacket(hPcap, arpPacket, 0x2A);
}
#endif

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2009, HustMoon Studio
*
* mystate.h
*
* HustMoon@BYHH
*/
#ifndef HUSTMOON_MYSTATE_H
#define HUSTMOON_MYSTATE_H
#define ID_DISCONNECT 0 /* 断开状态 */
#define ID_START 1 /* 寻找服务器 */
#define ID_IDENTITY 2 /* 发送用户名 */
#define ID_CHALLENGE 3 /* 发送密码 */
#define ID_ECHO 4 /* 发送心跳包 */
#define ID_DHCP 5 /* 更新IP */
#define ID_WAITECHO 6 /* 等待心跳包 */
int switchState(int type); /* 改变状态 */
int restart(); /* 重启认证 */
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,36 @@
/**
* Copyright(c) 2012-2013, All Rights Reserved.
*
* @file strnormalize.h
* @details Check GBK character you could do
* code >= 0x8000 && _pGbk2Utf16[code - 0x8000] != 0
* @author cnangel
* @version 1.0.0
* @date 2012/10/09 11:44:58
*/
#ifndef __STRNORMALIZE_H__
#define __STRNORMALIZE_H__
#ifdef __cplusplus
extern "C" {
#endif
#define SNO_TO_LOWER 1
#define SNO_TO_UPPER 2
#define SNO_TO_HALF 4
#define SNO_TO_SIMPLIFIED 8
void str_normalize_init();
void str_normalize_gbk(char *text, unsigned options);
void str_normalize_utf8(char *text, unsigned options);
int gbk_to_utf8(const char *from, unsigned int from_len, char **to, unsigned int *to_len);
int utf8_to_gbk(const char *from, unsigned int from_len, char **to, unsigned int *to_len);
#ifdef __cplusplus
}
#endif
#endif /* __STRNORMALIZE_H__ */

View File

@ -0,0 +1,10 @@
#ifndef TYPES_H
#define TYPES_H
typedef unsigned char *POINTER;
typedef unsigned char BYTE;
typedef unsigned char UCHAR;
typedef unsigned short int WORD;
typedef int LONG;
typedef unsigned int DWORD;
typedef unsigned int UINT4;
#endif

85
gost/Makefile Normal file
View File

@ -0,0 +1,85 @@
#
# Copyright (C) 2021 ImmortalWrt
# <https://immortalwrt.org>
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=gost
PKG_VERSION:=2.11.1
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/ginuerzh/gost/tar.gz/v$(PKG_VERSION)?
PKG_HASH:=skip
PKG_LICENSE:=MIT
PKG_LICENSE_FILE:=LICENSE
PKG_MAINTAINER:=CN_SZTL <cnsztl@immortalwrt.org>
PKG_CONFIG_DEPENDS:= \
CONFIG_GOST_COMPRESS_GOPROXY \
CONFIG_GOST_COMPRESS_UPX
PKG_BUILD_DEPENDS:=golang/host
PKG_BUILD_PARALLEL:=1
PKG_USE_MIPS16:=0
GO_PKG:=github.com/ginuerzh/gost
GO_PKG_BUILD_PKG:=github.com/ginuerzh/gost/cmd/gost
GO_PKG_LDFLAGS:=-s -w
include $(INCLUDE_DIR)/package.mk
include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk
define Package/gost
SECTION:=net
CATEGORY:=Network
TITLE:=GO Simple Tunnel
URL:=https://github.com/ginuerzh/gost
DEPENDS:=$(GO_ARCH_DEPENDS)
endef
define Package/gost/description
A simple security tunnel written in Golang
endef
define Package/gost/config
config GOST_COMPRESS_GOPROXY
bool "Compiling with GOPROXY proxy"
default n
config GOST_COMPRESS_UPX
bool "Compress executable files with UPX"
default y
endef
ifeq ($(CONFIG_GOST_COMPRESS_GOPROXY),y)
export GO111MODULE=on
export GOPROXY=https://goproxy.io
endif
define Build/Compile
$(call GoPackage/Build/Compile)
ifeq ($(CONFIG_GOST_COMPRESS_UPX),y)
$(STAGING_DIR_HOST)/bin/upx --lzma --best $(GO_PKG_BUILD_BIN_DIR)/gost
endif
endef
define Package/gost/install
$(call GoPackage/Package/Install/Bin,$(PKG_INSTALL_DIR))
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/gost $(1)/usr/bin/gost
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) $(CURDIR)/files/gost.config $(1)/etc/config/gost
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) $(CURDIR)/files/gost.init $(1)/etc/init.d/gost
endef
$(eval $(call GoBinPackage,gost))
$(eval $(call BuildPackage,gost))

5
gost/files/gost.config Normal file
View File

@ -0,0 +1,5 @@
config gost
option enable '0'
option run_command ''

22
gost/files/gost.init Executable file
View File

@ -0,0 +1,22 @@
#!/bin/sh /etc/rc.common
# Created By ImmortalWrt
# https://github.com/project-openwrt
START=90
STOP=10
enable="$(uci get gost.@gost[0].enable)"
run_command="$(uci get gost.@gost[0].run_command)"
start()
{
stop
[ "${enable}" -ne "1" ] && exit 0
/usr/bin/gost ${run_command} &
}
stop()
{
killall -9 "gost" > "/dev/null" 2>&1
}

83
gowebdav/Makefile Normal file
View File

@ -0,0 +1,83 @@
#
# Copyright (C) 2021 ImmortalWrt
# <https://immortalwrt.org>
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=gowebdav
PKG_VERSION:=0.0.2
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/1715173329/gowebdav/tar.gz/v$(PKG_VERSION)?
PKG_HASH:=0a6a2af4f24905ffea247b6044d01129d938af4b3a256bf19b42c52bb452f947
PKG_MAINTAINER:=CN_SZTL <cnsztl@immortalwrt.org>
PKG_CONFIG_DEPENDS:= \
CONFIG_GOWEBDAV_COMPRESS_GOPROXY \
CONFIG_GOWEBDAV_COMPRESS_UPX
PKG_BUILD_DEPENDS:=golang/host
PKG_BUILD_PARALLEL:=1
PKG_USE_MIPS16:=0
GO_PKG:=github.com/1715173329/gowebdav
GO_PKG_LDFLAGS:=-s -w
include $(INCLUDE_DIR)/package.mk
include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk
define Package/gowebdav
SECTION:=net
CATEGORY:=Network
SUBMENU:=File Transfer
TITLE:=A simple WebDav server written in Golang.
URL:=https://github.com/1715173329/gowebdav
DEPENDS:=$(GO_ARCH_DEPENDS)
endef
define Package/gowebdav/description
A simple WebDav server written in Golang.
endef
define Package/gowebdav/config
config GOWEBDAV_COMPRESS_GOPROXY
bool "Compiling with GOPROXY proxy"
default n
config GOWEBDAV_COMPRESS_UPX
bool "Compress executable files with UPX"
default y
endef
ifeq ($(CONFIG_GOWEBDAV_COMPRESS_GOPROXY),y)
export GO111MODULE=on
export GOPROXY=https://goproxy.io
endif
define Build/Compile
$(call GoPackage/Build/Compile)
ifeq ($(CONFIG_GOWEBDAV_COMPRESS_UPX),y)
$(STAGING_DIR_HOST)/bin/upx --lzma --best $(GO_PKG_BUILD_BIN_DIR)/gowebdav
endif
endef
define Package/gowebdav/install
$(call GoPackage/Package/Install/Bin,$(PKG_INSTALL_DIR))
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/gowebdav $(1)/usr/bin/gowebdav
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) $(CURDIR)/files/gowebdav.config $(1)/etc/config/gowebdav
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) $(CURDIR)/files/gowebdav.init $(1)/etc/init.d/gowebdav
endef
$(eval $(call GoBinPackage,gowebdav))
$(eval $(call BuildPackage,gowebdav))

View File

@ -0,0 +1,12 @@
config gowebdav 'config'
option enable '0'
option listen_port '6086'
option username 'user'
option password 'pass'
option root_dir '/mnt'
option read_only '0'
option allow_wan '0'
option use_https '0'
option cert_cer ''
option cert_key ''

56
gowebdav/files/gowebdav.init Executable file
View File

@ -0,0 +1,56 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2021 ImmortalWrt
START=99
STOP=10
init_conf() {
config_load "gowebdav"
config_get "enable" "config" "enable" "0"
config_get "listen_port" "config" "listen_port" "6086"
config_get "username" "config" "username"
config_get "password" "config" "password"
config_get "root_dir" "config" "root_dir" "/mnt"
config_get "read_only" "config" "read_only" "0"
config_get "allow_wan" "config" "allow_wan" "0"
config_get "use_https" "config" "use_https" "0"
config_get "cert_cer" "config" "cert_cer"
config_get "cert_key" "config" "cert_key"
config_load "network"
config_get "lan_addr" "lan" "ipaddr" "192.168.1.1"
}
set_firewall() {
if [ "${set_type}" = "start" ]; then
mkdir -p "/var/etc/"
iptables -I INPUT -p tcp --dport "${listen_port}" -j ACCEPT
echo "iptables -I INPUT -p tcp --dport "${listen_port}" -j ACCEPT" > "/var/etc/gowebdav.include"
elif [ "${set_type}" = "stop" ]; then
iptables -D INPUT -p tcp --dport "${listen_port}" -j ACCEPT
echo "" > "/var/etc/gowebdav.include"
fi
}
start() {
init_conf
stop
[ "${enable}" -ne "1" ] && exit 0
mkdir -p "${root_dir}"
[ "${allow_wan}" -ne "1" ] && listen_addr="${lan_addr}" || { listen_addr="0.0.0.0"; set_type="start" && set_firewall 2>"/dev/null"; }
{ [ -n "${username}" ] && [ -n "${password}" ]; } && auth_arg="-user ${username} -password ${password}"
[ "${read_only}" -eq "1" ] && readonly_arg="-read-only"
{ [ "${use_https}" -eq "1" ] && [ -e "${cert_cer}" ] && [ -e "${cert_key}" ]; } && https_arg="-https-mode -https-cert-file ${cert_cer} -https-key-file ${cert_key}"
/usr/bin/gowebdav -dir "${root_dir}" -http "${listen_addr}:${listen_port}" ${auth_arg} ${readonly_arg} ${https_arg} &
}
stop() {
init_conf
set_type="stop" && set_firewall 2>"/dev/null"
killall "gowebdav" 2>"/dev/null"
}

50
iptvhelper/Makefile Normal file
View File

@ -0,0 +1,50 @@
# Copyright 2019 Shun Li <riverscn@gmail.com>
# Licensed to the public under the GNU General Public License v3.
include $(TOPDIR)/rules.mk
PKG_NAME:=iptvhelper
PKG_VERSION:=0.1.1
PKG_RELEASE:=1
PKG_MAINTAINER:=Shun Li <riverscn@gmail.com>
PKG_LICENSE:=GPL-3.0
include $(INCLUDE_DIR)/package.mk
define Package/iptvhelper
SECTION:=net
CATEGORY:=Network
SUBMENU:=Routing and Redirection
DEPENDS:= \
+ipset \
+iptables
TITLE:=Scripts for configure IPTV easily
MAINTAINER:=Shun Li <riverscn@gmail.com>
PKGARCH:=all
endef
define Package/iptvhelper/description
Scripts for configure IPTV easily
endef
define Package/iptvhelper/conffiles
/etc/config/iptvhelper
/etc/firewall.iptvhelper
endef
define Build/Compile
endef
define Package/iptvhelper/postinst
#!/bin/sh
endef
define Package/iptvhelper/postrm
#!/bin/sh
endef
define Package/iptvhelper/install
$(CP) ./files/* $(1)
endef
$(eval $(call BuildPackage,iptvhelper))

View File

@ -0,0 +1,8 @@
config tvbox 'default'
option disabled '1'
option respawn '1'
option mac '00:00:00:00:00:00'
option ipset '1'
option dns_redir '1'

View File

@ -0,0 +1,2 @@
#!/bin/sh
test -s "/etc/init.d/iptvhelper" && /etc/init.d/iptvhelper reload

View File

@ -0,0 +1,127 @@
#!/bin/sh /etc/rc.common
# Copyright 2019 Shun Li <riverscn@gmail.com>
# Licensed to the public under the GNU General Public License v3.
START=95
USE_PROCD=1
_ipt() {
cmd="$(echo "$@" | sed 's|-A|-D|g;s|-I|-D|g')"
while iptables $cmd &>/dev/null; do
:
done
iptables $@
}
destroy_iptv_ipset() {
for ip_set in $(ipset list | awk '/iptvhelper/ {print $2}'); do ipset destroy $ip_set; done
}
clear_iptv_rules() {
iptables-save --counters | grep -v "iptvhelper-rule" | iptables-restore --counters
}
append_arg() {
local cfg="$1"
local var="$2"
local opt="$3"
local def="$4"
local val
config_get val "$cfg" "$var"
[ -n "$val" -o -n "$def" ] && procd_append_param command $opt "${val:-$def}"
}
append_bool() {
local cfg="$1"
local var="$2"
local opt="$3"
local def="$4"
local val
config_get_bool val "$cfg" "$var" "$def"
[ "$val" = 1 ] && procd_append_param command "$opt"
}
start_instance() {
local cfg="$1"
local aux
config_get_bool aux "$cfg" 'disabled' '0'
[ "$aux" = 1 ] && return 1
logger "iptvhelper.$cfg: instance starting"
local IPTV_MAC
local IPTV_DNS_REDIR
local IPTV_IPSET
config_get IPTV_MAC $cfg mac
config_get IPTV_DNS_REDIR $cfg dns_redir
config_get IPTV_IPSET $cfg ipset
logger "iptvhelper.$cfg: topbox mac=$IPTV_MAC"
if [[ $IPTV_DNS_REDIR == '1' ]]; then
logger "iptvhelper.$cfg: topbox DNS redierct enabled"
_ipt -t nat -A PREROUTING -m mac --mac-source $IPTV_MAC -m comment --comment "iptvhelper-rule" -p udp --dport 53 -j REDIRECT --to-ports 53
fi
if [[ $IPTV_IPSET='1' ]]; then
logger "iptvhelper.$cfg: topbox ipset enabled"
if ! ipset -q list iptvhelper_$cfg >/dev/null; then
ipset create iptvhelper_$cfg nethash
fi
_ipt -t nat -I PREROUTING -m mac --mac-source $IPTV_MAC -m comment --comment "iptvhelper-rule" -m set ! --match-set iptvhelper_$cfg dst -m conntrack --ctstate NEW -j LOG --log-prefix "iptvhelper.$cfg:"
procd_open_instance
procd_set_param command /usr/sbin/iptvhelper.sh $cfg
config_get_bool aux "$cfg" 'respawn' '0'
[ "$aux" = 1 ] && procd_set_param respawn
procd_set_param pidfile /var/run/iptvhelper_$cfg.pid
procd_close_instance
fi
}
service_triggers() {
procd_add_reload_trigger "iptvhelper"
}
start_service() {
logger "iptvhelper: starting"
echo "iptvhelper: starting"
config_load iptvhelper
config_foreach start_instance tvbox
if uci -q show firewall >/dev/null; then
if ! uci -q get firewall.iptvhelper >/dev/null; then
uci -q batch <<-EOF >/dev/null
set firewall.iptvhelper=include
set firewall.iptvhelper.type='script'
set firewall.iptvhelper.path='/etc/firewall.iptvhelper'
set firewall.iptvhelper.family='any'
set firewall.iptvhelper.reload='1'
commit firewall
EOF
fi
fi
}
stop_service() {
if uci -q show firewall >/dev/null; then
if uci -q get firewall.iptvhelper >/dev/null; then
uci delete firewall.iptvhelper
uci commit firewall
fi
fi
for pid in $(ps | grep -v awk | awk '/iptvhelper.sh/ {print $1}'); do kill -9 $pid; done
for pid in $(ps | grep -v awk | awk '/logread -e iptvhelper/ {print $1}'); do kill -9 $pid; done
clear_iptv_rules
destroy_iptv_ipset
logger "iptvhelper: stopped"
echo "iptvhelper: stopped"
}
reload_service() {
logger "iptvhelper: reloading"
echo "iptvhelper: reloading"
stop
start
}

View File

@ -0,0 +1,24 @@
#!/bin/sh
# Copyright 2019 Shun Li <riverscn@gmail.com>
# Licensed to the public under the GNU General Public License v3.
add_to_set() {
local ip=$1
local cfg=$2
local subnet=$ip/24
ping -W1 -c1 $ip &>/dev/null && return
if ! ipset -q test iptvhelper_$cfg $subnet; then
ipset add iptvhelper_$cfg $subnet
echo added $subnet to set iptvhelper_$cfg
fi
}
echo $1
logread -e "iptvhelper\.$1" -f |
while read line; do
ip=$(echo "$line" | sed -r 's|.*DST=([0-9.]+).*|\1|')
echo requested $ip
add_to_set $ip $1 &
done

674
luci-app-airwhu/LICENSE Executable file
View File

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

51
luci-app-airwhu/Makefile Executable file
View File

@ -0,0 +1,51 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-airwhu
PKG_VERSION=1.0
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/luci-app-airwhu
SECTION:=luci
CATEGORY:=LuCI
SUBMENU:=3. Applications
DEPENDS:=+mentohust +kmod-ipt-nat6
TITLE:=luci-app-airwhu
PKGARCH:=all
endef
define Package/luci-app-airwhu/description
LuCI web-interface for Ruijie 802.1X Client with IPv6 NAT.
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./* $(PKG_BUILD_DIR)/
po2lmo $(PKG_BUILD_DIR)/po/airwhu.zh_Hans.po $(PKG_BUILD_DIR)/po/airwhu.zh-cn.lmo
endef
define Build/Compile
endef
define Package/luci-app-airwhu/install
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
$(INSTALL_DIR) $(1)/bin
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/model/cbi
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/controller
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/i18n
$(INSTALL_CONF) ./files/root/etc/config/airwhu $(1)/etc/config/airwhu
$(INSTALL_BIN) ./files/root/etc/init.d/mentohust $(1)/etc/init.d/mentohust
$(INSTALL_BIN) ./files/root/etc/hotplug.d/iface/99-ipv6nat $(1)/etc/hotplug.d/iface/99-ipv6nat
$(INSTALL_BIN) ./files/root/bin/ipv6masq.sh $(1)/bin/ipv6masq.sh
$(INSTALL_DATA) ./files/root/usr/lib/lua/luci/model/cbi/airwhu.lua $(1)/usr/lib/lua/luci/model/cbi/airwhu.lua
$(INSTALL_DATA) ./files/root/usr/lib/lua/luci/controller/airwhu.lua $(1)/usr/lib/lua/luci/controller/airwhu.lua
$(INSTALL_DATA) $(PKG_BUILD_DIR)/po/airwhu.zh-cn.lmo $(1)/usr/lib/lua/luci/i18n/airwhu.zh-cn.lmo
endef
$(eval $(call BuildPackage,luci-app-airwhu))

23
luci-app-airwhu/README.md Normal file
View File

@ -0,0 +1,23 @@
## Compile
在OpenWrt SDK中的package目录下执行如下命令
`$ git clone https://github.com/KyleRicardo/luci-app-airwhu.git`
在luci-app-airwhu/tools/po2lmo下打开终端运行如下命令
`$ make && sudo make install`
然后在OpenWrt SDK根目录下执行如下命令
`$ make package/luci-app-airwhu/compile V=s`
编译成功后找到生成的ipk文件拷贝到路由器中用opkg安装就可以使用了。
## Install
代码中只包含Lua和Bash脚本所以不受限于平台编译后的文件可以在任何平台安装
`$ opkg install luci-app-airwhu_1.0-1_all.ipk`
该luci界面依赖MentoHUST以及kmod-ipt-nat6这两个ipk包。

View File

@ -0,0 +1,41 @@
#!/bin/sh /etc/rc.common
#Author:KyleRicardo
#Email:shaoyz714@126.com
action=$1
if [ "$action"x = "install"x ]; then
uci delete network.globals.ula_prefix
uci set network.wan6.peerdns='0'
uci set network.wan6.dns='2001:da8:202:10::36'
uci delete network.lan.ip6assign
uci set network.lan.ip6addr='BABE:BABE:BABE:BABE::1/64'
uci set network.lan.ip6prefix='BABE:BABE:BABE:BABE::/64'
uci set dhcp.lan.ra_management='1'
uci set dhcp.lan.ra_default='1'
uci set $(uci show firewall|grep Allow-ICMPv6-Forward|sed -e 's/.name[^ ]*'//).enabled='0'
uci commit
elif [ "$action"x = "uninstall"x ]; then
uci set network.globals.ula_prefix='fdad:91b7:54bb::/48'
uci delete network.wan6.peerdns='0'
uci delete network.wan6.dns='2001:da8:202:10::36'
uci set network.lan.ip6assign='60'
uci delete network.lan.ip6addr='BABE:BABE:BABE:BABE::1/64'
uci delete network.lan.ip6prefix='BABE:BABE:BABE:BABE::/64'
uci delete dhcp.lan.ra_management='1'
uci delete dhcp.lan.ra_default='1'
uci delete $(uci show firewall|grep Allow-ICMPv6-Forward|sed -e 's/.name[^ ]*'//).enabled
uci commit
fi

View File

@ -0,0 +1,25 @@
config switch
option enableauth
option startwithboot
option enableipv6
config auth
option Username
option Password
option ifname
option IP
option Mask
option Gateway
option DNS
option PingHost
option Timeout
option EchoInterval
option RestartWait
option MaxFail
option StartMode
option DHCPMode
option DaemonMode
option ShowNotify
option Version
option DataFile
option DHCPScript

View File

@ -0,0 +1,56 @@
#!/bin/sh /etc/rc.common
#Author:KyleRicardo
#Email:shaoyz714@126.com
[ "$ACTION" = ifup ] || exit 0
iface=wan6
[ -z "$iface" -o "$INTERFACE" = "$iface" ] || exit 0
ip -6 route add `ip -6 route show default|sed -e 's/from [^ ]* //'`
logger -t IPv6 "Add IPv6 default route."
MAX_TRIES=99
WAN6_NAME="wan6"
WAN6_INTERFACE=$(uci get "network.$WAN6_NAME.ifname")
#eth0.2 by default
LAN_IP6PREFIX=$(uci get network.lan.ip6prefix)
#e.g. aaaa:bbbb:cccc:dddd::/64
#LAN_ULA_PREFIX=$(uci get network.globals.ula_prefix)
#e.g. ddc2:d512:65f5::/48
PROBE=0
COUNT=1
while [ $PROBE -eq 0 ]
do
if [ $COUNT -gt $MAX_TRIES ]
then
logger -t NAT6 "No IPv6 route found (reached retry limit $MAX_TRIES times)" && exit 1
fi
sleep 5
logger -t NAT6 "Probing IPv6 route ($COUNT time)"
COUNT=$((COUNT+1))
PROBE=$(route -A inet6 | grep -c '::/0')
done
#ip6tables -t nat -I POSTROUTING -s "$LAN_ULA_PREFIX" -o "$WAN6_INTERFACE" -j MASQUERADE
ip6tables -t nat -I POSTROUTING -s "$LAN_IP6PREFIX" -o "$WAN6_INTERFACE" -j MASQUERADE
#WAN6_GATEWAY=$(route -A inet6 -e | grep "$WAN6_INTERFACE" | awk '/::\/0/{print $2; exit}')
#get gateway from routing table. !!!Caution!!! May not work !
WAN6_GATEWAY=$(ifconfig eth0.2 | grep 'Global' | awk '{print $3}'| awk -F':' '{print $1":"$2":"$3":"$4"::1"}')
#caculate gateway from wan ipv6
#WAN6_GATEWAY=$(tracepath6 -n tv.byr.cn | grep ' 1: ' | awk 'NR==1 {print $2}')
#opkg install iputils-tracepath6 . change tv.byr.cn for faster site. e.g. ipv6.bjtu.edu.cn
#route -A inet6 add 2000::/3 gw "$WAN6_GATEWAY" dev "$WAN6_INTERFACE"
route -A inet6 add default gw "$WAN6_GATEWAY" dev "$WAN6_INTERFACE"
logger -t NAT6 "Done with IPv6 settings"

View File

@ -0,0 +1,49 @@
#!/bin/sh /etc/rc.common
#Author:KyleRicardo
#Email:shaoyz714@126.com
START=65
STOP=10
start()
{
if [ $(uci get airwhu.@switch[0].enableauth) ] ;
then
local Username=$(uci get airwhu.@auth[0].Username)
local Password=$(uci get airwhu.@auth[0].Password)
local ifname=$(uci get airwhu.@auth[0].ifname)
local IP=$(uci get airwhu.@auth[0].IP)
local Mask=$(uci get airwhu.@auth[0].Mask)
local Gateway=$(uci get airwhu.@auth[0].Gateway)
local DNS=$(uci get airwhu.@auth[0].DNS)
local PingHost=$(uci get airwhu.@auth[0].PingHost)
local Timeout=$(uci get airwhu.@auth[0].Timeout)
local EchoInterval=$(uci get airwhu.@auth[0].EchoInterval)
local RestartWait=$(uci get airwhu.@auth[0].RestartWait)
local MaxFail=$(uci get airwhu.@auth[0].MaxFail)
local StartMode=$(uci get airwhu.@auth[0].StartMode)
local DHCPMode=$(uci get airwhu.@auth[0].DHCPMode)
local DaemonMode=$(uci get airwhu.@auth[0].DaemonMode)
local ShowNotify=$(uci get airwhu.@auth[0].ShowNotify)
local Version=$(uci get airwhu.@auth[0].Version)
local DataFile=$(uci get airwhu.@auth[0].DataFile)
local DHCPScript=$(uci get airwhu.@auth[0].DHCPScript)
mentohust -u$Username -p$Password -n$ifname -b$DaemonMode -a$StartMode -d$DaemonMode -c"$DHCPScript" -w>/dev/null 2>&1
#Temporarily designed only for whu. To be continued...
else
stop
fi
}
stop()
{
sync
mentohust -k >/dev/null 2>&1
}
restart()
{
stop
start
}

View File

@ -0,0 +1,5 @@
module("luci.controller.airwhu", package.seeall)
function index()
entry({"admin", "services", "AirWHU"}, cbi("airwhu"), _("AirWHU"), 100)
end

View File

@ -0,0 +1,115 @@
--[[
LuCI - Lua Configuration Interface
LICENSE under GPLv3.
Copyright 2017 KyleRicardo[W.B.L.E. TeAm] <shaoyz714@126.com>
]]
--
require("luci.sys")
require("luci.tools.webadmin")
local IsOnAir = (luci.sys.call("pidof mentohust > /dev/null") == 0)
if IsOnAir then
state_msg = "<b><font color=\"green\">" .. translate("Running") .. "</font></b>"
else
state_msg = "<b><font color=\"red\">" .. translate("Not Running") .. "</font></b>"
end
m = Map("airwhu", translate("AirWHU"), translate("Configure Ruijie 802.1X client with IPv6 NAT based on Masquerade.") .. "<br /><br />" .. translate("Status") .. " : " .. state_msg)
s = m:section(TypedSection, "switch", translate("Global Switch"), translate("Configure global 802.1X Authentication and IPv6-NAT on-off."))
s.addremove = false
s.anonymous = true
s:option(Flag, "enableauth", translate("Enable 802.1X Auth"), translate("Enable or disable Ruijie 802.1X authentication."))
tmp = s:option(Flag, "startwithboot", translate("Start with boot"), translate("Start Ruijie 802.1X Authentication based on MentoHUST when the router is booting."))
tmp:depends("enableauth","1")
s:option(Flag, "enableipv6", translate("Enable IPv6 NAT"), translate("Enable IPv6 NAT pass-through based on ip6tables MASQUERADE."))
s = m:section(TypedSection, "auth", translate("Config Authentication"), translate("The options below are all of MentoHUST's arguments."))
s.anonymous = true
s.addremove = false
ur = s:option(Value, "Username", translate("Username"))
ur.rmempty = false
pw = s:option(Value, "Password", translate("Password"))
pw.password = true
pw.rmempty = false
wan_dev = luci.sys.exec("uci get network.wan.ifname")
wan_dev = string.sub(wan_dev,1,string.len(wan_dev)-1)
ifname = s:option(ListValue, "ifname", translate("Interfaces"))
ifname:value(wan_dev)
s:option(Value, "IP", translate("IP"), translate("default to localhost's IP")).default = "0.0.0.0"
s:option(Value, "Mask", translate("Netmask"), translate("default to localhost's netmask")).default = "255.255.255.0"
s:option(Value, "Gateway", translate("Gateway"), translate("default to 0.0.0.0")).default = "0.0.0.0"
s:option(Value, "DNS", translate("DNS"), translate("default to 0.0.0.0")).default = "0.0.0.0"
s:option(Value, "PingHost", translate("Ping host"), translate("default to 0.0.0.0,i.e. disable this function")).default = "0.0.0.0"
s:option(Value, "Timeout", translate("Authenticate timeout(s)"), translate("default to 8s")).default = "8"
s:option(Value, "EchoInterval", translate("Heartbeat timeout(s)"), translate("default to 30s")).default = "30"
s:option(Value, "RestartWait", translate("Timeout on failure(s)"), translate("default to 15s")).default = "15"
s:option(Value, "MaxFail", translate("Max failure times"), translate("0 means no limit,default to 8")).default = "8"
t = s:option(ListValue, "StartMode", translate("mulcast address"), translate("default to 1"))
t:value("0", translate("0(standard)"))
t:value("1", translate("1(ruijjie)"))
t:value("2", translate("2(saier)"))
t.default = "1"
t = s:option(ListValue, "DHCPMode", translate("DHCP type"), translate("default to 1"))
t:value("0", translate("0(not in used)"))
t:value("1", translate("1(secondary authenticate)"))
t:value("2", translate("2(post authenticate)"))
t:value("3", translate("3(pre authenticate)"))
t.default = "1"
t = s:option(ListValue, "DaemonMode", translate("run in daemon mode"), translate("default to 3"))
t:value("0", translate("0(no)"))
t:value("1", translate("1(yes,turn off output)"))
t:value("2", translate("2(yes,persevere output)"))
t:value("3", translate("3(yes,output to file)"))
t.default = "3"
s:option(Value, "ShowNotify", translate("display notification"), translate("0(no),1-20(yes),default to 0")).default = "0"
s:option(Value, "Version", translate("client version"), translate("default to 0.00,compatible with xrgsu")).default = "0.00"
tmp = s:option(Value, "DataFile", translate("customized data file"), translate("not in used by default"))
tmp.rmempty = true
script = s:option(Value, "DHCPScript", translate("DHCP script"), translate("use dhclient by default"))
script.default = "udhcpc -i "..wan_dev
local apply = luci.http.formvalue("cbi.apply")
if apply then
if luci.sys.exec("uci get airwhu.@switch[0].enableauth") then
luci.sys.exec("/etc/init.d/mentohust restart")
else
luci.sys.exec("/etc/init.d/mentohust stop")
end
if luci.sys.exec("uci get airwhu.@switch[0].startwithboot") then
luci.sys.exec("/etc/init.d/mentohust enable")
else
luci.sys.exec("/etc/init.d/mentohust disable")
end
if luci.sys.exec("uci get airwhu.@switch[0].enableipv6") then
luci.sys.exec("sh /bin/ipv6masq.sh install")
else
luci.sys.exec("sh /bin/ipv6masq.sh uninstall")
end
end
return m

View File

@ -0,0 +1,258 @@
msgid ""
msgstr ""
"Project-Id-Version: airwhu\n"
"POT-Creation-Date: 2017-05-11 19:39+0800\n"
"PO-Revision-Date: 2017-05-11 19:40+0800\n"
"Last-Translator: KyleRicardo <shaoyz714@126.com>\n"
"Language-Team: [W.B.L.E. TeAm] <shaoyz714@126.com>\n"
"Language: en_US\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.8.8\n"
"X-Poedit-Basepath: ../files\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-KeywordsList: translate\n"
"X-Poedit-SearchPath-0: .\n"
#: root/usr/lib/lua/luci/controller/airwhu.lua:4
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:19
msgid "AirWHU"
msgstr "AirWHU"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:14
msgid "Running"
msgstr "运行中"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:16
msgid "Not Running"
msgstr "未运行"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:19
msgid "Configure Ruijie 802.1X client with IPv6 NAT based on Masquerade."
msgstr "配置基于IPv6 Masquerade技术的锐捷802.1X认证网络。"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:19
msgid "Status"
msgstr "状态"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:21
msgid "Global Switch"
msgstr "全局开关"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:21
msgid "Configure global 802.1X Authentication and IPv6-NAT on-off."
msgstr "配置全局802.1X认证与IPv6 NAT开关。"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:25
msgid "Enable 802.1X Auth"
msgstr "开启锐捷认证"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:25
msgid "Enable or disable Ruijie 802.1X authentication."
msgstr "打开或关闭锐捷802.1X认证。"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:26
msgid "Start with boot"
msgstr "开机启动"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:26
msgid ""
"Start Ruijie 802.1X Authentication based on MentoHUST when the router is "
"booting."
msgstr "开机自动启动基于MentoHUST的锐捷802.1X认证客户端。"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:28
msgid "Enable IPv6 NAT"
msgstr "开启IPv6 NAT"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:28
msgid "Enable IPv6 NAT pass-through based on ip6tables MASQUERADE."
msgstr "开启基于ip6tables Masquerade技术的IPv6 NAT穿透。"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:30
msgid "Config Authentication"
msgstr "配置认证参数"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:30
msgid "The options below are all of MentoHUST's arguments."
msgstr "以下是全部的MentoHUST认证参数。"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:34
msgid "Username"
msgstr "用户名"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:36
msgid "Password"
msgstr "密码"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:41
msgid "Interfaces"
msgstr "网卡"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:51
msgid "IP"
msgstr "IP地址"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:51
msgid "default to localhost's IP"
msgstr "默认为localhost的IP地址"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:53
msgid "Netmask"
msgstr "掩码"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:53
msgid "default to localhost's netmask"
msgstr "默认为localhost的掩码"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:55
msgid "Gateway"
msgstr "网关"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:55
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:57
msgid "default to 0.0.0.0"
msgstr "默认为0.0.0.0"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:57
msgid "DNS"
msgstr "DNS服务器"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:59
msgid "Ping host"
msgstr "Ping主机"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:59
msgid "default to 0.0.0.0,i.e. disable this function"
msgstr "默认为0.0.0.0,即关闭该功能"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:61
msgid "Authenticate timeout(s)"
msgstr "认证超时(秒)"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:61
msgid "default to 8s"
msgstr "默认为8秒"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:63
msgid "Heartbeat timeout(s)"
msgstr "心跳包超时(秒)"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:63
msgid "default to 30s"
msgstr "默认为30秒"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:65
msgid "Timeout on failure(s)"
msgstr "失败等待(秒)"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:65
msgid "default to 15s"
msgstr "默认为15秒"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:67
msgid "Max failure times"
msgstr "允许失败次数"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:67
msgid "0 means no limit,default to 8"
msgstr "0表示无限制默认为8"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:69
msgid "mulcast address"
msgstr "多播地址"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:69
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:75
msgid "default to 1"
msgstr "默认为1"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:70
msgid "0(standard)"
msgstr "0标准"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:71
msgid "1(ruijjie)"
msgstr "1锐捷"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:72
msgid "2(saier)"
msgstr "2赛尔"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:75
msgid "DHCP type"
msgstr "DHCP方式"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:76
msgid "0(not in used)"
msgstr "0不使用"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:77
msgid "1(secondary authenticate)"
msgstr "1二次认证"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:78
msgid "2(post authenticate)"
msgstr "3认证后"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:79
msgid "3(pre authenticate)"
msgstr "3认证前"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:82
msgid "run in daemon mode"
msgstr "后台运行模式"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:82
msgid "default to 3"
msgstr "默认为3"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:83
msgid "0(no)"
msgstr "0不使用后台模式"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:84
msgid "1(yes,turn off output)"
msgstr "1后台模式关闭输出"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:85
msgid "2(yes,persevere output)"
msgstr "2后台模式保留输出"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:86
msgid "3(yes,output to file)"
msgstr "3后台模式输出到日志文件"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:89
msgid "display notification"
msgstr "显示通知"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:89
msgid "0(no),1-20(yes),default to 0"
msgstr "0不使用1-20使用默认为0"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:91
msgid "client version"
msgstr "客户端版本号"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:91
msgid "default to 0.00,compatible with xrgsu"
msgstr "默认为0.00表示兼容xrgsu"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:93
msgid "customized data file"
msgstr "自定义数据文件"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:93
msgid "not in used by default"
msgstr "默认不使用"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:96
msgid "DHCP script"
msgstr "DHCP脚本"
#: root/usr/lib/lua/luci/model/cbi/airwhu.lua:96
msgid "use dhclient by default"
msgstr "默认使用dhclient"

View File

@ -0,0 +1,12 @@
INSTALL = install
PREFIX = /usr/bin
po2lmo: src/po2lmo.o src/template_lmo.o
$(CC) $(LDFLAGS) -o src/po2lmo src/po2lmo.o src/template_lmo.o
install:
$(INSTALL) -m 755 src/po2lmo $(PREFIX)
clean:
$(RM) src/po2lmo src/*.o

Binary file not shown.

View File

@ -0,0 +1,247 @@
/*
* lmo - Lua Machine Objects - PO to LMO conversion tool
*
* Copyright (C) 2009-2012 Jo-Philipp Wich <xm@subsignal.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "template_lmo.h"
static void die(const char *msg)
{
fprintf(stderr, "Error: %s\n", msg);
exit(1);
}
static void usage(const char *name)
{
fprintf(stderr, "Usage: %s input.po output.lmo\n", name);
exit(1);
}
static void print(const void *ptr, size_t size, size_t nmemb, FILE *stream)
{
if( fwrite(ptr, size, nmemb, stream) == 0 )
die("Failed to write stdout");
}
static int extract_string(const char *src, char *dest, int len)
{
int pos = 0;
int esc = 0;
int off = -1;
for( pos = 0; (pos < strlen(src)) && (pos < len); pos++ )
{
if( (off == -1) && (src[pos] == '"') )
{
off = pos + 1;
}
else if( off >= 0 )
{
if( esc == 1 )
{
switch (src[pos])
{
case '"':
case '\\':
off++;
break;
}
dest[pos-off] = src[pos];
esc = 0;
}
else if( src[pos] == '\\' )
{
dest[pos-off] = src[pos];
esc = 1;
}
else if( src[pos] != '"' )
{
dest[pos-off] = src[pos];
}
else
{
dest[pos-off] = '\0';
break;
}
}
}
return (off > -1) ? strlen(dest) : -1;
}
static int cmp_index(const void *a, const void *b)
{
uint32_t x = ((const lmo_entry_t *)a)->key_id;
uint32_t y = ((const lmo_entry_t *)b)->key_id;
if (x < y)
return -1;
else if (x > y)
return 1;
return 0;
}
static void print_uint32(uint32_t x, FILE *out)
{
uint32_t y = htonl(x);
print(&y, sizeof(uint32_t), 1, out);
}
static void print_index(void *array, int n, FILE *out)
{
lmo_entry_t *e;
qsort(array, n, sizeof(*e), cmp_index);
for (e = array; n > 0; n--, e++)
{
print_uint32(e->key_id, out);
print_uint32(e->val_id, out);
print_uint32(e->offset, out);
print_uint32(e->length, out);
}
}
int main(int argc, char *argv[])
{
char line[4096];
char key[4096];
char val[4096];
char tmp[4096];
int state = 0;
int offset = 0;
int length = 0;
int n_entries = 0;
void *array = NULL;
lmo_entry_t *entry = NULL;
uint32_t key_id, val_id;
FILE *in;
FILE *out;
if( (argc != 3) || ((in = fopen(argv[1], "r")) == NULL) || ((out = fopen(argv[2], "w")) == NULL) )
usage(argv[0]);
memset(line, 0, sizeof(key));
memset(key, 0, sizeof(val));
memset(val, 0, sizeof(val));
while( (NULL != fgets(line, sizeof(line), in)) || (state >= 2 && feof(in)) )
{
if( state == 0 && strstr(line, "msgid \"") == line )
{
switch(extract_string(line, key, sizeof(key)))
{
case -1:
die("Syntax error in msgid");
case 0:
state = 1;
break;
default:
state = 2;
}
}
else if( state == 1 || state == 2 )
{
if( strstr(line, "msgstr \"") == line || state == 2 )
{
switch(extract_string(line, val, sizeof(val)))
{
case -1:
state = 4;
break;
default:
state = 3;
}
}
else
{
switch(extract_string(line, tmp, sizeof(tmp)))
{
case -1:
state = 2;
break;
default:
strcat(key, tmp);
}
}
}
else if( state == 3 )
{
switch(extract_string(line, tmp, sizeof(tmp)))
{
case -1:
state = 4;
break;
default:
strcat(val, tmp);
}
}
if( state == 4 )
{
if( strlen(key) > 0 && strlen(val) > 0 )
{
key_id = sfh_hash(key, strlen(key));
val_id = sfh_hash(val, strlen(val));
if( key_id != val_id )
{
n_entries++;
array = realloc(array, n_entries * sizeof(lmo_entry_t));
entry = (lmo_entry_t *)array + n_entries - 1;
if (!array)
die("Out of memory");
entry->key_id = key_id;
entry->val_id = val_id;
entry->offset = offset;
entry->length = strlen(val);
length = strlen(val) + ((4 - (strlen(val) % 4)) % 4);
print(val, length, 1, out);
offset += length;
}
}
state = 0;
memset(key, 0, sizeof(key));
memset(val, 0, sizeof(val));
}
memset(line, 0, sizeof(line));
}
print_index(array, n_entries, out);
if( offset > 0 )
{
print_uint32(offset, out);
fsync(fileno(out));
fclose(out);
}
else
{
fclose(out);
unlink(argv[2]);
}
fclose(in);
return(0);
}

Binary file not shown.

View File

@ -0,0 +1,328 @@
/*
* lmo - Lua Machine Objects - Base functions
*
* Copyright (C) 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "template_lmo.h"
/*
* Hash function from http://www.azillionmonkeys.com/qed/hash.html
* Copyright (C) 2004-2008 by Paul Hsieh
*/
uint32_t sfh_hash(const char *data, int len)
{
uint32_t hash = len, tmp;
int rem;
if (len <= 0 || data == NULL) return 0;
rem = len & 3;
len >>= 2;
/* Main loop */
for (;len > 0; len--) {
hash += sfh_get16(data);
tmp = (sfh_get16(data+2) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2*sizeof(uint16_t);
hash += hash >> 11;
}
/* Handle end cases */
switch (rem) {
case 3: hash += sfh_get16(data);
hash ^= hash << 16;
hash ^= data[sizeof(uint16_t)] << 18;
hash += hash >> 11;
break;
case 2: hash += sfh_get16(data);
hash ^= hash << 11;
hash += hash >> 17;
break;
case 1: hash += *data;
hash ^= hash << 10;
hash += hash >> 1;
}
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}
uint32_t lmo_canon_hash(const char *str, int len)
{
char res[4096];
char *ptr, prev;
int off;
if (!str || len >= sizeof(res))
return 0;
for (prev = ' ', ptr = res, off = 0; off < len; prev = *str, off++, str++)
{
if (isspace(*str))
{
if (!isspace(prev))
*ptr++ = ' ';
}
else
{
*ptr++ = *str;
}
}
if ((ptr > res) && isspace(*(ptr-1)))
ptr--;
return sfh_hash(res, ptr - res);
}
lmo_archive_t * lmo_open(const char *file)
{
int in = -1;
uint32_t idx_offset = 0;
struct stat s;
lmo_archive_t *ar = NULL;
if (stat(file, &s) == -1)
goto err;
if ((in = open(file, O_RDONLY)) == -1)
goto err;
if ((ar = (lmo_archive_t *)malloc(sizeof(*ar))) != NULL)
{
memset(ar, 0, sizeof(*ar));
ar->fd = in;
ar->size = s.st_size;
fcntl(ar->fd, F_SETFD, fcntl(ar->fd, F_GETFD) | FD_CLOEXEC);
if ((ar->mmap = mmap(NULL, ar->size, PROT_READ, MAP_SHARED, ar->fd, 0)) == MAP_FAILED)
goto err;
idx_offset = ntohl(*((const uint32_t *)
(ar->mmap + ar->size - sizeof(uint32_t))));
if (idx_offset >= ar->size)
goto err;
ar->index = (lmo_entry_t *)(ar->mmap + idx_offset);
ar->length = (ar->size - idx_offset - sizeof(uint32_t)) / sizeof(lmo_entry_t);
ar->end = ar->mmap + ar->size;
return ar;
}
err:
if (in > -1)
close(in);
if (ar != NULL)
{
if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED))
munmap(ar->mmap, ar->size);
free(ar);
}
return NULL;
}
void lmo_close(lmo_archive_t *ar)
{
if (ar != NULL)
{
if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED))
munmap(ar->mmap, ar->size);
close(ar->fd);
free(ar);
ar = NULL;
}
}
lmo_catalog_t *_lmo_catalogs = NULL;
lmo_catalog_t *_lmo_active_catalog = NULL;
int lmo_load_catalog(const char *lang, const char *dir)
{
DIR *dh = NULL;
char pattern[16];
char path[PATH_MAX];
struct dirent *de = NULL;
lmo_archive_t *ar = NULL;
lmo_catalog_t *cat = NULL;
if (!lmo_change_catalog(lang))
return 0;
if (!dir || !(dh = opendir(dir)))
goto err;
if (!(cat = malloc(sizeof(*cat))))
goto err;
memset(cat, 0, sizeof(*cat));
snprintf(cat->lang, sizeof(cat->lang), "%s", lang);
snprintf(pattern, sizeof(pattern), "*.%s.lmo", lang);
while ((de = readdir(dh)) != NULL)
{
if (!fnmatch(pattern, de->d_name, 0))
{
snprintf(path, sizeof(path), "%s/%s", dir, de->d_name);
ar = lmo_open(path);
if (ar)
{
ar->next = cat->archives;
cat->archives = ar;
}
}
}
closedir(dh);
cat->next = _lmo_catalogs;
_lmo_catalogs = cat;
if (!_lmo_active_catalog)
_lmo_active_catalog = cat;
return 0;
err:
if (dh) closedir(dh);
if (cat) free(cat);
return -1;
}
int lmo_change_catalog(const char *lang)
{
lmo_catalog_t *cat;
for (cat = _lmo_catalogs; cat; cat = cat->next)
{
if (!strncmp(cat->lang, lang, sizeof(cat->lang)))
{
_lmo_active_catalog = cat;
return 0;
}
}
return -1;
}
static lmo_entry_t * lmo_find_entry(lmo_archive_t *ar, uint32_t hash)
{
unsigned int m, l, r;
uint32_t k;
l = 0;
r = ar->length - 1;
while (1)
{
m = l + ((r - l) / 2);
if (r < l)
break;
k = ntohl(ar->index[m].key_id);
if (k == hash)
return &ar->index[m];
if (k > hash)
{
if (!m)
break;
r = m - 1;
}
else
{
l = m + 1;
}
}
return NULL;
}
int lmo_translate(const char *key, int keylen, char **out, int *outlen)
{
uint32_t hash;
lmo_entry_t *e;
lmo_archive_t *ar;
if (!key || !_lmo_active_catalog)
return -2;
hash = lmo_canon_hash(key, keylen);
for (ar = _lmo_active_catalog->archives; ar; ar = ar->next)
{
if ((e = lmo_find_entry(ar, hash)) != NULL)
{
*out = ar->mmap + ntohl(e->offset);
*outlen = ntohl(e->length);
return 0;
}
}
return -1;
}
void lmo_close_catalog(const char *lang)
{
lmo_archive_t *ar, *next;
lmo_catalog_t *cat, *prev;
for (prev = NULL, cat = _lmo_catalogs; cat; prev = cat, cat = cat->next)
{
if (!strncmp(cat->lang, lang, sizeof(cat->lang)))
{
if (prev)
prev->next = cat->next;
else
_lmo_catalogs = cat->next;
for (ar = cat->archives; ar; ar = next)
{
next = ar->next;
lmo_close(ar);
}
free(cat);
break;
}
}
}

View File

@ -0,0 +1,92 @@
/*
* lmo - Lua Machine Objects - General header
*
* Copyright (C) 2009-2012 Jo-Philipp Wich <xm@subsignal.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _TEMPLATE_LMO_H_
#define _TEMPLATE_LMO_H_
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <fnmatch.h>
#include <dirent.h>
#include <ctype.h>
#include <limits.h>
#if (defined(__GNUC__) && defined(__i386__))
#define sfh_get16(d) (*((const uint16_t *) (d)))
#else
#define sfh_get16(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+(uint32_t)(((const uint8_t *)(d))[0]) )
#endif
struct lmo_entry {
uint32_t key_id;
uint32_t val_id;
uint32_t offset;
uint32_t length;
} __attribute__((packed));
typedef struct lmo_entry lmo_entry_t;
struct lmo_archive {
int fd;
int length;
uint32_t size;
lmo_entry_t *index;
char *mmap;
char *end;
struct lmo_archive *next;
};
typedef struct lmo_archive lmo_archive_t;
struct lmo_catalog {
char lang[6];
struct lmo_archive *archives;
struct lmo_catalog *next;
};
typedef struct lmo_catalog lmo_catalog_t;
uint32_t sfh_hash(const char *data, int len);
uint32_t lmo_canon_hash(const char *data, int len);
lmo_archive_t * lmo_open(const char *file);
void lmo_close(lmo_archive_t *ar);
extern lmo_catalog_t *_lmo_catalogs;
extern lmo_catalog_t *_lmo_active_catalog;
int lmo_load_catalog(const char *lang, const char *dir);
int lmo_change_catalog(const char *lang);
int lmo_translate(const char *key, int keylen, char **out, int *outlen);
void lmo_close_catalog(const char *lang);
#endif

Binary file not shown.

View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

2
luci-app-autoipsetadder/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.bak

View File

@ -0,0 +1,64 @@
# Copyright (C) 2018-2019 Lienol
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-autoipsetadder
PKG_VERSION:=1.0
PKG_RELEASE:=7
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/luci-app-autoipsetadder
SECTION:=luci
CATEGORY:=LuCI
SUBMENU:=3. Applications
TITLE:=LuCI Support for autoipsetadder
PKGARCH:=all
DEPENDS:= +httping +curl
endef
define Package/luci-app-autoipsetadder/description
LuCI support for autoipsetadder
endef
define Build/Prepare
endef
define Build/Compile
endef
define Package/luci-app-autoipsetadder/conffiles
/etc/config/autoipsetadder
endef
define Package/luci-app-autoipsetadder/install
$(INSTALL_DIR) $(1)/usr/lib/lua/luci
cp -pR ./luasrc/* $(1)/usr/lib/lua/luci
$(INSTALL_DIR) $(1)/
cp -pR ./root/* $(1)/
endef
define Package/luci-app-autoipsetadder/postinst
#!/bin/sh
/etc/init.d/autoipsetadder enable >/dev/null 2>&1
/etc/init.d/autoipsetadder start
rm -f /tmp/luci-indexcache
rm -f /tmp/luci-modulecache/*
exit 0
endef
define Package/luci-app-autoipsetadder/prerm
#!/bin/sh
if [ -z "$${IPKG_INSTROOT}" ]; then
/etc/init.d/autoipsetadder disable
/etc/init.d/autoipsetadder stop
fi
exit 0
endef
$(eval $(call BuildPackage,luci-app-autoipsetadder))

View File

@ -0,0 +1,4 @@
# luci-app-autoipsetadder
需要ipset china 和 ipset gfwlist<br>
更多信息https://github.com/rufengsuixing/auto-ipsetadder-for-openwrt
![Screenshot_2019-12-27 newifi-d1 - 基础设置 - LuCI(1)](https://user-images.githubusercontent.com/22387141/71496667-63eafb80-288f-11ea-93b7-52b154450d2b.png)

View File

@ -0,0 +1,56 @@
module("luci.controller.autoipsetadder",package.seeall)
local io = require "io"
local fs=require"nixio.fs"
local sys=require"luci.sys"
local uci=require"luci.model.uci".cursor()
function index()
entry({"admin","services","autoipsetadder"},firstchild(),_("autoipsetadder"),30).dependent=true
entry({"admin","services","autoipsetadder","autoipsetadder"},cbi("autoipsetadder"),_("Base Setting"),1)
entry({"admin","services","autoipsetadder","status"},call("act_status")).leaf=true
entry({"admin", "services", "autoipsetadder", "getlog"}, call("get_log"))
entry({"admin", "services", "autoipsetadder", "dodellog"}, call("do_del_log"))
entry({"admin", "services", "autoipsetadder", "debugip"}, call("do_debug_ip"))
end
function act_status()
local e={}
e.running=luci.sys.call("pgrep -f /usr/bin/autoipsetadder/autoaddlist.sh >/dev/null")==0
luci.http.prepare_content("application/json")
luci.http.write_json(e)
end
function do_del_log()
local logfile=uci:get("autoipsetadder","autoipsetadder","logfile") or "/tmp/addlist.log"
nixio.fs.writefile(logfile,"")
luci.http.prepare_content("application/json")
luci.http.write('')
end
function do_debug_ip()
luci.http.prepare_content("text/plain; charset=utf-8")
local a=sys.exec("/usr/bin/autoipsetadder/debugip.sh")
if (a=="") then
a="noproblem"
end
luci.http.write(a)
end
function get_log()
local logfile,fdp
logfile=uci:get("autoipsetadder","autoipsetadder","logfile") or "/tmp/addlist.log"
luci.http.prepare_content("text/plain; charset=utf-8")
if not fs.access(logfile) then
luci.http.write("")
return
end
if fs.access("/var/run/lucilogreload") then
fdp=0
fs.remove("/var/run/lucilogreload")
else
fdp=tonumber(fs.readfile("/var/run/lucilogpos")) or 0
end
local f=io.open(logfile, "r+")
f:seek("set",fdp)
local a=f:read(2048000) or ""
fdp=f:seek()
fs.writefile("/var/run/lucilogpos",tostring(fdp))
f:close()
luci.http.write(a)
end

View File

@ -0,0 +1,97 @@
require("luci.sys")
require("luci.util")
local fs=require"nixio.fs"
local uci=require"luci.model.uci".cursor()
local m,s,o
m = Map("autoipsetadder", translate("ipsetautoadder"))
m.description = translate("自动将联不通的域名加入ipset")
m:section(SimpleSection).template = "autoipsetadder/status"
s = m:section(TypedSection, "autoipsetadder")
s.anonymous=true
s.addremove=false
---- enable
o = s:option(Flag, "enabled", translate("启用"))
o.default = 0
o.rmempty = false
---- logview
o=s:option(TextValue, "show", "日志")
o.template = "autoipsetadder/check"
---- logpath
o = s:option(Value, "logfile", translate("Runtime log file"))
o.datatype = "string"
o.default="/tmp/addlist.log"
o.optional = false
o.validate=function(self, value)
if fs.stat(value,"type")=="dir" then
fs.rmdir(value)
end
if fs.stat(value,"type")=="dir" then
if m.message then
m.message =m.message.."\nerror!log file is a dir"
else
m.message ="error!log file is a dir"
end
return nil
end
return value
end
---- dnsmasq log
o = s:option(Value, "dnslogfile", translate("dnsmasq log file"))
o.datatype = "string"
o.optional = false
o.default="/tmp/dnsmasq.log"
o.validate=function(self, value)
if fs.stat(value,"type")=="dir" then
fs.rmdir(value)
end
if fs.stat(value,"type")=="dir" then
if m.message then
m.message =m.message.."\nerror!log file is a dir"
else
m.message ="error!log file is a dir"
end
return nil
end
return value
end
---- crontab
o = s:option(MultiValue, "crontab", translate("Crontab task"),translate("Please change time and args in crontab"))
o:value("autodeldnslog",translate("Auto del dnsmasq log"))
o:value("autotaillog",translate("Auto tail runtime log"))
o.widget = "checkbox"
o.default = "autodeldnslog autotaillog"
o.rmempty= true
o = s:option(MultiValue, "config", translate("the way add to gfwlist"))
o:value("nochina",translate("no china ip"))
o:value("pingadd",translate("5ping loss1-4"))
o:value("packetpass",translate("packet >12 pass"))
o.widget = "checkbox"
o.default = "nochina pingadd packetpass"
o.rmempty=true
---- apply
nixio.fs.writefile("/var/run/lucilogreload","")
function m.on_commit(map)
local ucitracktest=uci:get("autoipsetadder","autoipsetadder","ucitracktest")
if ucitracktest=="1" then
return
elseif ucitracktest=="0" then
io.popen("/etc/init.d/autoipsetadder reload &")
else
if (fs.access("/var/run/AdGucitest")) then
uci:set("autoipsetadder","autoipsetadder","ucitracktest","0")
io.popen("/etc/init.d/autoipsetadder reload &")
else
fs.writefile("/var/run/AdGucitest","")
if (ucitracktest=="2") then
uci:set("autoipsetadder","autoipsetadder","ucitracktest","1")
else
uci:set("autoipsetadder","autoipsetadder","ucitracktest","2")
end
end
uci:save("autoipsetadder")
uci:commit("autoipsetadder")
end
end
return m

View File

@ -0,0 +1,62 @@
<%+cbi/valueheader%>
<%uci=require"luci.model.uci".cursor()%>
<%nixio=require"nixio"%>
<%if uci:get("autoipsetadder","autoipsetadder","enabled")=="1" then%>
<textarea id="cbid.logview.1.conf" class="cbi-input-textarea" style="width: 100%;display:inline" data-update="change" rows="10" cols="60" readonly="readonly" > </textarea>
<input type="checkbox" value="reverse" onclick=" return reverselog()" style="vertical-align:middle;height: auto;" checked><%:reverse%></input>
<input type="button" class="cbi-button cbi-button-apply" id="apply_update_button" value="dellog" onclick=" return apply_del_log() "/>
<input type="button" class="cbi-button cbi-button-apply" id="apply_update_button" value="debug" onclick=" return debug_ip() "/>
<textarea id="cbid.logview.2.conf" class="cbi-input-textarea" style="width: 100%;display:none" data-update="change" rows="10" cols="60" readonly="readonly" > </textarea>
<script type="text/javascript">//<![CDATA[
var islogreverse = true;
function apply_del_log(){
XHR.get('<%=url([[admin]], [[services]], [[autoipsetadder]], [[dodellog]])%>',null,function(x, data){
var lv = document.getElementById('cbid.logview.1.conf');
lv.innerHTML="";
}
);
return
}
function reverselog(){
var lv = document.getElementById('cbid.logview.1.conf');
lv.innerHTML=lv.innerHTML.split('\n').reverse().join('\n')
if (islogreverse){
islogreverse=false;
}else{
islogreverse=true;
}
return
}
function debug_ip(){
var lv2 = document.getElementById('cbid.logview.2.conf');
lv2.style.display="inline"
XHR.get('<%=url([[admin]], [[services]], [[autoipsetadder]], [[debugip]])%>',null,function(x, data){
var lv2 = document.getElementById('cbid.logview.2.conf');
lv2.innerHTML = x.responseText;
}
);
return
}
function poll_check(){
XHR.poll(3, '<%=url([[admin]], [[services]], [[autoipsetadder]], [[getlog]])%>', null,
function(x, data) {
var lv = document.getElementById('cbid.logview.1.conf');
if (x.responseText && lv) {
if (islogreverse){
lv.innerHTML = x.responseText.split('\n').reverse().join('\n')+lv.innerHTML;
}else{
lv.innerHTML += x.responseText;
}
}
}
);}
poll_check();
//]]>
</script>
<%end%>
<%+cbi/valuefooter%>

View File

@ -0,0 +1,22 @@
<script type="text/javascript">//<![CDATA[
XHR.poll(3, '<%=url([[admin]], [[services]], [[autoipsetadder]], [[status]])%>', null,
function(x, data) {
var tb = document.getElementById('autoipsetadder_status');
if (data && tb) {
if (data.running) {
var links = '<em><b><font color=green>autoipsetadder <%:RUNNING%></font></b></em>';
tb.innerHTML = links;
} else {
tb.innerHTML = '<em><b><font color=red>autoipsetadder <%:NOT RUNNING%></font></b></em>';
}
}
}
);
//]]>
</script>
<style>.mar-10 {margin-left: 50px; margin-right: 10px;}</style>
<fieldset class="cbi-section">
<p id="autoipsetadder_status">
<em><%:Collecting data...%></em>
</p>
</fieldset>

View File

@ -0,0 +1,2 @@
config autoipsetadder 'autoipsetadder'
option enabled '0'

View File

@ -0,0 +1,126 @@
#!/bin/sh /etc/rc.common
USE_PROCD=1
START=99
STOP=01
CRON_FILE=/etc/crontabs/root
CONFIGURATION=autoipsetadder
EXTRA_COMMANDS="test_crontab"
EXTRA_HELP="
test_crontab"
set_dnsmasq_log()
{
sed -i '/log-facility/d' /etc/dnsmasq.conf
sed -i '/log-queries/d' /etc/dnsmasq.conf
uci set dhcp.@dnsmasq[0].logfacility='/tmp/dnsmasq.log'
uci delete dhcp.@dnsmasq[0].logqueries
echo log-queries >> /etc/dnsmasq.conf
uci commit dhcp
/etc/init.d/dnsmasq reload
}
stop_dnsmasq_log()
{
sed -i '/log-queries/d' /etc/dnsmasq.conf
uci delete dhcp.@dnsmasq[0].logfacility
uci commit dhcp
/etc/init.d/dnsmasq reload
}
reload_service()
{
rm -f /var/run/AdGucitest 2>/dev/null
kill $(cat /var/run/autoipsetadder.pid)
start
}
service_triggers() {
procd_add_reload_trigger "$CONFIGURATION"
}
start_service() {
# Reading config
config_load "${CONFIGURATION}"
mkdir -p /tmp/run/autoipsetadder
local enabled
config_get_bool enabled $CONFIGURATION enabled 0
do_crontab
if [ "$enabled" == "1" ]; then
set_dnsmasq_log
procd_open_instance
procd_set_param respawn
# pass config to script on start
procd_set_param command sh /usr/bin/autoipsetadder/autoaddlist.sh
procd_close_instance
echo "autoipsetadder turn on"
echo "enabled=$enabled"
else
stop_dnsmasq_log
echo "autoipsetadder turn off"
echo "enabled=$enabled"
fi
}
stop_service()
{
config_load "${CONFIGURATION}"
stop_dnsmasq_log
do_crontab
kill $(cat /var/run/autoipsetadder.pid)
echo "autoipsetadder turn off"
echo "enabled="$enabled""
}
do_crontab(){
config_get_bool enabled $CONFIGURATION enabled 0
#config_get logfile $CONFIGURATION logfile "/tmp/addlist.log"
#config_get dnslogfile $CONFIGURATION dnslogfile "/tmp/dnsmasq.log"
config_get crontab $CONFIGURATION crontab ""
cronreload=0
findstr="echo qingkong > \$(uci get autoipsetadder.autoipsetadder.dnslogfile)"
default="0 * * * * echo qingkong > \$(uci get autoipsetadder.autoipsetadder.dnslogfile)"
#[ -n "$lastdnslogfile" ] && findstr="echo qingkong > $lastdnslogfile" && [ "$lastdnslogfile" != "$dnslogfile" ] && replace="${lastdnslogfile//\//\\/}/${dnslogfile//\//\\/}"
[ "$enabled" == "0" ] || [ "${crontab//autodeldnslog/}" == "$crontab" ] && cronenable=0 || cronenable=1
crontab_editor
#[ "$lastdnslogfile" != "$dnslogfile" ] && uci set autoipsetadder.autoipsetadder.lastdnslogfile="$dnslogfile" && commit=1
findstr="/usr/bin/autoipsetadder/tailto.sh [0-9]* \$(uci get autoipsetadder.autoipsetadder.logfile)"
default="0 0 * * * /usr/bin/autoipsetadder/tailto.sh 2000 \$(uci get autoipsetadder.autoipsetadder.logfile)"
#[ -n "$lastlogfile" ] && findstr="/usr/bin/autoipsetadder/tailto.sh [0-9]* $lastlogfile" && [ "$lastlogfile" != "$logfile" ] && replace="${lastlogfile//\//\\/}/${logfile//\//\\/}"
[ "$enabled" == "0" ] || [ "${crontab//autotaillog/}" == "$crontab" ] && cronenable=0 || cronenable=1
crontab_editor
#[ -n "$logfile" ] && [ "$lastlogfile" != "$logfile" ] && uci set autoipsetadder.autoipsetadder.lastlogfile="$logfile" && commit=1
[ "$cronreload" -gt 0 ] && /etc/init.d/cron restart
#[ "$commit" -gt 0 ] && uci commit autoipsetadder
}
crontab_editor(){
local testline reload
local line="$(grep "$findstr" $CRON_FILE)"
[ -n "$replace" ] && [ -n "$line" ] && eval testline="\${line//$replace}" && [ "$testline" != "$line" ] && line="$testline" && reload="1" && replace=""
if [ "${line:0:1}" != "#" ]; then
if [ $cronenable -eq 1 ]; then
[ -z "$line" ] && line="$default" && reload="1"
if [ -n "$reload" ]; then
sed -i "\,$findstr,d" $CRON_FILE
echo "$line" >> $CRON_FILE
cronreload=$((cronreload+1))
fi
elif [ -n "$line" ]; then
sed -i "\,$findstr,d" $CRON_FILE
echo "#$line" >> $CRON_FILE
cronreload=$((cronreload+1))
fi
else
if [ $cronenable -eq 1 ]; then
sed -i "\,$findstr,d" $CRON_FILE
echo "${line:1}" >> $CRON_FILE
cronreload=$((cronreload+1))
elif [ -z "$reload" ]; then
sed -i "\,$findstr,d" $CRON_FILE
echo "$line" >> $CRON_FILE
fi
fi
}
test_crontab(){
config_load "${CONFIGURATION}"
do_crontab
}

View File

@ -0,0 +1,11 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete ucitrack.@autoipsetadder[-1]
add ucitrack autoipsetadder
set ucitrack.@autoipsetadder[-1].init=autoipsetadder
commit ucitrack
EOF
rm -f /tmp/luci-indexcache
exit 0

View File

@ -0,0 +1,164 @@
#!/bin/sh
PATH="/usr/sbin:/usr/bin:/sbin:/bin"
logfile=$(uci get autoipsetadder.autoipsetadder.logfile)
[ -z "$logfile" ] && logfile="/tmp/addlist.log"
dnslogfile=$(uci get autoipsetadder.autoipsetadder.dnslogfile)
[ -z "$logfile" ] && dnslogfile="/tmp/dnsmasq.log"
config=$(uci get autoipsetadder.autoipsetadder.config 2>/dev/null)
[ "${config//nochina/}" == "$config" ] && nochina="0" || nochina="1"
[ "${config//packetpass/}" == "$config" ] && packetpass="0" || packetpass="1"
(tail -F $dnslogfile & echo $! >/var/run/autoipsetadder.pid ) | awk -v nochina="$nochina" -v packetpass="$packetpass" -F "[, ]+" '/reply/{
ip=$8;
if (ip=="" || ip=="127.0.0.1"|| ip=="0.0.0.0")
{
next;
}
if (index(ip,"<CNAME>")!=0)
{
if (cname==1)
{
next;
}
cname=1;
domain=$6;
#第一次cname时锁定域名防止解析cname对其改动
next;
}
#以上获得上行是否为cname本行不是cname执行以下内容
#lastdomain记录上次非cname的域名与本次域名对比
if(lastdomain!=$6){
for (ipindex in ipcache)
{
delete ipcache[ipindex];
}
ipcount=0;
createpid=1;
#上行非cname并且不是同cname解析域名的多个ip更新域名清理同域名免试flag
if (cname!=1)
{
domain=$6;
testall=0;
}}
ipcount++;
cname=0;
lastdomain=$6
#去除非ipv4
if (index(ip,".")==0)
{
next;
}
#不重复探测ip
if (!(ip in a))
{
#包数>12的同域名放过
if (passdomain==domain)
{
print(ip" "domain" pass by same domain ok");
a[ip]=domain;
next;
}
if (nochina==1){
"ipset test china "ip" 2>&1"| getline ipset;
close("ipset test china "ip" 2>&1");
if (index(ipset,"Warning")!=0){
print("china "ip" pass");
a[ip]=domain;
next;
}}
"ipset test gfwlist "ip" 2>&1"| getline ipset;
close("ipset test gfwlist "ip" 2>&1");
if (index(ipset,"Warning")!=0){
print("gfwlist "ip" pass");
a[ip]=domain;
next;
}
#ip压入缓存用于未检测到443/80的缓存
ipcache[ipcount]=ip;
if (testall==0){
tryhttps=0;
tryhttp=0;
#探测 nf_conntrack 的443/80
while ("grep "ip" /proc/net/nf_conntrack"| getline ret > 0)
{
split(ret, b," +");
split(b[11], pagnum,"=");
#包数>12的放过
if (packetpass==1 && pagnum[2]>12)
{
print("pass by packets="pagnum[2]" "ip" "domain);
for (ipindex in ipcache)
{
a[ipcache[ipindex]]=domain;
delete ipcache[ipindex];
}
passdomain=domain;
close("grep "ip" /proc/net/nf_conntrack");
ipcount--;
next;
}
if (b[8]=="dst="ip)
{
if (b[10]=="dport=443"){
tryhttps=1;
break;
}
else if (b[10]=="dport=80"){
tryhttp=1;
}
}
}
close("grep "ip" /proc/net/nf_conntrack");
}else{
if (testall==443)
{
tryhttps=1
}else{
tryhttp=1
}
}
if (tryhttps==1)
{ if (createpid==1)
{
print "">"/tmp/run/autoipsetadder/"domain
close("/tmp/run/autoipsetadder/"domain);
print("create"domain);
print(ip" "domain" 443"ipcount-1);
a[ip]=domain;
#正在使用的ip用最大延迟最后探测减少打断tcp的可能
system("/usr/bin/autoipsetadder/testip.sh "ip" "domain" 443 "ipcount-1" &");
delete ipcache[ipcount];
createpid=0;
}
#未检测到443/80同域名缓存的ip进行测试ipindex-1为测试延迟时间
for (ipindex in ipcache){
print(ipcache[ipindex]" "domain" 443 "ipindex-1);
a[ipcache[ipindex]]=domain;
system("/usr/bin/autoipsetadder/testip.sh "ipcache[ipindex]" "domain" 443 "ipindex-1" &");
delete ipcache[ipindex];
}
#后续同域名ip免nf_conntrack测试
testall=443;
}
else if (tryhttp==1)
{
if (createpid==1)
{
print "">"/tmp/run/autoipsetadder/"domain
close("/tmp/run/autoipsetadder/"domain);
print("create"domain);
print(ip" "domain" 80 "ipcount-1);
a[ip]=domain;
system("/usr/bin/autoipsetadder/testip.sh "ip" "domain" 80 "ipcount-1" &");
delete ipcache[ipcount];
createpid=0;
}
for (ipindex in ipcache){
print(ipcache[ipindex]" "domain" 80 "ipindex-1);
a[ipcache[ipindex]]=domain;
system("/usr/bin/autoipsetadder/testip.sh "ipcache[ipindex]" "domain" 80 "ipindex-1" &");
delete ipcache[ipindex];
}
testall=80;
}}
}' >> $logfile

View File

@ -0,0 +1,56 @@
#!/bin/sh
PATH="/usr/sbin:/usr/bin:/sbin:/bin"
dlchina=$1;
logfile=$(uci get autoipsetadder.autoipsetadder.logfile)
[ -z "$logfile" ] && logfile="/tmp/addlist.log"
dnslogfile=$(uci get autoipsetadder.autoipsetadder.dnslogfile)
[ -z "$logfile" ] && dnslogfile="/tmp/dnsmasq.log"
ipset list gfwlist | awk -v dlchina="$dlchina" -v dnslogfile="$dnslogfile" -v logfile="$logfile" '{
if (index($0,".")==0)
{
next;
}
if ($0=="127.0.0.1") {system("ipset d gfwlist 127.0.0.1");next;}
"ipset test whitelist "$0" 2>&1"| getline ipset;
close("ipset test whitelist "$0" 2>&1");
if (index(ipset,"Warning")==0){
white=0;
}else{
white=1;
}
"ipset test china "$0" 2>&1"| getline ipset;
close("ipset test china "$0" 2>&1");
if (index(ipset,"Warning")!=0){
china=1;
}
else{
china=0;
}
if (white==1)
{
if (china==0)
{
print("warning white ip not china"$0);
ret=system("grep "$0" "logfile);
if (ret!=0)
{
ret=system("grep "$0" "dnslogfile);
}
}
}else if (china==1)
{
print("warning china ip not white"$0);
ret=system("grep "$0" "logfile)
if (ret!=0)
{
ret=system("grep "$0" "dnslogfile);
}
if (dlchina)
{
system("ipset del gfwlist "$0);
}
}
}'

View File

@ -0,0 +1,4 @@
#!/bin/sh
tail -n $1 "$2" > /var/run/tailtmp
cat /var/run/tailtmp > "$2"
rm /var/run/tailtmp

View File

@ -0,0 +1,182 @@
#!/bin/sh
config=$(uci get autoipsetadder.autoipsetadder.config 2>/dev/null)
[ "${config//pingadd/}" == "$config" ] && pingadd="0" || pingadd="1"
echo $* | awk -v pingadd="$pingadd" '{
if ($4=="")
{
wait=0;
}else
{wait=$4;}
system("sleep "wait);
ERRNO="";
pidfile="/tmp/run/autoipsetadder/"$2
getline drop< pidfile;
close(pidfile);
if (ERRNO) {
addlist=0;
print("bypass"$1" "$2);
next;}
if ($3=="443")
{
cmd=("httping -c 1 -t 4 -l "$2" --divert-connect "$1);
}
else if ($3=="80")
{
cmd=("httping -c 1 -t 4 "$2" --divert-connect "$1);
}
addlist=0;
slow=0;
while ((cmd | getline ret) > 0)
{
if (addlist!=0)
{
continue;
}
else if (index(ret,"short read")!=0)
{
if (system("httping -q -c 1 -t 4 -l "$2" --divert-connect "$1)==0)
{
addlist=-1;
break;
}else{
print("doname rst autoaddip "$1" "$2);
addlist=1;
}
}
else if (index(ret,"timeout")!=0)
{
while ((cmd | getline ret) > 0)
{
if (index(ret,"timeout")!=0)
{
print("direct so slow autoaddip "$1" "$2);
addlist=1;
slow=1;
}
}
}else if (index(ret,"SSL handshake error: (null)")!=0)
{
if(system("curl -m 10 --resolve "$2":443:"$1" https://"$2" -o /dev/null 2>/dev/null")==0){
addlist=-1;
break;
}
}else if (index(ret,"Connection refused")!=0){
print("direct Connection refused autoaddip"$1" "$2);
addlist=1;
}
}
close(cmd);
if (addlist!=1)
{
if (addlist==0){
split(ret, c,"[ /]+");
print(c[6]);
if (c[6]=="failed,"){
print("can not connect autoaddip "$1" "$2);
addlist=1;
}
else if (c[6]+0>10000)
{
print("direct ssl so slow autoaddip "$1" "$2);
addlist=1;
}else{
addlist=-1;}
}
if (addlist==-1 && pingadd==1)
{
while (("ping -c 5 -q -A "$1 | getline ret) > 0)
{
if (index(ret,"packet loss")!=0)
{
split(ret, p,"[ ]+");
if (p[4]>0 && p[4]<5)
{
print("ping packet loss autoaddip "$1" "$2);
pingloss=1;
addlist=1;
}else{pingloss=0;}
break;
}
}
close("ping -c 5 -q "$1);
}
}
ERRNO="";
if (pingloss!=1){
getline drop< pidfile;
close(pidfile);
}
if (ERRNO) {addlist=0;next;}
if (addlist==1){
system("ipset add gfwlist "$1);
while ((cmd | getline ret) > 0)
{
if (addlist==1)
{
if (index(ret,"short read")!=0)
{
system("ipset del gfwlist "$1);
print("doname proxy rst autodelip "$1" "$2);
addlist=-2;
}
else if (index(ret,"SSL handshake error: (null)")!=0)
{
if(system("curl -m 10 --resolve "$2":443:"$1" https://"$2" -o /dev/null 2>/dev/null")==0)
{
addlist=2;
}
}
}
}
close(cmd);
if (addlist==1){
split(ret, c,"[ /]+");
print(c[6]);
if (c[6]=="failed,")
{
system("ipset del gfwlist "$1);
print("proxy can not connect autodelip "$1" "$2);
addlist=-2;
}else{
addlist=2;
}
}
}
}END{
if (addlist==2)
{ if (pingloss==0){
ERRNO="";
getline drop< pidfile;
if (ERRNO) {
system("ipset del gfwlist "$1);
print("cancel add myself "$1" "$2" due to one ip success direct");
}else{
print $1"\n">>pidfile;
}
close(pidfile);}
}else if (addlist==-1)
{
print($1" "$2" direct success");
while ((getline ret< pidfile) > 0)
{
if (ret!=""){
system("ipset del gfwlist "ret);
print("cancel add someone "ret" "$2" due to me"$1" success direct");
}
}
close(pidfile);
system("rm "pidfile" 2>/dev/null");
print($1" del "$2);
}else if (addlist==-2)
{
system("sleep 10");
while ((getline ret< pidfile) > 0)
{
if (ret!=""){
system("ipset add gfwlist "$1);
print("add "ret" "$2" due to one ip success proxy");
break;}
}
close(pidfile);
}}'

View File

@ -0,0 +1,11 @@
{
"luci-app-autoipsetadder": {
"description": "Grant UCI access for luci-app-autoipsetadder",
"read": {
"uci": [ "autoipsetadder" ]
},
"write": {
"uci": [ "autoipsetadder" ]
}
}
}

2
luci-app-beardropper/.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

2
luci-app-beardropper/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.DS_Store

View File

@ -0,0 +1,622 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS

View File

@ -0,0 +1,22 @@
#
# Copyright (C) 2020 Nate Ding
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
LUCI_Title:=LuCI Support for BearDropper
LUCI_PKGARCH=all
PKG_VERSION:=1.1
PKG_RELEASE:=20200522
PKG_MAINTANINER:=Nate Ding <natelol@github.com>
PKG_LICENSE:=GLPv3
PKG_LICENSE_FILES:=LICENSE
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -0,0 +1,59 @@
luci-app-beardropper
===
[Preview][preview]
---
luci-app-beardropper, a log examination script w/ iptables firewall rule generation response.
This is the LuCI app built for the elegant firewall rule generation on-the-fly script [bearDropper][bearDropper], only a few modifications were made to work with Luci.
Targets/Devices
---
Written in shell scripts, so it shall work all good on all devices.
Config
---
The config file path is: `/etc/config/beardropper` and this is the uci configuration format.
Compile
---
RECOMMENDED!!!! (推荐使用右边的feeds---->)You can use [natelol feeds][feeds]
OR
0. Go under `openwrt/`
1. Make your own local feeds, say a folder `mkdir yourfeeds`
2. Clone master under feeds to have `git clone https://github.com/natelol/luci-app-beardropper yourefeeds/luci-app-beardropper`
3. Append `src-link yourfeeds /path/to/openwrt/yourfeeds` in the file `openwrt/feeds.conf(.default)`
4. Run following scripts under `openwrt`:
```bash
# Update feeds
./scripts/feeds update -a
./scripts/feeds install -a
# M select luci-app-beardropper in LuCI -> 3. Applications also 2. Modules->Translations if you want translations together
make menuconfig
# compile
make package/feeds/luci-app-beardropper/compile V=99
```
Logs
---
`2020-05-21` Added a new tab listing the blocked IPs.
[preview]: https://github.com/natelol/luci-app-beardropper/tree/master/preview
[bearDropper]: https://github.com/robzr/bearDropper
[feeds]: https://github.com/natelol/natelol

View File

@ -0,0 +1,19 @@
module("luci.controller.beardropper", package.seeall)
function index()
if not nixio.fs.access("/etc/config/beardropper") then
return
end
entry({"admin", "services", "beardropper"}, alias("admin", "services", "beardropper", "setting"),_("BearDropper"), 20).dependent = true
entry({"admin", "services", "beardropper", "status"}, call("act_status"))
entry({"admin", "services", "beardropper", "setting"}, cbi("beardropper/setting"), _("Setting"), 30).leaf= true
entry({"admin", "services", "beardropper", "log"}, form("beardropper/log"),_("Log"),40).leaf= true
--entry:
end
function act_status()
local e={}
e.running = luci.sys.call("pgrep -f /usr/sbin/beardropper >/dev/null")==0
luci.http.prepare_content("application/json")
luci.http.write_json(e)
end

View File

@ -0,0 +1,17 @@
f = SimpleForm("logview")
f.reset = false
f.submit = false
t = f:field(TextValue, "conf")
t.rmempty = true
t.rows = 20
function t.cfgvalue()
local logs = luci.util.execi("logread | grep authpriv | grep beardropper")
local s = ""
for line in logs do
s = line .. "\n" .. s
end
return s
end
t.readonly="readonly"
return f

View File

@ -0,0 +1,54 @@
m = Map("beardropper", translate("BearDropper"),
translate("luci-app-beardropper, the LuCI app built with the elegant firewall rule generation on-the-fly script bearDropper. <br /> <br /> Should you have any questions, please refer to the repo: ")..[[<a href="https://github.com/NateLol/luci-app-bearDropper" target="_blank">luci-app-beardropper</a>]]
)
m:chain("luci")
m:section(SimpleSection).template="beardropper/status"
s = m:section(TypedSection, "beardropper", translate(""))
s.anonymous = true
s.addremove = false
-- TABS
s:tab("options", translate("Options"))
s:tab("blocked", translate("Blocked IP"))
o = s:taboption("options", Flag, "enabled",translate("Enabled"))
o.default = 0
-- OPTIONS
o = s:taboption("options", ListValue, "defaultMode", translate("Running Mode"))
o.default = "follow"
o:value("follow", translate("Follow"))
o:value("entire", translate("Entire"))
o:value("today", translate("Today"))
o:value("wipe", translate("Wipe"))
o = s:taboption("options", Value, "attemptCount", translate("Attempt Tolerance"), translate("failure attempts from a given IP required to trigger a ban"))
o = s:taboption("options", Value, "attemptPeriod", translate("Attempt Cycle"), translate("time period during which attemptCount must be exceeded in order to trigger a ban <br> Format: 1w2d3h4m5s represents 1week 2days 3hours 4minutes 5 seconds"))
o = s:taboption("options", Value, "banLength", translate("Ban Period"), translate("how long a ban exist once the attempt threshold is exceeded"))
o = s:taboption("options", ListValue, "logLevel", translate("Log Level"))
o.default = "1"
o:value("0", translate("Silent"))
o:value("1", translate("Default"))
o:value("2", translate("Verbose"))
o:value("3", translate("Debug"))
o = s:taboption("blocked", Value, "blocked", translate("Blocked IP List"))
o.template="cbi/tvalue"
o.rows=40
o.wrap="off"
o.readonly="true"
function o.cfgvalue(e, e)
return luci.sys.exec("cat /tmp/beardropper.bddb | awk /'=1/'| awk -F '=' '{print $1}' | awk '{print substr($0,6)}' | awk 'gsub(/_/,\":\",$0)'")
end
return m

View File

@ -0,0 +1,22 @@
<script type="text/javascript">//<![CDATA[
XHR.poll(3, '<%=url([[admin]], [[services]], [[beardropper]], [[status]])%>', null,
function(x, data) {
var tb = document.getElementById('beardropper_status');
if (data && tb) {
if (data.running) {
var links = '<em><b><font color=green>BearDropper <%:RUNNING%></font></b></em>';
tb.innerHTML = links;
} else {
tb.innerHTML = '<em><b><font color=red>BearDropper <%:NOT RUNNING%></font></b></em>';
}
}
}
);
//]]>
</script>
<style>.mar-10 {margin-left: 50px; margin-right: 10px;}</style>
<fieldset class="cbi-section">
<p id="beardropper_status">
<em><%:Collecting data...%></em>
</p>
</fieldset>

View File

@ -0,0 +1,115 @@
bearDropper#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:36
msgid "Attempt Cycle"
msgstr "尝试登录时间段"
msgid "Setting"
msgstr "设置"
msgid "Log"
msgstr "日志"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:34
msgid "Attempt Tolerance"
msgstr "最大尝试登录次数"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:38
msgid "Ban Period"
msgstr "封禁IP时长"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/controller/bearDropper.lua:7
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:7
msgid "BearDropper"
msgstr ""
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:20
msgid "Blocked IP"
msgstr "屏蔽列表"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:52
msgid "Blocked IP List"
msgstr "已屏蔽IP列表"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/view/bearDropper/status.htm:20
msgid "Collecting data..."
msgstr ""
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:45
msgid "Debug"
msgstr "调试"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:43
msgid "Default"
msgstr "默认"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:22
msgid "Enabled"
msgstr "启用"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:29
msgid "Entire"
msgstr "已有记录"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:28
msgid "Follow"
msgstr "后台监控"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:40
msgid "Log Level"
msgstr "日志等级"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/view/bearDropper/status.htm:10
msgid "NOT RUNNING"
msgstr ""
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:19
msgid "Options"
msgstr "选项"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/view/bearDropper/status.htm:7
msgid "RUNNING"
msgstr ""
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:26
msgid "Running Mode"
msgstr "运行模式"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:42
msgid "Silent"
msgstr "安静"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:30
msgid "Today"
msgstr "仅今日"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:44
msgid "Verbose"
msgstr "详细"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:31
msgid "Wipe"
msgstr "清除所有"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:34
msgid "failure attempts from a given IP required to trigger a ban"
msgstr "尝试登录超过设定值次数的IP将被封禁"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:38
msgid "how long a ban exist once the attempt threshold is exceeded"
msgstr "IP将被封禁设定的时间"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:8
msgid ""
"luci-app-beardropper, the LuCI app built with the elegant firewall rule "
"generation on-the-fly script bearDropper. <br /> <br /> Should you have any "
"questions, please refer to the repo:"
msgstr ""
"luci-app-beardropper, 是一款能够在开启公网访问之后对潜在的ssh attack进行防御"
"的脚本. <br /> <br /> 如果你在使用中有任何问题,请到项目中提问: "
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:36
msgid ""
"time period during which attemptCount must be exceeded in order to trigger a "
"ban <br> Format: 1w2d3h4m5s represents 1week 2days 3hours 4minutes 5 seconds"
msgstr ""
"在设定的时间段内连续尝试失败 <br> 格式1w2d3h4m5s代表1周2天3小时4分5秒"

View File

@ -0,0 +1,115 @@
bearDropper#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:36
msgid "Attempt Cycle"
msgstr "嘗試登錄時間段"
msgid "Setting"
msgstr "設置"
msgid "Log"
msgstr "日誌"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:34
msgid "Attempt Tolerance"
msgstr "最大嘗試登錄次數"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:38
msgid "Ban Period"
msgstr "封禁IP時長"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/controller/bearDropper.lua:7
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:7
msgid "BearDropper"
msgstr ""
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:20
msgid "Blocked IP"
msgstr "屏蔽列表"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:52
msgid "Blocked IP List"
msgstr "已屏蔽IP列表"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/view/bearDropper/status.htm:20
msgid "Collecting data..."
msgstr ""
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:45
msgid "Debug"
msgstr "調試"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:43
msgid "Default"
msgstr "默認"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:22
msgid "Enabled"
msgstr "啟用"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:29
msgid "Entire"
msgstr "已有記錄"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:28
msgid "Follow"
msgstr "後臺監控"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:40
msgid "Log Level"
msgstr "日誌等級"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/view/bearDropper/status.htm:10
msgid "NOT RUNNING"
msgstr ""
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:19
msgid "Options"
msgstr "選項"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/view/bearDropper/status.htm:7
msgid "RUNNING"
msgstr ""
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:26
msgid "Running Mode"
msgstr "運行模式"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:42
msgid "Silent"
msgstr "安靜"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:30
msgid "Today"
msgstr "僅今日"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:44
msgid "Verbose"
msgstr "詳細"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:31
msgid "Wipe"
msgstr "清除所有"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:34
msgid "failure attempts from a given IP required to trigger a ban"
msgstr "嘗試登錄超過設定值次數的IP將被封禁"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:38
msgid "how long a ban exist once the attempt threshold is exceeded"
msgstr "IP將被封禁設定的時間"
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:8
msgid ""
"luci-app-beardropper, the LuCI app built with the elegant firewall rule "
"generation on-the-fly script bearDropper. <br /> <br /> Should you have any "
"questions, please refer to the repo:"
msgstr ""
"luci-app-beardropper, 是壹款能夠在開啟公網訪問之後對潛在的ssh attack進行防禦"
"的腳本. <br /> <br /> 如果妳在使用中有任何問題,請到項目中提問: "
#: ../../package/feeds/luci/luci-app-beardropper/luasrc/model/cbi/bearDropper/setting.lua:36
msgid ""
"time period during which attemptCount must be exceeded in order to trigger a "
"ban <br> Format: 1w2d3h4m5s represents 1week 2days 3hours 4minutes 5 seconds"
msgstr ""
"在設定的時間段內連續嘗試失敗 <br> 格式1w2d3h4m5s代表1周2天3小時4分5秒"

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

View File

@ -0,0 +1,18 @@
config beardropper
option attemptCount '5'
option attemptPeriod '12h'
option banLength '1w'
option logFacility 'authpriv.notice'
option fileStateType 'bddb'
option fileStateTempPrefix '/tmp/beardropper'
option fileStatePersistPrefix '/etc/beardropper'
list firewallHookChain 'input_wan_rule:1'
list firewallHookChain 'forwarding_wan_rule:1'
option firewallTarget 'DROP'
list logRegex 's/[`$"\'\'']//g'
list logRegex '/has invalid shell, rejected$/d'
list logRegex '/^[A-Za-z ]+[0-9: ]+authpriv.warn dropbear\[.+([0-9]+\.){3}[0-9]+/p'
list logRegex '/^[A-Za-z ]+[0-9: ]+authpriv.info dropbear\[.+:\ Exit before auth:.*/p'
option defaultMode 'follow'
option enabled '1'
option logLevel '2'

View File

@ -0,0 +1,46 @@
#!/bin/sh /etc/rc.common
START=98
PROG=/usr/sbin/beardropper
SERVICE_DAEMONIZE=1
SERVICE_WRITE_PID=1
getKids() {
egrep "^PPid: *$1$" /proc/[0-9]*/s*s 2>/dev/null | cut -f3 -d/ | xargs echo
}
start() {
service_start ${PROG} -m follow
echo "beardropper started!"
}
stop() {
#PID=`cat /var/run/bearDropper.pid`
#kill `getKids $PID`
kill -9 `pgrep -f /usr/sbin/beardropper`
sleep 1
service_stop ${PROG}
echo "beardropper exit...."
}
restart() {
enabled=$(uci get beardropper.@beardropper[0].enabled)
pgrep -f ${PROG} >/dev/null
if [ $? -eq 0 ];then #running
if [ $enabled -eq 1 ]; then
stop
sleep 1
echo "beardropper is restarting..."
start
else
stop
fi
else
if [ $enabled -eq 1 ]; then
start
else
exit 0
fi
fi
}

View File

@ -0,0 +1,11 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete ucitrack.@beardropper[-1]
add ucitrack beardropper
set ucitrack.@beardropper[-1].init=beardropper
commit ucitrack
EOF
rm -rf /tmp/luci-*
exit 0

View File

@ -0,0 +1,517 @@
#!/bin/ash
#
# beardropper - dropbear log parsing ban agent for OpenWRT (Chaos Calmer rewrite of dropBrute.sh)
# http://github.com/robzr/bearDropper -- Rob Zwissler 11/2015
#
# - lightweight, no dependencies, busybox ash + native OpenWRT commands
# - uses uci for configuration, overrideable via command line arguments
# - runs continuously in background (via init script) or periodically (via cron)
# - uses BIND time shorthand, ex: 1w5d3h1m8s is 1 week, 5 days, 3 hours, 1 minute, 8 seconds
# - Whitelist IP or CIDR entries (TBD) in uci config file
# - Records state file to tmpfs and intelligently syncs to persistent storage (can disable)
# - Persistent sync routines are optimized to avoid excessive writes (persistentStateWritePeriod)
# - Every run occurs in one of the following modes. If not specified, interval mode (24 hours) is
# the default when not specified (the init script specifies follow mode via command line)
#
# "follow" mode follows syslog to process entries as they happen; generally launched via init
# script. Responds the fastest, runs the most efficiently, but is always in memory.
# "interval" mode only processes entries going back the specified interval; requires
# more processing than today mode, but responds more accurately. Use with cron.
# "today" mode looks at log entries from the day it is being run, simple and lightweight,
# generally run from cron periodically (same simplistic behavior as dropBrute.sh)
# "entire" mode runs through entire contents of the syslog ring buffer
# "wipe" mode tears down the firewall rules and removes the state files
# Load UCI config variable, or use default if not set
# Args: $1 = variable name (also uci option name), $2 = default_value
uciSection='beardropper.@[0]'
uciLoadVar () {
local getUci
getUci=`uci -q get ${uciSection}."$1"` || getUci="$2"
eval $1=\'$getUci\';
}
uciLoad() {
local tFile=`mktemp` delim="
"
[ "$1" = -d ] && { delim="$2"; shift 2; }
uci -q -d"$delim" get "$uciSection.$1" 2>/dev/null >$tFile
if [ $? = 0 ] ; then
sed -e s/^\'// -e s/\'$// <$tFile
else
while [ -n "$2" ]; do echo $2; shift; done
fi
rm -f $tFile
}
# Common config variables - edit these in /etc/config/beardropper
# or they can be overridden at runtime with command line options
#
uciLoadVar defaultMode entire
uciLoadVar enabled 0
uciLoadVar attemptCount 10
uciLoadVar attemptPeriod 12h
uciLoadVar banLength 1w
uciLoadVar logLevel 1
uciLoadVar logFacility authpriv.notice
uciLoadVar persistentStateWritePeriod -1
uciLoadVar fileStateType bddb
uciLoadVar fileStateTempPrefix /tmp/beardropper
uciLoadVar fileStatePersistPrefix /etc/beardropper
firewallHookChains="`uciLoad -d \ firewallHookChain input_wan_rule:1 forwarding_wan_rule:1`"
uciLoadVar firewallTarget DROP
# Not commonly changed, but changeable via uci or cmdline (primarily
# to enable multiple parallel runs with different parameters)
uciLoadVar firewallChain beardropper
# Advanced variables, changeable via uci only (no cmdline), it is
# unlikely that these will need to be changed, but just in case...
#
uciLoadVar syslogTag "beardropper[$$]"
# how often to attempt to expire bans when in follow mode
uciLoadVar followModeCheckInterval 30m
uciLoadVar cmdLogread 'logread' # for tuning, ex: "logread -l250"
uciLoadVar cmdLogreadEba 'logread' # for "Exit before auth:" backscanning
uciLoadVar formatLogDate '%b %e %H:%M:%S %Y' # used to convert syslog dates
uciLoadVar formatTodayLogDateRegex '^%a %b %e ..:..:.. %Y' # filter for today mode
# Begin functions
#
# Clear bddb entries from environment
bddbClear () {
local bddbVar
for bddbVar in `set | egrep '^bddb_[0-9_]*=' | cut -f1 -d= | xargs echo -n` ; do eval unset $bddbVar ; done
bddbStateChange=1
}
# Returns count of unique IP entries in environment
bddbCount () { set | egrep '^bddb_[0-9_]*=' | wc -l ; }
# Loads existing bddb file into environment
# Arg: $1 = file, $2 = type (bddb/bddbz), $3 =
bddbLoad () {
local loadFile="$1.$2" fileType="$2"
if [ "$fileType" = bddb -a -f "$loadFile" ] ; then
. "$loadFile"
elif [ "$fileType" = bddbz -a -f "$loadFile" ] ; then
local tmpFile="`mktemp`"
zcat $loadFile > "$tmpFile"
. "$tmpFile"
rm -f "$tmpFile"
fi
bddbStateChange=0
}
# Saves environment bddb entries to file, Arg: $1 = file to save in
bddbSave () {
local saveFile="$1.$2" fileType="$2"
if [ "$fileType" = bddb ] ; then
set | egrep '^bddb_[0-9_]*=' | sed s/\'//g > "$saveFile"
elif [ "$fileType" = bddbz ] ; then
set | egrep '^bddb_[0-9_]*=' | sed s/\'//g | gzip -c > "$saveFile"
fi
bddbStateChange=0
}
# Set bddb record status=1, update ban time flag with newest
# Args: $1=IP Address $2=timeFlag
bddbEnableStatus () {
local record=`echo $1 | sed -e 's/\./_/g' -e 's/^/bddb_/'`
local newestTime=`bddbGetTimes $1 | sed 's/.* //' | xargs echo $2 | tr \ '\n' | sort -n | tail -1 `
eval $record="1,$newestTime"
bddbStateChange=1
}
# Args: $1=IP Address
bddbGetStatus () {
bddbGetRecord $1 | cut -d, -f1
}
# Args: $1=IP Address
bddbGetTimes () {
bddbGetRecord $1 | cut -d, -f2-
}
# Args: $1 = IP address, $2 [$3 ...] = timestamp (seconds since epoch)
bddbAddRecord () {
local ip="`echo "$1" | tr . _`" ; shift
local newEpochList="$@" status="`eval echo \\\$bddb_$ip | cut -f1 -d,`"
local oldEpochList="`eval echo \\\$bddb_$ip | cut -f2- -d, | tr , \ `"
local epochList=`echo $oldEpochList $newEpochList | xargs -n 1 echo | sort -un | xargs echo -n | tr \ ,`
[ -z "$status" ] && status=0
eval "bddb_$ip"\=\"$status,$epochList\"
bddbStateChange=1
}
# Args: $1 = IP address
bddbRemoveRecord () {
local ip="`echo "$1" | tr . _`"
eval unset bddb_$ip
bddbStateChange=1
}
# Returns all IPs (not CIDR) present in records
bddbGetAllIPs () {
local ipRaw record
set | egrep '^bddb_[0-9_]*=' | tr \' \ | while read record ; do
ipRaw=`echo $record | cut -f1 -d= | sed 's/^bddb_//'`
if [ `echo $ipRaw | tr _ \ | wc -w` -eq 4 ] ; then
echo $ipRaw | tr _ .
fi
done
}
# retrieve single IP record, Args: $1=IP
bddbGetRecord () {
local record
record=`echo $1 | sed -e 's/\./_/g' -e 's/^/bddb_/'`
eval echo \$$record
}
isValidBindTime () { echo "$1" | egrep -q '^[0-9]+$|^([0-9]+[wdhms]?)+$' ; }
# expands Bind time syntax into seconds (ex: 3w6d23h59m59s), Arg: $1=time string
expandBindTime () {
isValidBindTime "$1" || { logLine 0 "Error: Invalid time specified ($1)" >&2 ; exit 254 ; }
echo $((`echo "$1" | sed -e 's/w+*/*7d+/g' -e 's/d+*/*24h+/g' -e 's/h+*/*60m+/g' -e 's/m+*/*60+/g' \
-e s/s//g -e s/+\$//`))
}
# Args: $1 = loglevel, $2 = info to log
logLine () {
[ $1 -gt $logLevel ] && return
shift
if [ "$logFacility" = "stdout" ] ; then echo "$@"
elif [ "$logFacility" = "stderr" ] ; then echo "$@" >&2
else logger -t "$syslogTag" -p "$logFacility" "$@"
fi
}
# extra validation, fails safe. Args: $1=log line
getLogTime () {
local logDateString=`echo "$1" | sed -n \
's/^[A-Z][a-z]* \([A-Z][a-z]* *[0-9][0-9]* *[0-9][0-9]*:[0-9][0-9]:[0-9][0-9] [0-9][0-9]*\) .*$/\1/p'`
date -d"$logDateString" -D"$formatLogDate" +%s || logLine 1 \
"Error: logDateString($logDateString) malformed line ($1)"
}
# extra validation, fails safe. Args: $1=log line
getLogIP () {
local logLine="$1"
local ebaPID=`echo "$logLine" | sed -n 's/^.*authpriv.info \(dropbear\[[0-9]*\]:\) Exit before auth:.*/\1/p'`
[ -n "$ebaPID" ] && logLine=`$cmdLogreadEba | fgrep "${ebaPID} Child connection from "`
echo "$logLine" | sed -n 's/^.*[^0-9]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*$/\1/p'
}
# Args: $1=IP
unBanIP () {
if iptables -C $firewallChain -s $ip -j "$firewallTarget" 2>/dev/null ; then
logLine 1 "Removing ban rule for IP $ip from iptables"
iptables -D $firewallChain -s $ip -j "$firewallTarget"
else
logLine 3 "unBanIP() Ban rule for $ip not present in iptables"
fi
}
# Args: $1=IP
banIP () {
local ip="$1" x chain position
if ! iptables -nL $firewallChain >/dev/null 2>/dev/null ; then
logLine 1 "Creating iptables chain $firewallChain"
iptables -N $firewallChain
fi
for x in $firewallHookChains ; do
chain="${x%:*}" ; position="${x#*:}"
if [ $position -ge 0 ] && ! iptables -C $chain -j $firewallChain 2>/dev/null ; then
logLine 1 "Inserting hook into iptables chain $chain"
if [ $position = 0 ] ; then
iptables -A $chain -j $firewallChain
else
iptables -I $chain $position -j $firewallChain
fi ; fi
done
if ! iptables -C $firewallChain -s $ip -j "$firewallTarget" 2>/dev/null ; then
logLine 1 "Inserting ban rule for IP $ip into iptables chain $firewallChain"
iptables -A $firewallChain -s $ip -j "$firewallTarget"
else
logLine 3 "banIP() rule for $ip already present in iptables chain"
fi
}
wipeFirewall () {
local x chain position
for x in $firewallHookChains ; do
chain="${x%:*}" ; position="${x#*:}"
if [ $position -ge 0 ] ; then
if iptables -C $chain -j $firewallChain 2>/dev/null ; then
logLine 1 "Removing hook from iptables chain $chain"
iptables -D $chain -j $firewallChain
fi ; fi
done
if iptables -nL $firewallChain >/dev/null 2>/dev/null ; then
logLine 1 "Flushing and removing iptables chain $firewallChain"
iptables -F $firewallChain 2>/dev/null
iptables -X $firewallChain 2>/dev/null
fi
}
# review state file for expired records - we could add the bantime to
# the rule via --comment but I can't think of a reason why that would
# be necessary unless there is a bug in the expiration logic. The
# state db should be more resiliant than the firewall in practice.
#
bddbCheckStatusAll () {
local now=`date +%s`
bddbGetAllIPs | while read ip ; do
if [ `bddbGetStatus $ip` -eq 1 ] ; then
logLine 3 "bddbCheckStatusAll($ip) testing banLength:$banLength + bddbGetTimes:`bddbGetTimes $ip` vs. now:$now"
if [ $((banLength + `bddbGetTimes $ip`)) -lt $now ] ; then
logLine 1 "Ban expired for $ip, removing from iptables"
unBanIP $ip
bddbRemoveRecord $ip
else
logLine 3 "bddbCheckStatusAll($ip) not expired yet"
banIP $ip
fi
elif [ `bddbGetStatus $ip` -eq 0 ] ; then
local times=`bddbGetTimes $ip | tr , \ `
local timeCount=`echo $times | wc -w`
local lastTime=`echo $times | cut -d\ -f$timeCount`
if [ $((lastTime + attemptPeriod)) -lt $now ] ; then
bddbRemoveRecord $ip
fi ; fi
saveState
done
loadState
}
# Only used when status is already 0 and possibly going to 1, Args: $1=IP
bddbEvaluateRecord () {
local ip=$1 firstTime lastTime
local times=`bddbGetRecord $1 | cut -d, -f2- | tr , \ `
local timeCount=`echo $times | wc -w`
local didBan=0
# 1: not enough attempts => do nothing and exit
# 2: attempts exceed threshold in time period => ban
# 3: attempts exceed threshold but time period is too long => trim oldest time, recalculate
while [ $timeCount -ge $attemptCount ] ; do
firstTime=`echo $times | cut -d\ -f1`
lastTime=`echo $times | cut -d\ -f$timeCount`
timeDiff=$((lastTime - firstTime))
logLine 3 "bddbEvaluateRecord($ip) count=$timeCount timeDiff=$timeDiff/$attemptPeriod"
if [ $timeDiff -le $attemptPeriod ] ; then
bddbEnableStatus $ip $lastTime
logLine 2 "bddbEvaluateRecord($ip) exceeded ban threshold, adding to iptables"
banIP $ip
didBan=1
fi
times=`echo $times | cut -d\ -f2-`
timeCount=`echo $times | wc -w`
done
[ $didBan = 0 ] && logLine 2 "bddbEvaluateRecord($ip) does not exceed threshhold, skipping"
}
# Reads filtered log line and evaluates for action Args: $1=log line
processLogLine () {
local time=`getLogTime "$1"`
local ip=`getLogIP "$1"`
local status="`bddbGetStatus $ip`"
if [ "$status" = -1 ] ; then
logLine 2 "processLogLine($ip,$time) IP is whitelisted"
elif [ "$status" = 1 ] ; then
if [ "`bddbGetTimes $ip`" -ge $time ] ; then
logLine 2 "processLogLine($ip,$time) already banned, ban timestamp already equal or newer"
else
logLine 2 "processLogLine($ip,$time) already banned, updating ban timestamp"
bddbEnableStatus $ip $time
fi
banIP $ip
elif [ -n "$ip" -a -n "$time" ] ; then
bddbAddRecord $ip $time
logLine 2 "processLogLine($ip,$time) Added record, comparing"
bddbEvaluateRecord $ip
else
logLine 1 "processLogLine($ip,$time) malformed line ($1)"
fi
}
# Args, $1=-f to force a persistent write (unless lastPersistentStateWrite=-1)
saveState () {
local forcePersistent=0
[ "$1" = "-f" ] && forcePersistent=1
if [ $bddbStateChange -gt 0 ] ; then
logLine 3 "saveState() saving to temp state file"
bddbSave "$fileStateTempPrefix" "$fileStateType"
logLine 3 "saveState() now=`date +%s` lPSW=$lastPersistentStateWrite pSWP=$persistentStateWritePeriod fP=$forcePersistent"
fi
if [ $persistentStateWritePeriod -gt 1 ] || [ $persistentStateWritePeriod -eq 0 -a $forcePersistent -eq 1 ] ; then
if [ $((`date +%s` - lastPersistentStateWrite)) -ge $persistentStateWritePeriod ] || [ $forcePersistent -eq 1 ] ; then
if [ ! -f "$fileStatePersist" ] || ! cmp -s "$fileStateTemp" "$fileStatePersist" ; then
logLine 2 "saveState() writing to persistent state file"
bddbSave "$fileStatePersistPrefix" "$fileStateType"
lastPersistentStateWrite="`date +%s`"
fi ; fi ; fi
}
loadState () {
bddbClear
bddbLoad "$fileStatePersistPrefix" "$fileStateType"
bddbLoad "$fileStateTempPrefix" "$fileStateType"
logLine 2 "loadState() loaded `bddbCount` entries"
}
printUsage () {
cat <<-_EOF_
Usage: beardropper [-m mode] [-a #] [-b #] [-c ...] [-C ...] [-f ...] [-l #] [-j ...] [-p #] [-P #] [-s ...]
Running Modes (-m) (def: $defaultMode)
follow constantly monitors log
entire processes entire log contents
today processes log entries from same day only
# interval mode, specify time string or seconds
wipe wipe state files, unhook and remove firewall chain
Options
-a # attempt count before banning (def: $attemptCount)
-b # ban length once attempts hit threshold (def: $banLength)
-c ... firewall chain to record bans (def: $firewallChain)
-C ... firewall chains/positions to hook into (def: $firewallHookChains)
-f ... log facility (syslog facility or stdout/stderr) (def: $logFacility)
-j ... firewall target (def: $firewallTarget)
-l # log level - 0=off, 1=standard, 2=verbose (def: $logLevel)
-p # attempt period which attempt counts must happen in (def: $attemptPeriod)
-P # persistent state file write period (def: $persistentStateWritePeriod)
-s ... persistent state file prefix (def: $fileStatePersistPrefix)
-t ... temporary state file prefix (def: $fileStateTempPrefix)
All time strings can be specified in seconds, or using BIND style
time strings, ex: 1w2d3h5m30s is 1 week, 2 days, 3 hours, etc...
_EOF_
}
# Begin main logic
#
unset logMode
while getopts a:b:c:C:f:hj:l:m:p:P:s:t: arg ; do
case "$arg" in
a) attemptCount="$OPTARG" ;;
b) banLength="$OPTARG" ;;
c) firewallChain="$OPTARG" ;;
C) firewallHookChains="$OPTARG" ;;
f) logFacility="$OPTARG" ;;
j) firewallTarget="$OPTARG" ;;
l) logLevel="$OPTARG" ;;
m) logMode="$OPTARG" ;;
p) attemptPeriod="$OPTARG" ;;
P) persistentStateWritePeriod="$OPTARG" ;;
s) fileStatePersistPrefix="$OPTARG" ;;
s) fileStatePersistPrefix="$OPTARG" ;;
*) printUsage
exit 254
esac
shift `expr $OPTIND - 1`
done
[ -z $logMode ] && logMode="$defaultMode"
fileStateTemp="$fileStateTempPrefix.$fileStateType"
fileStatePersist="$fileStatePersistPrefix.$fileStateType"
attemptPeriod=`expandBindTime $attemptPeriod`
banLength=`expandBindTime $banLength`
[ $persistentStateWritePeriod != -1 ] && persistentStateWritePeriod=`expandBindTime $persistentStateWritePeriod`
followModeCheckInterval=`expandBindTime $followModeCheckInterval`
exitStatus=0
# Here we convert the logRegex list into a sed -f file
fileRegex="/tmp/beardropper.$$.regex"
uciLoad logRegex 's/[`$"'\\\'']//g' '/has invalid shell, rejected$/d' \
'/^[A-Za-z ]+[0-9: ]+authpriv.warn dropbear\[.+([0-9]+\.){3}[0-9]+/p' \
'/^[A-Za-z ]+[0-9: ]+authpriv.info dropbear\[.+:\ Exit before auth:.*/p' > "$fileRegex"
lastPersistentStateWrite="`date +%s`"
loadState
bddbCheckStatusAll
# main event loops
if [ "$logMode" = follow ] ; then
logLine 1 "Running in follow mode"
readsSinceSave=0 lastCheckAll=0 worstCaseReads=1 tmpFile="/tmp/beardropper.$$.1"
# Verify if these do any good - try saving to a temp. Scope may make saveState useless.
trap "rm -f "$tmpFile" "$fileRegex" ; exit " SIGINT
[ $persistentStateWritePeriod -gt 1 ] && worstCaseReads=$((persistentStateWritePeriod / followModeCheckInterval))
firstRun=1
$cmdLogread -f | while read -t $followModeCheckInterval line || true ; do
if [ $firstRun -eq 1 ] ; then
trap "saveState -f" SIGHUP
trap "saveState -f; exit" SIGINT
firstRun=0
fi
sed -nEf "$fileRegex" > "$tmpFile" <<-_EOF_
$line
_EOF_
line="`cat $tmpFile`"
[ -n "$line" ] && processLogLine "$line"
logLine 3 "ReadComp:$readsSinceSave/$worstCaseReads"
if [ $((++readsSinceSave)) -ge $worstCaseReads ] ; then
now="`date +%s`"
if [ $((now - lastCheckAll)) -ge $followModeCheckInterval ] ; then
bddbCheckStatusAll
lastCheckAll="$now"
saveState
readsSinceSave=0
fi
fi
done
elif [ "$logMode" = entire ] ; then
logLine 1 "Running in entire mode"
$cmdLogread | sed -nEf "$fileRegex" | while read line ; do
processLogLine "$line"
saveState
done
loadState
bddbCheckStatusAll
saveState -f
elif [ "$logMode" = today ] ; then
logLine 1 "Running in today mode"
# merge the egrep into sed with -e /^$formatTodayLogDateRegex/!d
$cmdLogread | egrep "`date +\'$formatTodayLogDateRegex\'`" | sed -nEf "$fileRegex" | while read line ; do
processLogLine "$line"
saveState
done
loadState
bddbCheckStatusAll
saveState -f
elif isValidBindTime "$logMode" ; then
logInterval=`expandBindTime $logMode`
logLine 1 "Running in interval mode (reviewing $logInterval seconds of log entries)..."
timeStart=$((`date +%s` - logInterval))
$cmdLogread | sed -nEf "$fileRegex" | while read line ; do
timeWhen=`getLogTime "$line"`
[ $timeWhen -ge $timeStart ] && processLogLine "$line"
saveState
done
loadState
bddbCheckStatusAll
saveState -f
elif [ "$logMode" = wipe ] ; then
logLine 2 "Wiping state files, unhooking and removing iptables chains"
wipeFirewall
if [ -f "$fileStateTemp" ] ; then
logLine 1 "Removing non-persistent statefile ($fileStateTemp)"
rm -f "$fileStateTemp"
fi
if [ -f "$fileStatePersist" ] ; then
logLine 1 "Removing persistent statefile ($fileStatePersist)"
rm -f "$fileStatePersist"
fi
else
logLine 0 "Error: invalid log mode ($logMode)"
exitStatus=254
fi
rm -f "$fileRegex"
exit $exitStatus

View File

@ -0,0 +1,11 @@
{
"luci-app-beardropper": {
"description": "Grant UCI access for luci-app-beardropper",
"read": {
"uci": [ "beardropper" ]
},
"write": {
"uci": [ "beardropper" ]
}
}
}

View File

@ -0,0 +1,76 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-godproxy
PKG_VERSION:=3.8.5
PKG_RELEASE:=3-20210323
PKG_MAINTAINER:=panda-mute <wxuzju@gmail.com>
PKG_LICENSE:=GPLv3
PKG_LICENSE_FILES:=LICENSE
PKG_BUILD_PARALLEL:=1
RSTRIP:=true
include $(INCLUDE_DIR)/package.mk
define Package/luci-app-godproxy
SECTION:=luci
CATEGORY:=LuCI
SUBMENU:=3. Applications
TITLE:=LuCI support for koolproxy
DEPENDS:=+openssl-util +ipset +dnsmasq-full +@BUSYBOX_CONFIG_DIFF +iptables-mod-nat-extra +wget
MAINTAINER:=panda-mute
endef
define Package/luci-app-godproxy/description
This package contains LuCI configuration pages for koolproxy.
endef
define Build/Compile
endef
define Package/luci-app-godproxy/postinst
#!/bin/sh
if [ -z "$${IPKG_INSTROOT}" ]; then
( . /etc/uci-defaults/luci-koolproxy ) && rm -f /etc/uci-defaults/luci-koolproxy
rm -f /tmp/luci-indexcache
fi
exit 0
endef
define Package/luci-app-godproxy/conffiles
/etc/config/koolproxy
/usr/share/koolproxy/data/rules/
endef
define Package/luci-app-godproxy/install
$(INSTALL_DIR) $(1)/usr/lib/lua/luci
cp -pR ./luasrc/* $(1)/usr/lib/lua/luci
$(INSTALL_DIR) $(1)/
cp -pR ./root/* $(1)/
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/i18n
po2lmo ./po/zh_Hans/koolproxy.po $(1)/usr/lib/lua/luci/i18n/koolproxy.zh-cn.lmo
ifeq ($(ARCH),mipsel)
$(INSTALL_BIN) ./bin/mipsel $(1)/usr/share/koolproxy/koolproxy
endif
ifeq ($(ARCH),mips)
$(INSTALL_BIN) ./bin/mips $(1)/usr/share/koolproxy/koolproxy
endif
ifeq ($(ARCH),x86)
$(INSTALL_BIN) ./bin/x86 $(1)/usr/share/koolproxy/koolproxy
endif
ifeq ($(ARCH),x86_64)
$(INSTALL_BIN) ./bin/x86_64 $(1)/usr/share/koolproxy/koolproxy
endif
ifeq ($(ARCH),arm)
$(INSTALL_BIN) ./bin/arm $(1)/usr/share/koolproxy/koolproxy
endif
ifeq ($(ARCH),aarch64)
$(INSTALL_BIN) ./bin/aarch64 $(1)/usr/share/koolproxy/koolproxy
endif
endef
$(eval $(call BuildPackage,luci-app-godproxy))

140
luci-app-godproxy/README.md Normal file
View File

@ -0,0 +1,140 @@
## 更新2021年3月23日
感谢 [maple's sky](https://github.com/maplesky) 大佬提供技术支持,修复状态栏不动态问题。
## 更新2021年3月4日
感谢 [xiaoqi2020](https://github.com/xiaoqi2020) 提供,选择规则托管国内。
## 更新2021年2月26日元宵
原来的码云以及coding规则已经无法获取被封了。现在托管在github上。
## 更名声明:
原ledeproxy于2021年1月23日更名为 GodProxy。特此知晓以前的规则更新链接会失效
## 整理声明:
GodProxy是基于koolproxyR Plus+重新整理而来。主要参考:
1、以前Ameykyl大神的[KoolProxyR Plus+](https://github.com/Ameykyl/luci-app-koolproxyR) (源码已经2020年4月删除。源码来源于[project-openwrt](https://github.com/project-openwrt/luci-app-koolproxyR)收录的ameykyl的2020年3月最后一次更新。
2、新的目录来源[Beginner-Go](https://github.com/Beginner-Go/luci-app-koolproxyR)
3、感谢koolproxy官方组、shaoxia、Ameykyl、project-openwrt组、Beginner-Go等的无私奉献
4、规则来源于[GodProxy](https://github.com/godros/GodProxy) 。
## 本来是完全没有必要再造一个的因为浪费时间。但各位大神都好久没有更新了有些规则更新需要翻墙有些名字是KP有些是KPRKPR PlusKPR Plus+。所以没有办法只能暂且叫GodProxy。望理解
## 免责声明:
KoolProxy 是一个免费软件,著作权归属 KoolProxy.com用户可以非商业性地复制和使用 KoolProxy但禁止将 KoolProxy 用于商业用途。
KoolProxy 可以对 https 网络数据进行识别代理,使用 https 功能的用户需要自己提供相关证书,本程序提供的证书生成脚本仅供用户参考,证书的保密工作由用户自行负责。
使用本软件的风险由用户自行承担在适用法律允许的最大范围内对因使用本产品所产生的损害及风险包括但不限于直接或间接的个人损害、商业赢利的丧失、贸易中断、商业信息的丢失或任何其它经济损失KoolProxy.com 不承担任何责任。
## 1、前言
感謝 koolshare.cn 提供 KoolProxy, 使用风险由用户自行承担
本程序运行需要联网下载最新的 KoolProxy 到内存中运行, 也正因此本程序大小可以忽略不计.为了区分暂且更名为GodProxy
## 2、简介
本软件包是 KoolProxy 的 LuCI 控制界面,
## 3、软件包文件结构:
## 4、依赖
软件包的正常使用需要依赖 curl, dnsmasq-full, iptables, ipset 和 dnsmasq-extra, openssl-util, diffutils, iptables-mod-nat-extra, wget, ca-bundle, ca-certificates, libustream-openssl
手动安装:在终端运行:
opkg install openssl-util ipset dnsmasq-full diffutils iptables-mod-nat-extra wget ca-bundle ca-certificates libustream-openssl
如果没有 openssl 就不能正常生成证书导致https过滤失败
如果没有 ipset, dnsmasq-full, diffutils黑名单模式也会出现问题ipset 需要版本6,如果你的固件的busybox带有支持diff支持那么diffutils包可以不安装
如果没有 iptables-mod-nat-extra 会导致mac过滤失效
如果没有 wget, ca-bundle, ca-certificates, libustream-openssllua-openssl会导致规则文件更新失败host规则条数变为0,如果你的固件的busybox带有支持https的wget那么这几个包可以不安装。
懒人版本,在.config文件里添加如下代码
#koolproxy支持
CONFIG_PACKAGE_iptables-mod-nat-extra=y
CONFIG_PACKAGE_kmod-ipt-extra=y
CONFIG_PACKAGE_diffutils=y
CONFIG_PACKAGE_openssl-util=y
CONFIG_PACKAGE_dnsmasq-full=y
CONFIG_PACKAGE_ca-bundle=y
CONFIG_PACKAGE_ca-certificates=y
CONFIG_PACKAGE_libustream-openssl=y
CONFIG_PACKAGE_lua-openssl=y
## 5、配置,
软件包的配置文件路径: /etc/config/koolproxy
此文件为 UCI 配置文件, 配置方式可参考 Wiki -> Use-UCI-system 和 OpenWrt Wiki
## 6、编译
git clone https://github.com/godros/luci-app-godproxy.git package/luci-app-godproxy
make && sudo make install
选择要编译的包 LuCI -> 3. Applications
make menuconfig
开始编译
make package/feeds/luci-app-godproxy/compile V=s
# 7、关于IPv6支持(基于透明代理一刀切)
需要在防火墙添加一条规则:
ip6tables -t nat -I PREROUTING -p tcp -j REDIRECT --to-ports 3000
```
#已知副作用:
#一刀切劫持内网所以设备的IPv6 TCP流量.
#无法使用IPv6建立主动传入连接.
#如果未安装证书,打开启用HTTPS的网站会报错.
```
**NOTE:**
如果出现国外流量无法去广告(IPv4),请修改所使用代理的防火墙规则,必须让KP的规则在代理规则之上,检测命令:
``` bash
iptables -t nat -L PREROUTING
```
观察**KOOLPROXY**规则是否在所使用的代理的规则之上.
### 8、内置规则列表
[静态规则] [每日规则] [视频规则] [ipse] [adblock]
### 9、第三方规则已做了转换koolproxy能识别不要用乘风大神的通用规则会导致koolproxy停止运行
[ABP规则]
ABP规则是CJX's Annoyance List+China+EasyList的二合一规则CJX's Annoyance List (反自我推广,移除anti adblock,防跟踪规则列表)是"EasyList China+EasyList" & "EasyPrivacy"的补充)
[Yhosts规则]
[Fanboy规则]
[AntiAD规则]
[乘风视频]
### 10、订阅规则user1121114685大神和某位大神忘记名字了整合而成能过滤youtube等
[订阅规则]
### 首次运行koolproxy的时候保存并提交速度较慢因为会生成证书。

View File

@ -0,0 +1,194 @@
koolproxy插件/固件开发文档1.3
更新日期2017年7月7日koolproxy 3.6.1
================================================================================================
声明:
KoolProxy 是一个免费软件,著作权归属 KoolProxy.com用户可以非商业性地复制和使用 KoolProxy但禁止将 KoolProxy 用于商业用途。
KoolProxy 可以对 https 网络数据进行识别代理,使用 https 功能的用户需要自己提供相关证书,本程序提供的证书生成脚本仅供用户参考,证书的保密工作由用户自行负责。
使用本软件的风险由用户自行承担在适用法律允许的最大范围内对因使用本产品所产生的损害及风险包括但不限于直接或间接的个人损害、商业赢利的丧失、贸易中断、商业信息的丢失或任何其它经济损失KoolProxy.com 不承担任何责任。
================================================================================================
KoolProxy By Xiaobao & Crwnet v3.6.1
USAGE:
koolproxy [options] [arguments...]
OPTIONS:
-p value listen port, default value is 3000
-l value log level (0:DEBUG, 1:INFO, 2:AD, 3:WARNING, 4:ERROR), default value is ERROR
-c value thread count, default value is the number of cpus
-b value data path, default value is './data'
-d run as daemon mode
-v show version
-h show help
ADVANCED:
--cert generate ssl cert
--ipv6 enable ipv6, works for ipv6 nat mode
--video | -e video mode, load video rules only
--mark mark mode, set the socket mark(src ip) when connect to remote host. requires the CAP_NET_ADMIN capability
--ttl value ttl mode, set the socket ttl when connect to remote host. default value is 0 (disable)
================================================================================================
交流地址:
1 QQ群1 595300867
2 QQ群2 203726739
3 TG群 https://t.me/joinchat/AAAAAD-tO7GPvfOU131_vg
4 更新日志http://koolshare.cn/thread-64086-1-1.html
================================================================================================
#koolproxy部署文件目录参考1使用openssl生成证书
.
├── data
│   ├── gen_ca.sh #证书生成脚本
│   ├── koolproxy_ipset.conf #ipset名单
│   ├── openssl.cnf #证书生成所用配置文件
│   ├── rules #规则存放文件夹
│   │   ├── kp.dat #视频规则
│   │   ├── koolproxy.txt #静态规则
│   │   ├── daily.txt #每日规则
│   │   └── user.txt #自定义规则
│   └── version #插件版本号(merlin)
└── koolproxy #koolproxy二进制(为了保证二进制顺利更新,请保证目录可写)
1 证书生成使用命令 sh gen_ca.sh该脚本会调用系统内的openssl来生成证书运行成功后会自动创建data/private data/cert目录
私钥和公钥会分别存在data/private data/cert目录下使用http://110.110.110.110会下载路由器内的证书
------------------------------------------------------------------------------------------------
#koolproxy部署文件目录参考2使用koolproxy生成证书
.
└── koolproxy #koolproxy二进制(为了保证二进制顺利更新,请保证目录可写)
1 因为规则文件会由koolproxy自动下载,下载后会自动创建data/rules目录
2 使用koolproxy --cert命令可以生成证书运行成功后会自动创建data/private data/cert目录
私钥和公钥会分别存在data/private data/cert目录下使用http://110.110.110.110会下载路由器内的证书
因为mbedtls性能原因在非软路由机器上用koolproxy --cert生成证书需要时间较长请耐心等待
================================================================================================
说明:
1 koolproxy启动会自动检测规则更新如果没有./data/rules文件夹会自己创建并下载规则到此处
2 koolproxy启动后会检测二进制文件更新如果有更新会替换./koolproxy并且由父进程重启koolproxy以后每20分钟检测一次更新
3 现在不支持规则订阅了只能识别kp.dat, koolproxy.txt, user.txt,daily.txt需要自定义规则的可以修改user.txt
# 二进制下载固定地址
https://koolproxy.com/downloads/i386
https://koolproxy.com/downloads/x86_64
https://koolproxy.com/downloads/arm
https://koolproxy.com/downloads/mips
https://koolproxy.com/downloads/mipsel
# 规则下载固定地址
https://kprule.com/koolproxy.txt
https://kprule.com/daily.txt
https://kprule.com/kp.dat
https://kprule.com/user.txt
# 规则下载对应的CDN地址
https://kprules.b0.upaiyun.com/koolproxy.txt
https://kprules.b0.upaiyun.com/daily.txt
https://kprules.b0.upaiyun.com/kp.dat
https://kprules.b0.upaiyun.com/user.txt
# 二进制文件和规则 github备份地址
二进制https://github.com/koolproxy/koolproxy-bin (已作废)
规则https://github.com/koolproxy/koolproxy_rules (已作废)
1 建议从上面的链接获取最新的二进制和基本的规则文件,然后按照上面的目录结构来部署
2 如果不需要https过滤只需要一个koolproxy程序就足够了data文件夹和rules文件夹都会自己创建。
3 koolproxy.txt内有视频规则、静态规则、每日规则的更新日期可以用于提取并显示到界面
================================================================================================
koolproxy运行
1 在koolproxy主程序目录运行例如merlin固件下运行cd /koolshare/koolproxy && koolproxy -d
2 不在koolproxy主程序目录运行例如将koolproxy放在环境变量中例如merlin固件下运行koolproxy -b /koolshare/koolproxy -d -b为data路径
其它运行方式可能会造成koolproxy识别不到data目录而无法加载规则
koolproxy运行后默认会使用端口3000作为透明代理端口需要利用iptables将数据导到端口3000才能发挥作用。
视频模式:
1 使用命令koolproxy -e 即可开启
2 开启后只会加载视频规则kp.dat和user.txt
调试模式:
1 使用命令koolproxy -l0 即可开启l后面的数字代表不同的日志详细程度
2 需要检查规则命中行数可以需要使用-l2
ttl功能
1 使用命令koolproxy --ttl 160 即可开启ttl功能后面的数值代表ttl大小
2 ttl功能开启后koolproxy会对经过它的所有数据ttl进行调整可以利用iptables的match ttl功能数据进行匹配
mark功能
1 使用命令koolproxy --mark 即可开启mark功能
2 mark功能开启后koolproxy会对经过它的所有数据打上标记mark值等于该数据的源ip转换为十六进制的值
3 例如局域网内192.168.1.100的数据将会被打上0xc0a80164的mark192 = c0, 168 = a8, 1 = 01, 100 = 64
4 开发者可以用此功和SS配合达到既科学上网又能过滤这些科学上网的流量还不影响科学上网访问控制的功能
5 ip转换为mark值参考命令echo 192.168.1.100 | awk -F "." '{printf ("0x%02x", $1)} {printf ("%02x", $2)} {printf ("%02x", $3)} {printf ("%02x\n", $4)}'
================================================================================================
ss + kp过滤方案2017年7月7日
方案1优先SS其次KP不推荐
1 在NAT PREROUTING链内SS在前KP在后流量将先走SS经过SS分流后国外流量走ss-redir实现翻墙
2 而剩下国内流量在PREROUTING链内继续往下匹配到koolrpxy规则流量最终走koolproxy实现过滤。
结果koolproxy只能过滤国内流量SS剩下的
方案2优先KP其次SS不推荐;
1 在NAT PREROUTING链内KP在前SS在后流量将先走KP实现过滤
2 为了SS能拿到KP过滤后的数据使用match ttl匹配在OUTPUT链内将流量全部给SS实现翻墙
结果因为在OUTPUT链内没有源ip信息流量给SS后无法匹配到源ip因此SS失去了acl访问控制功能。
方案3 (优先kp其次SS推荐)
为便于理解以下iptables配置只展示流量经过顺序不是iptables的创建顺序PREROUTING内规则的创建实际上应该在最后
0 koolproxy默认开启ttl和mark功能 KoolProxy --ttl 160 --mark -d固件不支持ttl的仅开启mark也行: KoolProxy --mark -d
1 在NAT PREROUTING链内KP在前SS在后KP开启--mark流量将先走KP80,443实现过滤过滤后每个主机会被打上不同的mark
#KP在前所有tcp流量全部交给KOOLPROXY链
-A PREROUTING -p tcp -j KOOLPROXY
#SS在后在kp开启的时候只能拿到非80,443的流量在kp关闭后可以拿到所有端口的流量
-A PREROUTING -p tcp -j SHADOWSOCKS
2 例如局域网内192.168.1.100主机的数据经过kp过滤后将会被打上0xc0a80164的mark192 = c0, 168 = a8, 1 = 01, 100 = 64
#创建KOOLPROXY链用于白名单和访问控制
-N KOOLPROXY
#创建KOOLPROXY_HTTP链用于过滤http流量
-N KOOLPROXY_HTTP
#创建KOOLPROXY_HTTPS链用于过滤https流量
-N KOOLPROXY_HTTPS
#局域网和保留地址不走kp
-A KOOLPROXY -m set --match-set white_kp_list dst -j RETURN
#主机192.168.1.100需要https过滤
-A KOOLPROXY -s 192.168.1.100/32 -p tcp -g KOOLPROXY_HTTPS
#其它主机过滤http流量
-A KOOLPROXY -p tcp -j KOOLPROXY_HTTP
3 为了SS能拿到数据在NAT OUTPUT链中使用match ttl匹配在OUTPUT链内将流量全部给SHADOWSOCKS_EXT链
#创建SHADOWSOCKS_EXT链用于开启kp情况下ss的访问控制实现
-N SHADOWSOCKS_EXT
#使用ttl匹配将KP过滤后的数据转到SHADOWSOCKS_EXT链如果固件不支持ttl匹配使用下面的命令
-A OUTPUT -p tcp -m ttl --ttl-eq 160 -j SHADOWSOCKS_EXT
#如果固件不支持ttl match可以用mark匹配ip地址的前三位用0xffffff00作为掩码的形式来将KP过滤后的数据转到SHADOWSOCKS_EXT链
# echo 192.168.1 | awk -F "." '{printf ("0x%02x", $1)} {printf ("%02x", $2)} {printf ("%02x", $3)} {printf ("00/0xffffff00\n")}' = 0xc0a80100/0xffffff00
-A OUTPUT -p tcp -m mark --mark 0xc0a80100/0xffffff00 -j SHADOWSOCKS_EXT
4 如果开启了acl比如需要192.168.1.75不走SS全端口192.168.1.246走gfwlist模式80,443端口192.168.1.214走大陆白名单模式22,80,443端口剩余主机全部走大陆白名单模式全端口
#主机192.168.1.750xc0a8014b流量经过KP过滤后并打上mark后通过OUTPUT链进入SHADOWSOCKS_EXT链而未能翻墙RETURN
-A SHADOWSOCKS_EXT -p tcp -m mark --mark 0xc0a8014b -j RETURN
#主机192.168.1.2460xc0a801f6流量经过KP过滤后并打上mark后通过OUTPUT链进入SHADOWSOCKS_EXT链在此流量被导向了SHADOWSOCKS_GFW链实现gfwlist模式翻墙80,443端口
-A SHADOWSOCKS_EXT -p tcp -m multiport --dports 80,443 -m mark --mark 0xc0a801f6 -g SHADOWSOCKS_GFW
#主机192.168.1.2140xc0a801f6流量经过KP过滤后并打上mark后通过OUTPUT链进入SHADOWSOCKS_EXT链在此流量被导向了SHADOWSOCKS_CHN链实现大陆白名单模式翻墙22,80,443端口
-A SHADOWSOCKS_EXT -p tcp -m multiport --dports 22,,80,443 -m mark --mark 0xc0a801d6 -g SHADOWSOCKS_CHN
#剩余的主机流量经过KP过滤后并打上mark后通过OUTPUT链进入SHADOWSOCKS_EXT链在此流量被导向了SHADOWSOCKS_CHN链实现大陆白名单模式翻墙全端口
-A SHADOWSOCKS_EXT -p tcp -j SHADOWSOCKS_CHN
情形:
1 当SS开启kp未开启所有流量走ss PREROUTING过经过分流后国内的流量在经过OUTPUT的时候因为KP没开数据不会匹配到ttl值或者没匹配到mark值所以不会过滤广告翻墙正常
2 当KP开启SS未开启所有流量走kp PREROUTING过广告过滤正常
3 当SS开启翻墙和acl工作正常的时候开启KPKP在PREROUTING内插入到SS前面会先得到流量广告过滤正常
4 当KP开启过滤广告正常的时候开启SSSS从原来的从PREROUTING拿流量变成从OUTPUT内拿流量翻墙和acl会同样正常
5 当KP和SS都开启此时关闭SSkp过滤广告正常
6 当KP和SS都开启此时关闭KPss翻墙和acl正常
总结:
使用 ttl + mark 或者纯mark的方式可以实现原先很难实现的过滤经过SS流量的广告
主要的改动在于给SS预置好OUTPUT和SHADOWSOCKS_EXT规则链当kp启用时它们就会工作kp关闭时不会影响正常数据
次要的改动就是给koolproxy默认开启ttl + mark或者纯mark功能
================================================================================================

BIN
luci-app-godproxy/bin/aarch64 Executable file

Binary file not shown.

BIN
luci-app-godproxy/bin/arm Executable file

Binary file not shown.

BIN
luci-app-godproxy/bin/mips Executable file

Binary file not shown.

BIN
luci-app-godproxy/bin/mipsel Executable file

Binary file not shown.

BIN
luci-app-godproxy/bin/x86 Executable file

Binary file not shown.

BIN
luci-app-godproxy/bin/x86_64 Executable file

Binary file not shown.

View File

@ -0,0 +1,16 @@
module("luci.controller.koolproxy",package.seeall)
function index()
if not nixio.fs.access("/etc/config/koolproxy")then
return
end
entry({"admin","services","koolproxy"},cbi("koolproxy/global"),_("GodProxy滤广告"),1).dependent=true
entry({"admin","services","koolproxy","rss_rule"},cbi("koolproxy/rss_rule"), nil).leaf=true
entry({"admin","services","koolproxy","status"},call("act_status")).leaf=true
end
function act_status()
local e={}
e.koolproxy=luci.sys.call("pidof %s >/dev/null"%"koolproxy")==0
luci.http.prepare_content("application/json")
luci.http.write_json(e)
end

View File

@ -0,0 +1,409 @@
-- Copyright 2018 Nick Peng (pymumu@gmail.com)
require ("nixio.fs")
require ("luci.http")
require ("luci.dispatcher")
require ("nixio.fs")
local fs = require "nixio.fs"
local sys = require "luci.sys"
local http = require "luci.http"
local o,t,e
local v=luci.sys.exec("/usr/share/koolproxy/koolproxy -v")
local a=luci.sys.exec("head -3 /usr/share/koolproxy/data/rules/koolproxy.txt | grep rules | awk -F' ' '{print $3,$4}'")
local b=luci.sys.exec("head -4 /usr/share/koolproxy/data/rules/koolproxy.txt | grep video | awk -F' ' '{print $3,$4}'")
local c=luci.sys.exec("head -3 /usr/share/koolproxy/data/rules/daily.txt | grep rules | awk -F' ' '{print $3,$4}'")
local s=luci.sys.exec("grep -v !x /usr/share/koolproxy/data/rules/easylistchina.txt | wc -l")
local m=luci.sys.exec("grep -v !x /usr/share/koolproxy/data/rules/mv.txt | wc -l")
local u=luci.sys.exec("grep -v !x /usr/share/koolproxy/data/rules/fanboy.txt | wc -l")
local p=luci.sys.exec("grep -v !x /usr/share/koolproxy/data/rules/yhosts.txt | wc -l")
local h=luci.sys.exec("grep -v '^!' /usr/share/koolproxy/data/rules/user.txt | wc -l")
local l=luci.sys.exec("grep -v !x /usr/share/koolproxy/data/rules/koolproxy.txt | wc -l")
local q=luci.sys.exec("grep -v !x /usr/share/koolproxy/data/rules/daily.txt | wc -l")
local f=luci.sys.exec("grep -v !x /usr/share/koolproxy/data/rules/anti-ad.txt | wc -l")
local i=luci.sys.exec("cat /usr/share/koolproxy/dnsmasq.adblock | wc -l")
if luci.sys.call("pidof koolproxy >/dev/null") == 0 then
status = translate("<strong class=\"koolproxy_status\"><font color=\"green\">GodProxy滤广告 运行中</font></strong>")
else
status = translate("<strong class=\"koolproxy_status\"><font color=\"red\">GodProxy滤广告 未运行</font></strong>")
end
o = Map("koolproxy", translate("GodProxy滤广告 "), translate("GodProxy是基于KoolProxyR Plus重新整理的能识别adblock规则的免费开源软件,追求体验更快、更清洁的网络,屏蔽烦人的广告!"))
o.template="koolproxy/koolproxy_status"
t = o:section(TypedSection, "global")
t.anonymous = true
t.description = translate(string.format("%s<br /><br />", status))
t:tab("base",translate("Basic Settings"))
e = t:taboption("base", Flag, "enabled", translate("Enable"))
e.default = 0
e.rmempty = false
e = t:taboption("base", DummyValue, "koolproxy_status", translate("程序版本"))
e.value = string.format("[ %s ]", v)
e = t:taboption("base", Value, "startup_delay", translate("启动延迟"))
e:value(0, translate("不启用"))
for _, v in ipairs({5, 10, 15, 25, 40, 60}) do
e:value(v, translate("%u 秒") %{v})
end
e.datatype = "uinteger"
e.default = 0
e.rmempty = false
e = t:taboption("base", ListValue, "koolproxy_mode", translate("Filter Mode"))
e.default = 1
e.rmempty = false
e:value(1, translate("全局模式"))
e:value(2, translate("IPSET模式"))
e:value(3, translate("视频模式"))
e = t:taboption("base", MultiValue, "koolproxy_rules", translate("内置规则"))
e.optional = false
e.rmempty = false
e:value("koolproxy.txt", translate("静态规则"))
e:value("daily.txt", translate("每日规则"))
e:value("kp.dat", translate("视频规则"))
e:value("user.txt", translate("自定义规则"))
e = t:taboption("base", MultiValue, "thirdparty_rules", translate("第三方规则"))
e.optional = true
e.rmempty = false
e:value("easylistchina.txt", translate("ABP规则"))
e:value("fanboy.txt", translate("Fanboy规则"))
e:value("yhosts.txt", translate("Yhosts规则"))
e:value("anti-ad.txt", translate("Anti-AD规则"))
e:value("mv.txt", translate("乘风视频"))
e = t:taboption("base", ListValue, "koolproxy_port", translate("端口控制"))
e.default = 0
e.rmempty = false
e:value(0, translate("关闭"))
e:value(1, translate("开启"))
e = t:taboption("base", ListValue, "koolproxy_ipv6", translate("IPv6支持"))
e.default = 0
e.rmempty = false
e:value(0, translate("关闭"))
e:value(1, translate("开启"))
e = t:taboption("base", Value, "koolproxy_bp_port", translate("例外端口"))
e:depends("koolproxy_port", "1")
e.rmempty = false
e.description = translate(string.format("<font color=\"red\"><strong>单端口:80&nbsp;&nbsp;多端口:80,443</strong></font>"))
e=t:taboption("base",Flag,"koolproxy_host",translate("开启Adblock Plus Hosts"))
e.default=0
e:depends("koolproxy_mode","2")
e = t:taboption("base", ListValue, "koolproxy_acl_default", translate("默认访问控制"))
e.default = 1
e.rmempty = false
e:value(0, translate("不过滤"))
e:value(1, translate("过滤HTTP协议"))
e:value(2, translate("过滤HTTP(S)协议"))
e:value(3, translate("全部过滤"))
e.description = translate(string.format("<font color=\"blue\"><strong>访问控制设置中其他主机的默认规则</strong></font>"))
e = t:taboption("base", ListValue, "time_update", translate("定时更新"))
for t = 0,23 do
e:value(t,translate("每天"..t..""))
end
e:value(nil, translate("关闭"))
e.default = 0
e.rmempty = false
e.description = translate(string.format("<font color=\"red\"><strong>定时更新规则。请把时间修改掉,默认时间使用人数多会更新失败</strong></font>"))
e = t:taboption("base", Button, "restart", translate("规则状态"))
e.inputtitle = translate("更新规则")
e.inputstyle = "reload"
e.write = function()
luci.sys.call("/usr/share/koolproxy/kpupdate 2>&1 >/dev/null")
luci.http.redirect(luci.dispatcher.build_url("admin","services","koolproxy"))
end
e.description = translate(string.format("<font color=\"red\"><strong>更新订阅规则与Adblock Plus Hosts</strong></font><br /><font color=\"green\">ABP规则: %s条<br />Fanboy规则: %s条<br />Yhosts规则: %s条<br />Anti-AD规则: %s条<br />静态规则: %s条<br />视频规则: %s<br />乘风视频: %s条<br />每日规则: %s条<br />自定义规则: %s条<br />Host: %s条</font><br />", s, u, p, f, l, b, m, q, h, i))
t:tab("cert",translate("Certificate Management"))
e=t:taboption("cert",DummyValue,"c1status",translate("<div align=\"left\"><strong>证书恢复</strong></div>"))
e=t:taboption("cert",FileUpload,"")
e.template="koolproxy/caupload"
e=t:taboption("cert",DummyValue,"",nil)
e.template="koolproxy/cadvalue"
if nixio.fs.access("/usr/share/koolproxy/data/certs/ca.crt")then
e=t:taboption("cert",DummyValue,"c2status",translate("<div align=\"left\"><strong>证书备份</strong></div>"))
e=t:taboption("cert",Button,"certificate")
e.inputtitle=translate("Backup Download")
e.inputstyle="reload"
e.write=function()
luci.sys.call("/usr/share/koolproxy/camanagement backup 2>&1 >/dev/null")
Download()
luci.http.redirect(luci.dispatcher.build_url("admin","services","koolproxy"))
end
end
t:tab("white_weblist",translate("网站白名单设置"))
local i = "/etc/adblocklist/adbypass"
e = t:taboption("white_weblist", TextValue, "adbypass_domain")
e.description = translate("这些已经加入的网站将不会使用过滤器。请输入网站的域名每行只能输入一个网站域名。例如google.com。")
e.rows = 28
e.wrap = "off"
e.rmempty = false
function e.cfgvalue()
return fs.readfile(i) or ""
end
function e.write(self, section, value)
if value then
value = value:gsub("\r\n", "\n")
else
value = ""
end
fs.writefile("/tmp/adbypass", value)
if (luci.sys.call("cmp -s /tmp/adbypass /etc/adblocklist/adbypass") == 1) then
fs.writefile(i, value)
end
fs.remove("/tmp/adbypass")
end
t:tab("weblist",translate("Set Backlist Of Websites"))
local i = "/etc/adblocklist/adblock"
e = t:taboption("weblist", TextValue, "adblock_domain")
e.description = translate("加入的网址将走广告过滤端口。只针对黑名单模式。只能输入WEB地址google.com每个地址一行。")
e.rows = 28
e.wrap = "off"
e.rmempty = false
function e.cfgvalue()
return fs.readfile(i) or ""
end
function e.write(self, section, value)
if value then
value = value:gsub("\r\n", "\n")
else
value = ""
end
fs.writefile("/tmp/adblock", value)
if (luci.sys.call("cmp -s /tmp/adblock /etc/adblocklist/adblock") == 1) then
fs.writefile(i, value)
end
fs.remove("/tmp/adblock")
end
t:tab("white_iplist",translate("IP白名单设置"))
local i = "/etc/adblocklist/adbypassip"
e = t:taboption("white_iplist", TextValue, "adbypass_ip")
e.description = translate("这些已加入的ip地址将使用代理但只有GFW型号。请输入ip地址或ip地址段每行只能输入一个ip地址。例如112.123.134.145 / 24或112.123.134.145。")
e.rows = 28
e.wrap = "off"
e.rmempty = false
function e.cfgvalue()
return fs.readfile(i) or ""
end
function e.write(self, section, value)
if value then
value = value:gsub("\r\n", "\n")
else
value = ""
end
fs.writefile("/tmp/adbypassip", value)
if (luci.sys.call("cmp -s /tmp/adbypassip /etc/adblocklist/adbypassip") == 1) then
fs.writefile(i, value)
end
fs.remove("/tmp/adbypassip")
end
t:tab("iplist",translate("IP黑名单设置"))
local i = "/etc/adblocklist/adblockip"
e = t:taboption("iplist", TextValue, "adblock_ip")
e.description = translate("这些已经加入的ip地址不会使用过滤器.请输入ip地址或ip地址段每行只能输入一个ip地址。例如112.123.134.145 / 24或112.123.134.145。")
e.rows = 28
e.wrap = "off"
e.rmempty = false
function e.cfgvalue()
return fs.readfile(i) or ""
end
function e.write(self, section, value)
if value then
value = value:gsub("\r\n", "\n")
else
value = ""
end
fs.writefile("/tmp/adblockip", value)
if (luci.sys.call("cmp -s /tmp/adblockip /etc/adblocklist/adblockip") == 1) then
fs.writefile(i, value)
end
fs.remove("/tmp/adblockip")
end
t:tab("customlist", translate("Set Backlist Of custom"))
local i = "/usr/share/koolproxy/data/user.txt"
e = t:taboption("customlist", TextValue, "user_rule")
e.description = translate("Enter your custom rules, each row.")
e.rows = 28
e.wrap = "off"
e.rmempty = false
function e.cfgvalue()
return fs.readfile(i) or ""
end
function e.write(self, section, value)
if value then
value = value:gsub("\r\n", "\n")
else
value = ""
end
fs.writefile("/tmp/user.txt", value)
if (luci.sys.call("cmp -s /tmp/user.txt /usr/share/koolproxy/data/user.txt") == 1) then
fs.writefile(i, value)
end
fs.remove("/tmp/user.txt")
end
t:tab("logs",translate("View the logs"))
local i = "/var/log/koolproxy.log"
e = t:taboption("logs", TextValue, "kpupdate_log")
e.description = translate("Koolproxy Logs")
e.rows = 28
e.wrap = "off"
e.rmempty = false
function e.cfgvalue()
return fs.readfile(i) or ""
end
function e.write(self, section, value)
end
t=o:section(TypedSection,"acl_rule",translate("GodProxy 访问控制"),
translate("ACLs is a tools which used to designate specific IP filter mode,The MAC addresses added to the list will be filtered using https"))
t.template="cbi/tblsection"
t.sortable=true
t.anonymous=true
t.addremove=true
e=t:option(Value,"remarks",translate("Client Remarks"))
e.width="30%"
e.rmempty=true
e=t:option(Value,"ipaddr",translate("IP Address"))
e.width="20%"
e.datatype="ip4addr"
luci.ip.neighbors({family = 4}, function(neighbor)
if neighbor.reachable then
e:value(neighbor.dest:string(), "%s (%s)" %{neighbor.dest:string(), neighbor.mac})
end
end)
e=t:option(Value,"mac",translate("MAC Address"))
e.width="20%"
e.rmempty=true
e.datatype="macaddr"
luci.ip.neighbors({family = 4}, function(neighbor)
if neighbor.reachable then
e:value(neighbor.mac, "%s (%s)" %{neighbor.mac, neighbor.dest:string()})
end
end)
e=t:option(ListValue,"proxy_mode",translate("访问控制"))
e.width="20%"
e.default=1
e.rmempty=false
e:value(0,translate("不过滤"))
e:value(1,translate("过滤 HTTP"))
e:value(2,translate("过滤HTTP + HTTPS"))
e:value(3,translate("过滤全端口"))
t=o:section(TypedSection,"rss_rule",translate("GodProxy 规则订阅"), translate("请确保订阅规则的兼容性"))
t.anonymous=true
t.addremove=true
t.sortable=true
t.template="cbi/tblsection"
t.extedit=luci.dispatcher.build_url("admin/services/koolproxy/rss_rule/%s")
t.create=function(...)
local sid=TypedSection.create(...)
if sid then
luci.http.redirect(t.extedit % sid)
return
end
end
e=t:option(Flag,"load",translate("启用"))
e.default=0
e.rmempty=false
e=t:option(DummyValue,"name",translate("规则名称"))
function e.cfgvalue(...)
return Value.cfgvalue(...) or translate("None")
end
e=t:option(DummyValue,"url",translate("规则地址"))
function e.cfgvalue(...)
return Value.cfgvalue(...) or translate("None")
end
e=t:option(DummyValue,"time",translate("更新时间"))
function Download()
local t,e
t=nixio.open("/tmp/upload/koolproxyca.tar.gz","r")
luci.http.header('Content-Disposition','attachment; filename="koolproxyCA.tar.gz"')
luci.http.prepare_content("application/octet-stream")
while true do
e=t:read(nixio.const.buffersize)
if(not e)or(#e==0)then
break
else
luci.http.write(e)
end
end
t:close()
luci.http.close()
end
local t,e
t="/tmp/upload/"
nixio.fs.mkdir(t)
luci.http.setfilehandler(
function(o,a,i)
if not e then
if not o then return end
e=nixio.open(t..o.file,"w")
if not e then
return
end
end
if a and e then
e:write(a)
end
if i and e then
e:close()
e=nil
luci.sys.call("/usr/share/koolproxy/camanagement restore 2>&1 >/dev/null")
end
end
)
t=o:section(TypedSection,"usetips",translate("GodProxy 帮助支持"))
t.anonymous = true
t:append(Template("koolproxy/feedback"))
return o

View File

@ -0,0 +1,36 @@
local m, s, o
local koolproxy = "koolproxy"
local sid = arg[1]
m = Map(koolproxy, "%s - %s" %{translate("GodProxy滤广告"), translate("编辑规则")})
m.redirect = luci.dispatcher.build_url("admin/services/koolproxy")
if not arg[1] or m.uci:get(koolproxy, sid) ~= "rss_rule" then
luci.http.redirect(m.redirect)
return
end
-- [[ Edit Rule ]]--
s = m:section(NamedSection, sid, "rss_rule")
s.anonymous = true
s.addremove = true
o=s:option(Flag,"load",translate("启用"))
o.default=0
o.rmempty=false
o=s:option(Value,"name",translate("规则描述"))
o.rmempty=true
o=s:option(Value,"url",translate("规则地址"))
o.rmempty=false
o.placeholder="[https|http|ftp]://[Hostname]/[File]"
function o.validate(self, value)
if not value then
return nil
else
return value
end
end
return m

View File

@ -0,0 +1,8 @@
<%+cbi/valueheader%>
<span style="color: green">
<%
local val = self:cfgvalue(section) or self.default or ""
write(pcdata(val))
%>
</span>
<%+cbi/valuefooter%>

View File

@ -0,0 +1,5 @@
<%+cbi/valueheader%>
<label class="cbi-value" style="display:inline-block; width: 400px" for="ulfile"><font color="red"><%:Upload backup file,The file name must be koolproxyCA.tar.gz%></font></label><br />
<input class="cbi-input-file" style="width: 400px" type="file" id="ulfile" name="ulfile" />
<input type="submit" class="cbi-button cbi-input-apply" name="upload" value="<%:Upload Restore%>" />
<%+cbi/valuefooter%>

View File

@ -0,0 +1,3 @@
<%+cbi/valueheader%>
<span class="koolproxy_status"><%=pcdata(self:cfgvalue(section) or self.default or "")%></span>
<%+cbi/valuefooter%>

View File

@ -0,0 +1,31 @@
</style>
<div class="cbi-value">
<label class="cbi-value-title">GodProxy重要简洁的使用Tips</label>
<div class="cbi-value-field">
<br />
1、 推荐配置:过滤模式(全局模式)+ 默认访问控制过滤http协议达到最佳的过滤效果。
<br />
2、 使用步骤A、更新规则B、恢复证书C、设置要过滤的https客户端ipD、清除浏览器或APP数据。
<br />
3、 Adblock Plus的Host列表 + KoolProxy黑名单模式运行更流畅上网体验。
<br />
4、 要过滤视频广告,必须选中规则中的视频规则。因为其他规则里面已经剔除了视频的网站。
<br />
5、 过滤HTTPS广告需要为相应客户端安装证书在“控制控制”里添加客户端ip或者mac地址并选择用<u><font color='#FF0000'>HTTP + HTTPS</font></u>过滤!
<br />
6、 在路由器下的设备,在浏览器中输入<u><font color='#FF0000'>110.110.110.110</font></u>来下载证书,导入证书目录请选择“受信任的根证书颁发机构”。
<br />
7、 安装完证书后请清除浏览器的缓存、视频APP的全部数据。如果访问网页弹出不安全提示请检查证书是否安装正确。
<br />
8、 如果想在多台路由器上使用一个证书,请先备份证书,然后再在另一个路由器上恢复证书即可。
<br />
</div>
<div class="cbi-value">
<label class="cbi-value-title">Shaoxia的KoolProxyR详细使用说明</label>
<div class="cbi-value-field">
<input type="button" class="cbi-button cbi-input-reload" value="点击前往" onclick="javascript:window.open('https://shaoxia.xyz/post/koolproxyr%E6%8C%87%E5%8D%97/','target');" />
</div>
</div>
</fieldset>
</fieldset>

Some files were not shown because too many files have changed in this diff Show More