update: improve http tunnel and slug extraction from domain
This commit is contained in:
66
http/http.go
66
http/http.go
@ -2,34 +2,60 @@ package httpServer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"tunnel_pls/session"
|
"tunnel_pls/session"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Listen() {
|
func Listen() {
|
||||||
server := http.Server{
|
server, err := net.Listen("tcp", ":80")
|
||||||
Addr: ":80",
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer server.Close()
|
||||||
|
log.Println("Listening on :80")
|
||||||
|
for {
|
||||||
|
conn, err := server.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
go handleRequest(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleRequest(conn net.Conn) {
|
||||||
|
defer conn.Close()
|
||||||
var rawRequest string
|
var rawRequest string
|
||||||
|
|
||||||
|
reader := bufio.NewReader(conn)
|
||||||
|
r, err := http.ReadRequest(reader)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error reading request:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
slug := strings.Split(r.Host, ".")[0]
|
slug := strings.Split(r.Host, ".")[0]
|
||||||
if slug == "" {
|
if slug == "" {
|
||||||
http.Error(w, "You fuck up man", http.StatusBadRequest)
|
fmt.Println("Error parsing slug: ", r.Host)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sshSession, ok := session.Clients[slug]
|
sshSession, ok := session.Clients[slug]
|
||||||
if !ok {
|
if !ok {
|
||||||
http.Error(w, "Bad Gateway", http.StatusBadGateway)
|
fmt.Println("Error finding ssh session: ", slug)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rawRequest += fmt.Sprintf("%s %s %s\r\n", r.Method, r.URL.RequestURI(), r.Proto)
|
rawRequest += fmt.Sprintf("%s %s %s\r\n", r.Method, r.URL.RequestURI(), r.Proto)
|
||||||
rawRequest += fmt.Sprintf("Host: %s\r\n", r.Host)
|
rawRequest += fmt.Sprintf("Host: %s\r\n", r.Host)
|
||||||
|
|
||||||
for k, v := range r.Header {
|
for k, v := range r.Header {
|
||||||
rawRequest += fmt.Sprintf("%s: %s\r\n", k, v[0])
|
rawRequest += fmt.Sprintf("%s: %s\r\n", k, v[0])
|
||||||
}
|
}
|
||||||
@ -43,31 +69,9 @@ func Listen() {
|
|||||||
rawRequest += string(body)
|
rawRequest += string(body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
payload := []byte(rawRequest)
|
payload := []byte(rawRequest)
|
||||||
|
|
||||||
host, originPort := session.ParseAddr(r.RemoteAddr)
|
host, originPort := session.ParseAddr(conn.RemoteAddr().String())
|
||||||
data := sshSession.GetForwardedConnection(host, sshSession.Connection, payload, originPort, 80)
|
sshSession.GetForwardedConnection(conn, host, sshSession.Connection, payload, originPort, 80)
|
||||||
|
|
||||||
response, err := http.ReadResponse(bufio.NewReader(bytes.NewReader(data)), r)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var isServerSet = false
|
|
||||||
for k, v := range response.Header {
|
|
||||||
if k == "Server" {
|
|
||||||
isServerSet = true
|
|
||||||
w.Header().Set(k, fmt.Sprintf("Tunnel_Pls/%v", response.Header[k][0]))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
w.Header().Set(k, v[0])
|
|
||||||
}
|
|
||||||
if !isServerSet {
|
|
||||||
w.Header().Set("Server", "Tunnel_Pls")
|
|
||||||
}
|
|
||||||
w.WriteHeader(response.StatusCode)
|
|
||||||
io.Copy(w, response.Body)
|
|
||||||
})
|
|
||||||
|
|
||||||
fmt.Println("Listening on port 80")
|
|
||||||
server.ListenAndServe()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package session
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -14,6 +13,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
"tunnel_pls/proto"
|
"tunnel_pls/proto"
|
||||||
|
"tunnel_pls/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Session) handleGlobalRequest() {
|
func (s *Session) handleGlobalRequest() {
|
||||||
@ -45,12 +45,19 @@ func (s *Session) handleGlobalRequest() {
|
|||||||
|
|
||||||
if portToBind == 80 || portToBind == 443 {
|
if portToBind == 80 || portToBind == 443 {
|
||||||
s.TunnelType = HTTP
|
s.TunnelType = HTTP
|
||||||
Clients["test"] = s
|
var slug string
|
||||||
// TODO: dont forward traffic to the listener below
|
for {
|
||||||
|
slug = utils.GenerateRandomString(32)
|
||||||
|
if _, ok := Clients[slug]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
Clients[slug] = s
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
binary.Write(buf, binary.BigEndian, uint32(portToBind))
|
binary.Write(buf, binary.BigEndian, uint32(portToBind))
|
||||||
|
|
||||||
log.Printf("Forwarding approved on port: %d", portToBind)
|
log.Printf("Forwarding approved on port: %d", portToBind)
|
||||||
|
s.ConnChannels[0].Write([]byte(fmt.Sprintf("Forwarding your traffic to http://%s.tunnl.live", slug)))
|
||||||
req.Reply(true, buf.Bytes())
|
req.Reply(true, buf.Bytes())
|
||||||
} else {
|
} else {
|
||||||
s.TunnelType = TCP
|
s.TunnelType = TCP
|
||||||
@ -73,7 +80,7 @@ func (s *Session) handleGlobalRequest() {
|
|||||||
log.Printf("Error accepting connection: %v", err)
|
log.Printf("Error accepting connection: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Println("ini bind : ", portToBind)
|
|
||||||
go s.HandleForwardedConnection(conn, s.Connection, portToBind)
|
go s.HandleForwardedConnection(conn, s.Connection, portToBind)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -184,6 +191,7 @@ func (s *Session) HandleSessionChannel(newChannel ssh.NewChannel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
connection.Write([]byte("\r\n\r\n"))
|
connection.Write([]byte("\r\n\r\n"))
|
||||||
|
go s.handleGlobalRequest()
|
||||||
|
|
||||||
for req := range requests {
|
for req := range requests {
|
||||||
switch req.Type {
|
switch req.Type {
|
||||||
@ -247,66 +255,35 @@ func (s *Session) HandleForwardedConnection(conn net.Conn, sshConn *ssh.ServerCo
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Session) GetForwardedConnection(host string, sshConn *ssh.ServerConn, payload []byte, originPort, port uint32) []byte {
|
func (s *Session) GetForwardedConnection(conn net.Conn, host string, sshConn *ssh.ServerConn, payload []byte, originPort, port uint32) {
|
||||||
fmt.Println("Here 1")
|
defer conn.Close()
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
channelPayload := createForwardedTCPIPPayload(host, originPort, port)
|
channelPayload := createForwardedTCPIPPayload(host, originPort, port)
|
||||||
channel, reqs, err := sshConn.OpenChannel("forwarded-tcpip", channelPayload)
|
channel, reqs, err := sshConn.OpenChannel("forwarded-tcpip", channelPayload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to open forwarded-tcpip channel: %v", err)
|
log.Printf("Failed to open forwarded-tcpip channel: %v", err)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
fmt.Println("Here 2")
|
|
||||||
|
|
||||||
defer channel.Close()
|
defer channel.Close()
|
||||||
|
|
||||||
head := bytes.NewReader(payload)
|
connReader := bufio.NewReader(conn)
|
||||||
go io.Copy(channel, head)
|
initalPayload := bytes.NewReader(payload)
|
||||||
fmt.Println("Here 3")
|
io.Copy(channel, initalPayload)
|
||||||
|
go io.Copy(channel, connReader)
|
||||||
|
|
||||||
|
reader := bufio.NewReader(channel)
|
||||||
|
_, err = reader.Peek(1)
|
||||||
|
if err == io.EOF {
|
||||||
|
io.Copy(conn, bytes.NewReader([]byte("HTTP/1.1 502 Bad Gateway\r\nContent-Length: 11\r\nContent-Type: text/plain\r\n\r\nBad Gateway")))
|
||||||
|
s.ConnChannels[0].Write([]byte("Could not forward request to the tunnel addr\r\n"))
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
io.Copy(conn, reader)
|
||||||
|
}
|
||||||
go func() {
|
go func() {
|
||||||
for req := range reqs {
|
for req := range reqs {
|
||||||
req.Reply(false, nil)
|
req.Reply(false, nil)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
fmt.Println("Here 4")
|
|
||||||
|
|
||||||
var data bytes.Buffer
|
|
||||||
done := make(chan error, 1)
|
|
||||||
go func() {
|
|
||||||
io.Copy(&data, channel)
|
|
||||||
done <- err
|
|
||||||
}()
|
|
||||||
go func() {
|
|
||||||
var lastSize int
|
|
||||||
ticker := time.NewTicker(100)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
case <-ticker.C:
|
|
||||||
currentSize := data.Len()
|
|
||||||
fmt.Println("Size buffer:", currentSize)
|
|
||||||
|
|
||||||
if currentSize == lastSize && currentSize > 0 {
|
|
||||||
fmt.Println("Buffer size unchanged, closing channel...")
|
|
||||||
cancel()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
lastSize = currentSize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return data.Bytes()
|
|
||||||
case err = <-done:
|
|
||||||
return data.Bytes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeSSHString(buffer *bytes.Buffer, str string) {
|
func writeSSHString(buffer *bytes.Buffer, str string) {
|
||||||
@ -317,7 +294,7 @@ func writeSSHString(buffer *bytes.Buffer, str string) {
|
|||||||
func ParseAddr(addr string) (string, uint32) {
|
func ParseAddr(addr string) (string, uint32) {
|
||||||
host, portStr, err := net.SplitHostPort(addr)
|
host, portStr, err := net.SplitHostPort(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Failed to parse origin address:", err)
|
log.Printf("Failed to parse origin address: %s from address %s", err.Error(), addr)
|
||||||
return "0.0.0.0", uint32(0)
|
return "0.0.0.0", uint32(0)
|
||||||
}
|
}
|
||||||
port, _ := strconv.Atoi(portStr)
|
port, _ := strconv.Atoi(portStr)
|
||||||
|
|||||||
@ -39,8 +39,6 @@ func New(conn *ssh.ServerConn, sshChannel <-chan ssh.NewChannel, req <-chan *ssh
|
|||||||
Done: make(chan bool),
|
Done: make(chan bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
go session.handleGlobalRequest()
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for newChannel := range sshChannel {
|
for newChannel := range sshChannel {
|
||||||
go session.HandleSessionChannel(newChannel)
|
go session.HandleSessionChannel(newChannel)
|
||||||
@ -65,5 +63,4 @@ func (session *Session) Close() {
|
|||||||
if err := session.Connection.Close(); err != nil {
|
if err := session.Connection.Close(); err != nil {
|
||||||
fmt.Println("Error closing connection : ", err.Error())
|
fmt.Println("Error closing connection : ", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
18
utils/utils.go
Normal file
18
utils/utils.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenerateRandomString(length int) string {
|
||||||
|
const charset = "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
seededRand := rand.New(rand.NewSource(time.Now().UnixNano() + int64(rand.Intn(9999))))
|
||||||
|
var result strings.Builder
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
randomIndex := seededRand.Intn(len(charset))
|
||||||
|
result.WriteString(string(charset[randomIndex]))
|
||||||
|
}
|
||||||
|
return result.String()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user