Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion client.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,21 @@ type Client struct {
addrs *notify.V[advertiseAddrs]
natlocal *nat.Local
natpmp *nat.PMP
natpcp *nat.PCP
}

type advertiseAddrs struct {
STUN []netip.AddrPort
PMP []netip.AddrPort
PCP []netip.AddrPort
Local []netip.AddrPort
}

func (d advertiseAddrs) all() []netip.AddrPort {
addrs := make([]netip.AddrPort, 0, len(d.STUN)+len(d.PMP)+len(d.Local))
addrs := make([]netip.AddrPort, 0, len(d.STUN)+len(d.PMP)+len(d.PCP)+len(d.Local))
addrs = append(addrs, d.STUN...)
addrs = append(addrs, d.PMP...)
addrs = append(addrs, d.PCP...)
addrs = append(addrs, d.Local...)
return addrs
}
Expand Down Expand Up @@ -134,13 +137,16 @@ func (c *Client) runClient(ctx context.Context, errCh chan error) {

c.natlocal = nat.NewLocal(uint16(c.directAddr.Port), c.logger)
c.natpmp = nat.NewPMP(c.natPMP, transport, uint16(c.directAddr.Port), c.logger)
c.natpcp = nat.NewPCP(c.natPCP, transport, uint16(c.directAddr.Port), c.logger)

g := reliable.NewGroup(ctx)

g.Go(ds.Run)
g.Go(c.natpmp.Run)
g.Go(c.natpcp.Run)
g.Go(c.listenNatlocal)
g.Go(c.listenNatpmp)
g.Go(c.listenNatpcp)
g.Go(func(ctx context.Context) error { return c.run(ctx, transport, errCh) })

if err := g.Wait(); err != nil {
Expand Down Expand Up @@ -430,6 +436,17 @@ func (c *Client) listenNatpmp(ctx context.Context) error {
})
}

func (c *Client) listenNatpcp(ctx context.Context) error {
return c.natpcp.Listen(ctx, func(ap []netip.AddrPort) error {
c.logger.Debug("updating nat pcp", "addrs", ap)
c.addrs.Update(func(d advertiseAddrs) advertiseAddrs {
d.PCP = ap
return d
})
return nil
})
}

type ClientStatus struct {
// Overall status of this client
Status statusc.Status `json:"status"`
Expand All @@ -447,6 +464,8 @@ type ClientStatus struct {
STUNAddrs []string `json:"stun-addresses"`
// NATPMPAddrs reports the set of addresses this peer is reachable at, resolved from natpmp
NATPMPAddrs []string `json:"natpmp-addresses"`
// NATPCPAddrs reports the set of addresses this peer is reachable at, resolved from natpcp
NATPCPAddrs []string `json:"natpcp-addresses"`
// Status of each active destination for this client
Destinations map[model.Endpoint]DestinationStatus `json:"destinations"`
// Status of each active source for this client
Expand Down Expand Up @@ -478,6 +497,7 @@ func (c *Client) Status(ctx context.Context) (ClientStatus, error) {
LocalAddrs: iterc.MapSliceStrings(addrs.Local),
STUNAddrs: iterc.MapSliceStrings(addrs.STUN),
NATPMPAddrs: iterc.MapSliceStrings(addrs.PMP),
NATPCPAddrs: iterc.MapSliceStrings(addrs.PCP),
Destinations: dsts,
Sources: srcs,
}, nil
Expand Down
18 changes: 18 additions & 0 deletions cmd/connet/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type ClientConfig struct {

StatusAddr string `toml:"status-addr"`
NatPMP string `toml:"nat-pmp"`
NatPCP string `toml:"nat-pcp"`
HandshakeIdleTimeout durationValue `toml:"handshake-idle-timeout"`

RelayEncryptions []string `toml:"relay-encryptions"`
Expand Down Expand Up @@ -100,6 +101,7 @@ func clientCmd() *cobra.Command {

addStatusAddrFlag(cmd, &flagsConfig.Client.StatusAddr)
cmd.Flags().StringVar(&flagsConfig.Client.NatPMP, "nat-pmp", "", "nat-pmp behavior, one of [system, dial, disabled] (defaults to 'system')")
cmd.Flags().StringVar(&flagsConfig.Client.NatPCP, "nat-pcp", "", "nat-pcp behavior, one of [system, dial, disabled] (defaults to 'system')")

var dstName string
var dstCfg DestinationConfig
Expand Down Expand Up @@ -218,6 +220,21 @@ func clientRun(ctx context.Context, cfg ClientConfig, logger *slog.Logger) error
}
opts = append(opts, connet.NatPMPConfig(pmpCfg))

var pcpCfg nat.PCPConfig
switch cfg.NatPCP {
case "", "system":
pcpCfg.LocalResolver = nat.LocalIPSystemResolver()
pcpCfg.GatewayResolver = nat.GatewayIPSystemResolver()
case "disabled":
pcpCfg.Disabled = true
case "dial":
pcpCfg.LocalResolver = nat.LocalIPDialResolver(cfg.ServerAddr)
pcpCfg.GatewayResolver = nat.GatewayIPNet24Resolver()
default:
return fmt.Errorf("invalid Nat-PCP config option: %s", cfg.NatPCP)
}
opts = append(opts, connet.NatPCPConfig(pcpCfg))

if cfg.HandshakeIdleTimeout > 0 {
opts = append(opts, connet.HandshakeIdleTimeout(cfg.HandshakeIdleTimeout.get()))
}
Expand Down Expand Up @@ -566,6 +583,7 @@ func (c *ClientConfig) merge(o ClientConfig) {

c.StatusAddr = override(c.StatusAddr, o.StatusAddr)
c.NatPMP = override(c.NatPMP, o.NatPMP)
c.NatPCP = override(c.NatPCP, o.NatPCP)
c.HandshakeIdleTimeout = override(c.HandshakeIdleTimeout, o.HandshakeIdleTimeout)

c.RelayEncryptions = overrides(c.RelayEncryptions, o.RelayEncryptions)
Expand Down
13 changes: 13 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type config struct {
directResetKey *quic.StatelessResetKey

natPMP nat.PMPConfig
natPCP nat.PCPConfig
handshakeIdleTimeout time.Duration

logger *slog.Logger
Expand All @@ -40,6 +41,10 @@ func newConfig(opts []Option) (*config, error) {
LocalResolver: nat.LocalIPSystemResolver(),
GatewayResolver: nat.GatewayIPSystemResolver(),
},
natPCP: nat.PCPConfig{
LocalResolver: nat.LocalIPSystemResolver(),
GatewayResolver: nat.GatewayIPSystemResolver(),
},
logger: slog.Default(),
}
for _, opt := range opts {
Expand Down Expand Up @@ -287,6 +292,14 @@ func NatPMPConfig(pmp nat.PMPConfig) Option {
}
}

// NatPCPConfig configures NAT-PCP behavior
func NatPCPConfig(pcp nat.PCPConfig) Option {
return func(cfg *config) error {
cfg.natPCP = pcp
return nil
}
}

// HandshakeIdleTimeout configures the handshake idle timeout to use by default when connecting to control/relay/peers
func HandshakeIdleTimeout(d time.Duration) Option {
return func(cfg *config) error {
Expand Down
Loading