222 lines
5.7 KiB
Go
222 lines
5.7 KiB
Go
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)
|
||
}
|
||
} |