diff --git a/tool_create.py b/tool_create.py index fa2d065..753846f 100644 --- a/tool_create.py +++ b/tool_create.py @@ -24,7 +24,8 @@ if op_mode not in ("c", "s", "m"): udp2raw_config = { "server": [], - "client": [] + "client": [], + "demuxer": [], # w2u } if op_mode in ("s", "m"): @@ -113,12 +114,37 @@ if op_mode in ("c", "m"): "enable": False } - udp2raw_config["client"].append({ - "remote": udp_server_address, - "password": udp_server_password, - "port": 29100 + len(udp2raw_config["client"]), - "speeder": speeder_info - }) + is_enable_balance = input("Enable Load Balance? [y/N]: ").strip() + if is_enable_balance and is_enable_balance.lower() in ('y', 'yes'): + balance_count = input("Enter Balance Underlay Connection counts (default to 10): ").strip() or "10" + balance_count = int(balance_count) + + default_balancer_port = 29000 + len(udp2raw_config["demuxer"]) + balancer_port = input("Enter Balancer Listen Port (default to {}): ".format(default_balancer_port)).strip() or default_balancer_port + balancer_port = int(balancer_port) + + udp2raw_config["demuxer"].append({ + "port": balancer_port, + "forward": 29100 + len(udp2raw_config["client"]), + "size": balance_count + }) + + for i in range(balance_count): + udp2raw_config["client"].append({ + "remote": udp_server_address, + "password": udp_server_password, + "port": 29100 + len(udp2raw_config["client"]), + "speeder": speeder_info, + "balanced": True + }) + else: + udp2raw_config["client"].append({ + "remote": udp_server_address, + "password": udp_server_password, + "port": 29100 + len(udp2raw_config["client"]), + "speeder": speeder_info, + "balanced": False + }) if not input("Add more udp2raw client? (Keep empty to finish)").strip(): break diff --git a/tool_generate.py b/tool_generate.py index b4bce82..a941e5d 100644 --- a/tool_generate.py +++ b/tool_generate.py @@ -36,6 +36,7 @@ if "version" not in config or int(config["version"]) < 1: op_mode = config["mode"] udp_clients = config["udp2raw"]["client"] udp_servers = config["udp2raw"]["server"] +udp_demuxer = config["udp2raw"]["demuxer"] logger.info("Generating WireGuard config...") @@ -59,31 +60,35 @@ PostUp=sysctl net.ipv4.tcp_congestion_control=bbr current_dir = os.getcwd() path_tunnel = os.path.join(current_dir, "bin", "udp2raw_amd64") path_speeder = os.path.join(current_dir, "bin", "speederv2_amd64") + path_demuxer = os.path.join(current_dir, "bin", "w2u") for info in udp_clients: if info["speeder"]["enable"]: # WG --> Speeder --> RawTunnel speeder = info["speeder"] - f.write('''PostUp={} new-window -t tunnel -d '{} -c -l127.0.0.1:{} -r 127.0.0.1:{} -f{} --mode 0' \n'''.format(tmux_path, path_speeder, speeder["port"], info["port"], speeder["ratio"])) + f.write('''PostUp={} new-window -t tunnel -d '{} -c -l127.0.0.1:{} -r 127.0.0.1:{} -f{} --mode 0'; sleep 2 \n'''.format(tmux_path, path_speeder, speeder["port"], info["port"], speeder["ratio"])) filename = write_tunnel_config("c", "127.0.0.1:{}".format(info["port"]), info["remote"], info["password"]) filepath = os.path.join(current_dir, "local", "tunnel", filename) - f.write('''PostUp={} new-window -t tunnel -d '{} --conf-file {}' \n'''.format(tmux_path, path_tunnel, filepath)) + f.write('''PostUp={} new-window -t tunnel -d '{} --conf-file {}'; sleep 2 \n'''.format(tmux_path, path_tunnel, filepath)) + + for info in udp_demuxer: + f.write('''PostUp={} new-window -t tunnel -d '{} -f {} -l {} -t {} -s {}' \n'''.format(tmux_path, path_demuxer, config["listen"], info["port"], info["forward"], info["size"])) for info in udp_servers: if info["speeder"]["enable"]: # RawTunnel --> Speeder --> WG speeder = info["speeder"] - f.write('''PostUp={} new-window -t tunnel -d '{} -s -l127.0.0.1:{} -r 127.0.0.1:{} -f{} --mode 0' \n'''.format(tmux_path, path_speeder, speeder["port"], config["listen"], speeder["ratio"])) + f.write('''PostUp={} new-window -t tunnel -d '{} -s -l127.0.0.1:{} -r 127.0.0.1:{} -f{} --mode 0'; sleep 2 \n'''.format(tmux_path, path_speeder, speeder["port"], config["listen"], speeder["ratio"])) filename = write_tunnel_config("s", "0.0.0.0:{}".format(info["port"]), "127.0.0.1:{}".format(speeder["port"]), info["password"]) filepath = os.path.join(current_dir, "local", "tunnel", filename) - f.write('''PostUp={} new-window -t tunnel -d '{} --conf-file {}' \n'''.format(tmux_path, path_tunnel, filepath)) + f.write('''PostUp={} new-window -t tunnel -d '{} --conf-file {}'; sleep 2 \n'''.format(tmux_path, path_tunnel, filepath)) else: # RawTunnel --> WG filename = write_tunnel_config("s", "0.0.0.0:{}".format(info["port"]), "127.0.0.1:{}".format(config["listen"]), info["password"]) filepath = os.path.join(current_dir, "local", "tunnel", filename) - f.write('''PostUp={} new-window -t tunnel -d '{} --conf-file {}' \n'''.format(tmux_path, path_tunnel, filepath)) + f.write('''PostUp={} new-window -t tunnel -d '{} --conf-file {}'; sleep 2 \n'''.format(tmux_path, path_tunnel, filepath)) # Generate PostDown f.write("PostDown={} kill-session -t tunnel\n".format(tmux_path)) diff --git a/w2u.c b/w2u.c new file mode 100644 index 0000000..af4d5c4 --- /dev/null +++ b/w2u.c @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// WireGuard ---> W2U --> Internet +int main(int argc, char* argv[]) +{ + int ret, flags; + int listener, sender, ep; + int PORT_WG=51820, PORT_ENDP=29000, PORT_UR_BEGIN=29100, PORT_UR_SIZE=10; + + while((ret = getopt(argc, argv, "hf:l:t:s:")) != -1) + { + switch(ret) + { + case 'f': + PORT_WG=atoi(optarg); + break; + case 'l': + PORT_ENDP=atoi(optarg); + break; + case 't': + PORT_UR_BEGIN=atoi(optarg); + break; + case 's': + PORT_UR_SIZE=atoi(optarg); + break; + case 'h': + default: + fprintf(stderr, "Usage: %s -f WGPort -l ListenPort -t TargetPort -s TargetRange\n", argv[0]); + exit(1); + } + } + + fprintf(stderr, "listening on %d, receiving from %d and sending to [%d,%d)\n", PORT_ENDP, PORT_WG, PORT_UR_BEGIN, PORT_UR_BEGIN+PORT_UR_SIZE); + + listener = socket(AF_INET, SOCK_DGRAM, 0); + struct sockaddr_in saddr; + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = INADDR_ANY; + saddr.sin_port = htons(PORT_ENDP); + ret = bind(listener, (const struct sockaddr*)&saddr, sizeof(saddr)); + if (ret < 0) { + perror("bind"); + exit(1); + } + + sender = socket(AF_INET, SOCK_DGRAM, 0); + + // Set to non-blocking + flags = fcntl(listener, F_GETFL, 0); + if (flags < 0) + { + perror("fcntl"); + exit(1); + } + flags |= O_NONBLOCK; + fcntl(listener, F_SETFL, flags); + + flags = fcntl(sender, F_GETFL, 0); + if (flags < 0) + { + perror("fcntl"); + exit(1); + } + flags |= O_NONBLOCK; + fcntl(sender, F_SETFL, flags); + + ep = epoll_create(1024); + + struct epoll_event ev1; + ev1.events = EPOLLIN; + ev1.data.fd = listener; + + struct epoll_event ev2; + ev2.events = EPOLLIN; + ev2.data.fd = sender; + + epoll_ctl(ep, EPOLL_CTL_ADD, listener, &ev1); + epoll_ctl(ep, EPOLL_CTL_ADD, sender, &ev2); + + struct epoll_event events[1024]; + + while(1) + { + int nfds = epoll_wait(ep, events, 1024, -1); + + if (nfds < 0) { + perror("epoll_wait"); + break; + } + + for (int i=0;i