diff --git a/app/app.go b/app/app.go index 66982fa28..44d00c679 100644 --- a/app/app.go +++ b/app/app.go @@ -19,16 +19,17 @@ 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 { @@ -36,6 +37,14 @@ type PsiphonOptions struct { } 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") } @@ -101,6 +110,66 @@ 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 + 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")) diff --git a/example_config.json b/example_config.json index e6a737544..76830149d 100644 --- a/example_config.json +++ b/example_config.json @@ -11,5 +11,6 @@ "rtt": "1000ms", "cache-dir": "", "tun-experimental": false, - "fwmark": "0x1375" + "fwmark": "0x1375", + "wgconf": "" } diff --git a/main.go b/main.go index 1ab25bb7b..b2bb56413 100644 --- a/main.go +++ b/main.go @@ -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") ) @@ -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 {