Skip to content

Commit

Permalink
temp ok
Browse files Browse the repository at this point in the history
  • Loading branch information
mojocn committed Nov 9, 2024
1 parent 066f289 commit 35818ec
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 93 deletions.
38 changes: 36 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/mojocn/felix

go 1.12
go 1.23

require (
github.com/PuerkitoBio/goquery v1.5.0
Expand All @@ -11,7 +11,7 @@ require (
github.com/gin-gonic/gin v1.4.0
github.com/gliderlabs/ssh v0.2.2
github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.4.0
github.com/gorilla/websocket v1.5.3
github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365
github.com/jinzhu/gorm v1.9.5
github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a
Expand All @@ -30,3 +30,37 @@ require (
golang.org/x/net v0.0.0-20190522155817-f3200d17e092
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b
)

require (
cloud.google.com/go v0.37.4 // indirect
github.com/andybalholm/cascadia v1.0.0 // indirect
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 // indirect
github.com/denisenkom/go-mssqldb v0.0.0-20190423183735-731ef375ac02 // indirect
github.com/fsnotify/fsnotify v1.4.7 // indirect
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 // indirect
github.com/go-sql-driver/mysql v1.4.1 // indirect
github.com/golang/protobuf v1.3.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/johntdyer/slack-go v0.0.0-20180213144715-95fac1160b22 // indirect
github.com/json-iterator/go v1.1.6 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.1 // indirect
github.com/kr/fs v0.1.0 // indirect
github.com/lib/pq v1.1.0 // indirect
github.com/magiconair/properties v1.8.0 // indirect
github.com/mattn/go-colorable v0.1.1 // indirect
github.com/mitchellh/mapstructure v1.1.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/pelletier/go-toml v1.2.0 // indirect
github.com/pkg/errors v0.8.0 // indirect
github.com/spf13/afero v1.1.2 // indirect
github.com/spf13/cast v1.3.0 // indirect
github.com/spf13/jwalterweatherman v1.0.0 // indirect
github.com/spf13/pflag v1.0.3 // indirect
github.com/ugorji/go v1.1.4 // indirect
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 // indirect
google.golang.org/appengine v1.4.0 // indirect
gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
gopkg.in/yaml.v2 v2.2.2 // indirect
)
5 changes: 2 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ github.com/denisenkom/go-mssqldb v0.0.0-20190423183735-731ef375ac02/go.mod h1:zA
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dhowden/itl v0.0.0-20170329215456-9fbe21093131/go.mod h1:eVWQJVQ67aMvYhpkDwaH2Goy2vo6v8JCMfGXfQ9sPtw=
github.com/dhowden/plist v0.0.0-20141002110153-5db6e0d9931a/go.mod h1:sLjdR6uwx3L6/Py8F+QgAfeiuY87xuYGwCDqRFrvCzw=
github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8 h1:OtSeLS5y0Uy01jaKK4mA/WVIYtpzVm63vLVAPzJXigg=
github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8/go.mod h1:apkPC/CR3s48O2D7Y++n1XWEpgPNNCjXYga3PPbJe2E=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
Expand Down Expand Up @@ -86,8 +84,9 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
Expand Down
154 changes: 68 additions & 86 deletions shadowos/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (ss *ShadowosApp) Run() {
}
}

func socks5packet(conn net.Conn, uuidS string) (connData []byte, err error) {
func handshake(conn net.Conn, uuidS string) (connData []byte, err error) {
uuidBytes, err := util.UUID2bytes(uuidS)
if err != nil {
return nil, fmt.Errorf("failed to parse UUID: %w", err)
Expand Down Expand Up @@ -141,125 +141,107 @@ func socks5packet(conn net.Conn, uuidS string) (connData []byte, err error) {

func (ss *ShadowosApp) handleConnection(conn net.Conn) {
defer conn.Close()

connBytes, err := socks5packet(conn, ss.UUID)
connBytes, err := handshake(conn, ss.UUID)
if err != nil {
log.Printf("failed to parse SOCKS5 request: %v", err)
return
}
// Read the version and number of authentication methods

// Connect to the target server
ws, err := NewWebsocketConn(ss.AddrWs)
session, err := NewProxySession(ss.AddrWs, connBytes)
if err != nil {
log.Printf("failed to connect to target: %v", err)
conn.Write([]byte{SOCKS5VERSION, 0x01, 0x00, 0x01, 0, 0, 0, 0, 0, 0})
return
} else { // Send success response
conn.Write([]byte{SOCKS5VERSION, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0})
}
defer ws.Close()
// Relay data between client and target server
pipeWebsocketSocks5(ws, conn, connBytes)
}

func pipeWebsocketSocks5(ws *WebsocketConn, s5 net.Conn, firstData []byte) {
go func() { // s5 -> ws
buf := make([]byte, 1024)
for {

n, err := s5.Read(buf)
if err == io.EOF {
log.Println("EOF from socks5")
continue
}
if err != nil {
log.Printf("read from socks5 error %T", err)
log.Println("read from socks5 error", err)
continue
}
log.Println("read from socks5", n)
data := buf[:n]
if len(firstData) > 0 {
log.Println("send version header only once")
data = append(firstData, buf[:n]...)
firstData = nil
}
_, err = ws.Write(data)
if err != nil {
log.Println("write error", err)
return
}

}
}()
isFirstData := true
for {
buf := make([]byte, 1024)
n, err := ws.Read(buf)
if err == io.EOF {
log.Println("EOF from ws")
continue
}
if err != nil {
log.Printf("read from ws -> socks5 error %T", err)
log.Println("read from ws -> socks5 error", err)
continue
}
fromByteIndex := 0
// skip the first data
if isFirstData && n >= 2 {
extraN := buf[1]
isFirstData = false
fromByteIndex = 2 + int(extraN)
}
_, err = s5.Write(buf[fromByteIndex:n])
if err != nil {
log.Println(" ws -> socks5 error", err)
return
}
defer session.Close()

}
go session.socks2ws(conn)
session.ws2socks(conn)

}

type WebsocketConn struct {
c *websocket.Conn
type ProxySession struct {
ws *websocket.Conn
connData []byte
isFirstData bool
ch chan struct{}
}

func NewWebsocketConn(url string) (*WebsocketConn, error) {
func NewProxySession(url string, initialData []byte) (*ProxySession, error) {
c, _, err := websocket.DefaultDialer.Dial(url, nil)
if err != nil {
return nil, fmt.Errorf("failed to connect to WebSocket server: %w", err)
}
return &WebsocketConn{c: c}, nil
return &ProxySession{
ws: c,
connData: initialData,
isFirstData: true,
ch: make(chan struct{}, 1),
}, nil
}

func (w WebsocketConn) Close() error {
err := w.c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
func (ps ProxySession) Close() error {
log.Println("websocket close message sent")

err := ps.ws.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println("failed to send close message", err)
return err
}
return w.c.Close()
return ps.ws.Close()
}

func (w WebsocketConn) Write(bytes []byte) (int, error) {
err := w.c.WriteMessage(websocket.BinaryMessage, bytes)
if err != nil {
return 0, err
func (ps *ProxySession) socks2ws(socks net.Conn) {
for {
buf := make([]byte, 1024)
n, err := socks.Read(buf)
log.Println("n", n)
if n > 0 {
log.Println("socks read N:", n)
if len(ps.connData) > 0 {
buf = append(ps.connData, buf[:n]...)
ps.connData = nil
} else {
buf = buf[:n]
}
err = ps.ws.WriteMessage(websocket.BinaryMessage, buf)
}
if err == io.EOF {
log.Println("socks5 connection closed")
return
}
if err != nil {
log.Println("failed to read from socks5 to websocket", err)
return
}
}
return len(bytes), nil
}

func (w WebsocketConn) Read(p []byte) (n int, err error) {
messageType, bytes, err := w.c.ReadMessage()
if err != nil {
return 0, err
}
if messageType != websocket.BinaryMessage {
return 0, fmt.Errorf("unexpected message type: %d", messageType)
func (ps *ProxySession) ws2socks(socks net.Conn) {
for {
messageType, data, err := ps.ws.ReadMessage()
log.Println("messageType", messageType)
log.Println("data", data)
log.Println("err", err)
if len(data) > 0 && messageType == websocket.BinaryMessage || messageType == websocket.TextMessage {
if ps.isFirstData && len(data) > 1 {
ps.isFirstData = false
extraN := int(data[1]) + 2
data = data[extraN:]
}
_, err = socks.Write(data)
}
if err == io.EOF {
return
}
if err != nil {
log.Println("messageType", messageType)
log.Println("failed to read from websocket to socks5", err)
return
}
}
n = copy(p, bytes)
return n, nil
}
4 changes: 3 additions & 1 deletion shadowos/app_test.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
package shadowos

import (
"github.com/sirupsen/logrus"
"log"
"testing"
)

var (
app = &ShadowosApp{
AddrWs: "ws://127.0.0.1:8787",
AddrWs: "ws://127.0.0.1:8787/53881505-c10c-464a-8949-e57184a576a9?clash",
AddrSocks5: "127.0.0.1:2080",
UUID: "53881505-c10c-464a-8949-e57184a576a9",
}
)

func TestShadowosApp_Run(t *testing.T) {
log.SetFlags(log.LstdFlags | log.Lshortfile)
logrus.SetReportCaller(true)
app.Run()
}
2 changes: 1 addition & 1 deletion shadowos/sock5_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func TestHttpOverSocks5(t *testing.T) {
}

func TestAAAAA(t *testing.T) {
list := []string{"a", "b", "c", "1"}
list := []string{"a", "b", "ws", "1"}
aa := list[1:2]
t.Log(aa)
}
79 changes: 79 additions & 0 deletions shadowos/socks5_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import socket
import socks
import json
import requests


def test_dns_query():
# Proxy details
proxy_host = '127.0.0.1'
proxy_port = 2080

# DNS server details
dns_server = '114.114.114.114' # Example: Google DNS
dns_port = 53

# Create a UDP socket with SOCKS5 proxy
sock = socks.socksocket(socket.AF_INET, socket.SOCK_DGRAM)
sock.set_proxy(socks.SOCKS5, proxy_host, proxy_port)
# DNS query message
# This is a simple DNS query for the domain "example.com"
# Transaction ID: 0x1234
# Flags: Standard query
# Questions: 1
# Answer RRs: 0
# Authority RRs: 0
# Additional RRs: 0
# Query: example.com, Type: A, Class: IN
message = b'\x12\x34' # Transaction ID
message += b'\x01\x00' # Flags
message += b'\x00\x01' # Questions
message += b'\x00\x00' # Answer RRs
message += b'\x00\x00' # Authority RRs
message += b'\x00\x00' # Additional RRs
message += b'\x07example\x03com\x00' # Query: example.com
message += b'\x00\x01' # Type: A
message += b'\x00\x01' # Class: IN

# Send the DNS query
sock.sendto(message, (dns_server, dns_port))

# Receive a response
response, addr = sock.recvfrom(4096)
print(f'Received response from {addr}: {response}')

# Close the socket
sock.close()


def test_http(size=1 * 1024):
# SOCKS5 proxy configuration
proxies = {
'http': 'socks5h://localhost:2080',
'https': 'socks5h://localhost:2080'
}

# Generate a 2MB JSON body
data = {'key': 'a' * size} # Adjusting for JSON formatting characters

# Convert the data to JSON format
json_data = json.dumps(data)

# URL to send the POST request to
url = 'http://httpbin.org/post'

# Send the POST request
response = requests.post(url, data=json_data, headers={'Content-Type': 'application/json'}, proxies=proxies)

# Print the response
print(f'Status Code: {response.status_code}')
print(f'Response Body: {response.text}')



# test_via_http()

test_http(5)
# test_dns_query()
# test_dns_query()
# test_http()

0 comments on commit 35818ec

Please sign in to comment.