Skip to content

Commit

Permalink
wireguard: add generic wireguard support
Browse files Browse the repository at this point in the history
Signed-off-by: Mark Pashmfouroush <[email protected]>
  • Loading branch information
markpash committed May 20, 2024
1 parent 9eedf37 commit f87e301
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 55 deletions.
97 changes: 87 additions & 10 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/netip"
"path"

"github.com/bepass-org/warp-plus/iputils"
"github.com/bepass-org/warp-plus/psiphon"
"github.com/bepass-org/warp-plus/warp"
"github.com/bepass-org/warp-plus/wiresocks"
Expand All @@ -19,23 +20,32 @@ const doubleMTU = 1280 // minimum mtu for IPv6, may cause frag reassembly somewh
const connTestEndpoint = "http://1.1.1.1:80/"

type WarpOptions struct {
Bind netip.AddrPort
Endpoint string
License string
DnsAddr netip.Addr
Psiphon *PsiphonOptions
Gool bool
Scan *wiresocks.ScanOptions
CacheDir string
Tun bool
FwMark uint32
Bind netip.AddrPort
Endpoint string
License string
DnsAddr netip.Addr
Psiphon *PsiphonOptions
Gool bool
Scan *wiresocks.ScanOptions
CacheDir string
Tun bool
FwMark uint32
WireguardConfig string
}

type PsiphonOptions struct {
Country string
}

func RunWarp(ctx context.Context, l *slog.Logger, opts WarpOptions) error {
if opts.WireguardConfig != "" {
if err := runWireguard(ctx, l, opts); err != nil {
return err
}

return nil
}

if opts.Psiphon != nil && opts.Gool {
return errors.New("can't use psiphon and gool at the same time")
}
Expand Down Expand Up @@ -101,6 +111,73 @@ func RunWarp(ctx context.Context, l *slog.Logger, opts WarpOptions) error {
return warpErr
}

func runWireguard(ctx context.Context, l *slog.Logger, opts WarpOptions) error {
conf, err := wiresocks.ParseConfig(opts.WireguardConfig)
if err != nil {
return err
}

// Set up MTU
conf.Interface.MTU = singleMTU
// Set up DNS Address
conf.Interface.DNS = []netip.Addr{opts.DnsAddr}

// Enable trick and keepalive on all peers in config
for i, peer := range conf.Peers {
peer.Trick = true
peer.KeepAlive = 3

// Try resolving if the endpoint is a domain
addr, err := iputils.ParseResolveAddressPort(peer.Endpoint, false)
if err == nil {
peer.Endpoint = addr.String()
}

conf.Peers[i] = peer
}

if opts.Tun {
// Create a new tun interface
tunDev, err := newNormalTun([]netip.Addr{opts.DnsAddr})
if err != nil {
return err
}

// Establish wireguard tunnel on tun interface
if err := establishWireguard(l, conf, tunDev, true, opts.FwMark); err != nil {
return err
}
l.Info("serving tun", "interface", "warp0")
return nil
}

// Create userspace tun network stack
tunDev, tnet, err := newUsermodeTun(conf)
if err != nil {
return err
}

// Establish wireguard on userspace stack
if err := establishWireguard(l, conf, tunDev, false, opts.FwMark); err != nil {
return err
}

// Test wireguard connectivity
if err := usermodeTunTest(ctx, l, tnet); err != nil {
return err
}

// Run a proxy on the userspace stack
_, err = wiresocks.StartProxy(ctx, l, tnet, opts.Bind)
if err != nil {
return err
}

l.Info("serving proxy", "address", opts.Bind)

return nil
}

func runWarp(ctx context.Context, l *slog.Logger, opts WarpOptions, endpoint string) error {
// Set up primary/outer warp config
conf, err := wiresocks.ParseConfig(path.Join(opts.CacheDir, "primary", "wgcf-profile.ini"))
Expand Down
3 changes: 2 additions & 1 deletion example_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
"rtt": "1000ms",
"cache-dir": "",
"tun-experimental": false,
"fwmark": "0x1375"
"fwmark": "0x1375",
"wgconf": ""
}
84 changes: 47 additions & 37 deletions iputils/iputils.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import (
"fmt"
"math/big"
"math/rand"
"net"
"net/netip"
"strconv"
"time"
)

Expand Down Expand Up @@ -55,40 +57,48 @@ func RandomIPFromPrefix(cidr netip.Prefix) (netip.Addr, error) {
return randomAddress.Unmap(), nil
}

// func ParseResolveAddressPort(hostname string) (netip.AddrPort, error) {
// // Attempt to split the hostname into a host and port
// host, port, err := net.SplitHostPort(hostname)
// if err != nil {
// return netip.AddrPort{}, fmt.Errorf("can't parse provided hostname into host and port: %w", err)
// }

// // Convert the string port to a uint16
// portInt, err := strconv.Atoi(port)
// if err != nil {
// return netip.AddrPort{}, fmt.Errorf("error parsing port: %w", err)
// }

// if portInt < 1 || portInt > 65535 {
// return netip.AddrPort{}, fmt.Errorf("port number %d is out of range", portInt)
// }

// // Attempt to parse the host into an IP. Return on success.
// addr, err := netip.ParseAddr(host)
// if err == nil {
// return netip.AddrPortFrom(addr.Unmap(), uint16(portInt)), nil
// }

// // If the host wasn't an IP, perform a lookup
// ips, err := net.LookupIP(host)
// if err != nil {
// return netip.AddrPort{}, fmt.Errorf("hostname lookup failed: %w", err)
// }

// // Take the first IP and then return it
// addr, ok := netip.AddrFromSlice(ips[0])
// if !ok {
// return netip.AddrPort{}, errors.New("failed to parse ip")
// }

// return netip.AddrPortFrom(addr.Unmap(), uint16(portInt)), nil
// }
func ParseResolveAddressPort(hostname string, includev6 bool) (netip.AddrPort, error) {
// Attempt to split the hostname into a host and port
host, port, err := net.SplitHostPort(hostname)
if err != nil {
return netip.AddrPort{}, fmt.Errorf("can't parse provided hostname into host and port: %w", err)
}

// Convert the string port to a uint16
portInt, err := strconv.Atoi(port)
if err != nil {
return netip.AddrPort{}, fmt.Errorf("error parsing port: %w", err)
}

if portInt < 1 || portInt > 65535 {
return netip.AddrPort{}, fmt.Errorf("port number %d is out of range", portInt)
}

// Attempt to parse the host into an IP. Return on success.
addr, err := netip.ParseAddr(host)
if err == nil {
return netip.AddrPortFrom(addr.Unmap(), uint16(portInt)), nil
}

// If the host wasn't an IP, perform a lookup
ips, err := net.LookupIP(host)
if err != nil {
return netip.AddrPort{}, fmt.Errorf("hostname lookup failed: %w", err)
}

for _, ip := range ips {
// Take the first IP and then return it
addr, ok := netip.AddrFromSlice(ip)
if !ok {
continue
}

if addr.Unmap().Is4() {
return netip.AddrPortFrom(addr.Unmap(), uint16(portInt)), nil
} else if includev6 {
return netip.AddrPortFrom(addr.Unmap(), uint16(portInt)), nil
}
}

return netip.AddrPort{}, errors.New("no valid IP addresses found")
}
16 changes: 9 additions & 7 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ func main() {
cacheDir = fs.StringLong("cache-dir", "", "directory to store generated profiles")
tun = fs.BoolLong("tun-experimental", "enable tun interface (experimental)")
fwmark = fs.UintLong("fwmark", 0x1375, "set linux firewall mark for tun mode")
wgConf = fs.StringLong("wgconf", "", "path to a normal wireguard config")
_ = fs.String('c', "config", "", "path to config file")
verFlag = fs.BoolLong("version", "displays version number")
)
Expand Down Expand Up @@ -138,13 +139,14 @@ func main() {
}

opts := app.WarpOptions{
Bind: bindAddrPort,
Endpoint: *endpoint,
License: *key,
DnsAddr: dnsAddr,
Gool: *gool,
Tun: *tun,
FwMark: uint32(*fwmark),
Bind: bindAddrPort,
Endpoint: *endpoint,
License: *key,
DnsAddr: dnsAddr,
Gool: *gool,
Tun: *tun,
FwMark: uint32(*fwmark),
WireguardConfig: *wgConf,
}

switch {
Expand Down

0 comments on commit f87e301

Please sign in to comment.