diff --git a/cmd/yggstack/main.go b/cmd/yggstack/main.go index c68be3e5..d4d6c89d 100644 --- a/cmd/yggstack/main.go +++ b/cmd/yggstack/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "crypto/ed25519" "encoding/hex" "encoding/json" @@ -15,6 +16,7 @@ import ( "github.com/gologme/log" gsyslog "github.com/hashicorp/go-syslog" "github.com/hjson/hjson-go" + "github.com/things-go/go-socks5" "github.com/yggdrasil-network/yggdrasil-go/contrib/netstack" "github.com/yggdrasil-network/yggdrasil-go/src/address" @@ -27,8 +29,19 @@ import ( _ "net/http/pprof" ) +type nameResolver struct{} + +func (r *nameResolver) Resolve(ctx context.Context, name string) (context.Context, net.IP, error) { + ip := net.ParseIP(name) + if ip == nil { + return nil, nil, fmt.Errorf("not a valid IP address") + } + return ctx, ip, nil +} + // The main function is responsible for configuring and starting Yggdrasil. func main() { + socks := flag.String("socks", "", "address to listen on for SOCKS, i.e. :1080") args := setup.ParseArguments() // Create a new logger that logs output to stdout. @@ -148,12 +161,21 @@ func main() { logger.Fatalln(err) } + if *socks != "" { + resolver := &nameResolver{} + server := socks5.NewServer( + socks5.WithDial(s.DialContext), + socks5.WithResolver(resolver), + ) + go server.ListenAndServe("tcp", *socks) // nolint:errcheck + } + listener, err := s.ListenTCP(&net.TCPAddr{Port: 80}) if err != nil { log.Panicln(err) } http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { - _, _ = io.WriteString(writer, "Hello from userspace TCP "+request.RemoteAddr) + _, _ = io.WriteString(writer, "I am Yggstack!") }) httpServer := &http.Server{} go httpServer.Serve(listener) // nolint:errcheck diff --git a/contrib/netstack/netstack.go b/contrib/netstack/netstack.go index 21177aee..7cf24044 100644 --- a/contrib/netstack/netstack.go +++ b/contrib/netstack/netstack.go @@ -1,8 +1,10 @@ package netstack import ( + "context" "fmt" "net" + "strconv" "github.com/yggdrasil-network/yggdrasil-go/src/core" @@ -38,30 +40,59 @@ func CreateYggdrasilNetstack(ygg *core.Core) (*YggdrasilNetstack, error) { return s, nil } -func convertToFullAddr(ip net.IP, port int) (tcpip.FullAddress, tcpip.NetworkProtocolNumber) { +func convertToFullAddr(ip net.IP, port int) (tcpip.FullAddress, tcpip.NetworkProtocolNumber, error) { return tcpip.FullAddress{ NIC: 1, Addr: tcpip.Address(ip), Port: uint16(port), - }, ipv6.ProtocolNumber + }, ipv6.ProtocolNumber, nil +} + +func convertToFullAddrFromString(endpoint string) (tcpip.FullAddress, tcpip.NetworkProtocolNumber, error) { + host, port, err := net.SplitHostPort(endpoint) + if err != nil { + return tcpip.FullAddress{}, 0, fmt.Errorf("net.SplitHostPort: %w", err) + } + pn := 80 + if port != "" { + if pn, err = strconv.Atoi(port); err != nil { + return tcpip.FullAddress{}, 0, fmt.Errorf("strconv.Atoi: %w", err) + } + } + return convertToFullAddr(net.ParseIP(host), pn) +} + +func (s *YggdrasilNetstack) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + fa, pn, err := convertToFullAddrFromString(address) + if err != nil { + return nil, fmt.Errorf("convertToFullAddrFromString: %w", err) + } + switch network { + case "tcp", "tcp6": + return gonet.DialContextTCP(ctx, s.stack, fa, pn) + case "udp", "udp6": + return gonet.DialUDP(s.stack, nil, &fa, pn) + default: + return nil, fmt.Errorf("not supported") + } } func (s *YggdrasilNetstack) DialTCP(addr *net.TCPAddr) (net.Conn, error) { - fa, pn := convertToFullAddr(addr.IP, addr.Port) + fa, pn, _ := convertToFullAddr(addr.IP, addr.Port) return gonet.DialTCP(s.stack, fa, pn) } func (s *YggdrasilNetstack) DialUDP(addr *net.UDPAddr) (net.PacketConn, error) { - fa, pn := convertToFullAddr(addr.IP, addr.Port) + fa, pn, _ := convertToFullAddr(addr.IP, addr.Port) return gonet.DialUDP(s.stack, nil, &fa, pn) } func (s *YggdrasilNetstack) ListenTCP(addr *net.TCPAddr) (net.Listener, error) { - fa, pn := convertToFullAddr(addr.IP, addr.Port) + fa, pn, _ := convertToFullAddr(addr.IP, addr.Port) return gonet.ListenTCP(s.stack, fa, pn) } func (s *YggdrasilNetstack) ListenUDP(addr *net.UDPAddr) (net.PacketConn, error) { - fa, pn := convertToFullAddr(addr.IP, addr.Port) + fa, pn, _ := convertToFullAddr(addr.IP, addr.Port) return gonet.DialUDP(s.stack, &fa, nil, pn) }