File transfers behind NAT

Hi,

I’‘m currently using Smack in an app that uses a lot of file transfers. I made most of my tests on my local network and files were always sent using the socks5 proxy, this is very fast. Then i began to try over the internet and smack always fallback to in-band bytestream (slower). Both computers are behind NAT so i didn’'t expect it to work right away.

But when i redirect port 7777 on both NAT, file transfers are still running through ibb. I monitored connections using my firewall and it seems that the socks 5 transfer negotiator is sending the internal IP address to the other user (ex: 192.168.0.51). The remote user tries to connect to this address and the connection fails after a long time out.

I don’'t know how the sock5 negotiation works, but if smack was able to get and send its external ip address, the sock5 transfer may be possible.

Do you think this could work ?

BTW, it could be nice to be able to change the listening port (7777) programmatically.

thanks

Nicolas

Message was edited by: nricheton

You need to set the jive property “xmpp.proxy.externalip” to the value of your external IP address in Wildfire. Also, when you want to set the port programatically what do you mean?

Thanks,

Alex

Hi,

thanks for your answer.

I’‘m using accounts on jabber.org so I don’'t have access to server properties.

My question was about the sock5 proxy which is created by smack on the sender side (not using an external proxy).

I mean be able to change the listening port in smack to allow two (or more) clients behind the same NAT to use sock5 file transfers. Currently, the listening port is hardcoded ( 7777 ) so you can only create one redirection in your NAT : one client will be able to use sock5, the others can only do ibb…

Thanks,

Nicolas

Message was edited by: nricheton

Hi again,

I took a deeper look to smack’'s file transfers and I noticed 3 problems/annoyances :

(I call “direct connect” when , in a file transfer, the sender starts a sock 5 proxy on his side to act as a stream host, and the receiver connects to this proxy. This is the fastest way to transfer files in smack and it doesn’'t create load on public sock5 proxies , and on jabber server (when falling back to IBB) )

1 - When a file transfer is started and the sender is on a local network (with a gateway/nat/…) : a direct connection with the receiver cannot be established, even if the port 7777 is redirected to the right computer.

2 - When a transfer is initiated and a stream host is unreachable, there is always a 30s delay before data transfer starts. (As my app uses a lot of file transfer, this is a problem for me)

3 - The port used for direct connect is always 7777 (hard coded) which limits to 1 the nb of users on the same local network that can do direct connect with clients from the internet.

Details and (possible) solutions :

1 - The problem is that when the sender sends his list of possible streamhosts, the local IP (ex: 192.168.0.1) is used for the local proxy sothe receiver cannot reach the stream host because it is not on his local network. I think a solution could be to duplicate the local streamhost infos by using the local ip the first time and the external ip the second time. This way, the receiver would be able to connect from everywhere.

2 - The delay exists because the socket takes time to found out that there is no answer. But I think there is no need to try again this streamhost for the following file transfer as it was unreachable the first time. I added & tested streamhost black listing on my copy of smack. And now every transfer (except the first one) starts in less than 1s. I can post my modifications if you think blacklisting is a good idea (i this so)

3 - Adding a method on the filetransfermanager to set the port used by the sock5 proxy can solve this issue.

What do you think of this ?

Thanks,

Nicolas

Hey Nicolas,

Thanks for the input! Our general use-case has been people either on a LAN or using a proxy on a server to communicate. I thought jabber.org had a proxy on it? Though, that was about last August when I was originally writing the file transfer code that I was using it for testing.

  1. It was something that we considered before - some sort of caching to remember connections that had failed before, it would be good functionality to have. Please, post back your code and I will get it into Smack!

  2. It would likely be useful to many users to be able to configure the port that the proxy uses.

Thanks,

Alex

Hi Alex

1 ) Yes, jabber.org has a proxy, but there may be a speed limit on it (i didn’'t check). Anyway, I think that a proxy should be used only when direct connection is really impossible, and in this case we could make it possible.

For my application, the use case where one or the 2 users are on differents LAN but can set up port forwarding is very common. That’'s why I insist on it.

Do you think that the duplication of the stream host description with 2 different address is against the JEP ? (We know that at least one of the streamhosts will not work)

Of course this duplication would only occur if smack find out that the local & external ip addresses are not equal.

The only trick is that the sender have to check if the selected host is his external ip address and use his local ip instead. I don’'t know if this could break the proxy transfer.

If you are ok with this, I will try to make it work and post the code here.

2 ) My code needs some rework, as i did a quick patch. I was keeping the list of host (address, port, user) smack failed to connect to in a vector, and checked if a host was in this list before trying to connect. Perhaps I need to add a size check to prevent the list from growing too big. The Vector was in the file transfer manager, but I think a better place is the Sock5 negociator. I’'ll clean the code and post it back

Thanks,

Nicolas

Hey Nicolas,

Do you have a way to determine your external IP or are you just passing it into Smack somehow? This in my mind is the largest hurdle… If we could somehow discover that information programatically, maybe UPnP or something along those lines.

I don’‘t think it is in conflict with the JEP to provide two ips different IPs from the same JID, it would then become more important to cache which ones are and aren’'t working.

Cheers,

Alex

Hi

An easy way to get the external IP is to do a GET on http://checkip.dyndns.org or set up a similar site. We may also take a look to Azureus source code to see if they ave a better way to do it (they support UPNP)

I think it should also be a way to set the value manualy. (If this value is set, the automatical check will be disabled)

Yes, it’'s true that caching must be done in this case.

Hi again,

I’'ve got some good results.

I’'m now sending at full speed ( > 100Ko/s this is my max upload) from behind a NAT gateway with an open port. All transfers after the first one are starting without waiting.

With 2 computers on the same lan, it’'s full speed again with no wait for all transfers.

External ip checking is done through checkip.dyndns.org

I allow the user to choose the port, force an external ip or disable my patch.

I still have to limit the size of the failed connections cache and some small changes.

Do you think this is a good idea to add these methods to FileTransferManager ?

setExternalIP( String ip )

getExternalIP()

setDiscoverExternalIP(boolean discoverExternalIP)

isDiscoverExternalIP()

getProxyPort()

setProxyPort(int proxyPort)

Nicolas

It is in the scope of the Socks5 negotiation process, so, no, but what we will need is an easy way maybe to configure file transfer properties. I will brainstorm on that and if anyone in the community has any good ideas please chime in.

Alex

Hi Alex.

An easy thing could be to have a Properties object in the FileTransferManager and allow negociators to read predefined values like “socks5.externalIP”…

(Just giving ideas )

Nicolas

I have created three issues to correspond with our discussion here:

SMACK-137

SMACK-138

SMACK-139

Alex

Hi Alex,

OK, I’'m waiting for your advice on how to set parameters in order to complete my patch.

Do you prefer that i post my changes now or wait until everything is done ?

Thanks

Nicolas

Post your changes as we go, so people can comment on them. I discussed it with the other developers here and we thought it would likely be the best plan to have a Properties object on the FileTransferManager. Your hard work is very much appreciated Nicolas!

Thanks,

Alex

Here is the file :

http://nicolas.richeton.free.fr/sharemedia/Socks5TransferNegotiator.java

I left some things unfinished :

  • updateSettings have to be filled with our upcoming global settings.

  • We probably have to call updatesettings before trying to send each file.

  • no size limit on the failed host vector

Update : http://nicolas.richeton.free.fr/sharemedia/SmackFileTransfers.zip

News:

  • Property object on FileTransferManager

  • Properties are available in the negociators

TODO:

  • no size limit on the failed host vector

Hi,

Any comments so far ?

Nicolas

Hi,

I’‘ve seen you’'ve fixed SMACK-138 in trunk. Is there anything I can do to help commiting the fix for the 2 remaining issues ?

BTW I would really like to be able to configure the number of tries and the cache time in SMACK-138.

Nicolas