func (s *Session) handleAuth() error { // accept ann auth stream raw, err := s.mux.Accept() if err != nil { return s.Error("Failed to accept auth stream: %v", err) } defer raw.Close() stream := conn.Wrap(raw, "session", "auth") // read the Auth message if err = proto.ReadMsgInto(stream, &s.auth); err != nil { return s.Error("Failed to read auth message; %v", err) } failAuth := func(e error) error { _ = proto.WriteMsg(stream, &proto.AuthResp{Error: e.Error()}) return e } // generate a client identifier s.id = s.auth.ClientId if s.id == "" { // it's a new session, assign an ID if s.id, err = util.SecureRandId(16); err != nil { return failAuth(fmt.Errorf("Failed generate client identifier: %v", err)) } } // put ourselves in the registry s.registry.register(s) // set logging prefix s.Logger.AddTags(s.id) // agree on protocol version // if proto.Version not in s.auth.Version if sort.SearchStrings(s.auth.Version, proto.Version) == len(s.auth.Version) { return failAuth(fmt.Errorf("No acceptable protocol version. Requested: %v, capable: %v", s.auth.Version, proto.Version)) } // auth hook if err = s.hooks.OnAuth(s, s.auth); err != nil { return failAuth(err) } // Respond to authentication authResp := &proto.AuthResp{ Version: proto.Version, ClientId: s.id, } if err = proto.WriteMsg(stream, authResp); err != nil { return failAuth(fmt.Errorf("Failed to write authentication response: %v", err)) } return nil }
func (s *Session) handleBind(stream conn.Conn, bind *proto.Bind) (err error) { stream.Debug("Binding new tunnel: %v", bind) respond := func(resp *proto.BindResp) { if err = proto.WriteMsg(stream, resp); err != nil { err = stream.Error("Failed to send bind response: %v", err) } } if err = s.hooks.OnBind(s, bind); err != nil { return } t, err := newTunnel(bind, s, s.binders, s.tunnelHooks) if err != nil { respond(&proto.BindResp{Error: err.Error()}) return } t.Info("Registered new tunnel on session %s", s.id) // add it to the list of tunnels s.addTunnel(t) // acknowledge success respond(&proto.BindResp{Url: t.url}) return }
// Opens a new proxy stream to the client and writes a StartProxy message // with the given client address and tunnel url. func (s *Session) openProxy(clientAddr, tunnelUrl string) (pxy conn.Conn, err error) { // open a new proxy stream pxyStream, err := s.mux.Open() if err != nil { return } pxy = conn.Wrap(pxyStream) // tell the client we're going to start using this proxy connection startProxy := &proto.StartProxy{ ClientAddr: clientAddr, Url: tunnelUrl, } if err = proto.WriteMsg(pxy, startProxy); err != nil { return } pxy.AddTags(tunnelUrl) return }
func (s *Session) handleUnbind(stream conn.Conn, unbind *proto.Unbind) (err error) { s.Debug("Unbinding tunnel") // remote it from the list of tunnels t, ok := s.delTunnel(unbind.Url) if !ok { return s.Error("Failed to unbind tunnel %s: no tunnel found.", unbind.Url) } if err = t.shutdown(); err != nil { return s.Error("Failed to unbind tunnel %s: %v", unbind.Url, err) } // acknowledge success unbindResp := &proto.UnbindResp{} if err = proto.WriteMsg(stream, unbindResp); err != nil { return s.Error("Failed to write unbind resp: %v", err) } return }
func (s *RawSession) req(tag string, req interface{}, resp interface{}) (err error) { stream, err := s.mux.Open() if err != nil { return } defer stream.Close() // log what happens on the stream c := conn.Wrap(stream, tag, s.id) // send the unlisten request if err = proto.WriteMsg(c, req); err != nil { return } // read out the unlisten response if err = proto.ReadMsgInto(c, resp); err != nil { return } return }