Files
natupnp/natmap/udp.go
2024-01-24 23:58:25 +08:00

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
}