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/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) } // ========================================== // ROLLERE GÖRE AYRIŞMA (SERVER vs CLIENT) // ========================================== // EXIT NODE (SERVER) MANTIĞI: // Gelen tüm stream isteklerini SOCKS5 sunucusuna yönlendir. 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!") // Gelen libp2p akışını doğrudan SOCKS5 sunucusuna teslim et // SOCKS5 sunucusu internete bağlanıp cevabı stream'e geri yazacak. socksServer.ServeConn(s) }) // Discovery Başlat routingDiscovery := routing.NewRoutingDiscovery(kademliaDHT) dutil.Advertise(ctx, routingDiscovery, *rendezvousString) fmt.Printf("[*] '%s' kanalında dinleniyor.\n", *rendezvousString) // CLIENT (KULLANICI) MANTIĞI: // Eğer -proxy 1080 bayrağı verildiyse, yerel portu dinle ve trafiği tünele at. if *proxyPort != "" { go startLocalProxy(ctx, h, routingDiscovery, *rendezvousString, *proxyPort) } select {} // Sonsuz bekleme } // startLocalProxy: Tarayıcıdan gelen trafiği yakalar ve tünele atar func startLocalProxy(ctx context.Context, h network.Network, 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 (Sadece bir tane bulmak yeterli) for !found { peerChan, err := discovery.FindPeers(ctx, rendezvous) if err != nil { panic(err) } for p := range peerChan { if p.ID == h.LocalPeer() { continue } // Bulunan kişiye bağlanmayı dene if err := h.DialPeer(ctx, p.ID); 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 (Örn: 1080) listener, err := net.Listen("tcp", ":"+port) if err != nil { log.Fatal(err) } for { // Tarayıcıdan gelen isteği kabul et conn, err := listener.Accept() if err != nil { log.Println("Accept hatası:", err) continue } // Her yeni istek için tünel üzerinden yeni bir stream aç go func(browserConn net.Conn) { defer browserConn.Close() // Çıkış düğümüne stream aç stream, err := h.NewStream(ctx, targetPeer.ID, protocolID) if err != nil { log.Println("Tünel açma hatası (Arkadaşın düştü mü?):", err) return } defer stream.Close() // Veriyi İki Yönlü Kopyala (Pipe) // Browser -> Tünel -> Arkadaş -> İnternet // İnternet -> Arkadaş -> Tünel -> Browser 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) } }