ccding / go-stun Goto Github PK
View Code? Open in Web Editor NEWA go implementation of the STUN client (RFC 3489 and RFC 5389)
License: Apache License 2.0
A go implementation of the STUN client (RFC 3489 and RFC 5389)
License: Apache License 2.0
stun/discover.go
line 111
if resp != nil &&
(resp.serverAddr.IP() == addr.IP.String() ||
resp.serverAddr.Port() == uint16(addr.Port)){
// Run to this position, on behalf of what happened?
}
You should put the license headers under the package keyword otherwise the docs get messed up: http://godoc.org/github.com/ccding/go-stun/stun
Excited to start trying this out! Worked great for me out of the box with Discover()
So first of all, I claim there is a bug here:
https://github.com/ccding/go-stun/blob/master/stun/discover.go#L142
I think this line should be removed, as if you look at this, it makes no sense:
[root@acro-syncer /home/jb]# ./foo
2016/08/18 22:05:33 Do Test1
2016/08/18 22:05:33 Send To: 217.10.68.152:3478
2016/08/18 22:05:33 Received: {packet nil: false, local: X.X.X.X:44444, remote: 217.10.68.152:3478, changed: 217.116.122.138:3479, identical: false}
2016/08/18 22:05:33 Do Test2
2016/08/18 22:05:33 Send To: 217.10.68.152:3478
2016/08/18 22:05:43 Received: Nil
2016/08/18 22:05:43 Do Test1
2016/08/18 22:05:43 Send To: 217.116.122.138:3479
2016/08/18 22:05:43 Received: {packet nil: false, local: X.X.X.X:44444, remote: 217.116.122.138:3479, changed: 217.10.68.152:3478, identical: false}
2016/08/18 22:05:43 Do Test3
2016/08/18 22:05:43 Send To: 217.116.122.138:3478
2016/08/18 22:05:43 Received: {packet nil: false, local: X.X.X.X:44444, remote: 217.116.122.138:3479, changed: 217.10.68.152:3478, identical: false}
Restricted NAT X.X.X.X:44444 <nil>
Ignore test 1 and test2, just focus on 2nd instance of Test 1 and Test 3.
We send to 217.116.122.138:3479, asking to bind.
Afterwards we set the port to the changed port (for no reason), and ask via 217.116.122.138:3478 to send us a packet on a changed port, which happens to be 217.116.122.138:3479... an address we already sent bind request to...
If you agree this is a bug let's continue.
I've removed the line at fault on two different configurations.
This one:
2016/08/18 22:11:49 Do Test1
2016/08/18 22:11:49 Send To: 217.10.68.152:3478
2016/08/18 22:11:49 Received: {packet nil: false, local: X.X.X.X:44444, remote: 217.10.68.152:3478, changed: 217.116.122.138:3479, identical: false}
2016/08/18 22:11:49 Do Test2
2016/08/18 22:11:49 Send To: 217.10.68.152:3478
2016/08/18 22:11:58 Received: Nil
2016/08/18 22:11:58 Do Test1
2016/08/18 22:11:58 Send To: 217.116.122.138:3479
2016/08/18 22:11:59 Received: {packet nil: false, local: X.X.X.X:44444, remote: 217.116.122.138:3479, changed: 217.10.68.152:3478, identical: false}
2016/08/18 22:11:59 Do Test3
2016/08/18 22:11:59 Send To: 217.116.122.138:3479
2016/08/18 22:12:08 Received: Nil
Port restricted NAT X.X.X.X:44444 <nil>
Looks ok, as it seems that it is port restricted and all local
shows the same ip port pair across all tests, and Test3 which just ask to change the port fails.
Now this one, I think is NOT OK:
jb@syno:~/tmp $ go run foo.go
2016/08/18 22:15:42 Do Test1
2016/08/18 22:15:42 Send To: 217.10.68.152:3478
2016/08/18 22:15:42 Received: {packet nil: false, local: Y.Y.Y.Y:9237, remote: 217.10.68.152:3478, changed: 217.116.122.136:3479, identical: false}
2016/08/18 22:15:42 Do Test2
2016/08/18 22:15:42 Send To: 217.10.68.152:3478
2016/08/18 22:15:52 Received: Nil
2016/08/18 22:15:52 Do Test1
2016/08/18 22:15:52 Send To: 217.116.122.136:3479
2016/08/18 22:15:52 Received: {packet nil: false, local: Y.Y.Y.Y:21548, remote: 217.116.122.136:3479, changed: 217.10.68.152:3478, identical: false}
2016/08/18 22:15:52 Do Test3
2016/08/18 22:15:52 Send To: 217.116.122.136:3479
2016/08/18 22:16:01 Received: Nil
Port restricted NAT Y.Y.Y.Y:9237 <nil>
local
is actually different on both tests, which implies that it's a symetric nat.
The reason this returns Port Restricted NAT, I believe is because we do not check the Port() equality on this line:
https://github.com/ccding/go-stun/blob/master/stun/discover.go#L139
Despite the comment in the code, I do end up getting NATUnknown, for example on an ec2 instance that doesn't have any incoming udp rules set.
2019/02/20 19:09:26 Do Test1
2019/02/20 19:09:26 Send To: 216.93.246.18:3478
2019/02/20 19:09:26
00000000 00 01 00 18 21 12 a4 42 89 7c 41 a3 25 31 77 80 |....!..B.|A.%1w.|
00000010 d1 6d 38 a9 80 22 00 0c 53 74 75 6e 43 6c 69 65 |.m8.."..StunClie|
00000020 6e 74 00 00 80 28 00 04 8a 52 09 fd |nt...(...R..|
2019/02/20 19:09:26
00000000 01 01 00 48 21 12 a4 42 89 7c 41 a3 25 31 77 80 |...H!..B.|A.%1w.|
00000010 d1 6d 38 a9 00 01 00 08 00 01 38 e1 2d 9d 9b 2a |.m8.......8.-..*|
00000020 00 04 00 08 00 01 93 f1 59 74 6a 2c 00 05 00 08 |........Ytj,....|
00000030 00 01 74 76 38 03 dc 5e 80 20 00 08 00 01 00 a3 |..tv8..^. ......|
00000040 7a d9 8e 0e 80 22 00 14 56 6f 76 69 64 61 2e 6f |z...."..Vovida.o|
00000050 72 67 20 30 2e 39 38 2d 43 50 43 00 |rg 0.98-CPC.|
2019/02/20 19:09:26 Received: {packet nil: false, local: 91.203.42.76:8625, remote: 216.93.246.18:3478, changed: 56.3.220.94:29814, other: <nil>, identical: false}
2019/02/20 19:09:26 Do Test2
2019/02/20 19:09:26 Send To: 216.93.246.18:3478
2019/02/20 19:09:26
00000000 00 01 00 20 21 12 a4 42 cd 28 92 d7 9a 77 a7 5d |... !..B.(...w.]|
00000010 5c fe b0 ee 80 22 00 0c 53 74 75 6e 43 6c 69 65 |\...."..StunClie|
00000020 6e 74 00 00 00 03 00 04 00 00 00 06 80 28 00 04 |nt...........(..|
00000030 3c 75 37 77 |<u7w|
2019/02/20 19:09:36 Received: Nil
2019/02/20 19:09:36 Do Test1
2019/02/20 19:09:36 Send To: 56.3.220.94:29814
2019/02/20 19:09:36
00000000 00 01 00 18 21 12 a4 42 73 01 e5 40 c9 cb cd 97 |....!..Bs..@....|
00000010 a6 15 79 01 80 22 00 0c 53 74 75 6e 43 6c 69 65 |..y.."..StunClie|
00000020 6e 74 00 00 80 28 00 04 9a 04 5d 35 |nt...(....]5|
2019/02/20 19:09:45 Received: Nil
NAT Type: Unexpected response from the STUN server
External IP Family: 1
External IP: 91.203.42.76
External Port: 8625
RFC 5389 do have support for TCP protocol,and https://github.com/jselbie/stunserver have implemented it, but It's a c++ version.
go-stun send binding request to coturn-4.5.0.6 will fail.
The binding request packet will drop for fingerprint. I have debug it in coturn.
packet check will fail in stun_is_command_message_full_check_str.
stun_is_command_message_full_check_str in src/client/ns_turn_msg.c
int stun_is_command_message_full_check_str(const u08bits* buf, size_t blen, int must_check_fingerprint, int *fingerprint_present) {
if(!stun_is_command_message_str(buf,blen))
return 0;
stun_attr_ref sar = stun_attr_get_first_by_type_str(buf, blen, STUN_ATTRIBUTE_FINGERPRINT);
if(!sar) {
if(fingerprint_present)
*fingerprint_present = 0;
if(stun_get_method_str(buf,blen) == STUN_METHOD_BINDING) {
return 1;
}
return !must_check_fingerprint;
}
if(stun_attr_get_len(sar) != 4)
return 0;
const u32bits* fingerprint = (const u32bits*)stun_attr_get_value(sar);
if(!fingerprint)
return !must_check_fingerprint;
u32bits crc32len = (u32bits)((((const u08bits*)fingerprint)-buf)-4);
int ret = (*fingerprint == nswap32(ns_crc32(buf,crc32len) ^ ((u32bits)0x5354554e)));
if(ret && fingerprint_present)
*fingerprint_present = ret;
return ret;
}
I can use chrome send binding request to coturn-4.5.0.6 。So, this is bug in go-stun?
Thank you for reply.
Hi,
I am testing this again, and I am hitting a strange issue, where my NAT is reported correctly as a full cone nat, but I believe it hasn't done proper testing.
I've made a small diff just for debugging:
@@ -125,6 +126,7 @@ func (v *packet) xorMappedAddr() *Host {
// Retransmissions continue with intervals of 1.6s until a response is
// received, or a total of 9 requests have been sent.
func (v *packet) send(conn net.PacketConn, addr net.Addr) (*packet, error) {
+ fmt.Println("send to", addr)
timeout := 100
for i := 0; i < 9; i++ {
length, err := conn.WriteTo(v.bytes(), addr)
@@ -142,8 +144,9 @@ func (v *packet) send(conn net.PacketConn, addr net.Addr) (*packet, error) {
timeout *= 2
}
packetBytes := make([]byte, 1024)
- length, _, err = conn.ReadFrom(packetBytes)
+ length, raddr, err := conn.ReadFrom(packetBytes)
if err == nil {
+ fmt.Println("recv", raddr)
return newPacketFromBytes(packetBytes[0:length])
}
if !err.(net.Error).Timeout() {
And the verbose output is as follows:
2016/08/05 22:46:58 Do Test1
2016/08/05 22:46:58 Send To: 64.233.165.127:19302
send to 64.233.165.127:19302
recv 64.233.165.127:19302
2016/08/05 22:46:58 Received: {isNil:false}
2016/08/05 22:46:58 Received: {changedAddr:'<nil>', identical:'false', host:'111.189.74.19:55777'}
2016/08/05 22:46:58 Do Test2
2016/08/05 22:46:58 Send To: 64.233.165.127:19302
send to 64.233.165.127:19302
recv 64.233.165.127:19302
2016/08/05 22:46:58 Received: {isNil:false}
Full cone NAT &{1 111.189.74.19 55777} <nil>
Now correct me if I am wrong, but the response in Test2 came from the same address as Test1, hence there is no evidence that it is actually a full cone nat?
I feel that it's the stun server misbehaving, yet perhaps sanity checks should be performed client side too?
Also, I changed my router since I ran the last tests when it actually worked, so perhaps it's my router re-writing the addresses and causing this impression?
As I seem to get the same result with multiple stun servers...
Does it support ipv6? Although our ipv6 does not have a nat, the superior route has a firewall, and the inbound is completely blocked, and because it is a 4G network, the firewall settings cannot be changed. I am wondering whether stun can be used in ipv6.
sir,why a test used 20 seconds?can it be faster?
NAT Type: Port restricted NAT
External IP Family: 1
External IP: 121.7.13.88
External Port: 10065
Time taken: 22.4233083
It took me a while to understand that NATSymmetricUDPFirewall
actually means Symmetric UDP Firewall
without any actual NAT being involved (as is also shown in the RFC and the flow chart in https://github.com/ccding/go-stun/blob/master/stun/discover.go ).
I wonder whether this constant should be renamed / aliased to SymmetricUDPFirewall
to better clarify that this is very different from NATSymmetric
?
package main
import(
"fmt"
"github.com/ccding/go-stun/stun"
)
func main(){
client := stun.NewClient()
client.SetServerAddr("stun.ekiga.net:3478")
fmt.Println(client.Discover())
}
returns:
5 &{1 46.XXX.151.XXX 56986} <nil>
5 being symetric
Where as pystun returns:
Audrius@Audrius ~ $ pystun --debug
DEBUG:pystun:Do Test1
DEBUG:pystun:Trying STUN host: stun.ekiga.net
DEBUG:pystun:sendto: ('stun.ekiga.net', 3478)
DEBUG:pystun:recvfrom: ('217.10.68.152', 3478)
DEBUG:pystun:Result: {'ExternalIP': '46.XXX.151.XXX', 'Resp': True, 'ExternalPort': 65465, 'ChangedPort': 3479, 'SourcePort': 3478, 'SourceIP': '217.10.68.152', 'ChangedIP': '217.116.122.138'}
DEBUG:pystun:Do Test2
DEBUG:pystun:sendto: ('stun.ekiga.net', 3478)
DEBUG:pystun:recvfrom: ('217.116.122.138', 3479)
DEBUG:pystun:Result: {'ExternalIP': '46.XXX.151.XXX', 'Resp': True, 'ExternalPort': 65465, 'ChangedPort': 3479, 'SourcePort': 3479, 'SourceIP': '217.116.122.138', 'ChangedIP': '217.116.122.138'}
NAT Type: Full Cone
External IP: 46.XXX.151.XXX
External Port: 65465
Any ideas where to start debugging?
Furthermore, a bit of a noob question.
This seems to only perform NAT type discovery, but does not give you any way to actually perform the punch through, because it does not return the local port used (so that I could reuse that port and advertise the external port returned by the discovery), nor does it allow requesting a specific port.
How do I actually use this to perform the punchthrough with this?
Hello,
Could you please tag this repository?
I am the Debian Maintainer for this project and tags would help Debian keep up with new releases/bugfixes.
See:
example.go doesn't run. according to this, provserver.televolution.net is no longer working.
use stun1.voiceeclipse.net or any other one instead
how use passwd and username?
Usage of ./go-stun
{'urls':'turn:turn.bistri.com:80?transport=udp','credential':'homeo','username':'homeo'},
{'urls':'stun:webrtcweb.com:4455?transport=udp','credential':'muazkh','username':'muazkh'},
{'urls':'stun:webrtcweb.com:8877?transport=udp','credential':'muazkh','username':'muazkh'},
Please add option to use fixed port for testing. Instead of random port.
Like this go-stun -s stun.syncthing.net:3478 -p6789
For example google ones:
stun.l.google.com:19302
stun1.l.google.com:19302
stun2.l.google.com:19302
stun3.l.google.com:19302
stun4.l.google.com:19302
Test1 fails with "No changed address." error. Any idea what could be wrong?
in RFC5780, the CHANGED-ADDRESS has been replaced by OTHER-ADDRESS.
something about issue9
thanks for this repo, just what I was looking for.
Question on UDP hole punching: is this something the big peer networks do reliable to the point they don't have to send people to https://portforward.com or do the majority of peer to peer networks not use UDP hole punching because it isn't 100% reliable and having the user go into their router and make a real open port is always a more reliable solution?
if I use the punchd port as a udp server ,a few minutes later, it will fail.
it needs a keep alive method.
the keepalive method can not cooperate with a server connection, because when keep alive called, this method will send and receive packet.
generally , there only one postion for receiving packet!
新版的External IP这个返回的是不是有问题?一直变动.
还有External Port有没有对应一个内部的端口呢?
Sorry, it is mistake
I need a stun & turn server for webrtc system.
This repo is all about stun. Is turn also supported ?
Currently this package only contains the Client implementation, would a Server implementation be within the Scope of this package, I certainly would hope it does?
I'm asking as I might be interested to have this working in a P2P network, where a peer would be both a client and server, so having a server implementation ready in Golang, would help a lot with that?
I'm prepared to do the work for this, would just need to know if:
编译运行之后,总报NAT Type: UDP is blocked
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.