func (e *attemptEngine) read() error { buf := make([]byte, 512) n, from, err := e.sock.ReadFromUDP(buf) if err != nil { if neterr, ok := err.(net.Error); ok && neterr.Timeout() { return nil } return err } packet, err := stun.ParsePacket(buf[:n], nil) if err != nil { return nil } if packet.Method != stun.MethodBinding { return nil } switch packet.Class { case stun.ClassRequest: response, err := stun.BindResponse(packet.Tid[:], from, nil, false) if err != nil { return nil } e.sock.WriteToUDP(response, from) if packet.UseCandidate { for i := range e.attempts { if from.String() != e.attempts[i].Addr.String() { continue } if !e.attempts[i].success { return errors.New("Initiator told us to use bad link") } e.p2pconn = newConn(e.sock, e.attempts[i].localaddr, e.attempts[i].Addr) return nil } } case stun.ClassSuccess: for i := range e.attempts { if !bytes.Equal(packet.Tid[:], e.attempts[i].tid) { continue } if from.String() != e.attempts[i].Addr.String() { return nil } if e.attempts[i].chosen { e.p2pconn = newConn(e.sock, e.attempts[i].localaddr, e.attempts[i].Addr) return nil } e.attempts[i].success = true e.attempts[i].localaddr = packet.Addr e.attempts[i].timeout = time.Now().Add(probeInterval) return nil } } return nil }
func getReflexive(sock *net.UDPConn) (*net.UDPAddr, error) { serverAddr, err := net.ResolveUDPAddr("udp", *stunserver) if err != nil { return nil, errors.New("Couldn't resolve STUN server") } var tid [12]byte if _, err = rand.Read(tid[:]); err != nil { return nil, err } request, err := stun.BindRequest(tid[:], nil, true, false) if err != nil { return nil, err } n, err := sock.WriteTo(request, serverAddr) if err != nil { return nil, err } if n < len(request) { return nil, err } var buf [1024]byte n, _, err = sock.ReadFromUDP(buf[:]) if err != nil { return nil, err } packet, err := stun.ParsePacket(buf[:n], nil) if err != nil { return nil, err } if packet.Class != stun.ClassSuccess || packet.Method != stun.MethodBinding || packet.Addr == nil || !bytes.Equal(tid[:], packet.Tid[:]) { return nil, errors.New("No address provided by STUN server") } return packet.Addr, nil }
func main() { flag.Parse() serverAddr, err := net.ResolveUDPAddr("udp", *server) if err != nil { fmt.Println("Couldn't resolve", *server) os.Exit(1) } tid := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc} request, err := stun.BindRequest(tid, nil, true, false) if err != nil { fmt.Println("Failed to build STUN request:", err) os.Exit(1) } sock, err := net.ListenUDP("udp", &net.UDPAddr{Port: *sourcePort}) if err != nil { fmt.Println("Couldn't listen on UDP port", *sourcePort) os.Exit(1) } if err := sock.SetDeadline(time.Now().Add(10 * time.Second)); err != nil { fmt.Println("Couldn't set the socket timeout:", err) os.Exit(1) } n, err := sock.WriteTo(request, serverAddr) if err != nil { fmt.Println("Couldn't send STUN request:", err) os.Exit(1) } if n < len(request) { fmt.Println("Short write") os.Exit(1) } buf := make([]byte, 1024) n, _, err = sock.ReadFromUDP(buf) if err != nil { fmt.Println("Error reading STUN response:", err) os.Exit(1) } sock.Close() packet, err := stun.ParsePacket(buf[:n], nil) if err != nil { fmt.Println("Failed to parse STUN packet:", err) os.Exit(1) } if packet.Error != nil { fmt.Println("STUN server returned an error:", packet.Error) os.Exit(1) } if packet.Addr == nil { fmt.Println("STUN server didn't provide a reflexive address") os.Exit(1) } fmt.Printf("According to STUN server %s, port %d maps to %s on your NAT\n", *server, *sourcePort, packet.Addr) }