mirror of
https://github.com/xmdhs/natupnp.git
synced 2025-09-27 03:15:53 +08:00
85 lines
1.8 KiB
Go
85 lines
1.8 KiB
Go
package natmap
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"net/netip"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/xmdhs/natupnp/reuse"
|
|
)
|
|
|
|
func NatMapUdp(ctx context.Context, stunAddr string, laddr netip.AddrPort, log func(error)) (*Map, netip.AddrPort, error) {
|
|
m := Map{}
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
m.cancel = cancel
|
|
|
|
mapAddr, err := getPubulicPort(ctx, stunAddr, laddr, false)
|
|
if err != nil {
|
|
return nil, netip.AddrPort{}, fmt.Errorf("NatMap: %w", err)
|
|
}
|
|
go keepaliveUDP(ctx, laddr, log)
|
|
return &m, mapAddr, nil
|
|
|
|
}
|
|
|
|
func keepaliveUDP(ctx context.Context, laddr netip.AddrPort, log func(error)) {
|
|
raddr := "223.5.5.5:53"
|
|
if laddr.Addr().Is6() {
|
|
raddr = "[2400:3200::1]:53"
|
|
}
|
|
r := net.Resolver{
|
|
PreferGo: true,
|
|
Dial: func(context context.Context, network, address string) (net.Conn, error) {
|
|
conn, err := reuse.DialContext(context, "udp", laddr.String(), raddr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return conn, nil
|
|
},
|
|
}
|
|
for {
|
|
func() {
|
|
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
|
defer cancel()
|
|
_, err := r.LookupNetIP(ctx, "ip4", "baidu.com")
|
|
if err != nil {
|
|
log(err)
|
|
return
|
|
}
|
|
defer time.Sleep(10 * time.Second)
|
|
}()
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
default:
|
|
}
|
|
}
|
|
}
|
|
|
|
type logger struct {
|
|
log func(string)
|
|
}
|
|
|
|
func (l logger) Println(v ...any) {
|
|
build := &strings.Builder{}
|
|
fmt.Fprint(build, v...)
|
|
l.log(build.String())
|
|
}
|
|
|
|
func ForwardUdp(ctx context.Context, laddr netip.AddrPort, target string, log func(string)) (io.Closer, error) {
|
|
lc, err := reuse.ListenPacket(ctx, "udp", laddr.String())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
f, err := forward(WithLogger(logger{log}), WithConn(lc.(*net.UDPConn)), WithDestination(target))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("ForwardUdp: %w", err)
|
|
}
|
|
return f, nil
|
|
}
|