rewrite the all code for using yaml config
master
Dingjun 8 years ago
parent 99ce1db7bb
commit 07994fed98

1
.gitignore vendored

@ -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()
var configfile string
flag.StringVar(&configfile, "c", "config.yaml", "config file")
flag.Parse()
if remote == "" {
log.Fatal("please use --remote to special the server")
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)
}
server_main()
return
}
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)
}
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)
}
if client {
local_main()
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
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…
Cancel
Save