func (s *Socks5Server) handleUDPConnect(req *gosocks5.Request) { cc, err := s.Base.Chain.GetConn() // connection error if err != nil && err != ErrEmptyChain { glog.V(LWARNING).Infof("[udp] %s <- %s : %s", s.conn.RemoteAddr(), req.Addr, err) reply := gosocks5.NewReply(gosocks5.Failure, nil) reply.Write(s.conn) glog.V(LDEBUG).Infof("[udp] %s <- %s\n%s", s.conn.RemoteAddr(), req.Addr, reply) return } // serve udp connect if err == ErrEmptyChain { s.udpConnect(req.Addr.String()) return } defer cc.Close() // forward request if err := req.Write(cc); err != nil { glog.V(LINFO).Infof("[udp] %s -> %s : %s", s.conn.RemoteAddr(), req.Addr, err) gosocks5.NewReply(gosocks5.Failure, nil).Write(s.conn) return } glog.V(LINFO).Infof("[udp] %s <-> %s", s.conn.RemoteAddr(), req.Addr) s.Base.transport(s.conn, cc) glog.V(LINFO).Infof("[udp] %s >-< %s", s.conn.RemoteAddr(), req.Addr) }
func requestSocks5(conn net.Conn, req *gosocks5.Request) (*gosocks5.Reply, error) { if err := req.Write(conn); err != nil { return nil, err } if glog.V(LDEBUG) { glog.Infoln(req.String()) } rep, err := gosocks5.ReadReply(conn) if err != nil { return nil, err } if glog.V(LDEBUG) { glog.Infoln(rep.String()) } return rep, nil }
func (s *Socks5Server) handleUDPTunnel(req *gosocks5.Request) { cc, err := s.Base.Chain.GetConn() // connection error if err != nil && err != ErrEmptyChain { glog.V(LWARNING).Infof("[socks5-udp] %s -> %s : %s", s.conn.RemoteAddr(), req.Addr, err) reply := gosocks5.NewReply(gosocks5.Failure, nil) reply.Write(s.conn) glog.V(LDEBUG).Infof("[socks5-udp] %s -> %s\n%s", s.conn.RemoteAddr(), req.Addr, reply) return } // serve tunnel udp, tunnel <-> remote, handle tunnel udp request if err == ErrEmptyChain { bindAddr, _ := net.ResolveUDPAddr("udp", req.Addr.String()) uc, err := net.ListenUDP("udp", bindAddr) if err != nil { glog.V(LWARNING).Infof("[socks5-udp] %s -> %s : %s", s.conn.RemoteAddr(), req.Addr, err) return } defer uc.Close() socksAddr := ToSocksAddr(uc.LocalAddr()) socksAddr.Host, _, _ = net.SplitHostPort(s.conn.LocalAddr().String()) reply := gosocks5.NewReply(gosocks5.Succeeded, socksAddr) if err := reply.Write(s.conn); err != nil { glog.V(LWARNING).Infof("[socks5-udp] %s <- %s : %s", s.conn.RemoteAddr(), socksAddr, err) return } glog.V(LDEBUG).Infof("[socks5-udp] %s <- %s\n%s", s.conn.RemoteAddr(), socksAddr, reply) glog.V(LINFO).Infof("[socks5-udp] %s <-> %s", s.conn.RemoteAddr(), socksAddr) s.tunnelUDP(uc, s.conn, false) glog.V(LINFO).Infof("[socks5-udp] %s >-< %s", s.conn.RemoteAddr(), socksAddr) return } defer cc.Close() // tunnel <-> tunnel, direct forwarding req.Write(cc) glog.V(LINFO).Infof("[socks5-udp] %s <-> %s [tun]", s.conn.RemoteAddr(), cc.RemoteAddr()) s.Base.transport(s.conn, cc) glog.V(LINFO).Infof("[socks5-udp] %s >-< %s [tun]", s.conn.RemoteAddr(), cc.RemoteAddr()) }
func forwardBind(req *gosocks5.Request, conn net.Conn) error { fconn, _, err := forwardChain(forwardArgs...) if err != nil { glog.V(LWARNING).Infoln("[socks5] BIND(forward)", req.Addr, err) if fconn != nil { fconn.Close() } rep := gosocks5.NewReply(gosocks5.Failure, nil) if err := rep.Write(conn); err != nil { glog.V(LWARNING).Infoln("socks5 bind forward:", err) } else { glog.V(LDEBUG).Infoln(rep) } return err } defer fconn.Close() if err := req.Write(fconn); err != nil { glog.V(LWARNING).Infoln("[socks5] BIND(forward)", err) gosocks5.NewReply(gosocks5.Failure, nil).Write(conn) return err } glog.V(LDEBUG).Infoln(req) // first reply rep, err := peekReply(conn, fconn) if err != nil { glog.V(LWARNING).Infoln("[socks5] BIND(forward)", err) return err } glog.V(LINFO).Infoln("[socks5] BIND(forward) on", rep.Addr, "OK") // second reply rep, err = peekReply(conn, fconn) if err != nil { glog.V(LWARNING).Infoln("[socks5] BIND(forward) accept", err) return err } glog.V(LINFO).Infoln("[socks5] BIND(forward) accept", rep.Addr) return Transport(conn, fconn) }
func (s *Socks5Server) handleUDPRelay(req *gosocks5.Request) { bindAddr, _ := net.ResolveUDPAddr("udp", req.Addr.String()) relay, err := net.ListenUDP("udp", bindAddr) // udp associate, strict mode: if the port already in use, it will return error if err != nil { glog.V(LWARNING).Infof("[socks5-udp] %s -> %s : %s", s.conn.RemoteAddr(), req.Addr, err) reply := gosocks5.NewReply(gosocks5.Failure, nil) reply.Write(s.conn) glog.V(LDEBUG).Infof("[socks5-udp] %s <- %s\n%s", s.conn.RemoteAddr(), req.Addr, reply) return } defer relay.Close() socksAddr := ToSocksAddr(relay.LocalAddr()) socksAddr.Host, _, _ = net.SplitHostPort(s.conn.LocalAddr().String()) reply := gosocks5.NewReply(gosocks5.Succeeded, socksAddr) if err := reply.Write(s.conn); err != nil { glog.V(LWARNING).Infof("[socks5-udp] %s <- %s : %s", s.conn.RemoteAddr(), req.Addr, err) return } glog.V(LDEBUG).Infof("[socks5-udp] %s <- %s\n%s", s.conn.RemoteAddr(), reply.Addr, reply) glog.V(LINFO).Infof("[socks5-udp] %s - %s BIND ON %s OK", s.conn.RemoteAddr(), req.Addr, socksAddr) cc, err := s.Base.Chain.GetConn() // connection error if err != nil && err != ErrEmptyChain { glog.V(LWARNING).Infof("[socks5-udp] %s -> %s : %s", s.conn.RemoteAddr(), socksAddr, err) return } // serve as standard socks5 udp relay local <-> remote if err == ErrEmptyChain { peer, er := net.ListenUDP("udp", nil) if er != nil { glog.V(LWARNING).Infof("[socks5-udp] %s -> %s : %s", s.conn.RemoteAddr(), socksAddr, er) return } defer peer.Close() go s.transportUDP(relay, peer) } // forward udp local <-> tunnel if err == nil { defer cc.Close() cc.SetWriteDeadline(time.Now().Add(WriteTimeout)) req := gosocks5.NewRequest(CmdUdpTun, nil) if err := req.Write(cc); err != nil { glog.V(LWARNING).Infoln("[socks5-udp] %s -> %s : %s", s.conn.RemoteAddr(), cc.RemoteAddr(), err) return } cc.SetWriteDeadline(time.Time{}) glog.V(LDEBUG).Infof("[socks5-udp] %s -> %s\n%s", s.conn.RemoteAddr(), cc.RemoteAddr(), req) cc.SetReadDeadline(time.Now().Add(ReadTimeout)) reply, err = gosocks5.ReadReply(cc) if err != nil { glog.V(LWARNING).Infoln("[socks5-udp] %s -> %s : %s", s.conn.RemoteAddr(), cc.RemoteAddr(), err) return } glog.V(LDEBUG).Infof("[socks5-udp] %s <- %s\n%s", s.conn.RemoteAddr(), cc.RemoteAddr(), reply) if reply.Rep != gosocks5.Succeeded { glog.V(LWARNING).Infoln("[socks5-udp] %s <- %s : udp associate failed", s.conn.RemoteAddr(), cc.RemoteAddr()) return } cc.SetReadDeadline(time.Time{}) glog.V(LINFO).Infof("[socks5-udp] %s <-> %s [tun: %s]", s.conn.RemoteAddr(), socksAddr, reply.Addr) go s.tunnelUDP(relay, cc, true) } glog.V(LINFO).Infof("[socks5-udp] %s <-> %s", s.conn.RemoteAddr(), socksAddr) b := make([]byte, SmallBufferSize) for { _, err := s.conn.Read(b) // discard any data from tcp connection if err != nil { glog.V(LWARNING).Infof("[socks5-udp] %s - %s : %s", s.conn.RemoteAddr(), socksAddr, err) break // client disconnected } } glog.V(LINFO).Infof("[socks5-udp] %s >-< %s", s.conn.RemoteAddr(), socksAddr) }