parent
99ce1db7bb
commit
07994fed98
@ -1,3 +1,4 @@
|
||||
gtunnel*
|
||||
*~
|
||||
*bak
|
||||
*swp
|
||||
|
@ -1,37 +1,22 @@
|
||||
gtunnel
|
||||
======
|
||||
|
||||
A stunnel like util write by golang
|
||||
A stunnel-like util write by golang
|
||||
|
||||
There are two work mode.
|
||||
work mode
|
||||
========
|
||||
|
||||
###Client mode
|
||||
- listen plain, forward through plain
|
||||
- listen plain, forward through TLS
|
||||
- listen TLS, forward through plain
|
||||
- listen TLS, forward through TLS
|
||||
|
||||
In this mode, listen for incoming plain connections and forward to server to use SSL/TLS connections
|
||||
|
||||
###Server mode
|
||||
|
||||
In this mode, listen for incoming SSL/TLS connections and forward to backend use plain connections
|
||||
|
||||
###Build
|
||||
usage
|
||||
====
|
||||
|
||||
go get github.com/fangdingjun/gtunnel
|
||||
cd $GOPATH/src/github.com/fangdingjun/gtunnel
|
||||
go build
|
||||
|
||||
###Usage
|
||||
|
||||
server mode
|
||||
|
||||
./gtunnel --server --cert server.crt --key server.key --port 8001 --remote 127.0.0.1:80
|
||||
|
||||
listen for SSL/TLS connections on port 8001 and forward to 127.0.0.1:80
|
||||
|
||||
client mode
|
||||
|
||||
./gtunnel --client --port 8002 --remote www.example.com:8081
|
||||
|
||||
listen for plain connections on port 8002 and forward to www.example.com:8081 to use SSL/TLS connections
|
||||
|
||||
use `./gtunnel -h` see more options
|
||||
cp $GOPATH/src/github.com/fangdingjun/config_example.yaml config.yaml
|
||||
vim config.yaml
|
||||
$GOPATH/bin/gtunnel -c config.yaml
|
||||
|
||||
|
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConf(t *testing.T) {
|
||||
c, err := loadConfig("config_example.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Printf("%#v\n", c)
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
//"fmt"
|
||||
"github.com/go-yaml/yaml"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
type server struct {
|
||||
Listen listen
|
||||
Backend backend
|
||||
}
|
||||
|
||||
type conf []server
|
||||
|
||||
type listen struct {
|
||||
Host string
|
||||
Port int
|
||||
Cert string
|
||||
Key string
|
||||
}
|
||||
|
||||
type backend struct {
|
||||
Host string
|
||||
Port int
|
||||
Hostname string
|
||||
TLS bool
|
||||
Insecure bool
|
||||
}
|
||||
|
||||
func loadConfig(fn string) (*conf, error) {
|
||||
data, err := ioutil.ReadFile(fn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := new(conf)
|
||||
err = yaml.Unmarshal(data, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
# gtunnel can do the follow things
|
||||
# a. listen plain, forward through TLS
|
||||
# b. listen plain, forward through plain
|
||||
# c. listen TLS, forward through plain
|
||||
# d. listen TLS, forward through TLS
|
||||
#
|
||||
# when cert and key specified it will listen on TLS
|
||||
#
|
||||
|
||||
-
|
||||
# listen plain and forward through TLS
|
||||
listen:
|
||||
host: 0.0.0.0
|
||||
port: 4120
|
||||
|
||||
backend:
|
||||
host: 1.2.3.4
|
||||
port: 443
|
||||
|
||||
# tls sni
|
||||
hostname: example.com
|
||||
|
||||
# use TLS
|
||||
tls: true
|
||||
|
||||
# verify server certificate or not
|
||||
# when set true, will not verify the server's certificate(danger)
|
||||
insecure: false
|
||||
|
||||
-
|
||||
# listen tls and forward through plain
|
||||
listen:
|
||||
host: 0.0.0.0
|
||||
port: 443
|
||||
cert: www.crt
|
||||
key: www.key
|
||||
|
||||
backend:
|
||||
host: 127.0.0.1
|
||||
port: 4120
|
||||
tls: false
|
||||
|
||||
# more port forwards
|
||||
|
||||
#-
|
||||
# # listen TLS, forward through TLS
|
||||
# listen:
|
||||
# host: 0.0.0.0
|
||||
# port: 3122
|
||||
# cert: file.crt
|
||||
# key: file.key
|
||||
#
|
||||
# backend:
|
||||
# host: www.example.com
|
||||
# port: 443
|
||||
# hostname: example.com
|
||||
# tls: true
|
@ -1,53 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
)
|
||||
|
||||
//var server string = "www.ratafee.nl:443"
|
||||
|
||||
func local_main() {
|
||||
l, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Printf("Listen on %s...", l.Addr())
|
||||
defer l.Close()
|
||||
|
||||
for {
|
||||
c, err := l.Accept()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
go handle_local(c)
|
||||
}
|
||||
}
|
||||
|
||||
func handle_local(c net.Conn) {
|
||||
//defer c.Close()
|
||||
log.Printf("accept connection from %s", c.RemoteAddr())
|
||||
log.Printf("connect to %s...", remote)
|
||||
s, err := tls.Dial("tcp", remote, nil)
|
||||
if err != nil {
|
||||
log.Printf("connect to %s failed: %s", remote, err.Error())
|
||||
c.Close()
|
||||
return
|
||||
}
|
||||
ch := make(chan int)
|
||||
//defer s.Close()
|
||||
go func() {
|
||||
count, _ := io.Copy(s, c)
|
||||
log.Printf("write %d bytes to %s", count, s.RemoteAddr())
|
||||
s.Close()
|
||||
ch <- 1
|
||||
}()
|
||||
co, _ := io.Copy(c, s)
|
||||
log.Printf("write %d bytes to %s", co, c.RemoteAddr())
|
||||
c.Close()
|
||||
<-ch
|
||||
}
|
@ -1,39 +1,111 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"flag"
|
||||
"github.com/fangdingjun/iniflags"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
)
|
||||
|
||||
var remote string
|
||||
|
||||
func main() {
|
||||
var server, client bool
|
||||
flag.StringVar(&remote, "remote", "", "remote server")
|
||||
flag.IntVar(&port, "port", 8080, "the listen port")
|
||||
flag.BoolVar(&server, "server", false, "tls server mode")
|
||||
flag.BoolVar(&client, "client", false, "tls client mode")
|
||||
flag.StringVar(&cert, "cert", "", "the certificate file")
|
||||
flag.StringVar(&key, "key", "", "the private key")
|
||||
iniflags.Parse()
|
||||
|
||||
if remote == "" {
|
||||
log.Fatal("please use --remote to special the server")
|
||||
var configfile string
|
||||
|
||||
flag.StringVar(&configfile, "c", "config.yaml", "config file")
|
||||
flag.Parse()
|
||||
|
||||
cfg, err := loadConfig(configfile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if server {
|
||||
if cert == "" || key == "" {
|
||||
log.Fatal("in server mode, you must special the certificate and private key")
|
||||
initServer(cfg)
|
||||
|
||||
select {}
|
||||
}
|
||||
|
||||
func initServer(cfg *conf) {
|
||||
for _, srv := range *cfg {
|
||||
go initListener(srv)
|
||||
}
|
||||
}
|
||||
|
||||
func initListener(srv server) {
|
||||
var l net.Listener
|
||||
var err error
|
||||
|
||||
host := net.JoinHostPort(srv.Listen.Host, fmt.Sprintf("%d", srv.Listen.Port))
|
||||
|
||||
if srv.Listen.Cert != "" && srv.Listen.Key != "" {
|
||||
cert, err := tls.LoadX509KeyPair(srv.Listen.Cert, srv.Listen.Key)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
server_main()
|
||||
return
|
||||
config := &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}
|
||||
|
||||
l, err = tls.Listen("tcp", host, config)
|
||||
} else {
|
||||
l, err = net.Listen("tcp", host)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for {
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
break
|
||||
}
|
||||
go handleConn(conn, srv.Backend)
|
||||
}
|
||||
}
|
||||
|
||||
func handleConn(conn net.Conn, b backend) {
|
||||
var c net.Conn
|
||||
var err error
|
||||
|
||||
if client {
|
||||
local_main()
|
||||
host := net.JoinHostPort(b.Host, fmt.Sprintf("%d", b.Port))
|
||||
if b.TLS {
|
||||
hostname := b.Host
|
||||
if b.Hostname != "" {
|
||||
hostname = b.Hostname
|
||||
}
|
||||
config := &tls.Config{
|
||||
ServerName: hostname,
|
||||
InsecureSkipVerify: b.Insecure,
|
||||
}
|
||||
c, err = tls.Dial("tcp", host, config)
|
||||
} else {
|
||||
c, err = net.Dial("tcp", host)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Fatal("please use --server or --client to special a work mode")
|
||||
pipeAndClose(conn, c)
|
||||
}
|
||||
|
||||
func pipeAndClose(c1, c2 net.Conn) {
|
||||
defer c1.Close()
|
||||
defer c2.Close()
|
||||
|
||||
ch := make(chan struct{}, 2)
|
||||
go func() {
|
||||
io.Copy(c1, c2)
|
||||
ch <- struct{}{}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
io.Copy(c2, c1)
|
||||
ch <- struct{}{}
|
||||
}()
|
||||
|
||||
<-ch
|
||||
}
|
||||
|
@ -1,60 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
)
|
||||
|
||||
//var backend = "127.0.0.1:8080"
|
||||
var cert = "server.crt"
|
||||
var key = "server.key"
|
||||
var port = 9000
|
||||
|
||||
func server_main() {
|
||||
certificate, err := tls.LoadX509KeyPair(cert, key)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
l, err := tls.Listen("tcp", fmt.Sprintf(":%d", port), &tls.Config{
|
||||
Certificates: []tls.Certificate{certificate},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
for {
|
||||
c, err := l.Accept()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
go handle_server(c)
|
||||
}
|
||||
}
|
||||
|
||||
func handle_server(c net.Conn) {
|
||||
log.Printf("accept connection from %s", c.RemoteAddr())
|
||||
s, err := net.Dial("tcp", remote)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
c.Close()
|
||||
return
|
||||
}
|
||||
|
||||
ch := make(chan int)
|
||||
go func() {
|
||||
count, _ := io.Copy(s, c)
|
||||
s.Close()
|
||||
log.Printf("write %d bytes to %s", count, s.RemoteAddr())
|
||||
ch <- 1
|
||||
}()
|
||||
|
||||
co, _ := io.Copy(c, s)
|
||||
c.Close()
|
||||
log.Printf("write %d bytes to %s", co, c.RemoteAddr())
|
||||
<-ch
|
||||
}
|
Loading…
Reference in New Issue