add dynamic http forward throungh secure channel

like dynamic forward, but this accept HTTP request incoming,
not socks5.
The destination is determined by http request, the quest is forwarded
through ssh secure channel.
tls
fangdingjun 7 years ago
parent 2413a56408
commit d91bc0bcf6

@ -1,15 +1,20 @@
package obfssh
import (
"bufio"
"fmt"
socks "github.com/fangdingjun/socks-go"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/terminal"
"io"
"net"
"net/http"
"os"
"os/signal"
"strings"
"syscall"
"time"
socks "github.com/fangdingjun/socks-go"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/terminal"
)
// Client is ssh client connection
@ -333,3 +338,110 @@ func (cc *Client) registerSignal() {
}
}
}
// AddDynamicHTTPForward add a http dynamic forward through
// secure channel
func (cc *Client) AddDynamicHTTPForward(addr string) error {
l, err := net.Listen("tcp", addr)
if err != nil {
Log(ERROR, "listen on %s failed, %s", addr, err)
return err
}
cc.listeners = append(cc.listeners, l)
go func(l net.Listener) {
// defer l.Close()
for {
c, err := l.Accept()
if err != nil {
Log(ERROR, "accept error %s", err)
break
}
go cc.handleHTTPIncoming(c)
}
}(l)
return nil
}
func (cc *Client) handleHTTPIncoming(c net.Conn) {
defer c.Close()
r := bufio.NewReader(c)
req, err := http.ReadRequest(r)
if err != nil {
Log(ERROR, "read http request error %s", err)
return
}
if req.Method == "CONNECT" {
cc.handleConnect(req, c)
return
}
cc.handleHTTPReq(req, c)
}
func (cc *Client) handleConnect(req *http.Request, c net.Conn) {
Log(DEBUG, "connect to %s", req.RequestURI)
c1, err := cc.client.Dial("tcp", req.RequestURI)
if err != nil {
fmt.Fprintf(c, "HTTP/1.0 503 connection failed\r\n\r\n")
Log(ERROR, "dial error %s", err)
return
}
defer c1.Close()
fmt.Fprintf(c, "HTTP/1.0 200 connection established\r\n\r\n")
ch := make(chan struct{}, 2)
go func() {
io.Copy(c1, c)
ch <- struct{}{}
}()
go func() {
io.Copy(c, c1)
ch <- struct{}{}
}()
<-ch
}
func (cc *Client) handleHTTPReq(req *http.Request, c net.Conn) {
host := req.Host
if !strings.Contains(host, ":") {
host = fmt.Sprintf("%s:80", host)
}
Log(DEBUG, "request to %s", host)
c1, err := cc.client.Dial("tcp", host)
if err != nil {
fmt.Fprintf(c, "HTTP/1.1 503 connection failed\r\nConnection: close\r\n\r\n")
Log(ERROR, "connection failed %s", err)
return
}
defer c1.Close()
if err = req.Write(c1); err != nil {
fmt.Fprintf(c, "HTTP/1.1 503 write to server error\r\nConnection: close\r\n\r\n")
Log(ERROR, "write request to server error %s", err)
return
}
ch := make(chan struct{}, 2)
go func() {
io.Copy(c1, c)
ch <- struct{}{}
}()
go func() {
io.Copy(c, c1)
ch <- struct{}{}
}()
<-ch
}

@ -7,7 +7,7 @@ import (
"time"
)
func testTimedOutConn(t *testing.T, timeout bool) {
func testTimedOutConn(t *testing.T, _timeout bool) {
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("listen failed: %s", err)
@ -37,7 +37,7 @@ func testTimedOutConn(t *testing.T, timeout bool) {
t.Fatalf("server read failed: %s", err)
}
if timeout {
if _timeout {
time.Sleep(timeout + 1*time.Second)
}
@ -62,7 +62,7 @@ func testTimedOutConn(t *testing.T, timeout bool) {
buf := make([]byte, 100)
n, err := cConn.Read(buf)
if timeout {
if _timeout {
if err == nil {
t.Errorf("expeced timeout error, got nil")
} else {

@ -2,9 +2,10 @@ package main
import (
"flag"
"github.com/go-yaml/yaml"
"io/ioutil"
"strings"
"github.com/go-yaml/yaml"
)
// stringSlice implemnts the flag.Value interface
@ -58,6 +59,7 @@ type config struct {
LocalForwards stringSlice `yaml:"local_forward"`
RemoteForwards stringSlice `yaml:"remote_forward"`
DynamicForwards stringSlice `yaml:"dynamic_forward"`
DynamicHTTP stringSlice `yaml:"dynamic_http"`
Proxy proxy
}

@ -154,3 +154,16 @@
# dynamic_forward:
# - :3224
# - 127.0.0.1:9883
# dynamic_http
#
# Listen a port to accept http request incoming
# and dynamic forward the request
# to remote server through secure channel.
# This option can be specified multiple times.
# format [bind_adress:]port
# dynamic_http:
# - :8080
# - :127.0.0.1:8180

@ -4,8 +4,6 @@ import (
"bufio"
"crypto/tls"
"fmt"
"github.com/fangdingjun/obfssh"
socks "github.com/fangdingjun/socks-go"
"io"
"net"
"net/textproto"
@ -14,6 +12,9 @@ import (
"strconv"
"strings"
"time"
"github.com/fangdingjun/obfssh"
socks "github.com/fangdingjun/socks-go"
)
type httpProxyConn struct {

@ -4,10 +4,6 @@ import (
"crypto/tls"
"flag"
"fmt"
"github.com/bgentry/speakeasy"
"github.com/fangdingjun/obfssh"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
"io/ioutil"
"log"
"net"
@ -15,6 +11,11 @@ import (
"path/filepath"
"strings"
"time"
"github.com/bgentry/speakeasy"
"github.com/fangdingjun/obfssh"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
var dialer = &net.Dialer{Timeout: 15 * time.Second}
@ -270,6 +271,19 @@ func main() {
}
}
for _, p := range cfg.DynamicHTTP {
if strings.Index(p, ":") == -1 {
local = fmt.Sprintf(":%s", p)
} else {
local = p
}
//log.Printf("listen on %s", local)
if err := client.AddDynamicHTTPForward(local); err != nil {
log.Println(err)
}
}
hasErr := false
if !cfg.NotRunCmd {

@ -2,10 +2,11 @@ package obfssh
import (
"fmt"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
"net"
"time"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
)
// Server is server connection

Loading…
Cancel
Save