示例#1
0
文件: nat.go 项目: yangxingpping/nat
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
}
示例#2
0
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
}
示例#3
0
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)
}