réplica de
				https://github.com/therootcompany/sclient
				synced 2025-11-04 07:12:48 +00:00 
			
		
		
		
	support pipes and stdin
Este commit está contenido en:
		
							padre
							
								
									2235bf3a55
								
							
						
					
					
						commit
						c786b0bd07
					
				
							
								
								
									
										16
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								README.md
									
									
									
									
									
								
							@ -96,3 +96,19 @@ Ignore a bad TLS/SSL/HTTPS certificate and connect anyway.
 | 
			
		||||
```bash
 | 
			
		||||
sclient -k badtls.telebit.cloud:443 localhost:3000
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Reading from stdin
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
sclient telebit.cloud:443 -
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
sclient telebit.cloud:443 - </path/to/file
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Piping
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
printf "GET / HTTP/1.1\r\nHost: telebit.cloud\r\n\r\n" | sclient telebit.cloud:443
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@ -25,12 +25,18 @@ func main() {
 | 
			
		||||
	insecure := flag.Bool("k", false, "ignore bad TLS/SSL/HTTPS certificates")
 | 
			
		||||
	flag.BoolVar(insecure, "insecure", false, "ignore bad TLS/SSL/HTTPS certificates")
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
	remotestr := flag.Arg(0)
 | 
			
		||||
	localstr := flag.Arg(1)
 | 
			
		||||
 | 
			
		||||
	// NArg, Arg, Args
 | 
			
		||||
	i := flag.NArg()
 | 
			
		||||
	if 2 != i {
 | 
			
		||||
		usage()
 | 
			
		||||
		os.Exit(0)
 | 
			
		||||
		// We may omit the second argument if we're going straight to stdin
 | 
			
		||||
		if stat, _ := os.Stdin.Stat(); 1 == i && (stat.Mode()&os.ModeCharDevice) == 0 {
 | 
			
		||||
			localstr = "|"
 | 
			
		||||
		} else {
 | 
			
		||||
			usage()
 | 
			
		||||
			os.Exit(1)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	opts := &SclientOpts{}
 | 
			
		||||
@ -38,8 +44,8 @@ func main() {
 | 
			
		||||
	opts.LocalAddress = "localhost"
 | 
			
		||||
	opts.InsecureSkipVerify = *insecure
 | 
			
		||||
 | 
			
		||||
	remote := strings.Split(flag.Arg(0), ":")
 | 
			
		||||
	//remoteAddr, remotePort, err := net.SplitHostPort(flag.Arg(0))
 | 
			
		||||
	remote := strings.Split(remotestr, ":")
 | 
			
		||||
	//remoteAddr, remotePort, err := net.SplitHostPort(remotestr)
 | 
			
		||||
	if 2 == len(remote) {
 | 
			
		||||
		rport, err := strconv.Atoi(remote[1])
 | 
			
		||||
		if nil != err {
 | 
			
		||||
@ -53,30 +59,37 @@ func main() {
 | 
			
		||||
	}
 | 
			
		||||
	opts.RemoteAddress = remote[0]
 | 
			
		||||
 | 
			
		||||
	local := strings.Split(flag.Arg(1), ":")
 | 
			
		||||
	//localAddr, localPort, err := net.SplitHostPort(flag.Arg(0))
 | 
			
		||||
 | 
			
		||||
	if 1 == len(local) {
 | 
			
		||||
		lport, err := strconv.Atoi(local[0])
 | 
			
		||||
		if nil != err {
 | 
			
		||||
			usage()
 | 
			
		||||
			os.Exit(0)
 | 
			
		||||
		}
 | 
			
		||||
		opts.LocalPort = lport
 | 
			
		||||
	if "-" == localstr || "|" == localstr {
 | 
			
		||||
		// User may specify stdin/stdout instead of net
 | 
			
		||||
		opts.LocalAddress = localstr
 | 
			
		||||
		opts.LocalPort = -1
 | 
			
		||||
	} else {
 | 
			
		||||
		lport, err := strconv.Atoi(local[1])
 | 
			
		||||
		if nil != err {
 | 
			
		||||
			usage()
 | 
			
		||||
			os.Exit(0)
 | 
			
		||||
		// Test that argument is a local address
 | 
			
		||||
		local := strings.Split(localstr, ":")
 | 
			
		||||
 | 
			
		||||
		if 1 == len(local) {
 | 
			
		||||
			lport, err := strconv.Atoi(local[0])
 | 
			
		||||
			if nil != err {
 | 
			
		||||
				usage()
 | 
			
		||||
				os.Exit(0)
 | 
			
		||||
			}
 | 
			
		||||
			opts.LocalPort = lport
 | 
			
		||||
		} else {
 | 
			
		||||
			lport, err := strconv.Atoi(local[1])
 | 
			
		||||
			if nil != err {
 | 
			
		||||
				usage()
 | 
			
		||||
				os.Exit(0)
 | 
			
		||||
			}
 | 
			
		||||
			opts.LocalAddress = local[0]
 | 
			
		||||
			opts.LocalPort = lport
 | 
			
		||||
		}
 | 
			
		||||
		opts.LocalAddress = local[0]
 | 
			
		||||
		opts.LocalPort = lport
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sclient := &Sclient{}
 | 
			
		||||
	err := sclient.DialAndListen(opts)
 | 
			
		||||
	if nil != err {
 | 
			
		||||
		usage()
 | 
			
		||||
		os.Exit(0)
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "%s\n", err)
 | 
			
		||||
		//usage()
 | 
			
		||||
		//os.Exit(6)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										60
									
								
								sclient.go
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								sclient.go
									
									
									
									
									
								
							@ -10,6 +10,36 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// I wonder if I can get this to exactly mirror UnixAddr without passing it in
 | 
			
		||||
type stdaddr struct {
 | 
			
		||||
	net.UnixAddr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type stdnet struct {
 | 
			
		||||
	in   *os.File // os.Stdin
 | 
			
		||||
	out  *os.File // os.Stdout
 | 
			
		||||
	addr *stdaddr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rw *stdnet) Read(buf []byte) (n int, err error) {
 | 
			
		||||
	return rw.in.Read(buf)
 | 
			
		||||
}
 | 
			
		||||
func (rw *stdnet) Write(buf []byte) (n int, err error) {
 | 
			
		||||
	return rw.out.Write(buf)
 | 
			
		||||
}
 | 
			
		||||
func (rw *stdnet) Close() error {
 | 
			
		||||
	return rw.in.Close()
 | 
			
		||||
}
 | 
			
		||||
func (rw *stdnet) RemoteAddr() net.Addr {
 | 
			
		||||
	return rw.addr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// not all of net.Conn, just RWC and RemoteAddr()
 | 
			
		||||
type Rwc interface {
 | 
			
		||||
	io.ReadWriteCloser
 | 
			
		||||
	RemoteAddr() net.Addr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SclientOpts struct {
 | 
			
		||||
	RemoteAddress      string
 | 
			
		||||
	RemotePort         int
 | 
			
		||||
@ -20,13 +50,13 @@ type SclientOpts struct {
 | 
			
		||||
 | 
			
		||||
type Sclient struct{}
 | 
			
		||||
 | 
			
		||||
func pipe(r net.Conn, w net.Conn, t string) {
 | 
			
		||||
func pipe(r Rwc, w Rwc, t string) {
 | 
			
		||||
	buffer := make([]byte, 2048)
 | 
			
		||||
	for {
 | 
			
		||||
		done := false
 | 
			
		||||
		// NOTE: count may be > 0 even if there's an err
 | 
			
		||||
		count, err := r.Read(buffer)
 | 
			
		||||
		//fmt.Fprintf(os.Stdout, "[debug] (%s) reading\n", t)
 | 
			
		||||
		count, err := r.Read(buffer)
 | 
			
		||||
		if nil != err {
 | 
			
		||||
			//fmt.Fprintf(os.Stdout, "[debug] (%s:%d) error reading %s\n", t, count, err)
 | 
			
		||||
			if io.EOF != err {
 | 
			
		||||
@ -56,7 +86,7 @@ func pipe(r net.Conn, w net.Conn, t string) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func handleConnection(remote string, conn net.Conn, opts *SclientOpts) {
 | 
			
		||||
func handleConnection(remote string, conn Rwc, opts *SclientOpts) {
 | 
			
		||||
	sclient, err := tls.Dial("tcp", remote,
 | 
			
		||||
		&tls.Config{InsecureSkipVerify: opts.InsecureSkipVerify})
 | 
			
		||||
 | 
			
		||||
@ -66,8 +96,13 @@ func handleConnection(remote string, conn net.Conn, opts *SclientOpts) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Fprintf(os.Stdout, "[connect] %s => %s:%d\n",
 | 
			
		||||
		strings.Replace(conn.RemoteAddr().String(), "[::1]:", "localhost:", 1), opts.RemoteAddress, opts.RemotePort)
 | 
			
		||||
	if "stdio" == conn.RemoteAddr().Network() {
 | 
			
		||||
		fmt.Fprintf(os.Stdout, "(connected to %s:%d and reading from %s)\n",
 | 
			
		||||
			opts.RemoteAddress, opts.RemotePort, conn.RemoteAddr().String())
 | 
			
		||||
	} else {
 | 
			
		||||
		fmt.Fprintf(os.Stdout, "[connect] %s => %s:%d\n",
 | 
			
		||||
			strings.Replace(conn.RemoteAddr().String(), "[::1]:", "localhost:", 1), opts.RemoteAddress, opts.RemotePort)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	go pipe(conn, sclient, "local")
 | 
			
		||||
	pipe(sclient, conn, "remote")
 | 
			
		||||
@ -84,6 +119,21 @@ func (*Sclient) DialAndListen(opts *SclientOpts) error {
 | 
			
		||||
		conn.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// use stdin/stdout
 | 
			
		||||
	if "-" == opts.LocalAddress || "|" == opts.LocalAddress {
 | 
			
		||||
		var name string
 | 
			
		||||
		network := "stdio"
 | 
			
		||||
		if "|" == opts.LocalAddress {
 | 
			
		||||
			name = "pipe"
 | 
			
		||||
		} else {
 | 
			
		||||
			name = "stdin"
 | 
			
		||||
		}
 | 
			
		||||
		conn := &stdnet{os.Stdin, os.Stdout, &stdaddr{net.UnixAddr{name, network}}}
 | 
			
		||||
		handleConnection(remote, conn, opts)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// use net.Conn
 | 
			
		||||
	local := opts.LocalAddress + ":" + strconv.Itoa(opts.LocalPort)
 | 
			
		||||
	ln, err := net.Listen("tcp", local)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										5
									
								
								tests/get.bin
									
									
									
									
									
										Archivo normal
									
								
							
							
						
						
									
										5
									
								
								tests/get.bin
									
									
									
									
									
										Archivo normal
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
GET / HTTP/1.1
 | 
			
		||||
Host: telebit.cloud
 | 
			
		||||
Connection: close
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										8
									
								
								tests/localhost.sh
									
									
									
									
									
										Archivo ejecutable
									
								
							
							
						
						
									
										8
									
								
								tests/localhost.sh
									
									
									
									
									
										Archivo ejecutable
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
go run -race sclient*.go telebit.cloud:443 localhost:3000 &
 | 
			
		||||
my_pid=$!
 | 
			
		||||
sleep 5
 | 
			
		||||
 | 
			
		||||
netcat localhost 3000 < tests/get.bin
 | 
			
		||||
kill $my_pid
 | 
			
		||||
							
								
								
									
										3
									
								
								tests/pipe.sh
									
									
									
									
									
										Archivo ejecutable
									
								
							
							
						
						
									
										3
									
								
								tests/pipe.sh
									
									
									
									
									
										Archivo ejecutable
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
cat tests/get.bin | go run -race sclient*.go telebit.cloud:443
 | 
			
		||||
							
								
								
									
										3
									
								
								tests/stdin.sh
									
									
									
									
									
										Archivo ejecutable
									
								
							
							
						
						
									
										3
									
								
								tests/stdin.sh
									
									
									
									
									
										Archivo ejecutable
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
go run -race sclient*.go telebit.cloud:443 - < ./tests/get.bin
 | 
			
		||||
		Cargando…
	
	
			
			x
			
			
		
	
		Referencia en una nueva incidencia
	
	Block a user