在windows上连接一个非445端口的smb服务

本文用于记录搭建一个可在windows以及其他操作系统下访问的远端smb网盘服务。

起因

由于不让使用自己的mac办公,在windows下工作了很长一段时间,期间,因为要使用linux,而不管是wsl还是wsl2都很坑的情况下,已经习惯用hyper-v架设一台虚拟机然后用ssh连接来办公,而在文件访问方面,突然发现用samba来开启网络共享盘给Windows主机直接访问编辑东西很是方便,于是就对自己在家的ftp服务和空闲的主机打起了网盘的念头,是否可以自己创建一个远程的samba服务来玩呢?答案是肯定的!而且非常简单,我们只需要:

  • 一台windows或者linux主机,windows下就共享一个盘或者文件夹并设置用户权限,linux就用apt install samba然后配置共享来架设smb服务,不管怎么样,这台主机就暴露了一个445端口(可能还有137~139);

  • 一个拥有真实外网ip的网络环境,并且这个环境的WAN口映射是可控的,比如家庭可以和电信申请真实ip并用路由器拨号,公司的要请网管喝杯奶茶,最终你要能够在NAT设备出口把这台主机的445端口映射出外网IP;

  • 准备好你的客户端,比如windows的资源管理器,mac的访达,其他手机的什么app等等。

开始部署一个linux上的samba

windows上的smb服务很简单,因为smb是微软发明的,基本就是系统功能,也就是我们常说的共享,我这里就搞个linux的吧,毕竟手上没有一直开机用的win主机。

很迅速的,我在老家的linux主机上搭建了samba服务,并且,老家的网络环境是非常棒的静态公网ip,而且整栋楼的路由器我有密码,大概像这样:

  • 安装samba

    1
    apt-get install samba -y
  • 配置一个共享,放出参考,编辑/etc/samba/smb.conf,并在大概在注释Share Definitions部分添加:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [smb_share]
    comment = share
    path = /root/smb-share
    public = yes
    browseable = yes
    public = yes
    read only = no
    valid users = root
    create mask = 0777
    directory mask = 0777
    force user = root
    available = yes

    这一段例子表示,共享一个共享名smb_share的目录,目录地址为/root/smb-share并且用户为root(就是登录服务的用户),并且强制使用系统的root用户进行操作(这样不用考虑那么多权限问题)

  • 为叫root的smb账户并设置密码

    1
    smbpasswd -a root

    按照提示完成密码的设置,这个密码就是后续客户端访问要输入的密码。

  • 重启smbd服务

    1
    service smbd restart

    这样,服务就搞好了。

  • 打开路由器设置一个映射

上图我也把139映射出去了。这样一来,理论上,我在客户端直接访问这个ip地址就可以映射一个网络硬盘了。为了优雅,我还在我的一个子域名上绑定了这个ip。

445端口竟然无法访问

我打开了mac的访达,直接按下cmd+k,调出smb连接:

按下去,竟然无法连接,不信邪的我使用telnet,竟然真的无法访问445端口。

考虑到这里,查了一下谷歌,发现原来445端口大部分运营商是不给用的,接着我就由在路由器加了一个映射,也就是446转445,前面的图也可以看到。访问时多加了446端口,于是成功了:

(为了方便我还设置了其他共享目录,在mac上连smb服务可以根据共享名来挂载储存)。

我还用手机一款叫FX的文件管理器创建了这一个一样的连接,这软件也是可以选择自定义smb端口的。

所以,整体的思路是:

重点来了,在windows上并没有办法访问非445端口的smb服务!

如上面所说的,445直接访问肯定是不行的,所以在windows的资源管理器中,映射驱动器时加上了端口,结果直接无法访问了:

image-20190817151426747

的确,经过谷歌等学习,在windows上,是不可能做到修改这个访问端口的,那我们要如何折腾,答案是有很多的,我们来分析一下,比如:

  • 知乎上就有使用windows自带的端口转发命令,设置端口转发,让本机的127.0.0.1:445转发到目标也就是这个smb服务器ip的446端口去,这样,连接硬盘就只需要连接本机就好了。但这个方案有个很严重的问题,127.0.0.1:445本身如果是开启了共享的,那肯定是被占用的,对于平常来说,不管是家里面的还是公司的电脑,共享盘肯定是有的,所以这个方案不行。

  • 于是还有说用上面的方法把445监听到127.0.0.2,不是很懂,但是没有成功,就像下图。

  • 还有一种方法就是用docker开启一个带nginx代理的容器,这个nginx使用tcp代理转发445端口,但是这样做,必须让宿主能直接访问到容器的ip地址,这个方案应该是可行的,但我没有尝试,因为在windows上用docker我是已经被坑过了,所以不管是工作还是平常,都不会安装docker。

  • 所以最后,我使用上面的方案,但换成直接运行一个带有独立ip的虚拟主机,并运行nginx代理445端口。

开始一波操作:

  1. 打开hyper-v,创建了一个linux,并且配置了最低的性能,然后使用桥接模式的网络:

  2. 根据nginx官方安装了一个nginx,并且添加了关于stream模块的配置:

    在配置目录的根配置文件nginx.conf中添加:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    stream {

    log_format proxy '$remote_addr [$time_local] '
    '$protocol $status $bytes_sent $bytes_received '
    '$session_time "$upstream_addr" '
    '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
    # 统一放置,方便管理
    include tcpConf/*.conf;
    }

    这里意为tcpConf目录下的配置文件都是关于stream的配置,接着我们创建这个目录,并添加具体的规则。

    在tcpConf下创建xxx.conf,写入:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    upstream smbd_445 {
    server xxx.xxx.xxx.xxx:446;
    }

    server {
    listen 445;
    proxy_connect_timeout 8s;
    proxy_timeout 24h;
    proxy_pass smbd_445;
    }

    这样就是将这台机的445转发到目标446的反向代理了。

  3. 重新加载nginx,运行:

    1
    nginx -s reload

    大功告成,查看端口,445已经在运行:

  4. 再回到windows的资源管理器中,对了,要给这个虚拟机设个固定ip比如我这里192.168.16.24,然后,直接映射这个ip,终于可以了:

玩到这里,就实现了在windows上连接一个非445端口的smb服务

其他尝试的东西和总结

  • 运营商不给访问445端口的时候,想过在云服务器上直接使用frp这种穿透工具映射445,结果发现,不管是GCP、digitalocean还是vultr等(国内的没试过,不过应该都一样),即使开放出445端口,telnet也是不通的,说明,这个445端口被封得狠。
  • 在家里有一台弃用的手机一直用来做服务器,是通过Termux来运行的,但是Termux中安装的nginx竟然没有开启stream模块,需要自己编译,就没折腾,如果可以,那家里面的Windows电脑就不用浪费性能再安装虚拟机了。
  • 这种搞法,在hyper-v上最少还要化半G内存来运行,不过现在内存多。
  • windows的smb和samba还是不同的,应该是前者比较高级和安全,而且还有其他端口比如137-139这些是什么用的没有详细研究,两种服务细节上有什么区别也没有详细了解。
  • 在工作中使用一个smb网盘还是有点方便的,在写一些不是git托管的东西,比如一些草稿性的文档,记录,表格等,可以直接丢上去,并且可以随时在手机,或者其他电脑上访问,而且因为是smb,操作和交互要比FTP好非常多。
Author: Hobai Riku
Link: https://blog.hobairiku.site/2019/08/17/alternate-smb-port/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.