func (s *UdpForwardServer) prepareUdpConnectTunnel(addr net.Addr) (net.Conn, error) { conn, err := s.Base.Chain.GetConn() if err != nil { return nil, err } conn.SetWriteDeadline(time.Now().Add(WriteTimeout)) if err = gosocks5.NewRequest(CmdUdpConnect, ToSocksAddr(addr)).Write(conn); err != nil { conn.Close() return nil, err } conn.SetWriteDeadline(time.Time{}) conn.SetReadDeadline(time.Now().Add(ReadTimeout)) reply, err := gosocks5.ReadReply(conn) if err != nil { conn.Close() return nil, err } conn.SetReadDeadline(time.Time{}) if reply.Rep != gosocks5.Succeeded { conn.Close() return nil, errors.New("failure") } return conn, nil }
func establish(conn net.Conn, addr string, arg Args) error { switch arg.Protocol { case "ss": // shadowsocks return nil case "socks", "socks5": host, port, err := net.SplitHostPort(addr) p, _ := strconv.Atoi(port) // TODO: support bind and udp req := gosocks5.NewRequest(gosocks5.CmdConnect, &gosocks5.Addr{ Type: gosocks5.AddrDomain, Host: host, Port: uint16(p), }) rep, err := requestSocks5(conn, req) if err != nil { return err } if rep.Rep != gosocks5.Succeeded { return errors.New("Service unavailable") } case "http": fallthrough default: req := &http.Request{ Method: "CONNECT", URL: &url.URL{Host: addr}, Host: addr, ProtoMajor: 1, ProtoMinor: 1, Header: make(http.Header), } req.Header.Set("Proxy-Connection", "keep-alive") if arg.User != nil { req.Header.Set("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(arg.User.String()))) } if err := req.Write(conn); err != nil { return err } if glog.V(LDEBUG) { dump, _ := httputil.DumpRequest(req, false) glog.Infoln(string(dump)) } resp, err := http.ReadResponse(bufio.NewReader(conn), req) if err != nil { return err } if glog.V(LDEBUG) { dump, _ := httputil.DumpResponse(resp, false) glog.Infoln(string(dump)) } if resp.StatusCode != http.StatusOK { return errors.New(resp.Status) } } return nil }
func (s *RTcpForwardServer) connectRTcpForward(conn net.Conn, laddr, raddr net.Addr) error { glog.V(LINFO).Infof("[rtcp] %s - %s", laddr, raddr) req := gosocks5.NewRequest(gosocks5.CmdBind, ToSocksAddr(laddr)) if err := req.Write(conn); err != nil { glog.V(LWARNING).Infof("[rtcp] %s -> %s : %s", laddr, raddr, err) return err } // first reply, bind status conn.SetReadDeadline(time.Now().Add(ReadTimeout)) rep, err := gosocks5.ReadReply(conn) if err != nil { glog.V(LWARNING).Infof("[rtcp] %s -> %s : %s", laddr, raddr, err) return err } conn.SetReadDeadline(time.Time{}) if rep.Rep != gosocks5.Succeeded { glog.V(LWARNING).Infof("[rtcp] %s -> %s : bind on %s failure", laddr, raddr, laddr) return errors.New("Bind on " + laddr.String() + " failure") } glog.V(LINFO).Infof("[rtcp] %s - %s BIND ON %s OK", laddr, raddr, rep.Addr) // second reply, peer connection rep, err = gosocks5.ReadReply(conn) if err != nil { glog.V(LWARNING).Infof("[rtcp] %s -> %s : %s", laddr, raddr, err) return err } if rep.Rep != gosocks5.Succeeded { glog.V(LWARNING).Infof("[rtcp] %s -> %s : peer connect failure", laddr, raddr) return errors.New("peer connect failure") } glog.V(LINFO).Infof("[rtcp] %s -> %s PEER %s CONNECTED", laddr, raddr, rep.Addr) go func() { defer conn.Close() lconn, err := net.DialTimeout("tcp", raddr.String(), time.Second*180) if err != nil { glog.V(LWARNING).Infof("[rtcp] %s -> %s : %s", rep.Addr, raddr, err) return } defer lconn.Close() glog.V(LINFO).Infof("[rtcp] %s <-> %s", rep.Addr, lconn.RemoteAddr()) s.Base.transport(lconn, conn) glog.V(LINFO).Infof("[rtcp] %s >-< %s", rep.Addr, lconn.RemoteAddr()) }() return nil }
func connectSocks5Proxy(addr string) (conn net.Conn, err error) { conn, err = dial(proxyURL.Host) if err != nil { return } conf := &gosocks5.Config{ // Methods: []uint8{gosocks5.MethodNoAuth, gosocks5.MethodUserPass}, MethodSelected: proxyMethodSelected, } if proxyURL.User != nil { conf.Methods = []uint8{gosocks5.MethodUserPass} } c := gosocks5.ClientConn(conn, conf) if err := c.Handleshake(); err != nil { conn.Close() return nil, err } conn = c s := strings.Split(addr, ":") host := s[0] port := 80 if len(s) == 2 { n, _ := strconv.ParseUint(s[1], 10, 16) port = int(n) } a := &gosocks5.Addr{ Type: gosocks5.AddrDomain, Host: host, Port: uint16(port), } if err := gosocks5.NewRequest(gosocks5.CmdConnect, a).Write(conn); err != nil { conn.Close() return nil, err } rep, err := gosocks5.ReadReply(conn) if err != nil { conn.Close() return nil, err } if rep.Rep != gosocks5.Succeeded { conn.Close() return nil, errors.New("Socks Failture") } return conn, nil }
func createServerConn(uconn *net.UDPConn, addr net.Addr) (c *UDPConn, err error) { if len(forwardArgs) == 0 { c = Server(uconn) return } fconn, _, err := forwardChain(forwardArgs...) if err != nil { if fconn != nil { fconn.Close() } return } glog.V(LINFO).Infoln("forward udp associate") req := gosocks5.NewRequest(gosocks5.CmdUdp, nil) if err = req.Write(fconn); err != nil { fconn.Close() return } glog.V(LDEBUG).Infoln(req) rep, err := gosocks5.ReadReply(fconn) if err != nil { fconn.Close() return } glog.V(LDEBUG).Infoln(rep) if rep.Rep != gosocks5.Succeeded { fconn.Close() return nil, errors.New("Failure") } glog.V(LINFO).Infoln("forward udp associate, on", rep.Addr, "OK") c = Server(fconn) return }
func handleShadow(conn net.Conn) { addr, extra, err := getShadowRequest(conn) if err != nil { log.Println(err) return } sconn, err := makeTunnel() if err != nil { log.Println(err) return } defer sconn.Close() req := gosocks5.NewRequest(gosocks5.CmdConnect, addr) if err := req.Write(sconn); err != nil { log.Println(err) return } rep, err := gosocks5.ReadReply(sconn) if err != nil || rep.Rep != gosocks5.Succeeded { log.Println(err) return } if extra != nil { if _, err := sconn.Write(extra); err != nil { log.Println(err) return } } if err := Transport(conn, sconn); err != nil { //log.Println(err) } }
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) }
// Connect connect to addr through this proxy node func (c *ProxyConn) Connect(addr string) error { switch c.Node.Protocol { case "ss": // shadowsocks host, port, err := net.SplitHostPort(addr) if err != nil { return err } p, _ := strconv.Atoi(port) req := gosocks5.NewRequest(gosocks5.CmdConnect, &gosocks5.Addr{ Type: gosocks5.AddrDomain, Host: host, Port: uint16(p), }) buf := bytes.Buffer{} if err := req.Write(&buf); err != nil { return err } b := buf.Bytes() if _, err := c.Write(b[3:]); err != nil { return err } glog.V(LDEBUG).Infoln("[ss]", req) case "socks", "socks5": host, port, err := net.SplitHostPort(addr) if err != nil { return err } p, _ := strconv.Atoi(port) req := gosocks5.NewRequest(gosocks5.CmdConnect, &gosocks5.Addr{ Type: gosocks5.AddrDomain, Host: host, Port: uint16(p), }) if err := req.Write(c); err != nil { return err } glog.V(LDEBUG).Infoln("[socks5]", req) reply, err := gosocks5.ReadReply(c) if err != nil { return err } glog.V(LDEBUG).Infoln("[socks5]", reply) if reply.Rep != gosocks5.Succeeded { return errors.New("Service unavailable") } case "http": fallthrough default: req := &http.Request{ Method: http.MethodConnect, URL: &url.URL{Host: addr}, Host: addr, ProtoMajor: 1, ProtoMinor: 1, Header: make(http.Header), } req.Header.Set("Proxy-Connection", "keep-alive") if c.Node.User != nil { req.Header.Set("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(c.Node.User.String()))) } if err := req.Write(c); err != nil { return err } if glog.V(LDEBUG) { dump, _ := httputil.DumpRequest(req, false) glog.Infoln(string(dump)) } resp, err := http.ReadResponse(bufio.NewReader(c), req) if err != nil { return err } if glog.V(LDEBUG) { dump, _ := httputil.DumpResponse(resp, false) glog.Infoln(string(dump)) } if resp.StatusCode != http.StatusOK { return errors.New(resp.Status) } } return nil }
func handleHttp(req *http.Request, conn net.Conn) { var host string var port uint16 if listenUrl != nil && listenUrl.User != nil { username := listenUrl.User.Username() password, _ := listenUrl.User.Password() if err := clientHttpAuth(req, conn, username, password); err != nil { log.Println(err) return } } s := strings.Split(req.Host, ":") host = s[0] port = 80 if len(s) == 2 { n, _ := strconv.ParseUint(s[1], 10, 16) port = uint16(n) } addr := &gosocks5.Addr{ Type: gosocks5.AddrDomain, Host: host, Port: port, } r := gosocks5.NewRequest(gosocks5.CmdConnect, addr) sconn, err := makeTunnel() if err != nil { conn.Write([]byte("HTTP/1.1 503 Service unavailable\r\n" + "Proxy-Agent: gost/" + Version + "\r\n\r\n")) log.Println(err) return } defer sconn.Close() if err := r.Write(sconn); err != nil { return } rep, err := gosocks5.ReadReply(sconn) if err != nil || rep.Rep != gosocks5.Succeeded { conn.Write([]byte("HTTP/1.1 503 Service unavailable\r\n" + "Proxy-Agent: gost/" + Version + "\r\n\r\n")) return } if req.Method == "CONNECT" { if _, err = conn.Write( []byte("HTTP/1.1 200 Connection established\r\n" + "Proxy-Agent: gost/" + Version + "\r\n\r\n")); err != nil { return } } else { if err := req.Write(sconn); err != nil { return } } if err := Transport(conn, sconn); err != nil { //log.Println(err) } }
func (s *RUdpForwardServer) connectRUdpForward(conn net.Conn, laddr, raddr *net.UDPAddr) error { glog.V(LINFO).Infof("[rudp] %s - %s", laddr, raddr) req := gosocks5.NewRequest(CmdUdpTun, ToSocksAddr(laddr)) conn.SetWriteDeadline(time.Now().Add(WriteTimeout)) if err := req.Write(conn); err != nil { glog.V(LWARNING).Infof("[rudp] %s -> %s : %s", laddr, raddr, err) return err } conn.SetWriteDeadline(time.Time{}) conn.SetReadDeadline(time.Now().Add(ReadTimeout)) rep, err := gosocks5.ReadReply(conn) if err != nil { glog.V(LWARNING).Infof("[rudp] %s <- %s : %s", laddr, raddr, err) return err } conn.SetReadDeadline(time.Time{}) if rep.Rep != gosocks5.Succeeded { glog.V(LWARNING).Infof("[rudp] %s <- %s : bind on %s failure", laddr, raddr, laddr) return errors.New(fmt.Sprintf("bind on %s failure", laddr)) } glog.V(LINFO).Infof("[rudp] %s - %s BIND ON %s OK", laddr, raddr, rep.Addr) for { dgram, err := gosocks5.ReadUDPDatagram(conn) if err != nil { glog.V(LWARNING).Infof("[rudp] %s <- %s : %s", laddr, raddr, err) return err } go func() { b := make([]byte, MediumBufferSize) relay, err := net.DialUDP("udp", nil, raddr) if err != nil { glog.V(LWARNING).Infof("[rudp] %s -> %s : %s", laddr, raddr, err) return } defer relay.Close() if _, err := relay.Write(dgram.Data); err != nil { glog.V(LWARNING).Infof("[rudp] %s -> %s : %s", laddr, raddr, err) return } glog.V(LDEBUG).Infof("[rudp] %s >>> %s length: %d", laddr, raddr, len(dgram.Data)) relay.SetReadDeadline(time.Now().Add(ReadTimeout)) n, err := relay.Read(b) if err != nil { glog.V(LWARNING).Infof("[rudp] %s <- %s : %s", laddr, raddr, err) return } relay.SetReadDeadline(time.Time{}) glog.V(LDEBUG).Infof("[rudp] %s <<< %s length: %d", laddr, raddr, n) conn.SetWriteDeadline(time.Now().Add(WriteTimeout)) if err := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(uint16(n), 0, dgram.Header.Addr), b[:n]).Write(conn); err != nil { glog.V(LWARNING).Infof("[rudp] %s <- %s : %s", laddr, raddr, err) return } conn.SetWriteDeadline(time.Time{}) }() } }