This commit is contained in:
Atakan Özgün
2025-12-04 03:47:30 +03:00
parent 6bb67345b8
commit be4edd12a1
3 changed files with 227 additions and 104 deletions

173
main.go
View File

@@ -3,136 +3,137 @@ package main
import (
"bufio"
"context"
"crypto/rand"
"flag"
"fmt"
"io"
"log"
"os"
"sync"
"time"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/crypto"
dht "github.com/libp2p/go-libp2p-kad-dht"
"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"
"github.com/libp2p/go-libp2p/p2p/discovery/routing"
dutil "github.com/libp2p/go-libp2p/p2p/discovery/util"
)
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)")
rendezvousString := flag.String("r", "gizli-tunel-sifresi", "Buluşma noktası için gizli kelime")
flag.Parse()
ctx := context.Background()
// 1. Libp2p Host (Düğüm) Oluştur
h, err := makeHost(*listenPort)
// 1. Libp2p Host'u oluştur (NAT Traversal ve Relay özellikleri açık)
h, err := libp2p.New(
libp2p.ListenAddrStrings("/ip4/0.0.0.0/tcp/0", "/ip4/0.0.0.0/udp/0/quic-v1"), // TCP ve QUIC dinle
libp2p.EnableHolePunching(), // NAT arkasından geçmeyi dene
libp2p.EnableNATService(),
libp2p.EnableRelay(), // Relay üzerinden geçmeye izin ver
)
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())
fmt.Printf("[*] Düğüm Başladı ID: %s\n", h.ID())
fmt.Println("[*] Küresel ağa bağlanılıyor (Bootstrapping)... Bu biraz sürebilir.")
// 2. DHT (Distributed Hash Table) Başlat
kademliaDHT, err := dht.New(ctx, h)
if err != nil {
log.Fatal(err)
}
// 2. Akış (Stream) Handler Belirle
// Eğer biri bize bağlanırsa bu fonksiyon çalışacak (Relay Modu)
// 3. Bootstrap (Başlangıç) Düğümlerine Bağlan
if err = kademliaDHT.Bootstrap(ctx); err != nil {
log.Fatal(err)
}
// Halka açık varsayılan IPFS düğümlerine bağlanarak ağa dahil ol
var wg sync.WaitGroup
for _, peerAddr := range dht.DefaultBootstrapPeers {
peerinfo, _ := peer.AddrInfoFromP2pAddr(peerAddr)
wg.Add(1)
go func() {
defer wg.Done()
if err := h.Connect(ctx, *peerinfo); err != nil {
// Bazılarına bağlanamamak normaldir
}
}()
}
wg.Wait()
fmt.Println("[+] Küresel ağa bağlandık! Şimdi arkadaşın aranıyor...")
// 4. Stream Handler (Gelen mesajları karşıla)
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ü
}
}
// 5. Discovery (Keşif) Mekanizması
routingDiscovery := routing.NewRoutingDiscovery(kademliaDHT)
dutil.Advertise(ctx, routingDiscovery, *rendezvousString)
fmt.Printf("[*] '%s' frekansında yayın yapılıyor.\n", *rendezvousString)
// 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
}
// 6. Arkadaşı Ara ve Bağlan
go func() {
for {
peerChan, err := routingDiscovery.FindPeers(ctx, *rendezvousString)
if err != nil {
panic(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))
for peer := range peerChan {
if peer.ID == h.ID() {
continue // Kendimize bağlanmayalım
}
return libp2p.New(
libp2p.Identity(priv),
libp2p.ListenAddrs(sourceMultiAddr),
)
}
fmt.Printf("[?] Bulunan Peer: %s. Bağlanılıyor...\n", peer.ID)
// Bağlantı dene
if err := h.Connect(ctx, peer); err != nil {
// Bağlantı başarısız olabilir (henüz delik açılmamış olabilir), tekrar deneriz
continue
}
// 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!")
fmt.Printf("[+] BAĞLANTI BAŞARILI! Tünel Kuruldu: %s\n", peer.ID)
// Stream aç
stream, err := h.NewStream(ctx, peer.ID, protocolID)
if err != nil {
fmt.Println("Stream hatası:", err)
continue
}
// 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)
rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))
go readData(rw)
go writeData(rw)
return // Bir kişi bulduk ve bağlandık, aramayı durdur (isteğe bağlı)
}
time.Sleep(time.Second * 2) // Kimse yoksa 2 saniye sonra tekrar ara
}
}()
select {} // Programıık tut
}
// Okuma Yardımcısı
func handleStream(s network.Stream) {
fmt.Println("\n[!] Biri tünelimize giriş yaptı!")
rw := bufio.NewReadWriter(bufio.NewReader(s), bufio.NewWriter(s))
go readData(rw)
go writeData(rw)
}
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)
fmt.Printf("\x1b[32m%s\x1b[0m: %s", "Gelen", str)
}
}
// Yazma Yardımcısı (Konsoldan girileni karşıya atar)
func writeData(rw *bufio.ReadWriter) {
stdReader := bufio.NewReader(os.Stdin)
for {