使用 c#“UDP 打孔到防火墙”将流量从端口 X 转发到计算机 B
我需要建立从我的家用计算机到我的办公室计算机的 TCP 连接。
办公室里有一个路由器,可以连接多台计算机。该路由器有互联网,因此连接到该路由器的所有计算机也有互联网。我家里有一台可以上网的电脑。我需要我的办公室计算机作为服务器,并需要我的家庭计算机来连接到它。以前,我曾经能够通过服务器上的端口转发流量进行连接,如下所示:
NATUPNPLib.UPnPNATClass upnpnat;
NATUPNPLib.IStaticPortMappingCollection mappings;
public ServerExample()
{
InitializeComponent();
upnpnat = new NATUPNPLib.UPnPNATClass();
mappings = upnpnat.StaticPortMappingCollection;
// server local IP address
mappings.Add(1300, "TCP", 1300, "192.168.150.146", true, "plsease work");
// this code tels the router to forward all tcp traffic comming from port
// 1300 to the server computer (it's lan ip address happens to be 192.168.150.146)
//...
并且我能够从我的房子进行连接。 (我知道简单的方法是打开办公室路由器上的端口并将它们转发到我的计算机,问题是我无法访问办公室路由器)
现在他们用更新的路由器替换了我办公室上的路由器,并且我无法使用我的代码。现在,使用新路由器,当我执行私有代码时,我得到:
注意映射返回null;因此,我无法添加映射。
我确信应该有一种方法来建立连接,因为办公室里的一些人使用 Limewire 或 Bit Torrent。我认为我的问题可能与权限有关?我该如何解决这个问题?
编辑
所以通过研究我发现我想做的是“UDP 打孔到防火墙”。我实际上想通过 TCP 连接来完成它。我不知道 tcp 和 upd puch Holing 之间有什么区别...我的意思是,这样做的目的是让客户端能够找到 pear,而无需在路由器上进行配置。
。
。
。
。
。
。
更新
好的,所以我相信我已经尝试用 c# 做你们在这个问题上发布的内容:好的,让我向您展示我做了什么:
请注意,您可能需要参考此图才能理解我将要解释的内容:
如您所知,我想在计算机 A 和计算机 B 之间建立 tcp 连接。我设法的方式这是通过所谓的 TCP 打孔来实现的。
步骤一: 我做的第一件事是开始监听服务器 S 上的新连接。
TcpListener server = new TcpListener(System.Net.IPAddress.Parse(“192.168.11.109”), 55550);
Server.Start();
var client = server.AcceptSocket(); \\ wait here until someone connects
第 2 步: 现在连接到计算机 A 的服务器:
TcpClient tcpClient = new TcpClient("192.168.11.109", 55550);
步骤 3: 在计算机 A 上执行步骤 2 代码后,服务器 S 调试应如下所示:
步骤 4: 现在我们的目标是从计算机 B 连接到计算机 A。服务器 S 拥有 B 建立连接所需的信息。实际上,我必须在计算机 B 和服务器 S 之间建立连接,以便服务器 S 可以为 B 提供适当的参数,以便 B 连接到 A。
步骤 5: 因为我正在调试,所以我能够看到参数,所以我现在将通过侦听端口 3313 将计算机 A 设为服务器。我希望计算机 A 现在侦听该端口 (3313),因为所有包都通过端口发送到路由器 X 3313 应发送到计算机 A。
\\ COMPUTER A
TcpListener server = new TcpListener(System.Net.IPAddress.Parse("192.168.0.120"), 3313);
server.Start();
var newClient = server.AcceptSocket(); \\ wait here until a client gets connected
第 6 步: 因此,计算机 A 现在应该在端口 3313 上侦听新连接。端口 3313 再次很重要,因为路由器 x 应该将从该端口收到的所有数据包转发到计算机 A。
计算机 A 正在等待新连接。
步骤 7: 所以现在快点!我们想从计算机 B 建立连接。实际上,服务器 S 将传递参数,但由于我只是想完成这项工作,所以我将在计算机 B 上快速编写程序。
TcpClient tcpClient = new TcpClient(“192.168.11.108”, 3313);
\\192.168.11.108 is the address of router X
最后:
由于某种原因,计算机 B 无法连接电脑A
无法连接的原因是路由器X没有转发将软件包发送到计算机 A。(我知道这一点是因为我已在路由器 X 上的端口 54540 上启用端口转发,当我使用该端口时,它可以工作)我的意思是我不明白为什么路由器 X 没有将从端口 3313 发送到计算机 A 的流量转发。计算机 A 已经建立了到服务器 S 的连接服务器S通过端口3313发送到路由器X的所有内容都发送到计算机A。为什么如果我通过端口3313向路由器X发送包,它们不会被计算机A接收!?
PS:
请注意,我在这里展示的所有内容,实际上我有三个路由器 X、Y 和 Z,而且我还有服务器 S、计算机 A 和计算机 B:
I need to establish a tcp connection from my house computer to my office computer.
on the office there is a router where several computers are connected to. that router has internet therefore all the computers connected to that router have internet as well. on my house I have a computer with internet access. I need my office computer to act as the server and my home computer to connect to it. Before, I used to be able to connect by port forwarding traffic on the server as:
NATUPNPLib.UPnPNATClass upnpnat;
NATUPNPLib.IStaticPortMappingCollection mappings;
public ServerExample()
{
InitializeComponent();
upnpnat = new NATUPNPLib.UPnPNATClass();
mappings = upnpnat.StaticPortMappingCollection;
// server local IP address
mappings.Add(1300, "TCP", 1300, "192.168.150.146", true, "plsease work");
// this code tels the router to forward all tcp traffic comming from port
// 1300 to the server computer (it's lan ip address happens to be 192.168.150.146)
//...
and I was able to connect from my house. (I know that the simple way will be to open the ports on the office router and forward them to my computer the problem is that I do not have access to the office router)
now they replaced the router on my office with a newer one and I am not able to use my code.Now, with the new router, when I execute the privious code I get:
note that mappings returns null; therefore, I am not able to add a mapping.
I am sure there should be a way to establish a connection because some people in the office use limewire for example or bit torrent. I think my problem has to do with permissions maybe? How can I resolve this?
Edit
So from researching I found that what I am trying to do is "UDP punch hole into firewall". I actually want to do it over a tcp connection. I don't know what is will be the difference between tcp and upd puch holing.... I mean the purpose of that is for a client to be able to find a pear without having to do configurations on the router.
.
.
.
.
.
.
UPDATE
OK so I believe I have tried doing what you guys posted on this question with c#: ok let me show you what I did:
note you may need to refer to this diagram in order to understand what I will be explain:
As you know I want to establish a tcp connection between computer A and computer B. The way I manage to do this is by doing what is called tcp punch holing.
Step 1:
The first thing that I do is to start listening for new connections on the server S.
TcpListener server = new TcpListener(System.Net.IPAddress.Parse(“192.168.11.109”), 55550);
Server.Start();
var client = server.AcceptSocket(); \\ wait here until someone connects
Step 2:
Now connect to the server with computer A as:
TcpClient tcpClient = new TcpClient("192.168.11.109", 55550);
Step 3:
After executing step 2 code on computer A the server S debug should look like:
Step 4:
Now our goal is to connect from computer B to computer A. Server S has the information that B needs in order to establish the connection. In reality I will have to establish a connection between computer B and server S so that server S can give B the appropriate parameters in order for B to connect to A.
Step 5:
since I am debuging I am able to see the parameters so I will make computer A a server now by listening on port 3313. I want computer A to be listening now on that port (3313) because all the packages sent to router X with port 3313 should be sent to computer A.
\\ COMPUTER A
TcpListener server = new TcpListener(System.Net.IPAddress.Parse("192.168.0.120"), 3313);
server.Start();
var newClient = server.AcceptSocket(); \\ wait here until a client gets connected
Step 6:
So computer A should now be listening for new connections on port 3313. again port 3313 is important because router x should forward all packages received from that port to computer A.
Computer A is waiting for new connections.
Step 7:
So now quickly! We want to establish that connection from computer B. In reality server S will pass the parameters but since I am just trying to make this work I will write the program really quick on computer B.
TcpClient tcpClient = new TcpClient(“192.168.11.108”, 3313);
\\192.168.11.108 is the address of router X
Finally:
For some reason, computer B is not able to connect to computer A.
The reason why it is not able to connect is because router X did not forwarded the packages to computer A. (I know this because I have enabled port forwarding on port 54540 on router X and when I use that port it works) I mean I don’t understand why router X did not forward traffic coming from port 3313 to computer A. Computer A already established a connection to server S and all the things that server S sent to router X through port 3313 got sent to computer A. why is it that if I send packages to router X through port 3313 they don’t get received by computer A!?
PS:
Note that everything that I showed here, I actually have the three routers X, Y and Z and also I have server S, computer A and computer B:
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您的新工作路由器可能已禁用 UPnP,因此您的引用为空。
如果没有这个,您的服务器将无法对入站流量可见,因为路由器不知道将入站数据包发送到哪里。在这种情况下,路由器充当防火墙,阻止传入服务器的流量。
解决此问题的基本方法是:
1) 打开 UPnP
这使您的应用程序能够指示路由器如何将入站流量转发回您的服务器。
2)设置端口转发
与上面一样,通过手动配置路由器。
3)使您的工作服务器成为客户端
路由器通过允许出站连接来启动连接来工作。它会记住返回地址,重写外部可见的 IP,并为外部流量提供未使用的端口进行回话 (NAT)。这允许出站请求与外部建立通信并绕过防火墙。如果您的家庭 IP 是固定的,您可以在工作中设置一个客户端,尝试按计划打电话回家(直到您启动服务器并可以建立连接)。
4)使用P2P(中介服务器)
我不知道你会从哪里开始,但原则是这样的。它通常工作在单个 UDP 端口上。使用不在 NAT 之后的服务器来建立连接。客户端在 UDP 数据包中将其 IP 发送到服务器,路由器用路由器返回地址重写 UDP 标头。服务器获取此数据并将其发送给其他对等点。现在每个人都知道彼此的返回地址,他们可以直接向彼此发送 TCP 流量,并且服务器会避开。
这里有一篇关于 NAT 基础知识的非常好的文章,用简单的术语进行了解释。 此处有一篇好文章,解释了 P2P 如何利用 NAT 绕过防火墙。
希望这能给您一些想法。
Your new work router has probably got
UPnP
disabled, hence your null reference.Without this your server cannot be made visible to inbound traffic as the router doesn't know where to send the inbound packets. In this case the router acts as a firewall blocking the incoming traffic to your server.
The basic ways around this are:
1) open up UPnP
This enables your application to instruct the router how to forward inbound traffic back to your server.
2) set up a port forwarding
As above by manually configuring the router.
3) make your work server the client
Routers work by allowing outbound connections to initiate the connection. It remembers the return address, rewrites the externally visible IP, and provides an unused port for external traffic to talk back on (NAT). This allows outbound requests to establish communication with the outside and bypass the firewall. If your home IP is fixed you could setup a client at work that tries to call home on a schedule (until you start the server and can establish the connection).
4) use P2P (mediation server)
I'm not sure where you would begin with this, but the principle is this. It usually works on a single UDP port. A server that is not behind NAT is used for establishing connections. The clients send their IP to the server in a UDP packet, and the router rewrites the UDP header with the router return address. The server takes this data and sends it to other peers. With everyone now knowing each others return address, they can send TCP traffic directly to each other and the server steps out of the way.
There's some really good article here regarding the basics of NAT, explained in simple terms. And a good article here which explains how P2P leverages NAT to bypass firewalls.
Hope this gives you some ideas.
TCP 打孔经常不起作用。最好的选择是坚持使用 UDP 打洞。如果您需要类似 TCP 的行为,则可以使用 RDP 或类似的协议来为您提供 TCP 行为,但可以使用 UDP 作为其传输。
另一种方法是通过服务器中继所有流量。每台主机都可以连接到服务器,并且服务器可以将流量从一个连接复制到另一个连接。
最好的解决方案是您可以从路由器获得一些支持,例如端口转发或 UPnP。
TCP hole punching frequently doesn't work. You're best bet is to stick to UDP hole punching. If you need TCP-like behavior, you can use RDP or a similar protocol that gives you TCP behavior but can use UDP as its transport.
The other approach is to relay all traffic through the server. Each host can connect to the server and the server can copy traffic from one connection to the other.
The best solution would be if you can get some support from the routers such as port forwarding or UPnP.
有一篇关于 UDP 和 TCP 打洞技术的优秀文章。
http://www.brynosaurus.com/pub/net/p2pnat/
但是,对于这种打孔技术,您需要一个众所周知的会合服务器,但我认为您不想设置它。
顺便说一句,您需要仔细检查公司关于在办公室拥有自己的服务器的政策。为了安全起见,我认为公司不会允许员工在内部设置自己的服务器。
There is an excellent article about UDP and TCP hole punching techniques.
http://www.brynosaurus.com/pub/net/p2pnat/
However, you need a well-known rendezvous server for this hole punching technique and I don't think you want to set it up.
By the way, you will want to double-check your company's policy about having your own server in the office. For security, I don't think a company allows an employee to set his or her own server inside.
您可以编写自己的代理:
服务器:
在 1300 上侦听来自 A 的连接,在 1301 上侦听来自 B 的连接。保留这两个连接的列表,当每个连接至少有一个时,创建一个代理对象。此时,您从 B 发出连接信号,表明您已建立连接,该连接可以是信号字节或端口,甚至是要连接的地址。之后当你从A获取数据时,将其发送到B。当你从B获取数据时,将其发送到A。
计算机B:
程序维护与服务器上端口 1301 的连接。如果连接断开,请重新建立它。当您收到信号(可能有地址和端口或只是“我有一个连接”字节)时,创建到所需端口的连接并将这两个连接存储在代理对象中。当您从一个接收数据时,将其发送给另一个。由于您正在使用该连接,因此请与服务器上的端口 1301 建立新连接以处理更多内容。
当然,您必须处理丢失的连接,在 B 和服务器之间始终打开的挂起连接之间发送保持活动信号会有所帮助。
这是我很久以前为进行代理而编写的示例类。我没有时间清理它,但是如果您看到 TcpProxy 是接受连接的父类,则 Client 是接受的连接,RemoteEndPoint 是要连接的端点。它还将数据写入文件并执行其他一些您可以忽略的操作。
You could write your own proxy:
Server:
Listen on 1300 for connection from A, and on 1301 for connection from B. Keep a list of both connections, when you have at least one of each, create a proxy object. At this time you signal your connection from B that you have a connection, which could be a signal byte or a port and even address to connect to. After that when you get data from A, send it to B. When you get data from B, send it to A.
Computer B:
Program maintains a connection to port 1301 on Server. If the connection ever drops, re-establish it. When you receive a signal (could have address and port or just be an "I have a connection" byte), create a connection to the desired port and store the two connections in a proxy object. When you receive data from one, send it to the other. Since you're using that connection, establish a new connection to port 1301 on the Server to handle more.
You'll have to handle dropped connections of course, sending a keep-alive signal between the always-open pending connection between B and the Server will help.
Here's a sample class I wrote a long time ago to do the proxying. I don't have time to clean it up, but if you see TcpProxy that is a parent class that accepts a connection, the Client is the accepted connection and RemoteEndPoint is the end point to connect to. It also writes the data to a file and does some other stuff you can ignore.