Skip to content

Commit

Permalink
lots of refactoring and cleanup
Browse files Browse the repository at this point in the history
Signed-off-by: Mark Pashmfouroush <mark@markpash.me>
  • Loading branch information
markpash committed Feb 24, 2024
1 parent cd34169 commit 71732fc
Show file tree
Hide file tree
Showing 9 changed files with 266 additions and 318 deletions.
172 changes: 73 additions & 99 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,76 +3,91 @@ package app
import (
"context"
"errors"
"flag"
"fmt"
"github.com/bepass-org/wireguard-go/psiphon"
"github.com/bepass-org/wireguard-go/warp"
"github.com/bepass-org/wireguard-go/wiresocks"
"log"
"net"
"net/netip"
"os"
"path/filepath"
"time"

"github.com/bepass-org/wireguard-go/psiphon"
"github.com/bepass-org/wireguard-go/warp"
"github.com/bepass-org/wireguard-go/wiresocks"
)

func RunWarp(psiphonEnabled, gool, scan, verbose bool, country, bindAddress, endpoint, license string, ctx context.Context, rtThreshold int) error {
// check if user input is not correct
if (psiphonEnabled && gool) || (!psiphonEnabled && country != "") {
log.Println("Wrong combination of flags!")
flag.Usage()
return errors.New("wrong command")
type WarpOptions struct {
LogLevel string
Bind netip.AddrPort
Endpoint string
License string
Psiphon *PsiphonOptions
Gool bool
Scan *ScanOptions
}

type PsiphonOptions struct {
Country string
}

type ScanOptions struct {
MaxRTT time.Duration
}

func RunWarp(ctx context.Context, opts WarpOptions) error {
if opts.Psiphon != nil && opts.Gool {
return errors.New("can't use psiphon and gool at the same time")
}

if opts.Psiphon != nil && opts.Psiphon.Country == "" {
return errors.New("must provide country for psiphon")
}

//create necessary file structures
if err := makeDirs(); err != nil {
return err
}
log.Println("'primary' and 'secondary' directories are ready")

// Change the current working directory to 'stuff'
if err := os.Chdir("stuff"); err != nil {
log.Printf("Error changing to 'stuff' directory: %v\n", err)
return fmt.Errorf("Error changing to 'stuff' directory: %v\n", err)
return fmt.Errorf("error changing to 'stuff' directory: %w", err)
}
log.Println("Changed working directory to 'stuff'")
defer func() {
// back where you where
if err := os.Chdir(".."); err != nil {
log.Fatal("Error changing to 'main' directory:", err)
}
}()

//create identities
if err := createPrimaryAndSecondaryIdentities(license); err != nil {
if err := createPrimaryAndSecondaryIdentities(opts.License); err != nil {
return err
}

//Decide Working Scenario
endpoints := []string{endpoint, endpoint}
endpoints := []string{opts.Endpoint, opts.Endpoint}

if scan {
if opts.Scan != nil {
var err error
endpoints, err = wiresocks.RunScan(&ctx, rtThreshold)
endpoints, err = wiresocks.RunScan(&ctx, opts.Scan.MaxRTT)
if err != nil {
return err
}
}

if !psiphonEnabled && !gool {
// just run primary warp on bindAddress
_, _, err := runWarp(bindAddress, endpoints, "./primary/wgcf-profile.ini", verbose, true, ctx, true)
return err
} else if psiphonEnabled && !gool {
var warpErr error
switch {
case opts.Psiphon != nil:
// run primary warp on a random tcp port and run psiphon on bind address
return runWarpWithPsiphon(bindAddress, endpoints, country, verbose, ctx)
} else if !psiphonEnabled && gool {
warpErr = runWarpWithPsiphon(opts.Bind, endpoints, opts.Psiphon.Country, opts.LogLevel == "debug", ctx)
case opts.Gool:
// run warp in warp
return runWarpInWarp(bindAddress, endpoints, verbose, ctx)
warpErr = runWarpInWarp(opts.Bind, endpoints, opts.LogLevel == "debug", ctx)
default:
// just run primary warp on bindAddress
_, _, warpErr = runWarp(opts.Bind, endpoints, "./primary/wgcf-profile.ini", opts.LogLevel == "debug", true, ctx)
}

return fmt.Errorf("unknown error, it seems core related issue")
return warpErr
}

func runWarp(bindAddress string, endpoints []string, confPath string, verbose, startProxy bool, ctx context.Context, showServing bool) (*wiresocks.VirtualTun, int, error) {
func runWarp(bind netip.AddrPort, endpoints []string, confPath string, verbose, startProxy bool, ctx context.Context) (*wiresocks.VirtualTun, int, error) {
conf, err := wiresocks.ParseConfig(confPath, endpoints[0])
if err != nil {
log.Println(err)
Expand All @@ -86,44 +101,40 @@ func runWarp(bindAddress string, endpoints []string, confPath string, verbose, s
}

if startProxy {
tnet.StartProxy(bindAddress)
}

if showServing {
log.Printf("Serving on %s\n", bindAddress)
tnet.StartProxy(bind)
}

return tnet, conf.Device.MTU, nil
}

func runWarpWithPsiphon(bindAddress string, endpoints []string, country string, verbose bool, ctx context.Context) error {
func runWarpWithPsiphon(bind netip.AddrPort, endpoints []string, country string, verbose bool, ctx context.Context) error {
// make a random bind address for warp
warpBindAddress, err := findFreePort("tcp")
if err != nil {
log.Println("There are no free tcp ports on Device!")
return err
}

_, _, err = runWarp(warpBindAddress, endpoints, "./primary/wgcf-profile.ini", verbose, true, ctx, false)
_, _, err = runWarp(warpBindAddress, endpoints, "./primary/wgcf-profile.ini", verbose, true, ctx)
if err != nil {
return err
}

// run psiphon
err = psiphon.RunPsiphon(warpBindAddress, bindAddress, country, ctx)
err = psiphon.RunPsiphon(warpBindAddress.String(), bind.String(), country, ctx)
if err != nil {
log.Printf("unable to run psiphon %v", err)
return fmt.Errorf("unable to run psiphon %v", err)
}

log.Printf("Serving on %s\n", bindAddress)
log.Printf("Serving on %s", bind)

return nil
}

func runWarpInWarp(bindAddress string, endpoints []string, verbose bool, ctx context.Context) error {
func runWarpInWarp(bind netip.AddrPort, endpoints []string, verbose bool, ctx context.Context) error {
// run secondary warp
vTUN, mtu, err := runWarp("", endpoints, "./secondary/wgcf-profile.ini", verbose, false, ctx, false)
vTUN, mtu, err := runWarp(netip.AddrPort{}, endpoints, "./secondary/wgcf-profile.ini", verbose, false, ctx)
if err != nil {
return err
}
Expand All @@ -135,60 +146,58 @@ func runWarpInWarp(bindAddress string, endpoints []string, verbose bool, ctx con
return err
}
addr := endpoints[1]
if addr == "notset" {
addr, _ = wiresocks.ResolveIPPAndPort("engage.cloudflareclient.com:2408")
if addr == "" {
warpEndpoint, err := warp.RandomWarpEndpoint()
if err != nil {
return err
}
addr = warpEndpoint.String()
}
err = wiresocks.NewVtunUDPForwarder(virtualEndpointBindAddress, addr, vTUN, mtu+100, ctx)
err = wiresocks.NewVtunUDPForwarder(virtualEndpointBindAddress.String(), addr, vTUN, mtu+100, ctx)
if err != nil {
log.Println(err)
return err
}

// run primary warp
_, _, err = runWarp(bindAddress, []string{virtualEndpointBindAddress}, "./primary/wgcf-profile.ini", verbose, true, ctx, true)
_, _, err = runWarp(bind, []string{virtualEndpointBindAddress.String()}, "./primary/wgcf-profile.ini", verbose, true, ctx)
if err != nil {
return err
}
return nil
}

func findFreePort(network string) (string, error) {
func findFreePort(network string) (netip.AddrPort, error) {
if network == "udp" {
addr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
if err != nil {
return "", err
return netip.AddrPort{}, err
}

conn, err := net.ListenUDP("udp", addr)
if err != nil {
return "", err
return netip.AddrPort{}, err
}
defer conn.Close()

return conn.LocalAddr().(*net.UDPAddr).String(), nil
return netip.MustParseAddrPort(conn.LocalAddr().String()), nil
}
// Listen on TCP port 0, which tells the OS to pick a free port.
listener, err := net.Listen(network, "127.0.0.1:0")
if err != nil {
return "", err // Return error if unable to listen on a port
return netip.AddrPort{}, err // Return error if unable to listen on a port
}
defer listener.Close() // Ensure the listener is closed when the function returns

// Get the port from the listener's address
addr := listener.Addr().String()

return addr, nil
return netip.MustParseAddrPort(listener.Addr().String()), nil
}

func createPrimaryAndSecondaryIdentities(license string) error {
// make primary identity
_license := license
if _license == "notset" {
_license = ""
}
warp.UpdatePath("./primary")
if !warp.CheckProfileExists(license) {
err := warp.LoadOrCreateIdentity(_license)
err := warp.LoadOrCreateIdentity(license)
if err != nil {
log.Printf("error: %v", err)
return fmt.Errorf("error: %v", err)
Expand All @@ -197,7 +206,7 @@ func createPrimaryAndSecondaryIdentities(license string) error {
// make secondary
warp.UpdatePath("./secondary")
if !warp.CheckProfileExists(license) {
err := warp.LoadOrCreateIdentity(_license)
err := warp.LoadOrCreateIdentity(license)
if err != nil {
log.Printf("error: %v", err)
return fmt.Errorf("error: %v", err)
Expand All @@ -213,54 +222,19 @@ func makeDirs() error {

// Check if 'stuff' directory exists, if not create it
if _, err := os.Stat(stuffDir); os.IsNotExist(err) {
log.Println("'stuff' directory does not exist, creating it...")
if err := os.Mkdir(stuffDir, 0755); err != nil {
log.Println("Error creating 'stuff' directory:", err)
return errors.New("Error creating 'stuff' directory:" + err.Error())
return fmt.Errorf("error creating 'stuff' directory: %w", err)
}
}

// Create 'primary' and 'secondary' directories if they don't exist
for _, dir := range []string{primaryDir, secondaryDir} {
if _, err := os.Stat(filepath.Join(stuffDir, dir)); os.IsNotExist(err) {
log.Printf("Creating '%s' directory...\n", dir)
if err := os.Mkdir(filepath.Join(stuffDir, dir), 0755); err != nil {
log.Printf("Error creating '%s' directory: %v\n", dir, err)
return fmt.Errorf("Error creating '%s' directory: %v\n", dir, err)
return fmt.Errorf("error creating '%s' directory: %w", dir, err)
}
}
}
log.Println("'primary' and 'secondary' directories are ready")
return nil
}
func isPortOpen(address string, timeout time.Duration) bool {
// Try to establish a connection
conn, err := net.DialTimeout("tcp", address, timeout)
if err != nil {
return false
}
defer conn.Close()

return true
}

func waitForPortToGetsOpenOrTimeout(addressToCheck string) {
timeout := 5 * time.Second
checkInterval := 500 * time.Millisecond

// Set a deadline for when to stop checking
deadline := time.Now().Add(timeout)

for {
if time.Now().After(deadline) {
log.Fatalf("Timeout reached, port %s is not open", addressToCheck)
}

if isPortOpen(addressToCheck, checkInterval) {
log.Printf("Port %s is now open", addressToCheck)
break
}

time.Sleep(checkInterval)
}
return nil
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/bepass-org/ipscanner v0.0.0-20240205155121-8927b7437d16
github.com/bepass-org/proxy v0.0.0-20240201095508-c86216dd0aea
github.com/go-ini/ini v1.67.0
github.com/peterbourgon/ff/v4 v4.0.0-alpha.4
github.com/refraction-networking/conjure v0.7.11-0.20240130155008-c8df96195ab2
github.com/refraction-networking/utls v1.3.3
golang.org/x/crypto v0.18.0
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR
github.com/pebbe/zmq4 v1.2.10 h1:wQkqRZ3CZeABIeidr3e8uQZMMH5YAykA/WN0L5zkd1c=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
github.com/peterbourgon/ff/v4 v4.0.0-alpha.4 h1:aiqS8aBlF9PsAKeMddMSfbwp3smONCn3UO8QfUg0Z7Y=
github.com/peterbourgon/ff/v4 v4.0.0-alpha.4/go.mod h1:H/13DK46DKXy7EaIxPhk2Y0EC8aubKm35nBjBe8AAGc=
github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8=
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
Expand Down Expand Up @@ -248,6 +251,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down
Loading

0 comments on commit 71732fc

Please sign in to comment.