Skip to content

Instantly share code, notes, and snippets.

@cs8425
Created January 11, 2016 06:55
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save cs8425/a742349a55596f1b251a to your computer and use it in GitHub Desktop.
Save cs8425/a742349a55596f1b251a to your computer and use it in GitHub Desktop.
golang simple tcp/tls proxy
# wrok like:
#
# raw tcp(9999) tls(127.0.0.1:25500) raw tcp(25501)
# client =============> tcp2tls_client.go =====================> tls2tcp_server.go ==============> real server
#Generated private key
openssl genrsa -out server.key 2048
#To generate a certificate
openssl req -new -x509 -key server.key -out server.pem -days 3650
package main
import (
"log"
"crypto/tls"
"net"
)
const localAddr string = "127.0.0.1:9999"
const remoteAddr string = "127.0.0.1:25500"
const MaxConn int16 = 3
func proxyConn(conn net.Conn) {
defer conn.Close()
rAddr, err := net.ResolveTCPAddr("tcp", remoteAddr)
if err != nil {
log.Print(err)
}
conf := &tls.Config{
InsecureSkipVerify: true,
}
//rConn, err := net.DialTCP("tcp", nil, rAddr)
rConn, err := tls.Dial("tcp", rAddr.String(), conf)
if err != nil {
log.Print(err)
return
}
defer rConn.Close()
// log.Printf("remoteAddr connected: %v\n", rAddr.String())
Pipe(conn, rConn)
// log.Printf("proxyConn end: %v -> %v\n", conn.RemoteAddr(), rConn.RemoteAddr())
}
func chanFromConn(conn net.Conn) chan []byte {
c := make(chan []byte)
go func() {
b := make([]byte, 1024)
for {
n, err := conn.Read(b)
if n > 0 {
res := make([]byte, n)
// Copy the buffer so it doesn't get changed while read by the recipient.
copy(res, b[:n])
c <- res
}
if err != nil {
c <- nil
break
}
}
}()
return c
}
func Pipe(conn1 net.Conn, conn2 net.Conn) {
chan1 := chanFromConn(conn1)
chan2 := chanFromConn(conn2)
for {
select {
case b1 := <-chan1:
if b1 == nil {
return
} else {
conn2.Write(b1)
}
case b2 := <-chan2:
if b2 == nil {
return
} else {
conn1.Write(b2)
}
}
}
}
func main() {
log.SetFlags(log.Lshortfile)
log.Printf("Listening: %v -> %v\n\n", localAddr, remoteAddr)
addr, err := net.ResolveTCPAddr("tcp", localAddr)
if err != nil {
panic(err)
}
listener, err := net.ListenTCP("tcp", addr)
if err != nil {
panic(err)
}
var i int16 = 0;
count := make(chan int16, 1)
for {
log.Printf("wait accepted...\n")
conn, err := listener.AcceptTCP()
if err != nil {
log.Print(err)
}
//go proxyConn(conn);
//log.Printf("accepted: %v\n", conn.RemoteAddr())
select {
case t := <- count:
i += t
// print("received ", i, "\n")
default:
}
if i < MaxConn {
i++
log.Printf("[%v/%v]accepted: %v\n", i, MaxConn, conn.RemoteAddr())
// Create a new goroutine which will call the connection handler and then free up the space.
go func(connection net.Conn) {
proxyConn(connection)
// log.Printf("[%v/%v]Closed connection from %s\r\n", i, MaxConn, connection.RemoteAddr())
log.Printf("Closed connection from %s\r\n", connection.RemoteAddr())
select {
case t := <- count:
count <- t-1
default:
count <- -1
}
}(conn)
}else{
conn.Close()
// log.Printf("closed: %v\n", i)
}
}
}
package main
import (
"log"
"crypto/tls"
"net"
)
const localAddr string = ":25500"
const remoteAddr string = "127.0.0.1:25501"
const MaxConn int16 = 3
func main() {
log.SetFlags(log.Lshortfile)
cer, err := tls.LoadX509KeyPair("server.pem", "server.key")
if err != nil {
log.Println(err)
return
}
config := &tls.Config{Certificates: []tls.Certificate{cer}}
ln, err := tls.Listen("tcp", localAddr, config)
if err != nil {
log.Println(err)
return
}
defer ln.Close()
log.Printf("Listening: %v -> %v\n\n", localAddr, remoteAddr)
for {
conn, err := ln.Accept()
if err != nil {
log.Println(err)
continue
}
go proxyConn(conn)
}
}
func proxyConn(conn net.Conn) {
defer conn.Close()
rAddr, err := net.ResolveTCPAddr("tcp", remoteAddr)
if err != nil {
log.Print(err)
}
rConn, err := net.DialTCP("tcp", nil, rAddr)
if err != nil {
log.Print(err)
}
defer rConn.Close()
Pipe(conn, rConn)
log.Printf("handleConnection end: %s\n", conn.RemoteAddr())
}
func chanFromConn(conn net.Conn) chan []byte {
c := make(chan []byte)
go func() {
b := make([]byte, 1024)
for {
n, err := conn.Read(b)
if n > 0 {
res := make([]byte, n)
// Copy the buffer so it doesn't get changed while read by the recipient.
copy(res, b[:n])
c <- res
}
if err != nil {
c <- nil
break
}
}
}()
return c
}
func Pipe(conn1 net.Conn, conn2 net.Conn) {
chan1 := chanFromConn(conn1)
chan2 := chanFromConn(conn2)
for {
select {
case b1 := <-chan1:
if b1 == nil {
return
} else {
conn2.Write(b1)
}
case b2 := <-chan2:
if b2 == nil {
return
} else {
conn1.Write(b2)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment