package main import ( "context" "flag" "fmt" "io" "log" "net" "strings" "sync" "time" "github.com/armon/go-socks5" "github.com/libp2p/go-libp2p" dht "github.com/libp2p/go-libp2p-kad-dht" "github.com/libp2p/go-libp2p/core/host" // EKLENDİ "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/p2p/discovery/routing" dutil "github.com/libp2p/go-libp2p/p2p/discovery/util" "github.com/libp2p/go-libp2p/p2p/host/autorelay" "github.com/multiformats/go-multiaddr" ) const protocolID = "/onion-proxy/1.0.0" // IPFS Statik Relay Listesi var relayNodes = []string{ "/ip4/147.75.83.83/tcp/4001/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb", "/ip4/147.75.76.67/tcp/4001/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", "/ip4/147.75.109.213/tcp/4001/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", } func main() { rendezvousString := flag.String("r", "gizli-tunel-sifresi", "Buluşma noktası için şifre") proxyPort := flag.String("proxy", "", "Client modu: Yerel SOCKS5 portu (Örn: 1080)") flag.Parse() ctx := context.Background() // 1. Statik Relay Listesini Hazırla var staticRelays []peer.AddrInfo for _, s := range relayNodes { ma, err := multiaddr.NewMultiaddr(s) if err != nil { continue } ai, err := peer.AddrInfoFromP2pAddr(ma) if err != nil { continue } staticRelays = append(staticRelays, *ai) } // 2. Libp2p Host'u oluştur h, err := libp2p.New( libp2p.ListenAddrStrings("/ip4/0.0.0.0/tcp/0", "/ip4/0.0.0.0/udp/0/quic-v1"), libp2p.EnableHolePunching(), libp2p.EnableNATService(), libp2p.EnableRelay(), libp2p.EnableAutoRelay(autorelay.WithStaticRelays(staticRelays)), libp2p.ForceReachabilityPrivate(), ) if err != nil { log.Fatal(err) } fmt.Printf("[*] Düğüm ID: %s\n", h.ID()) fmt.Println("[*] Küresel ağa bağlanılıyor (Bootstrapping)...") // 3. DHT Başlat kademliaDHT, err := dht.New(ctx, h, dht.Mode(dht.ModeClient)) if err != nil { log.Fatal(err) } if err = kademliaDHT.Bootstrap(ctx); err != nil { log.Fatal(err) } // 4. Bootstrap var wg sync.WaitGroup for _, peerAddr := range dht.DefaultBootstrapPeers { peerinfo, _ := peer.AddrInfoFromP2pAddr(peerAddr) wg.Add(1) go func() { defer wg.Done() h.Connect(ctx, *peerinfo) }() } wg.Wait() fmt.Println("[+] IPFS Ağına Bağlanıldı.") // 5. Relay Bekleme fmt.Print("[*] Relay bekleniyor...") for { hasRelay := false for _, addr := range h.Addrs() { if strings.Contains(addr.String(), "p2p-circuit") { hasRelay = true break } } if hasRelay { fmt.Println("\n[+] Relay Tüneli Hazır!") break } fmt.Print(".") time.Sleep(time.Second * 1) } // ========================================== // SERVER (EXIT NODE) MANTIĞI // ========================================== socksConf := &socks5.Config{} socksServer, err := socks5.New(socksConf) if err != nil { panic(err) } h.SetStreamHandler(protocolID, func(s network.Stream) { fmt.Println("\n[->] Tünelden yeni bir internet isteği geldi!") // HATA ÇÖZÜMÜ 1: Stream'i net.Conn uyumlu hale getiren Wrapper kullanıyoruz conn := StreamConn{Stream: s} // Artık socksServer bunu kabul eder socksServer.ServeConn(conn) }) // Discovery Başlat routingDiscovery := routing.NewRoutingDiscovery(kademliaDHT) dutil.Advertise(ctx, routingDiscovery, *rendezvousString) fmt.Printf("[*] '%s' kanalında dinleniyor.\n", *rendezvousString) // ========================================== // CLIENT (KULLANICI) MANTIĞI // ========================================== if *proxyPort != "" { // HATA ÇÖZÜMÜ 2: host.Host tipini doğru gönderiyoruz go startLocalProxy(ctx, h, routingDiscovery, *rendezvousString, *proxyPort) } select {} } // startLocalProxy: HATA ÇÖZÜMÜ 3: h değişkeninin tipi 'host.Host' olarak düzeltildi func startLocalProxy(ctx context.Context, h host.Host, discovery *routing.RoutingDiscovery, rendezvous, port string) { fmt.Println("------------------------------------------------") fmt.Printf("[CLIENT MODU] Yerel Proxy Başlatıldı: 127.0.0.1:%s\n", port) fmt.Println("Tarayıcının SOCKS5 ayarını buraya yönlendir.") fmt.Println("Çıkış Düğümü (Exit Node) aranıyor...") fmt.Println("------------------------------------------------") var targetPeer peer.AddrInfo found := false // 1. Çıkış Düğümü Bul for !found { peerChan, err := discovery.FindPeers(ctx, rendezvous) if err != nil { panic(err) } for p := range peerChan { if p.ID == h.ID() { // LocalPeer yerine h.ID() kullandık continue } // HATA ÇÖZÜMÜ 4: DialPeer yerine Connect kullanıyoruz if err := h.Connect(ctx, p); err == nil { fmt.Printf("[+] Çıkış Düğümü Bulundu ve Bağlandı: %s\n", p.ID) targetPeer = p found = true break } } if !found { time.Sleep(time.Second * 1) } } // 2. Yerel TCP Portunu Dinle listener, err := net.Listen("tcp", ":"+port) if err != nil { log.Fatal(err) } for { conn, err := listener.Accept() if err != nil { log.Println("Accept hatası:", err) continue } go func(browserConn net.Conn) { defer browserConn.Close() // HATA ÇÖZÜMÜ 5: Artık h host.Host olduğu için NewStream 3 argümanı kabul eder stream, err := h.NewStream(ctx, targetPeer.ID, protocolID) if err != nil { log.Println("Tünel açma hatası:", err) return } defer stream.Close() var wg sync.WaitGroup wg.Add(2) go func() { io.Copy(stream, browserConn) wg.Done() }() go func() { io.Copy(browserConn, stream) wg.Done() }() wg.Wait() }(conn) } } // ========================================== // HATA ÇÖZÜMÜ: Wrapper (Kapsayıcı) Struct // libp2p Stream'ini net.Conn gibi davranmaya zorlar. // ========================================== type StreamConn struct { network.Stream } // SOCKS5 kütüphanesi bu metodları arar, biz de sahte/boş cevaplar döneriz. func (c StreamConn) LocalAddr() net.Addr { return &net.TCPAddr{IP: net.IPv4zero, Port: 0} } func (c StreamConn) RemoteAddr() net.Addr { return &net.TCPAddr{IP: net.IPv4zero, Port: 0} }