diff --git a/Makefile b/Makefile index 01794dc..887aa3b 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,7 @@ SRCS=\ server.go \ server-ctl.go \ server-peer.go \ + server-proxy.go \ server-ws.go \ system.go diff --git a/client-ctl.go b/client-ctl.go index 9776161..e5f28a2 100644 --- a/client-ctl.go +++ b/client-ctl.go @@ -5,6 +5,7 @@ import "net/http" import "net/url" import "runtime" import "strconv" +import "unsafe" /* * POST GET PUT DELETE @@ -31,8 +32,9 @@ type json_in_client_conn struct { type json_in_client_route struct { ClientPeerAddr string `json:"client-peer-addr"` - ServerPeerNet string `json:"server-peer-net"` // allowed network in prefix notation - ServerPeerProto ROUTE_PROTO `json:"server-peer-proto"` + ServerPeerOption string `json:"server-peer-option"` + ServerPeerServiceAddr string `json:"server-peer-service-addr"` // desired listening address on the server side + ServerPeerServiceNet string `json:"server-peer-service-net"` // permitted network in prefix notation } type json_out_client_conn_id struct { @@ -55,9 +57,9 @@ type json_out_client_route_id struct { type json_out_client_route struct { Id RouteId `json:"id"` ClientPeerAddr string `json:"client-peer-addr"` - ServerPeerListenAddr string `json:"server-peer-listen-addr"` - ServerPeerNet string `json:"server-peer-net"` - ServerPeerProto ROUTE_PROTO `json:"server-peer-proto"` + ServerPeerOption string `json:"server-peer-option"` + ServerPeerListenAddr string `json:"server-peer-service-addr"` + ServerPeerNet string `json:"server-peer-service-net"` } type json_out_client_peer struct { @@ -152,7 +154,7 @@ func (ctl *client_ctl_client_conns) ServeHTTP(w http.ResponseWriter, req *http.R ClientPeerAddr: r.peer_addr, ServerPeerListenAddr: r.server_peer_listen_addr.String(), ServerPeerNet: r.server_peer_net, - ServerPeerProto: r.server_peer_proto, + ServerPeerOption: r.server_peer_proto.string(), }) } js = append(js, json_out_client_conn{ @@ -242,7 +244,7 @@ func (ctl *client_ctl_client_conns_id) ServeHTTP(w http.ResponseWriter, req *htt conn_id = req.PathValue("conn_id") - conn_nid, err = strconv.ParseUint(conn_id, 10, 32) + conn_nid, err = strconv.ParseUint(conn_id, 10, int(unsafe.Sizeof(conn_nid) * 8)) if err != nil { status_code = http.StatusBadRequest; w.WriteHeader(status_code) if err = je.Encode(json_errmsg{Text: "wrong connection id - " + conn_id}); err != nil { goto oops } @@ -270,7 +272,7 @@ func (ctl *client_ctl_client_conns_id) ServeHTTP(w http.ResponseWriter, req *htt ClientPeerAddr: r.peer_addr, ServerPeerListenAddr: r.server_peer_listen_addr.String(), ServerPeerNet: r.server_peer_net, - ServerPeerProto: r.server_peer_proto, + ServerPeerOption: r.server_peer_proto.string(), }) } js = &json_out_client_conn{ @@ -326,10 +328,10 @@ func (ctl *client_ctl_client_conns_id_routes) ServeHTTP(w http.ResponseWriter, r conn_id = req.PathValue("conn_id") - conn_nid, err = strconv.ParseUint(conn_id, 10, 32) + conn_nid, err = strconv.ParseUint(conn_id, 10, int(unsafe.Sizeof(conn_nid) * 8)) if err != nil { status_code = http.StatusBadRequest; w.WriteHeader(status_code) - if err = je.Encode(json_errmsg{Text: "wrong connection id - " + conn_id}); err != nil { goto oops } + if err = je.Encode(json_errmsg{Text: "wrong connection id - " + conn_id }); err != nil { goto oops } goto done } @@ -353,7 +355,7 @@ func (ctl *client_ctl_client_conns_id_routes) ServeHTTP(w http.ResponseWriter, r ClientPeerAddr: r.peer_addr, ServerPeerListenAddr: r.server_peer_listen_addr.String(), ServerPeerNet: r.server_peer_net, - ServerPeerProto: r.server_peer_proto, + ServerPeerOption: r.server_peer_proto.string(), }) } cts.route_mtx.Unlock() @@ -364,14 +366,21 @@ func (ctl *client_ctl_client_conns_id_routes) ServeHTTP(w http.ResponseWriter, r case http.MethodPost: var jcr json_in_client_route var r *ClientRoute + var server_peer_proto RouteOption err = json.NewDecoder(req.Body).Decode(&jcr) - if err != nil || jcr.ClientPeerAddr == "" || jcr.ServerPeerProto < 0 || jcr.ServerPeerProto > ROUTE_PROTO_TCP6 { + if err != nil || jcr.ClientPeerAddr == "" { status_code = http.StatusBadRequest; w.WriteHeader(status_code) goto done } - r, err = cts.AddNewClientRoute(jcr.ClientPeerAddr, jcr.ServerPeerNet, jcr.ServerPeerProto) + server_peer_proto = string_to_route_proto(jcr.ServerPeerOption) + if server_peer_proto == RouteOption(ROUTE_OPTION_UNSPEC) { + status_code = http.StatusBadRequest; w.WriteHeader(status_code) + goto done + } + + r, err = cts.AddNewClientRoute(jcr.ClientPeerAddr, jcr.ServerPeerServiceAddr, jcr.ServerPeerServiceNet, server_peer_proto) if err != nil { status_code = http.StatusInternalServerError; w.WriteHeader(status_code) if err = je.Encode(json_errmsg{Text: err.Error()}); err != nil { goto oops } @@ -424,13 +433,13 @@ func (ctl *client_ctl_client_conns_id_routes_id) ServeHTTP(w http.ResponseWriter conn_id = req.PathValue("conn_id") route_id = req.PathValue("route_id") - conn_nid, err = strconv.ParseUint(conn_id, 10, 32) + conn_nid, err = strconv.ParseUint(conn_id, 10, int(unsafe.Sizeof(conn_nid) * 8)) if err != nil { status_code = http.StatusBadRequest; w.WriteHeader(status_code) if err = je.Encode(json_errmsg{Text: "wrong connection id - " + conn_id}); err != nil { goto oops } goto done } - route_nid, err = strconv.ParseUint(route_id, 10, 32) + route_nid, err = strconv.ParseUint(route_id, 10, int(unsafe.Sizeof(route_nid) * 8)) if err != nil { status_code = http.StatusBadRequest; w.WriteHeader(status_code) if err = je.Encode(json_errmsg{Text: "wrong route id - " + route_id}); err != nil { goto oops } @@ -459,7 +468,7 @@ func (ctl *client_ctl_client_conns_id_routes_id) ServeHTTP(w http.ResponseWriter ClientPeerAddr: r.peer_addr, ServerPeerListenAddr: r.server_peer_listen_addr.String(), ServerPeerNet: r.server_peer_net, - ServerPeerProto: r.server_peer_proto, + ServerPeerOption: r.server_peer_proto.string(), }) if err != nil { goto oops } @@ -511,7 +520,7 @@ func (ctl *client_ctl_client_conns_id_routes_id_peers) ServeHTTP(w http.Response if err = je.Encode(json_errmsg{Text: "wrong connection id - " + conn_id}); err != nil { goto oops } goto done } - route_nid, err = strconv.ParseUint(route_id, 10, 32) + route_nid, err = strconv.ParseUint(route_id, 10, int(unsafe.Sizeof(route_nid) * 8)) if err != nil { status_code = http.StatusBadRequest; w.WriteHeader(status_code) if err = je.Encode(json_errmsg{Text: "wrong route id - " + route_id}); err != nil { goto oops } @@ -595,7 +604,7 @@ func (ctl *client_ctl_client_conns_id_routes_id_peers_id) ServeHTTP(w http.Respo if err = je.Encode(json_errmsg{Text: "wrong connection id - " + conn_id}); err != nil { goto oops } goto done } - route_nid, err = strconv.ParseUint(route_id, 10, 32) + route_nid, err = strconv.ParseUint(route_id, 10, int(unsafe.Sizeof(route_nid) * 8)) if err != nil { status_code = http.StatusBadRequest; w.WriteHeader(status_code) if err = je.Encode(json_errmsg{Text: "wrong route id - " + route_id}); err != nil { goto oops } diff --git a/client-peer.go b/client-peer.go index efb49b7..e716d61 100644 --- a/client-peer.go +++ b/client-peer.go @@ -3,6 +3,7 @@ package hodu import "errors" import "io" import "net" +import "strings" import "sync" func NewClientPeerConn(r *ClientRoute, c *net.TCPConn, id PeerId, pts_raddr string, pts_laddr string) *ClientPeerConn { @@ -29,7 +30,7 @@ func (cpc *ClientPeerConn) RunTask(wg *sync.WaitGroup) error { for { n, err = cpc.conn.Read(buf[:]) if err != nil { - if errors.Is(err, io.EOF) { + if errors.Is(err, io.EOF) || strings.Contains(err.Error(), "use of closed network connection") { // i hate checking this condition with strings.Contains() cpc.route.cts.cli.log.Write(cpc.route.cts.sid, LOG_INFO, "Client-side peer(%d,%d,%s,%s) closed", cpc.route.id, cpc.conn_id, cpc.conn.RemoteAddr().String(), cpc.conn.LocalAddr().String()) diff --git a/client.go b/client.go index 45a09d1..89a1842 100644 --- a/client.go +++ b/client.go @@ -8,6 +8,7 @@ import "log" import "math/rand" import "net" import "net/http" +import "strings" import "sync" import "sync/atomic" import "time" @@ -101,9 +102,12 @@ type ClientRoute struct { cts *ClientConn id RouteId peer_addr string - server_peer_listen_addr *net.TCPAddr + peer_proto RouteOption + + server_peer_listen_addr *net.TCPAddr // actual service-side service address + server_peer_addr string // desired server-side service address server_peer_net string - server_peer_proto ROUTE_PROTO + server_peer_proto RouteOption ptc_mtx sync.Mutex ptc_map ClientPeerConnMap @@ -151,7 +155,7 @@ func (g *GuardedPacketStreamClient) Context() context.Context { }*/ // -------------------------------------------------------------------- -func NewClientRoute(cts *ClientConn, id RouteId, client_peer_addr string, server_peer_net string, server_peer_proto ROUTE_PROTO) *ClientRoute { +func NewClientRoute(cts *ClientConn, id RouteId, client_peer_addr string, server_peer_svc_addr string, server_peer_svc_net string, server_peer_proto RouteOption) *ClientRoute { var r ClientRoute r.cts = cts @@ -159,7 +163,11 @@ func NewClientRoute(cts *ClientConn, id RouteId, client_peer_addr string, server r.ptc_map = make(ClientPeerConnMap) r.ptc_cancel_map = make(ClientPeerCancelFuncMap) r.peer_addr = client_peer_addr // client-side peer - r.server_peer_net = server_peer_net // permitted network for server-side peer + // if the client_peer_addr is a domain name, it can't tell between tcp4 and tcp6 + r.peer_proto = string_to_route_proto(tcp_addr_str_class(client_peer_addr)) + + r.server_peer_addr = server_peer_svc_addr + r.server_peer_net = server_peer_svc_net // permitted network for server-side peer r.server_peer_proto = server_peer_proto r.stop_req.Store(false) r.stop_chan = make(chan bool, 8) @@ -249,7 +257,7 @@ func (r *ClientRoute) RunTask(wg *sync.WaitGroup) { // most useful works are triggered by ReportEvent() and done by ConnectToPeer() defer wg.Done() - err = r.cts.psc.Send(MakeRouteStartPacket(r.id, r.server_peer_proto, r.peer_addr, r.server_peer_net)) + err = r.cts.psc.Send(MakeRouteStartPacket(r.id, r.server_peer_proto, r.peer_addr, r.server_peer_addr, r.server_peer_net)) if err != nil { r.cts.cli.log.Write(r.cts.sid, LOG_DEBUG, "Failed to send route_start for route(%d,%s,%v,%v) to %s", @@ -273,7 +281,7 @@ done: r.ReqStop() r.ptc_wg.Wait() // wait for all peer tasks are finished - err = r.cts.psc.Send(MakeRouteStopPacket(r.id, r.server_peer_proto, r.peer_addr, r.server_peer_net)) + err = r.cts.psc.Send(MakeRouteStopPacket(r.id, r.server_peer_proto, r.peer_addr, r.server_peer_addr, r.server_peer_net)) if err != nil { r.cts.cli.log.Write(r.cts.sid, LOG_DEBUG, "Failed to route_stop for route(%d,%s,%v,%v) to %s - %s", @@ -297,7 +305,7 @@ func (r *ClientRoute) ReqStop() { } } -func (r *ClientRoute) ConnectToPeer(pts_id PeerId, pts_raddr string, pts_laddr string, wg *sync.WaitGroup) { +func (r *ClientRoute) ConnectToPeer(pts_id PeerId, route_proto RouteOption, pts_raddr string, pts_laddr string, wg *sync.WaitGroup) { var err error var conn net.Conn var real_conn *net.TCPConn @@ -310,10 +318,14 @@ func (r *ClientRoute) ConnectToPeer(pts_id PeerId, pts_raddr string, pts_laddr s var tmout time.Duration var ok bool +// TODO: handle TTY +// if route_proto & RouteOption(ROUTE_OPTION_TTY) it must create a pseudo-tty insteaad of connecting to tcp address +// + defer wg.Done() tmout = time.Duration(r.cts.cli.ptc_tmout) - if tmout < 0 { tmout = 10 * time.Second} + if tmout <= 0 { tmout = 10 * time.Second} ctx, cancel = context.WithTimeout(r.cts.cli.ctx, tmout) r.ptc_mtx.Lock() r.ptc_cancel_map[pts_id] = cancel @@ -458,7 +470,7 @@ func (r *ClientRoute) ReportEvent(pts_id PeerId, event_type PACKET_KIND, event_d } } else { r.ptc_wg.Add(1) - go r.ConnectToPeer(pts_id, pd.RemoteAddrStr, pd.LocalAddrStr, &r.ptc_wg) + go r.ConnectToPeer(pts_id, r.peer_proto, pd.RemoteAddrStr, pd.LocalAddrStr, &r.ptc_wg) } } @@ -577,7 +589,7 @@ func NewClientConn(c *Client, cfg *ClientConfig) *ClientConn { return &cts } -func (cts *ClientConn) AddNewClientRoute(addr string, server_peer_net string, proto ROUTE_PROTO) (*ClientRoute, error) { +func (cts *ClientConn) AddNewClientRoute(addr string, server_peer_svc_addr string, server_peer_svc_net string, option RouteOption) (*ClientRoute, error) { var r *ClientRoute var id RouteId var nattempts RouteId @@ -599,11 +611,7 @@ func (cts *ClientConn) AddNewClientRoute(addr string, server_peer_net string, pr } } - //if cts.route_map[route_id] != nil { - // cts.route_mtx.Unlock() - // return nil, fmt.Errorf("existent route id - %d", route_id) - //} - r = NewClientRoute(cts, id, addr, server_peer_net, proto) + r = NewClientRoute(cts, id, addr, server_peer_svc_addr, server_peer_svc_net, option) cts.route_map[id] = r cts.cli.stats.routes.Add(1) cts.route_mtx.Unlock() @@ -701,10 +709,41 @@ func (cts *ClientConn) FindClientRouteById(route_id RouteId) *ClientRoute { func (cts *ClientConn) AddClientRoutes(peer_addrs []string) error { var v string + var port string + var option RouteOption + var va []string + var svc_addr string var err error for _, v = range peer_addrs { - _, err = cts.AddNewClientRoute(v, "", ROUTE_PROTO_TCP) + va = strings.Split(v, ",") + if len(va) <= 0 || len(va) > 2 { + return fmt.Errorf("invalid address %s") + } + + _, port, err = net.SplitHostPort(va[0]) + if err != nil { + return fmt.Errorf("invalid address %s", va[0], err.Error()) + } + + if len(va) >= 2 { + _, _, err = net.SplitHostPort(va[1]) + if err != nil { + return fmt.Errorf("invalid address %s", va[1], err.Error()) + } + svc_addr = va[1] + } + + option = RouteOption(ROUTE_OPTION_TCP) + // automatic determination of optioncol for common ports + switch port { + case "80": + option |= RouteOption(ROUTE_OPTION_HTTP) + case "443": + option |= RouteOption(ROUTE_OPTION_HTTPS) + } + + _, err = cts.AddNewClientRoute(va[0], svc_addr, "", option) if err != nil { return fmt.Errorf("unable to add client route for %s - %s", v, err.Error()) } diff --git a/cmd/config.go b/cmd/config.go index 987cbfd..f846ac7 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -47,6 +47,10 @@ type CTLServiceConfig struct { Addrs []string `yaml:"addresses"` } +type PXYServiceConfig struct { + Addrs []string `yaml:"addresses"` +} + type RPCServiceConfig struct { // rpc server-side configuration Addrs []string `yaml:"addresses"` } @@ -80,6 +84,11 @@ type ServerConfig struct { TLS ServerTLSConfig `yaml:"tls"` } `yaml:"ctl"` + PXY struct { + Service PXYServiceConfig `yaml:"service"` + TLS ServerTLSConfig `yaml:"tls"` + } `yaml:"pxy"` + RPC struct { Service RPCServiceConfig `yaml:"service"` TLS ServerTLSConfig `yaml:"tls"` diff --git a/cmd/main.go b/cmd/main.go index 6c4d5e5..683a40a 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -143,10 +143,11 @@ func (sh *signal_handler) WriteLog(id string, level hodu.LogLevel, fmt string, a // -------------------------------------------------------------------- -func server_main(ctl_addrs []string, rpc_addrs []string, cfg *ServerConfig) error { +func server_main(ctl_addrs []string, rpc_addrs []string, pxy_addrs []string, cfg *ServerConfig) error { var s *hodu.Server var ctltlscfg *tls.Config var rpctlscfg *tls.Config + var pxytlscfg *tls.Config var ctl_prefix string var logger *AppLogger var log_mask hodu.LogMask @@ -158,13 +159,11 @@ func server_main(ctl_addrs []string, rpc_addrs []string, cfg *ServerConfig) erro if cfg != nil { ctltlscfg, err = make_tls_server_config(&cfg.CTL.TLS) - if err != nil { - return err - } + if err != nil { return err } rpctlscfg, err = make_tls_server_config(&cfg.RPC.TLS) - if err != nil { - return err - } + if err != nil { return err } + pxytlscfg, err = make_tls_server_config(&cfg.PXY.TLS) + if err != nil { return err } if len(ctl_addrs) <= 0 { ctl_addrs = cfg.CTL.Service.Addrs @@ -174,6 +173,10 @@ func server_main(ctl_addrs []string, rpc_addrs []string, cfg *ServerConfig) erro rpc_addrs = cfg.RPC.Service.Addrs } + if len(pxy_addrs) <= 0 { + pxy_addrs = cfg.PXY.Service.Addrs + } + ctl_prefix = cfg.CTL.Service.Prefix log_mask = log_strings_to_mask(cfg.APP.LogMask) max_rpc_conns = cfg.APP.MaxRpcConns @@ -191,9 +194,11 @@ func server_main(ctl_addrs []string, rpc_addrs []string, cfg *ServerConfig) erro logger, ctl_addrs, rpc_addrs, + pxy_addrs, ctl_prefix, ctltlscfg, rpctlscfg, + pxytlscfg, max_rpc_conns, max_peers) if err != nil { @@ -202,6 +207,7 @@ func server_main(ctl_addrs []string, rpc_addrs []string, cfg *ServerConfig) erro s.StartService(nil) s.StartCtlService() + s.StartPxyService() s.StartExtService(&signal_handler{svc:s}, nil) s.WaitForTermination() @@ -278,13 +284,15 @@ func main() { if len(os.Args) < 2 { goto wrong_usage } if strings.EqualFold(os.Args[1], "server") { - var rpc_addrs[] string - var ctl_addrs[] string + var rpc_addrs []string + var ctl_addrs []string + var pxy_addrs []string var cfgfile string var cfg *ServerConfig ctl_addrs = make([]string, 0) rpc_addrs = make([]string, 0) + pxy_addrs = make([]string, 0) flgs = flag.NewFlagSet("", flag.ContinueOnError) flgs.Func("ctl-on", "specify a listening address for control channel", func(v string) error { @@ -295,6 +303,10 @@ func main() { rpc_addrs = append(rpc_addrs, v) return nil }) + flgs.Func("pxy-on", "specify a proxy listening address", func(v string) error { + pxy_addrs = append(pxy_addrs, v) + return nil + }) flgs.Func("config-file", "specify a configuration file path", func(v string) error { cfgfile = v return nil @@ -317,7 +329,7 @@ func main() { } } - err = server_main(ctl_addrs, rpc_addrs, cfg) + err = server_main(ctl_addrs, rpc_addrs, pxy_addrs, cfg) if err != nil { fmt.Fprintf(os.Stderr, "ERROR: server error - %s\n", err.Error()) goto oops diff --git a/hodu.go b/hodu.go index 747a1b0..30b3430 100644 --- a/hodu.go +++ b/hodu.go @@ -1,10 +1,13 @@ package hodu import "net/http" +import "net/netip" import "os" import "runtime" +import "strings" import "sync" + const HODU_RPC_VERSION uint32 = 0x010000 type LogLevel int @@ -20,6 +23,9 @@ const ( const LOG_ALL LogMask = LogMask(LOG_DEBUG | LOG_INFO | LOG_WARN | LOG_ERROR) const LOG_NONE LogMask = LogMask(0) +var IPV4_PREFIX_ZERO = netip.MustParsePrefix("0.0.0.0/0") +var IPV6_PREFIX_ZERO = netip.MustParsePrefix("::/0") + type Logger interface { Write(id string, level LogLevel, fmtstr string, args ...interface{}) } @@ -33,20 +39,68 @@ type Service interface { } func tcp_addr_str_class(addr string) string { + // the string is supposed to be addr:port + if len(addr) > 0 { - switch addr[0] { - case '[': - return "tcp6" - case ':': - return "tcp" - default: - return "tcp4" + var ap netip.AddrPort + var err error + ap, err = netip.ParseAddrPort(addr) + if err == nil { + if ap.Addr().Is6() { return "tcp6" } + if ap.Addr().Is4() { return "tcp4" } } } return "tcp" } +func word_to_route_proto(word string) RouteOption { + switch word { + case "tcp4": + return RouteOption(ROUTE_OPTION_TCP4) + case "tcp6": + return RouteOption(ROUTE_OPTION_TCP6) + case "tcp": + return RouteOption(ROUTE_OPTION_TCP) + case "tty": + return RouteOption(ROUTE_OPTION_TTY) + case "http": + return RouteOption(ROUTE_OPTION_HTTP) + case "https": + return RouteOption(ROUTE_OPTION_HTTPS) + } + + return RouteOption(ROUTE_OPTION_UNSPEC) +} + +func string_to_route_proto(desc string) RouteOption { + var fld string + var proto RouteOption + var p RouteOption + + proto = RouteOption(0) + for _, fld = range strings.Fields(desc) { + p = word_to_route_proto(fld) + if p == RouteOption(ROUTE_OPTION_UNSPEC) { return p } + proto |= p + } + return proto +} + +func (proto RouteOption) string() string { + var str string + + str = "" + if proto & RouteOption(ROUTE_OPTION_TCP6) != 0 { str += " tcp6" } + if proto & RouteOption(ROUTE_OPTION_TCP4) != 0 { str += " tcp4" } + if proto & RouteOption(ROUTE_OPTION_TCP) != 0 { str += " tcp" } + if proto & RouteOption(ROUTE_OPTION_TTY) != 0 { str += " tty" } + if proto & RouteOption(ROUTE_OPTION_HTTP) != 0 { str += " http" } + if proto & RouteOption(ROUTE_OPTION_HTTPS) != 0 { str += " https" } + if str == "" { return str } + return str[1:] // remove the leading space +} + func dump_call_frame_and_exit(log Logger, req *http.Request, err interface{}) { var buf []byte buf = make([]byte, 65536); buf = buf[:min(65536, runtime.Stack(buf, false))] diff --git a/hodu.pb.go b/hodu.pb.go index 20a6898..cb347e8 100644 --- a/hodu.pb.go +++ b/hodu.pb.go @@ -20,52 +20,64 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -type ROUTE_PROTO int32 +type ROUTE_OPTION int32 const ( - ROUTE_PROTO_TCP ROUTE_PROTO = 0 - ROUTE_PROTO_TCP4 ROUTE_PROTO = 1 - ROUTE_PROTO_TCP6 ROUTE_PROTO = 2 + ROUTE_OPTION_UNSPEC ROUTE_OPTION = 0 + ROUTE_OPTION_TCP ROUTE_OPTION = 1 + ROUTE_OPTION_TCP4 ROUTE_OPTION = 2 + ROUTE_OPTION_TCP6 ROUTE_OPTION = 4 + ROUTE_OPTION_TTY ROUTE_OPTION = 8 + ROUTE_OPTION_HTTP ROUTE_OPTION = 16 + ROUTE_OPTION_HTTPS ROUTE_OPTION = 32 ) -// Enum value maps for ROUTE_PROTO. +// Enum value maps for ROUTE_OPTION. var ( - ROUTE_PROTO_name = map[int32]string{ - 0: "TCP", - 1: "TCP4", - 2: "TCP6", + ROUTE_OPTION_name = map[int32]string{ + 0: "UNSPEC", + 1: "TCP", + 2: "TCP4", + 4: "TCP6", + 8: "TTY", + 16: "HTTP", + 32: "HTTPS", } - ROUTE_PROTO_value = map[string]int32{ - "TCP": 0, - "TCP4": 1, - "TCP6": 2, + ROUTE_OPTION_value = map[string]int32{ + "UNSPEC": 0, + "TCP": 1, + "TCP4": 2, + "TCP6": 4, + "TTY": 8, + "HTTP": 16, + "HTTPS": 32, } ) -func (x ROUTE_PROTO) Enum() *ROUTE_PROTO { - p := new(ROUTE_PROTO) +func (x ROUTE_OPTION) Enum() *ROUTE_OPTION { + p := new(ROUTE_OPTION) *p = x return p } -func (x ROUTE_PROTO) String() string { +func (x ROUTE_OPTION) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (ROUTE_PROTO) Descriptor() protoreflect.EnumDescriptor { +func (ROUTE_OPTION) Descriptor() protoreflect.EnumDescriptor { return file_hodu_proto_enumTypes[0].Descriptor() } -func (ROUTE_PROTO) Type() protoreflect.EnumType { +func (ROUTE_OPTION) Type() protoreflect.EnumType { return &file_hodu_proto_enumTypes[0] } -func (x ROUTE_PROTO) Number() protoreflect.EnumNumber { +func (x ROUTE_OPTION) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } -// Deprecated: Use ROUTE_PROTO.Descriptor instead. -func (ROUTE_PROTO) EnumDescriptor() ([]byte, []int) { +// Deprecated: Use ROUTE_OPTION.Descriptor instead. +func (ROUTE_OPTION) EnumDescriptor() ([]byte, []int) { return file_hodu_proto_rawDescGZIP(), []int{0} } @@ -197,10 +209,23 @@ type RouteDesc struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - RouteId uint32 `protobuf:"varint,1,opt,name=RouteId,proto3" json:"RouteId,omitempty"` - TargetAddrStr string `protobuf:"bytes,2,opt,name=TargetAddrStr,proto3" json:"TargetAddrStr,omitempty"` - ServiceProto ROUTE_PROTO `protobuf:"varint,3,opt,name=ServiceProto,proto3,enum=ROUTE_PROTO" json:"ServiceProto,omitempty"` - ServiceNetStr string `protobuf:"bytes,4,opt,name=ServiceNetStr,proto3" json:"ServiceNetStr,omitempty"` + RouteId uint32 `protobuf:"varint,1,opt,name=RouteId,proto3" json:"RouteId,omitempty"` + // C->S(ROUTE_START): client-side peer address + // S->C(ROUTE_STARTED): server-side listening address + TargetAddrStr string `protobuf:"bytes,2,opt,name=TargetAddrStr,proto3" json:"TargetAddrStr,omitempty"` + // C->S(ROUTE_START): desired listening option on the server-side(e.g. tcp, tcp4, tcp6) + + // + // hint to the service-side peer(e.g. local) + + // hint to the client-side peer(e.g. tty, http, https) + // + // S->C(ROUTE_STARTED): cloned as sent by C. + ServiceOption uint32 `protobuf:"varint,3,opt,name=ServiceOption,proto3" json:"ServiceOption,omitempty"` + // C->S(ROUTE_START): desired lisening address on the service-side + // S->C(ROUTE_STARTED): cloned as sent by C + ServiceAddrStr string `protobuf:"bytes,4,opt,name=ServiceAddrStr,proto3" json:"ServiceAddrStr,omitempty"` + // C->S(ROUTE_START): permitted network of server-side peers. + // S->C(ROUTE_STARTED): cloned as sent by C. + ServiceNetStr string `protobuf:"bytes,5,opt,name=ServiceNetStr,proto3" json:"ServiceNetStr,omitempty"` } func (x *RouteDesc) Reset() { @@ -247,11 +272,18 @@ func (x *RouteDesc) GetTargetAddrStr() string { return "" } -func (x *RouteDesc) GetServiceProto() ROUTE_PROTO { +func (x *RouteDesc) GetServiceOption() uint32 { if x != nil { - return x.ServiceProto + return x.ServiceOption } - return ROUTE_PROTO_TCP + return 0 +} + +func (x *RouteDesc) GetServiceAddrStr() string { + if x != nil { + return x.ServiceAddrStr + } + return "" } func (x *RouteDesc) GetServiceNetStr() string { @@ -499,60 +531,65 @@ var file_hodu_proto_rawDesc = []byte{ 0x53, 0x65, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x46, - 0x6c, 0x61, 0x67, 0x73, 0x22, 0xa3, 0x01, 0x0a, 0x09, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x44, 0x65, + 0x6c, 0x61, 0x67, 0x73, 0x22, 0xbf, 0x01, 0x0a, 0x09, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x44, 0x65, 0x73, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x53, 0x74, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x53, - 0x74, 0x72, 0x12, 0x30, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x52, 0x4f, 0x55, 0x54, 0x45, - 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x52, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x24, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, - 0x65, 0x74, 0x53, 0x74, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x4e, 0x65, 0x74, 0x53, 0x74, 0x72, 0x22, 0x86, 0x01, 0x0a, 0x08, 0x50, - 0x65, 0x65, 0x72, 0x44, 0x65, 0x73, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x52, 0x6f, 0x75, 0x74, 0x65, - 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x49, - 0x64, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x06, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x52, 0x65, 0x6d, - 0x6f, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x53, 0x74, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x53, 0x74, 0x72, 0x12, - 0x22, 0x0a, 0x0c, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x53, 0x74, 0x72, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, - 0x53, 0x74, 0x72, 0x22, 0x50, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, - 0x18, 0x0a, 0x07, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x07, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x65, 0x65, - 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x50, 0x65, 0x65, 0x72, 0x49, - 0x64, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x04, 0x44, 0x61, 0x74, 0x61, 0x22, 0x95, 0x01, 0x0a, 0x06, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, - 0x12, 0x20, 0x0a, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, - 0x2e, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x52, 0x04, 0x4b, 0x69, - 0x6e, 0x64, 0x12, 0x22, 0x0a, 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0a, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x44, 0x65, 0x73, 0x63, 0x48, 0x00, 0x52, - 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x44, 0x65, 0x73, 0x63, 0x48, - 0x00, 0x52, 0x04, 0x50, 0x65, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, - 0x48, 0x00, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x42, 0x03, 0x0a, 0x01, 0x55, 0x2a, 0x2a, 0x0a, - 0x0b, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x12, 0x07, 0x0a, 0x03, - 0x54, 0x43, 0x50, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x54, 0x43, 0x50, 0x34, 0x10, 0x01, 0x12, - 0x08, 0x0a, 0x04, 0x54, 0x43, 0x50, 0x36, 0x10, 0x02, 0x2a, 0xb5, 0x01, 0x0a, 0x0b, 0x50, 0x41, - 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, 0x53, - 0x45, 0x52, 0x56, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x4f, 0x55, 0x54, 0x45, - 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x4f, 0x55, 0x54, - 0x45, 0x5f, 0x53, 0x54, 0x4f, 0x50, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x4f, 0x55, 0x54, - 0x45, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x52, - 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, 0x04, 0x12, 0x10, - 0x0a, 0x0c, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x05, - 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x45, 0x44, - 0x10, 0x06, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x41, 0x42, 0x4f, 0x52, 0x54, - 0x45, 0x44, 0x10, 0x07, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x45, 0x4f, 0x46, - 0x10, 0x08, 0x12, 0x0d, 0x0a, 0x09, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x10, - 0x09, 0x32, 0x49, 0x0a, 0x04, 0x48, 0x6f, 0x64, 0x75, 0x12, 0x19, 0x0a, 0x07, 0x47, 0x65, 0x74, - 0x53, 0x65, 0x65, 0x64, 0x12, 0x05, 0x2e, 0x53, 0x65, 0x65, 0x64, 0x1a, 0x05, 0x2e, 0x53, 0x65, - 0x65, 0x64, 0x22, 0x00, 0x12, 0x26, 0x0a, 0x0c, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x12, 0x07, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x1a, 0x07, 0x2e, - 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x08, 0x5a, 0x06, - 0x2e, 0x2f, 0x68, 0x6f, 0x64, 0x75, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x72, 0x12, 0x24, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0e, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x41, 0x64, 0x64, 0x72, 0x53, 0x74, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x64, 0x64, 0x72, 0x53, 0x74, 0x72, + 0x12, 0x24, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x65, 0x74, 0x53, 0x74, + 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x4e, 0x65, 0x74, 0x53, 0x74, 0x72, 0x22, 0x86, 0x01, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x44, + 0x65, 0x73, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, + 0x06, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x50, + 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, + 0x64, 0x64, 0x72, 0x53, 0x74, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x52, 0x65, + 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x53, 0x74, 0x72, 0x12, 0x22, 0x0a, 0x0c, 0x4c, + 0x6f, 0x63, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x53, 0x74, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x53, 0x74, 0x72, 0x22, + 0x50, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x52, + 0x6f, 0x75, 0x74, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x52, 0x6f, + 0x75, 0x74, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, + 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, + 0x61, 0x22, 0x95, 0x01, 0x0a, 0x06, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x20, 0x0a, 0x04, + 0x4b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x50, 0x41, 0x43, + 0x4b, 0x45, 0x54, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x52, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x22, + 0x0a, 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, + 0x52, 0x6f, 0x75, 0x74, 0x65, 0x44, 0x65, 0x73, 0x63, 0x48, 0x00, 0x52, 0x05, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x09, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x44, 0x65, 0x73, 0x63, 0x48, 0x00, 0x52, 0x04, 0x50, + 0x65, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x09, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x04, + 0x44, 0x61, 0x74, 0x61, 0x42, 0x03, 0x0a, 0x01, 0x55, 0x2a, 0x55, 0x0a, 0x0c, 0x52, 0x4f, 0x55, + 0x54, 0x45, 0x5f, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x10, 0x01, 0x12, 0x08, + 0x0a, 0x04, 0x54, 0x43, 0x50, 0x34, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x54, 0x43, 0x50, 0x36, + 0x10, 0x04, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x54, 0x59, 0x10, 0x08, 0x12, 0x08, 0x0a, 0x04, 0x48, + 0x54, 0x54, 0x50, 0x10, 0x10, 0x12, 0x09, 0x0a, 0x05, 0x48, 0x54, 0x54, 0x50, 0x53, 0x10, 0x20, + 0x2a, 0xb5, 0x01, 0x0a, 0x0b, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x4b, 0x49, 0x4e, 0x44, + 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, 0x53, 0x45, 0x52, 0x56, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0f, + 0x0a, 0x0b, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x01, 0x12, + 0x0e, 0x0a, 0x0a, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x4f, 0x50, 0x10, 0x02, 0x12, + 0x11, 0x0a, 0x0d, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, + 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x4f, 0x50, + 0x50, 0x45, 0x44, 0x10, 0x04, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, + 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x05, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x45, 0x45, 0x52, 0x5f, + 0x53, 0x54, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, 0x06, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x45, 0x45, + 0x52, 0x5f, 0x41, 0x42, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x07, 0x12, 0x0c, 0x0a, 0x08, 0x50, + 0x45, 0x45, 0x52, 0x5f, 0x45, 0x4f, 0x46, 0x10, 0x08, 0x12, 0x0d, 0x0a, 0x09, 0x50, 0x45, 0x45, + 0x52, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x10, 0x09, 0x32, 0x49, 0x0a, 0x04, 0x48, 0x6f, 0x64, 0x75, + 0x12, 0x19, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x53, 0x65, 0x65, 0x64, 0x12, 0x05, 0x2e, 0x53, 0x65, + 0x65, 0x64, 0x1a, 0x05, 0x2e, 0x53, 0x65, 0x65, 0x64, 0x22, 0x00, 0x12, 0x26, 0x0a, 0x0c, 0x50, + 0x61, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x07, 0x2e, 0x50, 0x61, + 0x63, 0x6b, 0x65, 0x74, 0x1a, 0x07, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x00, 0x28, + 0x01, 0x30, 0x01, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x2f, 0x68, 0x6f, 0x64, 0x75, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -570,7 +607,7 @@ func file_hodu_proto_rawDescGZIP() []byte { var file_hodu_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_hodu_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_hodu_proto_goTypes = []any{ - (ROUTE_PROTO)(0), // 0: ROUTE_PROTO + (ROUTE_OPTION)(0), // 0: ROUTE_OPTION (PACKET_KIND)(0), // 1: PACKET_KIND (*Seed)(nil), // 2: Seed (*RouteDesc)(nil), // 3: RouteDesc @@ -579,20 +616,19 @@ var file_hodu_proto_goTypes = []any{ (*Packet)(nil), // 6: Packet } var file_hodu_proto_depIdxs = []int32{ - 0, // 0: RouteDesc.ServiceProto:type_name -> ROUTE_PROTO - 1, // 1: Packet.Kind:type_name -> PACKET_KIND - 3, // 2: Packet.Route:type_name -> RouteDesc - 4, // 3: Packet.Peer:type_name -> PeerDesc - 5, // 4: Packet.Data:type_name -> PeerData - 2, // 5: Hodu.GetSeed:input_type -> Seed - 6, // 6: Hodu.PacketStream:input_type -> Packet - 2, // 7: Hodu.GetSeed:output_type -> Seed - 6, // 8: Hodu.PacketStream:output_type -> Packet - 7, // [7:9] is the sub-list for method output_type - 5, // [5:7] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name + 1, // 0: Packet.Kind:type_name -> PACKET_KIND + 3, // 1: Packet.Route:type_name -> RouteDesc + 4, // 2: Packet.Peer:type_name -> PeerDesc + 5, // 3: Packet.Data:type_name -> PeerData + 2, // 4: Hodu.GetSeed:input_type -> Seed + 6, // 5: Hodu.PacketStream:input_type -> Packet + 2, // 6: Hodu.GetSeed:output_type -> Seed + 6, // 7: Hodu.PacketStream:output_type -> Packet + 6, // [6:8] is the sub-list for method output_type + 4, // [4:6] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_hodu_proto_init() } diff --git a/hodu.proto b/hodu.proto index a23942a..4761621 100644 --- a/hodu.proto +++ b/hodu.proto @@ -18,17 +18,36 @@ message Seed { uint64 Flags = 2; } -enum ROUTE_PROTO { - TCP = 0; - TCP4 = 1; - TCP6 = 2; +enum ROUTE_OPTION { + UNSPEC = 0; + TCP = 1; + TCP4 = 2; + TCP6 = 4; + TTY = 8; + HTTP = 16; + HTTPS = 32; }; message RouteDesc { - uint32 RouteId = 1; - string TargetAddrStr = 2; - ROUTE_PROTO ServiceProto = 3; - string ServiceNetStr = 4; + uint32 RouteId = 1; + + // C->S(ROUTE_START): client-side peer address + // S->C(ROUTE_STARTED): server-side listening address + string TargetAddrStr = 2; + + // C->S(ROUTE_START): desired listening option on the server-side(e.g. tcp, tcp4, tcp6) + + // hint to the service-side peer(e.g. local) + + // hint to the client-side peer(e.g. tty, http, https) + // S->C(ROUTE_STARTED): cloned as sent by C. + uint32 ServiceOption = 3; + + // C->S(ROUTE_START): desired lisening address on the service-side + // S->C(ROUTE_STARTED): cloned as sent by C + string ServiceAddrStr = 4; + + // C->S(ROUTE_START): permitted network of server-side peers. + // S->C(ROUTE_STARTED): cloned as sent by C. + string ServiceNetStr = 5; }; message PeerDesc { diff --git a/packet.go b/packet.go index 1c04675..d125cc5 100644 --- a/packet.go +++ b/packet.go @@ -1,31 +1,32 @@ package hodu -type ConnId uint64 -type RouteId uint32 // keep this in sync with the type of RouteId in hodu.proto -type PeerId uint32 // keep this in sync with the type of RouteId in hodu.proto +type ConnId uint64 +type RouteId uint32 // keep this in sync with the type of RouteId in hodu.proto +type PeerId uint32 // keep this in sync with the type of RouteId in hodu.proto +type RouteOption uint32 -func MakeRouteStartPacket(route_id RouteId, proto ROUTE_PROTO, addr string, svcnet string) *Packet { +func MakeRouteStartPacket(route_id RouteId, proto RouteOption, ptc_addr string, svc_addr string, svc_net string) *Packet { return &Packet{ Kind: PACKET_KIND_ROUTE_START, - U: &Packet_Route{Route: &RouteDesc{RouteId: uint32(route_id), ServiceProto: proto, TargetAddrStr: addr, ServiceNetStr: svcnet}}} + U: &Packet_Route{Route: &RouteDesc{RouteId: uint32(route_id), ServiceOption: uint32(proto), TargetAddrStr: ptc_addr, ServiceAddrStr: svc_addr, ServiceNetStr: svc_net}}} } -func MakeRouteStopPacket(route_id RouteId, proto ROUTE_PROTO, addr string, svcnet string) *Packet { +func MakeRouteStopPacket(route_id RouteId, proto RouteOption, ptc_addr string, svc_addr string, svc_net string) *Packet { return &Packet{ Kind: PACKET_KIND_ROUTE_STOP, - U: &Packet_Route{Route: &RouteDesc{RouteId: uint32(route_id), ServiceProto: proto, TargetAddrStr: addr, ServiceNetStr: svcnet}}} + U: &Packet_Route{Route: &RouteDesc{RouteId: uint32(route_id), ServiceOption: uint32(proto), TargetAddrStr: ptc_addr, ServiceAddrStr: svc_addr, ServiceNetStr: svc_net}}} } -func MakeRouteStartedPacket(route_id RouteId, proto ROUTE_PROTO, addr string, svcnet string) *Packet { +func MakeRouteStartedPacket(route_id RouteId, proto RouteOption, addr string, svc_addr string, svc_net string) *Packet { // the connection from a peer to the server has been established return &Packet{Kind: PACKET_KIND_ROUTE_STARTED, - U: &Packet_Route{Route: &RouteDesc{RouteId: uint32(route_id), ServiceProto: proto, TargetAddrStr: addr, ServiceNetStr: svcnet}}} + U: &Packet_Route{Route: &RouteDesc{RouteId: uint32(route_id), ServiceOption: uint32(proto), TargetAddrStr: addr, ServiceAddrStr: svc_addr, ServiceNetStr: svc_net}}} } -func MakeRouteStoppedPacket(route_id RouteId, proto ROUTE_PROTO, addr string, svcnet string) *Packet { +func MakeRouteStoppedPacket(route_id RouteId, proto RouteOption, addr string, svc_addr string, svc_net string) *Packet { // the connection from a peer to the server has been established return &Packet{Kind: PACKET_KIND_ROUTE_STOPPED, - U: &Packet_Route{Route: &RouteDesc{RouteId: uint32(route_id), ServiceProto: proto, TargetAddrStr: addr, ServiceNetStr: svcnet}}} + U: &Packet_Route{Route: &RouteDesc{RouteId: uint32(route_id), ServiceOption: uint32(proto), TargetAddrStr: addr, ServiceAddrStr: svc_addr, ServiceNetStr: svc_net}}} } func MakePeerStartedPacket(route_id RouteId, peer_id PeerId, remote_addr string, local_addr string) *Packet { diff --git a/server-ctl.go b/server-ctl.go index 3c35a3d..9f6777a 100644 --- a/server-ctl.go +++ b/server-ctl.go @@ -4,6 +4,7 @@ import "encoding/json" import "net/http" import "runtime" import "strconv" +import "unsafe" type json_out_server_conn struct { Id ConnId `json:"id"` @@ -15,9 +16,9 @@ type json_out_server_conn struct { type json_out_server_route struct { Id RouteId `json:"id"` ClientPeerAddr string `json:"client-peer-addr"` - ServerPeerListenAddr string `json:"server-peer-listen-addr"` - ServerPeerNet string `json:"server-peer-net"` - ServerPeerProto ROUTE_PROTO `json:"server-peer-proto"` + ServerPeerOption string `json:"server-peer-option"` + ServerPeerServiceAddr string `json:"server-peer-service-addr"` // actual listening address + ServerPeerServiceNet string `json:"server-peer-service-net"` } type json_out_server_stats struct { @@ -94,9 +95,9 @@ func (ctl *server_ctl_server_conns) ServeHTTP(w http.ResponseWriter, req *http.R jsp = append(jsp, json_out_server_route{ Id: r.id, ClientPeerAddr: r.ptc_addr, - ServerPeerListenAddr: r.svc_addr.String(), - ServerPeerNet: r.svc_permitted_net.String(), - ServerPeerProto: r.svc_proto, + ServerPeerServiceAddr: r.svc_addr.String(), + ServerPeerServiceNet: r.svc_permitted_net.String(), + ServerPeerOption: r.svc_option.string(), }) } js = append(js, json_out_server_conn{ @@ -176,9 +177,9 @@ func (ctl *server_ctl_server_conns_id) ServeHTTP(w http.ResponseWriter, req *htt jsp = append(jsp, json_out_server_route{ Id: r.id, ClientPeerAddr: r.ptc_addr, - ServerPeerListenAddr: r.svc_addr.String(), - ServerPeerNet: r.svc_permitted_net.String(), - ServerPeerProto: r.svc_proto, + ServerPeerServiceAddr: r.svc_addr.String(), + ServerPeerServiceNet: r.svc_permitted_net.String(), + ServerPeerOption: r.svc_option.string(), }) } js = &json_out_server_conn{ @@ -256,9 +257,9 @@ func (ctl *server_ctl_server_conns_id_routes) ServeHTTP(w http.ResponseWriter, r jsp = append(jsp, json_out_server_route{ Id: r.id, ClientPeerAddr: r.ptc_addr, - ServerPeerListenAddr: r.svc_addr.String(), - ServerPeerNet: r.svc_permitted_net.String(), - ServerPeerProto: r.svc_proto, + ServerPeerServiceAddr: r.svc_addr.String(), + ServerPeerServiceNet: r.svc_permitted_net.String(), + ServerPeerOption: r.svc_option.string(), }) } cts.route_mtx.Unlock() @@ -309,13 +310,13 @@ func (ctl *server_ctl_server_conns_id_routes_id) ServeHTTP(w http.ResponseWriter conn_id = req.PathValue("conn_id") route_id = req.PathValue("route_id") - conn_nid, err = strconv.ParseUint(conn_id, 10, 32) + conn_nid, err = strconv.ParseUint(conn_id, 10, int(unsafe.Sizeof(conn_nid) * 8)) if err != nil { status_code = http.StatusBadRequest; w.WriteHeader(status_code) if err = je.Encode(json_errmsg{Text: "wrong connection id - " + conn_id}); err != nil { goto oops } goto done } - route_nid, err = strconv.ParseUint(route_id, 10, 32) + route_nid, err = strconv.ParseUint(route_id, 10, int(unsafe.Sizeof(route_nid) * 8)) if err != nil { status_code = http.StatusBadRequest; w.WriteHeader(status_code) if err = je.Encode(json_errmsg{Text: "wrong route id - " + route_id}); err != nil { goto oops } @@ -342,9 +343,9 @@ func (ctl *server_ctl_server_conns_id_routes_id) ServeHTTP(w http.ResponseWriter err = je.Encode(json_out_server_route{ Id: r.id, ClientPeerAddr: r.ptc_addr, - ServerPeerListenAddr: r.svc_addr.String(), - ServerPeerNet: r.svc_permitted_net.String(), - ServerPeerProto: r.svc_proto, + ServerPeerServiceAddr: r.svc_addr.String(), + ServerPeerServiceNet: r.svc_permitted_net.String(), + ServerPeerOption: r.svc_option.string(), }) if err != nil { goto oops } diff --git a/server-peer.go b/server-peer.go index d210f06..223f6be 100644 --- a/server-peer.go +++ b/server-peer.go @@ -3,6 +3,7 @@ package hodu import "errors" import "io" import "net" +import "strings" import "sync" import "sync/atomic" import "time" @@ -90,7 +91,7 @@ wait_for_started: for { n, err = spc.conn.Read(buf[:]) if err != nil { - if errors.Is(err, io.EOF) { + if errors.Is(err, io.EOF) || strings.Contains(err.Error(), "use of closed network connection") { // i don't like this way to check this error. err = pss.Send(MakePeerEofPacket(spc.route.id, spc.conn_id)) if err != nil { spc.route.cts.svr.log.Write(spc.route.cts.sid, LOG_ERROR, diff --git a/server.go b/server.go index e7e4e1e..4b604bb 100644 --- a/server.go +++ b/server.go @@ -6,7 +6,7 @@ import "errors" import "fmt" import "io" import "log" -import "math/rand" +//import "math/rand" import "net" import "net/http" import "net/netip" @@ -28,10 +28,10 @@ type ServerConnMap = map[ConnId]*ServerConn type ServerRouteMap = map[RouteId]*ServerRoute type ServerPeerConnMap = map[PeerId]*ServerPeerConn - type Server struct { ctx context.Context ctx_cancel context.CancelFunc + pxytlscfg *tls.Config ctltlscfg *tls.Config rpctlscfg *tls.Config @@ -42,6 +42,10 @@ type Server struct { ext_mtx sync.Mutex ext_svcs []Service + pxy_addr []string + pxy_mux *http.ServeMux + pxy []*http.Server // proxy server + ctl_addr []string ctl_prefix string ctl_mux *http.ServeMux @@ -91,10 +95,11 @@ type ServerConn struct { type ServerRoute struct { cts *ServerConn - l *net.TCPListener - svc_addr *net.TCPAddr // listening address + svc_l *net.TCPListener + svc_addr *net.TCPAddr // actual listening address + svc_requested_addr string svc_permitted_net netip.Prefix - svc_proto ROUTE_PROTO + svc_option RouteOption ptc_addr string id RouteId @@ -136,7 +141,7 @@ func (g *GuardedPacketStreamServer) Context() context.Context { // ------------------------------------ -func NewServerRoute(cts *ServerConn, id RouteId, proto ROUTE_PROTO, ptc_addr string, svc_permitted_net string) (*ServerRoute, error) { +func NewServerRoute(cts *ServerConn, id RouteId, option RouteOption, ptc_addr string, svc_requested_addr string, svc_permitted_net string) (*ServerRoute, error) { var r ServerRoute var l *net.TCPListener var svcaddr *net.TCPAddr @@ -144,31 +149,34 @@ func NewServerRoute(cts *ServerConn, id RouteId, proto ROUTE_PROTO, ptc_addr str var err error if svc_permitted_net != "" { + // parse the permitted network before creating a listener. + // the listener opened doesn't have to be closed when parsing fails. svcnet, err = netip.ParsePrefix(svc_permitted_net) if err != nil { return nil , err } } - l, svcaddr, err = cts.make_route_listener(id, proto) + l, svcaddr, err = cts.make_route_listener(id, option, svc_requested_addr) if err != nil { return nil, err } if svc_permitted_net == "" { if svcaddr.IP.To4() != nil { - svcnet, _ = netip.ParsePrefix("0.0.0.0/0") + svcnet = IPV4_PREFIX_ZERO } else { - svcnet, _ = netip.ParsePrefix("::/0") + svcnet = IPV6_PREFIX_ZERO } } r.cts = cts r.id = id - r.l = l + r.svc_l = l r.svc_addr = svcaddr + r.svc_requested_addr = svc_requested_addr r.svc_permitted_net = svcnet - r.svc_proto = proto + r.svc_option = option r.ptc_addr = ptc_addr r.pts_limit = PTS_LIMIT @@ -230,7 +238,7 @@ func (r *ServerRoute) RunTask(wg *sync.WaitGroup) { defer wg.Done() for { - conn, err = r.l.AcceptTCP() + conn, err = r.svc_l.AcceptTCP() // this call is blocking... if err != nil { if errors.Is(err, net.ErrClosed) { r.cts.svr.log.Write(r.cts.sid, LOG_INFO, "Server-side peer listener closed on route(%d)", r.id) @@ -280,7 +288,7 @@ func (r *ServerRoute) ReqStop() { pts.ReqStop() } - r.l.Close() + r.svc_l.Close() } } @@ -300,52 +308,53 @@ func (r *ServerRoute) ReportEvent(pts_id PeerId, event_type PACKET_KIND, event_d } // ------------------------------------ -func (cts *ServerConn) make_route_listener(id RouteId, proto ROUTE_PROTO) (*net.TCPListener, *net.TCPAddr, error) { +func (cts *ServerConn) make_route_listener(id RouteId, option RouteOption, svc_requested_addr string) (*net.TCPListener, *net.TCPAddr, error) { var l *net.TCPListener - var err error var svcaddr *net.TCPAddr - var port int - var tries int = 0 var nw string - var ip string + var err error - switch proto { - case ROUTE_PROTO_TCP: + if svc_requested_addr != "" { + var ap netip.AddrPort + + ap, err = netip.ParseAddrPort(svc_requested_addr) + if err != nil { + return nil, nil, fmt.Errorf("invalid service address %s - %s", svc_requested_addr, err.Error()) + } + + svcaddr = &net.TCPAddr{IP: ap.Addr().AsSlice(), Port: int(ap.Port())} + } + + if option & RouteOption(ROUTE_OPTION_TCP) != 0 { nw = "tcp" - ip = "" - case ROUTE_PROTO_TCP4: - nw = "tcp4" - ip = "0.0.0.0" - case ROUTE_PROTO_TCP6: - nw = "tcp6" - ip = "[::]" - default: - return nil, nil, fmt.Errorf("invalid protocol number %d", proto) - } - - for { - port = rand.Intn(65535-32000+1) + 32000 // TODO: configurable port range - - svcaddr, err = net.ResolveTCPAddr(nw, fmt.Sprintf("%s:%d", ip, port)) - if err == nil { - l, err = net.ListenTCP(nw, svcaddr) // make the binding address configurable. support multiple binding addresses??? - if err == nil { - cts.svr.log.Write(cts.sid, LOG_DEBUG, "Route(%d) listening on %d", id, port) - return l, svcaddr, nil + if svcaddr == nil { + svcaddr = &net.TCPAddr{Port: 0} // port 0 for automatic assignment. } - } - - tries++ - if tries >= 1000 { - err = fmt.Errorf("unable to allocate port") - break - } + } else if option & RouteOption(ROUTE_OPTION_TCP4) != 0 { + nw = "tcp4" + if svcaddr == nil { + svcaddr = &net.TCPAddr{IP: net.IPv4zero, Port: 0} // port 0 for automatic assignment. + } + } else if option & RouteOption(ROUTE_OPTION_TCP6) != 0 { + nw = "tcp6" + if svcaddr == nil { + svcaddr = &net.TCPAddr{IP: net.IPv6zero, Port: 0} // port 0 for automatic assignment. + } + } else { + return nil, nil, fmt.Errorf("invalid route option value %d(%s)", option, option.string()) } - return nil, nil, err + l, err = net.ListenTCP(nw, svcaddr) // make the binding address configurable. support multiple binding addresses??? + if err != nil { + return nil, nil, err + } + + svcaddr = l.Addr().(*net.TCPAddr) + cts.svr.log.Write(cts.sid, LOG_DEBUG, "Route(%d) listening on %s", id, svcaddr.String()) + return l, svcaddr, nil } -func (cts *ServerConn) AddNewServerRoute(route_id RouteId, proto ROUTE_PROTO, ptc_addr string, svc_permitted_net string) (*ServerRoute, error) { +func (cts *ServerConn) AddNewServerRoute(route_id RouteId, proto RouteOption, ptc_addr string, svc_requested_addr string, svc_permitted_net string) (*ServerRoute, error) { var r *ServerRoute var err error @@ -358,7 +367,7 @@ func (cts *ServerConn) AddNewServerRoute(route_id RouteId, proto ROUTE_PROTO, pt cts.route_mtx.Unlock() return nil, fmt.Errorf("existent route id - %d", route_id) } - r, err = NewServerRoute(cts, route_id, proto, ptc_addr, svc_permitted_net) + r, err = NewServerRoute(cts, route_id, proto, ptc_addr, svc_requested_addr, svc_permitted_net) if err != nil { cts.route_mtx.Unlock() return nil, err @@ -478,34 +487,34 @@ func (cts *ServerConn) receive_from_stream(wg *sync.WaitGroup) { if ok { var r *ServerRoute - r, err = cts.AddNewServerRoute(RouteId(x.Route.RouteId), x.Route.ServiceProto, x.Route.TargetAddrStr, x.Route.ServiceNetStr) + r, err = cts.AddNewServerRoute(RouteId(x.Route.RouteId), RouteOption(x.Route.ServiceOption), x.Route.TargetAddrStr, x.Route.ServiceAddrStr, x.Route.ServiceNetStr) if err != nil { cts.svr.log.Write(cts.sid, LOG_ERROR, "Failed to add route(%d,%s) for %s - %s", x.Route.RouteId, x.Route.TargetAddrStr, cts.remote_addr, err.Error()) - err = cts.pss.Send(MakeRouteStoppedPacket(RouteId(x.Route.RouteId), x.Route.ServiceProto, x.Route.TargetAddrStr, x.Route.ServiceNetStr)) + err = cts.pss.Send(MakeRouteStoppedPacket(RouteId(x.Route.RouteId), RouteOption(x.Route.ServiceOption), x.Route.TargetAddrStr, x.Route.ServiceAddrStr, x.Route.ServiceNetStr)) if err != nil { cts.svr.log.Write(cts.sid, LOG_ERROR, "Failed to send route_stopped event(%d,%s,%v,%s) to client %s - %s", - x.Route.RouteId, x.Route.TargetAddrStr, x.Route.ServiceProto, x.Route.ServiceNetStr, cts.remote_addr, err.Error()) + x.Route.RouteId, x.Route.TargetAddrStr, x.Route.ServiceOption, x.Route.ServiceNetStr, cts.remote_addr, err.Error()) goto done } else { cts.svr.log.Write(cts.sid, LOG_DEBUG, "Sent route_stopped event(%d,%s,%v,%s) to client %s", - x.Route.RouteId, x.Route.TargetAddrStr, x.Route.ServiceProto, x.Route.ServiceNetStr, cts.remote_addr) + x.Route.RouteId, x.Route.TargetAddrStr, x.Route.ServiceOption, x.Route.ServiceNetStr, cts.remote_addr) } } else { cts.svr.log.Write(cts.sid, LOG_INFO, "Added route(%d,%s,%s,%v,%v) for client %s to cts(%d)", - r.id, r.ptc_addr, r.svc_addr.String(), r.svc_proto, r.svc_permitted_net, cts.remote_addr, cts.id) - err = cts.pss.Send(MakeRouteStartedPacket(r.id, r.svc_proto, r.svc_addr.String(), r.svc_permitted_net.String())) + r.id, r.ptc_addr, r.svc_addr.String(), r.svc_option, r.svc_permitted_net, cts.remote_addr, cts.id) + err = cts.pss.Send(MakeRouteStartedPacket(r.id, r.svc_option, r.svc_addr.String(), r.svc_requested_addr, r.svc_permitted_net.String())) if err != nil { r.ReqStop() cts.svr.log.Write(cts.sid, LOG_ERROR, "Failed to send route_started event(%d,%s,%s,%s%v,%v) to client %s - %s", - r.id, r.ptc_addr, r.svc_addr.String(), r.svc_proto, r.svc_permitted_net, cts.remote_addr, err.Error()) + r.id, r.ptc_addr, r.svc_addr.String(), r.svc_option, r.svc_permitted_net, cts.remote_addr, err.Error()) goto done } } @@ -529,13 +538,13 @@ func (cts *ServerConn) receive_from_stream(wg *sync.WaitGroup) { } else { cts.svr.log.Write(cts.sid, LOG_ERROR, "Deleted route(%d,%s,%s,%v,%v) for client %s", - r.id, r.ptc_addr, r.svc_addr.String(), r.svc_proto, r.svc_permitted_net.String(), cts.remote_addr) - err = cts.pss.Send(MakeRouteStoppedPacket(r.id, r.svc_proto, r.ptc_addr, r.svc_permitted_net.String())) + r.id, r.ptc_addr, r.svc_addr.String(), r.svc_option, r.svc_permitted_net.String(), cts.remote_addr) + err = cts.pss.Send(MakeRouteStoppedPacket(r.id, r.svc_option, r.ptc_addr, r.svc_requested_addr, r.svc_permitted_net.String())) if err != nil { r.ReqStop() cts.svr.log.Write(cts.sid, LOG_ERROR, "Failed to send route_stopped event(%d,%s,%s,%v.%v) to client %s - %s", - r.id, r.ptc_addr, r.svc_addr.String(), r.svc_proto, r.svc_permitted_net.String(), cts.remote_addr, err.Error()) + r.id, r.ptc_addr, r.svc_addr.String(), r.svc_option, r.svc_permitted_net.String(), cts.remote_addr, err.Error()) goto done } } @@ -846,18 +855,18 @@ func unaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServ } -type server_ctl_log_writer struct { +type server_http_log_writer struct { svr *Server } -func (hlw *server_ctl_log_writer) Write(p []byte) (n int, err error) { +func (hlw *server_http_log_writer) Write(p []byte) (n int, err error) { // the standard http.Server always requires *log.Logger // use this iowriter to create a logger to pass it to the http server. hlw.svr.log.Write("", LOG_INFO, string(p)) return len(p), nil } -func NewServer(ctx context.Context, logger Logger, ctl_addrs []string, rpc_addrs []string, ctl_prefix string, ctltlscfg *tls.Config, rpctlscfg *tls.Config, rpc_max int, peer_max int) (*Server, error) { +func NewServer(ctx context.Context, logger Logger, ctl_addrs []string, rpc_addrs []string, pxy_addrs []string, ctl_prefix string, ctltlscfg *tls.Config, rpctlscfg *tls.Config, pxytlscfg *tls.Config, rpc_max int, peer_max int) (*Server, error) { var s Server var l *net.TCPListener var rpcaddr *net.TCPAddr @@ -893,6 +902,7 @@ func NewServer(ctx context.Context, logger Logger, ctl_addrs []string, rpc_addrs s.ctltlscfg = ctltlscfg s.rpctlscfg = rpctlscfg + s.pxytlscfg = pxytlscfg s.ext_svcs = make([]Service, 0, 1) s.pts_limit = peer_max s.cts_limit = rpc_max @@ -916,10 +926,16 @@ func NewServer(ctx context.Context, logger Logger, ctl_addrs []string, rpc_addrs s.rpc_svr = grpc.NewServer(opts...) RegisterHoduServer(s.rpc_svr, &s) - s.ctl_prefix = ctl_prefix + // --------------------------------------------------------- + hs_log = log.New(&server_http_log_writer{svr: &s}, "", 0); + + // --------------------------------------------------------- + + s.ctl_prefix = ctl_prefix s.ctl_mux = http.NewServeMux() - cwd, _ = os.Getwd() + cwd, _ = os.Getwd() // TODO: + s.ctl_mux.Handle(s.ctl_prefix + "/ui/", http.StripPrefix(s.ctl_prefix, http.FileServer(http.Dir(cwd)))) // TODO: proper directory. it must not use the current working directory... s.ctl_mux.Handle(s.ctl_prefix + "/ws/tty", new_server_ctl_ws_tty(&s)) s.ctl_mux.Handle(s.ctl_prefix + "/server-conns", &server_ctl_server_conns{s: &s}) @@ -931,7 +947,6 @@ func NewServer(ctx context.Context, logger Logger, ctl_addrs []string, rpc_addrs s.ctl_addr = make([]string, len(ctl_addrs)) s.ctl = make([]*http.Server, len(ctl_addrs)) copy(s.ctl_addr, ctl_addrs) - hs_log = log.New(&server_ctl_log_writer{svr: &s}, "", 0); for i = 0; i < len(ctl_addrs); i++ { s.ctl[i] = &http.Server{ @@ -943,6 +958,26 @@ func NewServer(ctx context.Context, logger Logger, ctl_addrs []string, rpc_addrs } } + // --------------------------------------------------------- + s.pxy_mux = http.NewServeMux() // TODO: make /_init configurable... + s.pxy_mux.Handle("/_init/{conn_id}/{route_id}/{trailer...}", &server_proxy_http_init{s: &s}) + s.pxy_mux.Handle("/", &server_proxy_http_main{s: &s}) + + s.pxy_addr = make([]string, len(pxy_addrs)) + s.pxy = make([]*http.Server, len(pxy_addrs)) + copy(s.pxy_addr, pxy_addrs) + + for i = 0; i < len(pxy_addrs); i++ { + s.pxy[i] = &http.Server{ + Addr: pxy_addrs[i], + Handler: s.pxy_mux, + TLSConfig: s.pxytlscfg, + ErrorLog: hs_log, + // TODO: more settings + } + } + // --------------------------------------------------------- + s.stats.conns.Store(0) s.stats.routes.Store(0) s.stats.peers.Store(0) @@ -1032,7 +1067,6 @@ func (s *Server) RunCtlTask(wg *sync.WaitGroup) { s.log.Write("", LOG_INFO, "Control channel[%d] started on %s", i, s.ctl_addr[i]) - if s.stop_req.Load() == false { // defeat hard-coded "tcp" in ListenAndServe() and ListenAndServeTLS() // err = cs.ListenAndServe() @@ -1064,14 +1098,61 @@ func (s *Server) RunCtlTask(wg *sync.WaitGroup) { l_wg.Wait() } +func (s *Server) RunPxyTask(wg *sync.WaitGroup) { + var err error + var pxy *http.Server + var idx int + var l_wg sync.WaitGroup + + defer wg.Done() + + for idx, pxy = range s.pxy { + l_wg.Add(1) + go func(i int, cs *http.Server) { + var l net.Listener + + s.log.Write("", LOG_INFO, "Proxy channel[%d] started on %s", i, s.pxy_addr[i]) + + if s.stop_req.Load() == false { + l, err = net.Listen(tcp_addr_str_class(cs.Addr), cs.Addr) + if err == nil { + if s.stop_req.Load() == false { + if s.pxytlscfg == nil { // TODO: change this + err = cs.Serve(l) + } else { + err = cs.ServeTLS(l, "", "") // s.pxytlscfg must provide a certificate and a key + } + } else { + err = fmt.Errorf("stop requested") + } + l.Close() + } + } else { + err = fmt.Errorf("stop requested") + } + if errors.Is(err, http.ErrServerClosed) { + s.log.Write("", LOG_INFO, "Proxy channel[%d] ended", i) + } else { + s.log.Write("", LOG_ERROR, "Proxy channel[%d] error - %s", i, err.Error()) + } + l_wg.Done() + }(idx, pxy) + } + l_wg.Wait() +} + func (s *Server) ReqStop() { if s.stop_req.CompareAndSwap(false, true) { var l *net.TCPListener var cts *ServerConn - var ctl *http.Server + var hs *http.Server - for _, ctl = range s.ctl { - ctl.Shutdown(s.ctx) // to break c.ctl.ListenAndServe() + for _, hs = range s.ctl { + hs.Shutdown(s.ctx) // to break s.ctl.Serve() + } + + for _, hs = range s.pxy { + hs.Shutdown(s.ctx) // to break s.pxy.Serve() } //s.rpc_svr.GracefulStop() @@ -1222,6 +1303,23 @@ func (s *Server) FindServerConnByAddr(addr net.Addr) *ServerConn { return cts } + +func (s *Server) FindServerRouteById(id ConnId, route_id RouteId) *ServerRoute { + var cts *ServerConn + var ok bool + + s.cts_mtx.Lock() + defer s.cts_mtx.Unlock() + + cts, ok = s.cts_map[id] + if !ok { + return nil + } + + return cts.FindServerRouteById(route_id) +} + + func (s *Server) StartService(cfg interface{}) { s.wg.Add(1) go s.RunTask(&s.wg) @@ -1240,6 +1338,11 @@ func (s *Server) StartCtlService() { go s.RunCtlTask(&s.wg) } +func (s *Server) StartPxyService() { + s.wg.Add(1) + go s.RunPxyTask(&s.wg) +} + func (s *Server) StopServices() { var ext_svc Service s.ReqStop()