package main import ( "bufio" "context" "crypto/rand" "flag" "fmt" "io" "log" "os" "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/multiformats/go-multiaddr" ) const protocolID = "/sallik/1.0.0" func main() { // CLI argümanlarını al listenPort := flag.Int("p", 0, "Dinlenecek port (0 = rastgele)") targetPeer := flag.String("d", "", "Bağlanılacak hedef peer adresi (Client modu için)") flag.Parse() ctx := context.Background() // 1. Libp2p Host (Düğüm) Oluştur h, err := makeHost(*listenPort) if err != nil { log.Fatal(err) } // Host bilgilerini yazdır fmt.Printf("Benim ID'm: %s\n", h.ID()) for _, addr := range h.Addrs() { fmt.Printf("Dinleniyor: %s/p2p/%s\n", addr, h.ID()) } // 2. Akış (Stream) Handler Belirle // Eğer biri bize bağlanırsa bu fonksiyon çalışacak (Relay Modu) h.SetStreamHandler(protocolID, handleStream) // 3. Eğer hedef belirtildiyse Client moduna geç ve bağlan if *targetPeer != "" { runClient(ctx, h, *targetPeer) } else { // Hedef yoksa sadece Relay olarak bekle fmt.Println("\nRelay modu aktif. Bağlantı bekleniyor... (Çıkış için CTRL+C)") select {} // Sonsuz döngü } } // makeHost: Yeni bir libp2p düğümü başlatır func makeHost(port int) (host.Host, error) { // Kimlik için RSA anahtarı oluştur (Gerçekte bu kaydedilip tekrar yüklenmeli) priv, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, rand.Reader) if err != nil { return nil, err } // Belirtilen portta dinle (0.0.0.0 tüm arayüzler demek) sourceMultiAddr, _ := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", port)) return libp2p.New( libp2p.Identity(priv), libp2p.ListenAddrs(sourceMultiAddr), ) } // handleStream: Gelen bağlantıyı karşılar (Server tarafı) func handleStream(s network.Stream) { fmt.Println("\n[!] Yeni bir tünel bağlantısı kabul edildi!") // Gelen veriyi okumak ve yazmak için tampon (buffer) oluştur rw := bufio.NewReadWriter(bufio.NewReader(s), bufio.NewWriter(s)) // Basit bir echo/okuma döngüsü go readData(rw) go writeData(rw) // Sunucu da cevap yazabilsin } // runClient: Başka bir düğüme bağlanır (Client tarafı) func runClient(ctx context.Context, h host.Host, target string) { // Hedef adresi parse et maddr, err := multiaddr.NewMultiaddr(target) if err != nil { log.Fatalln(err) } // Adresten PeerID ve IP bilgisini ayır info, err := peer.AddrInfoFromP2pAddr(maddr) if err != nil { log.Fatalln(err) } // Hedefe bağlan (Host.Connect) if err := h.Connect(ctx, *info); err != nil { log.Fatalln("Bağlantı hatası:", err) } fmt.Println("\n[+] Hedef düğüme başarıyla bağlanıldı!") // Protokol üzerinden bir stream (kanal) aç s, err := h.NewStream(ctx, info.ID, protocolID) if err != nil { log.Fatalln("Stream açma hatası:", err) } rw := bufio.NewReadWriter(bufio.NewReader(s), bufio.NewWriter(s)) // Veri alışverişini başlat go readData(rw) go writeData(rw) select {} // Programı açık tut } // Okuma Yardımcısı func readData(rw *bufio.ReadWriter) { for { str, err := rw.ReadString('\n') if err != nil { if err != io.EOF { fmt.Println("Okuma hatası:", err) } return } fmt.Printf("\x1b[32m%s\x1b[0m: %s", "Gelen Mesaj", str) } } // Yazma Yardımcısı (Konsoldan girileni karşıya atar) func writeData(rw *bufio.ReadWriter) { stdReader := bufio.NewReader(os.Stdin) for { fmt.Print("> ") sendData, _ := stdReader.ReadString('\n') rw.WriteString(sendData) rw.Flush() } }