Skip to content

Commit

Permalink
working on udp
Browse files Browse the repository at this point in the history
  • Loading branch information
uoosef committed Aug 29, 2023
1 parent 2ea25a3 commit 9e481ce
Show file tree
Hide file tree
Showing 3 changed files with 216 additions and 70 deletions.
164 changes: 100 additions & 64 deletions relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"bufio"
"errors"
"flag"
"fmt"
"io"
Expand All @@ -10,6 +11,34 @@ import (
"strings"
)

var cfRanges = []string{
"127.0.0.0/8",
"103.21.244.0/22",
"103.22.200.0/22",
"103.31.4.0/22",
"104.16.0.0/12",
"108.162.192.0/18",
"131.0.72.0/22",
"141.101.64.0/18",
"162.158.0.0/15",
"172.64.0.0/13",
"173.245.48.0/20",
"188.114.96.0/20",
"190.93.240.0/20",
"197.234.240.0/22",
"198.41.128.0/17",
"::1/128",
"2400:cb00::/32",
"2405:8100::/32",
"2405:b500::/32",
"2606:4700::/32",
"2803:f800::/32",
"2c0f:f248::/32",
"2a06:98c0::/29",
}

var ipRange []*net.IPNet

// Server ...
type Server struct {
host string
Expand All @@ -35,66 +64,28 @@ func New(config *Config) *Server {
}
}

func checkIfSourceIsAllowed(ip string) bool {
// Check if IPv6
if strings.Contains(ip, ":") {
// Allow IPv6 localhost
if strings.HasPrefix(ip, "[::1]") {
return true
}

// Check against allowed IPv6 CIDR ranges
cfv6Ranges := []string{
"2400:cb00::/32",
"2606:4700::/32",
"2803:f800::/32",
"2405:b500::/32",
"2405:8100::/32",
"2a06:98c0::/29",
"2c0f:f248::/32",
// etc
}
func checkIfSourceIsAllowed(ipAddress string) bool {
for _, r := range ipRange {
ip := net.ParseIP(ipAddress)

for _, r := range cfv6Ranges {
if strings.HasPrefix(ip, r) {
return true
}
if r.Contains(ip) {
return true
}

return false
}

// Check IPv4
if strings.HasPrefix(ip, "127.0.0.1") {
return true
}
return false
}

cfv4Ranges := []string{
"173.245.48.0/20",
"103.21.244.0/22",
"103.22.200.0/22",
"103.31.4.0/22",
"141.101.64.0/18",
"108.162.192.0/18",
"190.93.240.0/20",
"188.114.96.0/20",
"197.234.240.0/22",
"198.41.128.0/17",
"162.158.0.0/15",
"104.16.0.0/13",
"104.24.0.0/14",
"172.64.0.0/13",
"131.0.72.0/22",
// etc
}
func init() {
ipRange = []*net.IPNet{}

for _, r := range cfv4Ranges {
if strings.HasPrefix(ip, r) {
return true
for _, r := range cfRanges {
_, cidr, err := net.ParseCIDR(r)
if err != nil {
continue
}
ipRange = append(ipRange, cidr)
}

return false
}

// Run ...
Expand All @@ -112,7 +103,14 @@ func (server *Server) Run() {
}

ip := conn.RemoteAddr().String()
if !checkIfSourceIsAllowed(ip) {
sh, sp, err := net.SplitHostPort(ip)
if err != nil {
fmt.Println(fmt.Errorf("unable to parse host %s", ip))
_ = conn.Close()
continue
}
if !checkIfSourceIsAllowed(sh) {
fmt.Println(fmt.Errorf("request from unacceptable source blocked: %s:%s", sh, sp))
_ = conn.Close()
continue
}
Expand All @@ -130,30 +128,68 @@ func (client *Client) handleRequest() {
if len(header) < 1 {
return
}
address := strings.Replace(string(header[:len(header)-1]), "$", ":", -1)
inputHeader := strings.Split(string(header[:len(header)-1]), "@")
if len(inputHeader) < 2 {
return
}
network := "tcp"
if inputHeader[0] == "udp" {
network = "udp"
}
address := strings.Replace(inputHeader[1], "$", ":", -1)
if strings.Contains(address, "temp-mail.org") {
return
}
fmt.Printf("Dialing to %s...\r\n", address)
rConn, err := net.Dial("tcp", address)
if err != nil {
fmt.Println(fmt.Errorf("failed to connect to socket: %v", err))

if network == "udp" {
handleUDPOverTCP(client.conn, address)
return
}

// transmit data
go Copy(client.conn, rConn)
Copy(rConn, client.conn)
log.Printf("%s Dialing to %s...\r\n", network, address)
rConn, err := net.Dial(network, address)
if err != nil {
log.Println(fmt.Errorf("failed to connect to socket: %v", err))
return
}

go Copy(network, client.conn, rConn)
Copy(network, rConn, client.conn)

_ = rConn.Close()
_ = client.conn.Close()
}

func Copy(src io.Reader, dst io.Writer) {
func Copy(network string, src io.Reader, dst io.Writer) {
buf := make([]byte, 256*1024)

_, err := io.CopyBuffer(dst, src, buf[:cap(buf)])
if err != nil {
fmt.Println(err)
for {
nr, er := src.Read(buf)
if nr > 0 {
nw, ew := dst.Write(buf[0:nr])
if nw < 0 || nr < nw {
nw = 0
if ew == nil {
log.Println("error")
return
}
}
if ew != nil {
log.Println(ew)
return
}
if nr != nw {
log.Println("error")
return
}
}
if er != nil {
if er != errors.New("EOF") {
log.Println(er)
}
return
}
}
}

Expand Down
109 changes: 109 additions & 0 deletions udp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package main

import (
"fmt"
"log"
"net"
)

var (
activeTunnels = make(map[string]chan []byte)
udpToTCPChannels = make(map[string]chan []byte)
)

func chanFromConn(conn net.Conn) chan []byte {
c := make(chan []byte)

go func() {
b := make([]byte, 256*1024)

for {
n, err := conn.Read(b)
if n > 0 {
c <- b[:n]
}
if err != nil {
log.Printf("Connection closed: %v--->%v\r\n", conn.LocalAddr(), conn.RemoteAddr())
c <- nil
break
}
}
}()

return c
}

func handleUDPOverTCP(conn net.Conn, destination string) {
writeToWebsocketChannel := make(chan []byte)
activeTunnels[destination] = writeToWebsocketChannel
wsReadDataChan := chanFromConn(conn)

defer conn.Close()
defer delete(activeTunnels, destination)
for {
select {
case dataThatReceivedFromWebsocket := <-wsReadDataChan:
if dataThatReceivedFromWebsocket == nil {
return
} else {
c, err := getOrCreateUDPChanFromWebSocketPacket(dataThatReceivedFromWebsocket, destination)
if err == nil {
c <- dataThatReceivedFromWebsocket
} else {
log.Printf("unable to create connection to destination network: %v\r\n", err)
}
}
case dataThatReceivedFromUDPChan := <-activeTunnels[destination]:
// it never is null
if dataThatReceivedFromUDPChan != nil {
_, err := conn.Write(dataThatReceivedFromUDPChan)
if err != nil {
log.Printf("unable to write on destination network: %v\r\n", err)
return
}
}
}
}
}

func getOrCreateUDPChanFromWebSocketPacket(packet []byte, destination string) (chan []byte, error) {
// the first 8 byte of each packet is user random id(6bytes) + channel id(2bytes)
if len(packet) < 8 {
return nil, fmt.Errorf("too small packet")
}
packetHeader := packet[:8]
channelID := destination + string(packetHeader)
if udpWriteChan, ok := udpToTCPChannels[channelID]; ok {
return udpWriteChan, nil
}
udpConn, err := net.Dial("udp", destination)
if err != nil {
return nil, err
}
udpToTCPChannels[channelID] = make(chan []byte)
udpReadChanFromConn := chanFromConn(udpConn)
go func() {
for {
select {
case dataThatReceivedFromWebsocketThroughChannel := <-udpToTCPChannels[channelID]:
_, err := udpConn.Write(dataThatReceivedFromWebsocketThroughChannel[8:])
if err != nil {
fmt.Print("fuck")
delete(udpToTCPChannels, channelID)
return
}
case dataThatReceivedFromUDPReadChan := <-udpReadChanFromConn:
if dataThatReceivedFromUDPReadChan == nil {
fmt.Print("fuck2")
delete(udpToTCPChannels, channelID)
return
}
if c, ok := activeTunnels[destination]; ok {
// no need to send userid
c <- append(packetHeader[6:], dataThatReceivedFromUDPReadChan...)
}
}
}
}()
return udpToTCPChannels[channelID], nil
}
13 changes: 7 additions & 6 deletions worker.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Welcome to Cloudflare Workers!This is your first worker.
* Welcome to Cloudflare Workers! This is your first worker.
*
* - Run "npm run dev" in your terminal to start a development server
* - Open a browser tab at http://localhost:8787/ to see your worker in action
Expand Down Expand Up @@ -77,6 +77,7 @@ async function bepassOverWs(request) {

const destinationHost = params["host"]
const destinationPort = params["port"]
const destinationNetwork = params["net"] ? params["net"].toString().toLowerCase() : "tcp"

const webSocketPair = new WebSocketPair();
const [client, webSocket] = Object.values(webSocketPair);
Expand Down Expand Up @@ -104,7 +105,7 @@ async function bepassOverWs(request) {
writer.releaseLock();
return;
}
handleTCPOutBound(remoteSocketWapper, destinationHost, destinationPort, chunk, webSocket, log);
handleTCPOutBound(remoteSocketWapper, destinationNetwork, destinationHost, destinationPort, chunk, webSocket, log);
},
close() {
log(`readableWebSocketStream is close`);
Expand Down Expand Up @@ -183,10 +184,10 @@ function longToByteArray(long) {
return byteArray;
};

async function handleTCPOutBound(remoteSocket, addressRemote, portRemote, rawClientData, webSocket, log,) {
async function handleTCPOutBound(remoteSocket, destinationNetwork, addressRemote, portRemote, rawClientData, webSocket, log,) {
async function connectAndWrite(address, port, rawHeaderEnabled) {
const mmd = addressRemote + "$" + portRemote
if(!rawHeaderEnabled && isIP(address) && (inRange(address, cf_ipv6) || inRange(address, cf_ipv4))){
const mmd = destinationNetwork + "@" + addressRemote + "$" + portRemote
if(destinationNetwork === "udp" || (!rawHeaderEnabled && isIP(address) && (inRange(address, cf_ipv6) || inRange(address, cf_ipv4)))){
address = proxyIP
port = proxyPort
rawHeaderEnabled = true;
Expand Down Expand Up @@ -1719,4 +1720,4 @@ export function displayIP(addr) {
} catch (err) {
return ''; //invalid IP address
}
}
}

0 comments on commit 9e481ce

Please sign in to comment.