heiher/hev-socks5-tunnel

连接本地socks5服务,报 Can't assign requested address 错误

Closed this issue · 15 comments

arror commented

苹果对广播包收发存在限制,需要额外申请权限。之前运行在iOS上时会出现Can't assign requested address错误。可能是因为苹果限制导致?所以来求证一下。

heiher commented

没有。先定位错误日志“Can't assign requested address”的来源吧,然后再分析原因。

arror commented

新的进展:
iPhone、Mac同一网络下。
Mac运行socks5服务(clash),手机端运行hev-socks5-tunnel,IP:MacIP地址,Port:socks5监听端口,iPhone可以通过Mac访问网络。证明对hev-socks5-tunnel的修改应该是没问题的😊。

heiher commented

不错,那基本是调通啦

arror commented

是这里的问题:

// hev-socks5-client.c

static int
hev_socks5_client_connect_server (HevSocks5Client *self, const char *addr,
                                  int port)

...
    struct sockaddr *saddr = NULL;
    struct sockaddr_in s;
    s.sin_family = AF_INET;
    s.sin_port = port;
    inet_pton(AF_INET, addr, &s.sin_addr);
    memcpy(saddr, &s, sizeof(s));

    // res = hev_socks5_resolve_to_sockaddr6 (addr, port, &saddr);
    // if (res < 0) {
    //     LOG_E ("%p socks5 client resolve [%s]:%d", self, addr, port);
    //     return -1;
    // }
...

我自己创建了sockaddr而不使用hev_socks5_resolve_to_sockaddr6返回的sockaddr_in6,就不会出现Can't assign requested address问题。

arror commented

具体为什么我还不太清楚😅,大佬可以解惑么。

arror commented

不好意思,Network Extension崩了,我还以为可以了。。。我在看看😅

heiher commented

hev_socks5_resolve_to_sockaddr6

socks5 library都是创建address family为AF_INET6的socket的,如果是IPv4地址,则使用IPv4-mapped IPv6地址,不确定是不是iOS没有启用IPv4-mapped支持导致的,那么可以做两个实验:

  1. 尝试使用IPv6地址连接socks5 server。
  2. 将hev_socks5_resolve_to_sockaddr6转换出的sockaddr_in6结果转换回可读字符串,在日志中输出以确认内容正确。
arror commented

hev_socks5_resolve_to_sockaddr6

socks5 library都是创建address family为AF_INET6的socket的,如果是IPv4地址,则使用IPv4-mapped IPv6地址,不确定是不是iOS没有启用IPv4-mapped支持导致的,那么可以做两个实验:

  1. 尝试使用IPv6地址连接socks5 server。
  2. 将hev_socks5_resolve_to_sockaddr6转换出的sockaddr_in6结果转换回可读字符串,在日志中输出以确认内容正确。

本地socks5服务监听::1,客户端address同为::1,连接成功。再也不用编译leaf作tun2socks实现了😂。

代码改动不大。lwip编译的时候需要去掉iOS不支持的函数。

int start_tun2socks (int fd, const char *config_path)
{
    const char *log_file;
    int tun_fd = -1;
    int log_level;
    int nofile;
    int res;

    int dup_fd = dup(fd);
    if (dup_fd < 0)
        return -100;

    int nonblock = 1;
    res = ioctl (fd, FIONBIO, (char *)&nonblock);
    if (res < 0)
        return -200;

    tun_fd = fd;

    res = hev_task_system_init ();
    if (res < 0)
        return -2;

    res = hev_config_init (config_path);
    if (res < 0)
        return -3;

    log_file = hev_config_get_misc_log_file ();
    log_level = hev_config_get_misc_log_level ();

    res = hev_logger_init (log_level, log_file);
    if (res < 0)
        return -4;

    res = hev_socks5_logger_init (log_level, log_file);
    if (res < 0)
        return -5;

    nofile = hev_config_get_misc_limit_nofile ();
    res = set_limit_nofile (nofile);
    if (res < 0)
        LOG_W ("set limit nofile");

    lwip_init ();

    res = hev_socks5_tunnel_init (tun_fd);
    if (res < 0)
        return -6;

    hev_socks5_tunnel_run ();

    hev_socks5_tunnel_fini ();
    hev_socks5_logger_fini ();
    hev_logger_fini ();
    hev_config_fini ();
    lwip_fini ();

    hev_task_system_fini ();

    return 0;
}

将hev-socks5-tunnel编译为静态库,再通过libtool将静态库合并。

PROJECT=hev-socks5-tunnel

CROSS_PREFIX :=
PP=xcrun --sdk iphoneos --toolchain iphoneos clang
CC=xcrun --sdk iphoneos --toolchain iphoneos clang
arror commented

感谢大佬耐心指点。由于C、编译功底较差😂,PR我就不提了。
以下是我得个人想法:
1、在Apple平台上,日志可以使用asl(我在调试的时候使用)

#include <os/log.h>

const os_log_t log_default = OS_LOG_DEFAULT;

os_log_error(log_default, "%{public}s", msg);

2、外部传入fd,那么gateway的初始化,应该可以不需要外部传入gateway相关配置(用Go实现实现过,C还没尝试)。

最后,感谢大佬。

heiher commented

Congratulations!

  1. 可以把必要的修改先发出来,我们再找时间整理一下集成起来,这样以后维护会方便一些。比如作为库使用的start_tun2socks入口,可以参考Android JNI的方式实现成Apple版的。
  2. hev_socks5_tunnel_fini时不会关闭外部传入的fd,所以退出时需要close或不要dup。
heiher commented

1、在Apple平台上,日志可以使用asl(我在调试的时候使用)

#include <os/log.h>

const os_log_t log_default = OS_LOG_DEFAULT;

os_log_error(log_default, "%{public}s", msg);

应该可以把Log的实现对接到目标平台,包括Android的。

2、外部传入fd,那么gateway的初始化,应该可以不需要外部传入gateway相关配置(用Go实现实现过,C还没尝试)。

LwIP网关侧的地址配置目前应该不可省略。

arror commented

hev-socks5-tunnel:

1、Makefile:PP、CC、CCFLAGS、LDFLAGS修改适用于third-part的Makefile

diff --git a/Makefile b/Makefile
index f9cd33c..463529f 100644
--- a/Makefile
+++ b/Makefile
@@ -3,17 +3,18 @@
 PROJECT=hev-socks5-tunnel
 
 CROSS_PREFIX :=
-PP=$(CROSS_PREFIX)cpp
-CC=$(CROSS_PREFIX)gcc
+PP=xcrun --sdk iphoneos --toolchain iphoneos clang
+CC=xcrun --sdk iphoneos --toolchain iphoneos clang
 STRIP=$(CROSS_PREFIX)strip
-CCFLAGS=-O3 -pipe -Wall -Werror $(CFLAGS) \
+CCFLAGS=-Wall -O3 -arch arm64 -mios-version-min=16.0   \
 		-I$(SRCDIR)/misc \
 		-I$(SRCDIR)/core/include  \
 		-I$(THIRDPARTDIR)/yaml/include \
 		-I$(THIRDPARTDIR)/lwip/include \
 		-I$(THIRDPARTDIR)/lwip/include/ports/unix \
 		-I$(THIRDPARTDIR)/hev-task-system/include
-LDFLAGS=-L$(THIRDPARTDIR)/yaml/bin -lyaml \
+LDFLAGS=-arch arm64 -mios-version-min=16.0   -Wl,  -Bsymbolic-functions \
+		-L$(THIRDPARTDIR)/yaml/bin -lyaml \
 		-L$(THIRDPARTDIR)/lwip/bin -llwip \
 		-L$(THIRDPARTDIR)/hev-task-system/bin -lhev-task-system \
 		-lpthread
@@ -39,6 +40,8 @@ LDOBJS=$(patsubst $(SRCDIR)/%.c,$(BUILDDIR)/%.o,$(CCSRCS)) \
 	   $(patsubst $(SRCDIR)/%.S,$(BUILDDIR)/%.o,$(ASSRCS))
 DEPEND=$(LDOBJS:.o=.dep)
 
+STATIC_TARGET=$(BINDIR)/lib$(PROJECT).a
+
 BUILDMSG="\e[1;31mBUILD\e[0m %s\n"
 LINKMSG="\e[1;34mLINK\e[0m  \e[1;32m%s\e[0m\n"
 STRIPMSG="\e[1;34mSTRIP\e[0m \e[1;32m%s\e[0m\n"
@@ -60,6 +63,8 @@ endif
 
 .PHONY: all clean install uninstall tp-build tp-clean
 
+static : $(STATIC_TARGET) tp-build
+
 all : $(TARGET)
 
 tp-build : $(THIRDPARTS)
@@ -80,6 +85,11 @@ uninstall :
 	$(ECHO_PREFIX) $(RM) -rf $(INSTDIR)/etc/$(PROJECT).yml
 	@printf $(UNINSMSG) $(INSTDIR)/etc/$(PROJECT).yml
 
+$(STATIC_TARGET) : $(LDOBJS)
+	$(ECHO_PREFIX) mkdir -p $(dir $@)
+	$(ECHO_PREFIX) $(AR) csq $@ $^
+	@printf $(LINKMSG) $@
+
 $(INSTDIR)/bin/$(PROJECT) : $(TARGET)
 	$(ECHO_PREFIX) install -d -m 0755 $(dir $@)
 	$(ECHO_PREFIX) install -m 0755 $< $@

2、main

diff --git a/src/hev-main.h b/src/hev-main.h
index 0ef7366..eba0444 100644
--- a/src/hev-main.h
+++ b/src/hev-main.h
@@ -10,7 +10,7 @@
 #ifndef __HEV_MAIN_H__
 #define __HEV_MAIN_H__
 
-int main (int argc, char *argv[]);
+int start_tun2socks (int tun_fd, const char *config_file_path);
 void quit (void);
 
 #endif /* __HEV_MAIN_H__ */


diff --git a/src/hev-main.c b/src/hev-main.c
index a8af3d6..285b18a 100644
--- a/src/hev-main.c
+++ b/src/hev-main.c
@@ -26,14 +26,6 @@
 
 #include "hev-main.h"
 
-static void
-show_help (const char *self_path)
-{
-    printf ("%s CONFIG_PATH [TUN_FD]\n", self_path);
-    printf ("Version: %u.%u.%u %s\n", MAJOR_VERSION, MINOR_VERSION,
-            MICRO_VERSION, COMMIT_ID);
-}
-
 static void
 run_as_daemon (const char *pid_file)
 {
@@ -85,28 +77,19 @@ lwip_fini (void)
 }
 
 int
-main (int argc, char *argv[])
+start_tun2socks (int tun_fd, const char *config_file_path)
 {
     const char *pid_file;
     const char *log_file;
-    int tun_fd = -1;
     int log_level;
     int nofile;
     int res;
 
-    if (argc < 2) {
-        show_help (argv[0]);
-        return -1;
-    }
-
-    if (argc > 2)
-        tun_fd = strtol (argv[2], NULL, 10);
-
     res = hev_task_system_init ();
     if (res < 0)
         return -2;
 
-    res = hev_config_init (argv[1]);
+    res = hev_config_init (config_file_path);
     if (res < 0)
         return -3;
 

3、hev-tunnel-macos

diff --git a/src/hev-tunnel-macos.c b/src/hev-tunnel-macos.c
index 8b6893d..9bf8fde 100644
--- a/src/hev-tunnel-macos.c
+++ b/src/hev-tunnel-macos.c
@@ -9,121 +9,28 @@
 
 #if defined(__APPLE__) || defined(__MACH__)
 
-#include <stdio.h>
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <net/if.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/sys_domain.h>
-#include <sys/kern_control.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <net/if_utun.h>
-#include <netinet6/in6_var.h>
-
 #include <hev-task.h>
 #include <hev-task-io.h>
 
-#include "hev-tunnel.h"
 
-static char tun_name[IFNAMSIZ];
+#include "hev-tunnel.h"
 
 int
 hev_tunnel_open (const char *name)
 {
-    socklen_t len = IFNAMSIZ;
-    struct sockaddr_ctl sc;
-    struct ctl_info ci;
-    int nonblock = 1;
-    int res = -1;
-    int fd;
-
-    memset (&ci, 0, sizeof (ci));
-    strncpy (ci.ctl_name, UTUN_CONTROL_NAME, sizeof (ci.ctl_name));
-
-    fd = socket (PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
-    if (fd < 0)
-        goto exit;
-
-    res = ioctl (fd, CTLIOCGINFO, &ci);
-    if (res < 0)
-        goto exit_close;
-
-    sc.sc_id = ci.ctl_id;
-    sc.sc_len = sizeof (sc);
-    sc.sc_family = AF_SYSTEM;
-    sc.ss_sysaddr = AF_SYS_CONTROL;
-    sc.sc_unit = 0;
-
-    res = connect (fd, (struct sockaddr *)&sc, sizeof (sc));
-    if (res < 0)
-        goto exit_close;
-
-    res = ioctl (fd, FIONBIO, (char *)&nonblock);
-    if (res < 0)
-        goto exit_close;
-
-    res = getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, tun_name, &len);
-    if (res < 0)
-        goto exit_close;
-
-    return fd;
-
-exit_close:
-    close (fd);
-exit:
-    return res;
+    return 0;
 }
 
 int
 hev_tunnel_set_mtu (int mtu)
 {
-    struct ifreq ifr = { .ifr_mtu = mtu };
-    int res = -1;
-    int fd;
-
-    fd = socket (AF_INET, SOCK_STREAM, 0);
-    if (fd < 0)
-        goto exit;
-
-    memcpy (ifr.ifr_name, tun_name, IFNAMSIZ);
-    res = ioctl (fd, SIOCSIFMTU, (void *)&ifr);
-
-    close (fd);
-exit:
-    return res;
+    return 0;
 }
 
 int
 hev_tunnel_set_state (int state)
 {
-    struct ifreq ifr = { 0 };
-    int res = -1;
-    int fd;
-
-    fd = socket (AF_INET, SOCK_STREAM, 0);
-    if (fd < 0)
-        goto exit;
-
-    memcpy (ifr.ifr_name, tun_name, IFNAMSIZ);
-    res = ioctl (fd, SIOCGIFFLAGS, (void *)&ifr);
-    if (res < 0)
-        goto exit_close;
-
-    if (state)
-        ifr.ifr_flags |= IFF_UP;
-    else
-        ifr.ifr_flags &= ~IFF_UP;
-    res = ioctl (fd, SIOCSIFFLAGS, (void *)&ifr);
-
-exit_close:
-    close (fd);
-exit:
-    return res;
+    return 0;
 }
 
 int

lwip:

diff --git a/src/ports/unix/port/netif/sio.c b/src/ports/unix/port/netif/sio.c
index 8653fc9..2731519 100644
--- a/src/ports/unix/port/netif/sio.c
+++ b/src/ports/unix/port/netif/sio.c
@@ -436,7 +436,7 @@ sio_fd_t sio_open(u8_t devnum)
 			"/sbin/ifconfig sl0 mtu %d %s pointopoint %s up",
 			SLIP_MAX_SIZE, "192.168.2.1", "192.168.2.2");
 		LWIP_DEBUGF(SIO_DEBUG, ("sio_open[%d]: system(\"%s\");\n", siostate->fd, buf));
-		ret = system(buf);
+        exit(0);
 		if (ret < 0) {
 		    perror("ifconfig failed");
 		    exit(1);



diff --git a/src/ports/unix/port/netif/tapif.c b/src/ports/unix/port/netif/tapif.c
index 3d53586..210d2fa 100644
--- a/src/ports/unix/port/netif/tapif.c
+++ b/src/ports/unix/port/netif/tapif.c
@@ -186,7 +186,7 @@ low_level_init(struct netif *netif)
              );
 
     LWIP_DEBUGF(TAPIF_DEBUG, ("tapif_init: system(\"%s\");\n", buf));
-    ret = system(buf);
+    exit(0);
     if (ret < 0) {
       perror("ifconfig failed");
       exit(1);
arror commented

基于2.4.5版本的所有修改全在这里了。

heiher commented

好的

  1. hev_socks5_tunnel_init如果从外部传入的tun fd,则不会执行hev_tunnel_set_xxx,hev-tunnel-macos中一些方法实现需要注释掉是因为编译出错?
  2. Tun设备事实上配置的MTU是多少?最好Tun设备和LwIP一致,默认为9000。
arror commented

好的

  1. hev_socks5_tunnel_init如果从外部传入的tun fd,则不会执行hev_tunnel_set_xxx,hev-tunnel-macos中一些方法实现需要注释掉是因为编译出错?

是的,编译错误

src/hev-tunnel-macos.c:21:10: fatal error: 'sys/sys_domain.h' file not found
#include <sys/sys_domain.h>
         ^~~~~~~~~~~~~~~~~~
1 error generated.
make: *** [build/hev-tunnel-macos.o] Error 1
  1. Tun设备事实上配置的MTU是多少?最好Tun设备和LwIP一致,默认为9000。

同为9000,保持和LwIP一致。