Skip to content

Commit 6035887

Browse files
doxxdoxx
doxx
authored and
doxx
committed
Server listen on 0.0.0.0 fixed, server -redirect host added. Client proxy support.
1 parent 12a4287 commit 6035887

14 files changed

+110
-44
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ I used 8080 with a Cloudflare proxy via HTTP for the firs test. Less overhead.
115115
- **TLS Security**: Because we're sneaky, not reckless
116116
- **Client-controlled destination addressing**: The destination (-d) is now specified on the client side and securely transmitted to the server
117117
- **Base64 encoded destination transmission**: The server no longer requires a destination parameter (-d has been removed)
118+
- **Reverse Proxy Support**: The client now supports SOCKS5 and HTTP(s) proxies.
119+
- **Custom 302**: Server now has defined 302 redirects for non-auth users.
118120

119121
## 🚀 Quick Start
120122

bin/checksums.txt

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# DarkFlare Binary Checksums
2-
# Generated: Sun Dec 22 18:06:43 UTC 2024
2+
# Generated: Sun Dec 22 18:20:29 UTC 2024
33

4-
7aca8ba2f3424a8fc7bd5b318ea64b065e2025c04b3bf56b75a580054485b65d checksums.txt
5-
b5b99d41710c1fa7c5972c16e2569e9669a5f33b3a47a43637b3c759a0b7c37e darkflare-client-darwin-amd64
6-
5fddf0bdeb8edbad23480667c52d0e80589796bd296cf0ddfde9687977af54c2 darkflare-client-darwin-arm64
7-
701ca0f8d425df0b081335d85209e3888835738d607b5595077fe53cf10ece80 darkflare-client-linux-amd64
8-
0c0576ade0937f2f5ff6999afcf22e2513f91f48aeaa0234552b7c2b9e1b509a darkflare-client-linux-arm64
9-
6d581afcdd58545577f6fe37f984237e8ceafb3a9e279128cb729e5d2507ceae darkflare-client-windows-amd64.exe
10-
047ea2e4b7adce407464ab539325d95e9258c25a83639384cea715641c6f5ca5 darkflare-server-darwin-amd64
11-
448c05be509e93de7f6dbf61121b52487654732b2b4424966715d27867df8a77 darkflare-server-darwin-arm64
12-
100ad4b1cf6f141616235be265620cf51eb12deae4c230516e6c55d28e643558 darkflare-server-linux-amd64
13-
59ec518896201dae5057710a89c4b909d558676d99c4f2e6c476509a19fc3bb0 darkflare-server-linux-arm64
14-
05799be76456dbe49c4424ca66c100077c31a811873694bbda92dc8cb8f984b5 darkflare-server-windows-amd64.exe
4+
e5e585abb6b5fc87f823cd1c916ed28591b0460ff352b51feb7426e69fb96aab checksums.txt
5+
4782d0a3f953355847561fda6a0ed0970c01cb4e46d3bd1f1590c24be409391e darkflare-client-darwin-amd64
6+
a7050875bb463ef5389f08522fe12613049f8ac29e078f654dac77745b93b2cf darkflare-client-darwin-arm64
7+
10abd137dfe6d1e62d5c01dc11fa5caa5dcc90ab931504a06b14a488b4a396d4 darkflare-client-linux-amd64
8+
43a26f48d61b3ee8f92e333922d4c39ee880ac576f2eb29233ce2d7d6b944eac darkflare-client-linux-arm64
9+
1d05cfeb741c6165acf4dc9829c146cdf850bae2bb7a0b5aa554770e5ee0bade darkflare-client-windows-amd64.exe
10+
f893a0498fd10517c54a3348d2aac33ccf04f8691bad3cf6b4f6631115127446 darkflare-server-darwin-amd64
11+
120c9b485a6b6102096800367d3e2c4f2dc4c0799881c4911e394e3bd53e0f9f darkflare-server-darwin-arm64
12+
1ed50cbc44075712642b3572f424789024451d750afe5142efdb9184d7450e18 darkflare-server-linux-amd64
13+
b43e3282bc3560f93012a9be1a9fd3d88eca7d7ae7d7bfeca47cf057c3bf4c1d darkflare-server-linux-arm64
14+
1cc5e59478c644020a7a197002dca56db497260288628603c40e8b74b5d37fab darkflare-server-windows-amd64.exe

bin/darkflare-client-darwin-amd64

4.08 KB
Binary file not shown.

bin/darkflare-client-darwin-arm64

80 Bytes
Binary file not shown.

bin/darkflare-client-linux-amd64

3.63 KB
Binary file not shown.

bin/darkflare-client-linux-arm64

2.6 KB
Binary file not shown.
2.5 KB
Binary file not shown.

bin/darkflare-server-darwin-amd64

16 Bytes
Binary file not shown.

bin/darkflare-server-darwin-arm64

0 Bytes
Binary file not shown.

bin/darkflare-server-linux-amd64

-1.69 KB
Binary file not shown.

bin/darkflare-server-linux-arm64

1.27 KB
Binary file not shown.
0 Bytes
Binary file not shown.

client/main.go

Lines changed: 65 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -137,24 +137,58 @@ func NewClient(cloudflareHost string, destPort int, scheme string, destAddr stri
137137

138138
// Configure proxy support
139139
if proxyURL != "" {
140-
if strings.HasPrefix(proxyURL, "socks") {
141-
// Handle SOCKS proxy
142-
dialer, err := proxy.SOCKS5("tcp", proxyURL[strings.Index(proxyURL, "//")+2:], nil, proxy.Direct)
143-
if err != nil {
144-
log.Printf("Error creating SOCKS5 dialer: %v", err)
145-
} else {
146-
transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
147-
return dialer.Dial(network, addr)
140+
if client.debug {
141+
client.debugLog("Configuring proxy: %s", proxyURL)
142+
}
143+
144+
proxyURLParsed, err := url.Parse(proxyURL)
145+
if err != nil {
146+
log.Printf("Invalid proxy URL: %v", err)
147+
return nil
148+
}
149+
150+
switch proxyURLParsed.Scheme {
151+
case "socks5", "socks5h":
152+
// Extract auth if present
153+
var auth *proxy.Auth
154+
if proxyURLParsed.User != nil {
155+
auth = &proxy.Auth{
156+
User: proxyURLParsed.User.Username(),
157+
}
158+
if password, ok := proxyURLParsed.User.Password(); ok {
159+
auth.Password = password
148160
}
149161
}
150-
} else {
151-
// Handle HTTP/HTTPS proxy
152-
proxyURLParsed, err := url.Parse(proxyURL)
162+
163+
// Create SOCKS5 dialer
164+
dialer, err := proxy.SOCKS5("tcp", proxyURLParsed.Host, auth, proxy.Direct)
153165
if err != nil {
154-
log.Printf("Error parsing proxy URL: %v", err)
155-
} else {
156-
transport.Proxy = http.ProxyURL(proxyURLParsed)
166+
log.Printf("Failed to create SOCKS5 dialer: %v", err)
167+
return nil
157168
}
169+
170+
transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
171+
if client.debug {
172+
client.debugLog("SOCKS5 dialing %s via %s", addr, proxyURLParsed.Host)
173+
}
174+
return dialer.Dial(network, addr)
175+
}
176+
177+
case "http", "https":
178+
transport.Proxy = http.ProxyURL(proxyURLParsed)
179+
180+
// Add proxy authentication if present
181+
if proxyURLParsed.User != nil {
182+
basicAuth := "Basic " + base64.StdEncoding.EncodeToString(
183+
[]byte(proxyURLParsed.User.String()))
184+
transport.ProxyConnectHeader = http.Header{
185+
"Proxy-Authorization": []string{basicAuth},
186+
}
187+
}
188+
189+
default:
190+
log.Printf("Unsupported proxy scheme: %s", proxyURLParsed.Scheme)
191+
return nil
158192
}
159193
}
160194

@@ -494,17 +528,27 @@ func main() {
494528
fmt.Fprintf(os.Stderr, " -debug Enable detailed debug logging\n")
495529
fmt.Fprintf(os.Stderr, " Shows connection details, data transfer, and errors\n\n")
496530
fmt.Fprintf(os.Stderr, " -p Proxy URL for outbound connections\n")
497-
fmt.Fprintf(os.Stderr, " Format: http://host:port or socks5://host:port\n\n")
531+
fmt.Fprintf(os.Stderr, " Format: scheme://[user:pass@]host:port\n")
532+
fmt.Fprintf(os.Stderr, " Supported schemes: http, https, socks5, socks5h\n\n")
498533
fmt.Fprintf(os.Stderr, "Examples:\n")
499534
fmt.Fprintf(os.Stderr, " Basic SSH tunnel:\n")
500-
fmt.Fprintf(os.Stderr, " %s -l 2222 -t https://cdn.miami.us.doxx.net -d ssh.destination.com:22\n\n", os.Args[0])
501-
fmt.Fprintf(os.Stderr, " Custom port with debugging:\n")
502-
fmt.Fprintf(os.Stderr, " %s -l 8080 -t https://tunnel.example.com:8443 -d internal.service:80 -debug\n\n", os.Args[0])
503-
fmt.Fprintf(os.Stderr, " HTTP proxy tunnel:\n")
504-
fmt.Fprintf(os.Stderr, " %s -l 8080 -t http://proxy.example.com -d target.site.com:80\n\n", os.Args[0])
535+
fmt.Fprintf(os.Stderr, " %s -l 2222 -t cdn.example.com -d ssh.target.com:22\n\n", os.Args[0])
536+
fmt.Fprintf(os.Stderr, " With HTTP proxy:\n")
537+
fmt.Fprintf(os.Stderr, " %s -l 2222 -t cdn.example.com -d ssh.target.com:22 \\\n", os.Args[0])
538+
fmt.Fprintf(os.Stderr, " -p http://proxy.example.com:8080\n\n")
539+
fmt.Fprintf(os.Stderr, " With authenticated SOCKS5 proxy:\n")
540+
fmt.Fprintf(os.Stderr, " %s -l 2222 -t cdn.example.com -d ssh.target.com:22 \\\n", os.Args[0])
541+
fmt.Fprintf(os.Stderr, " -p socks5://user:pass@proxy.example.com:1080\n\n")
542+
fmt.Fprintf(os.Stderr, " Debug mode with HTTPS proxy:\n")
543+
fmt.Fprintf(os.Stderr, " %s -l 8080 -t cdn.example.com -d internal.service:80 \\\n", os.Args[0])
544+
fmt.Fprintf(os.Stderr, " -p https://proxy.company.com:443 -debug\n\n")
505545
fmt.Fprintf(os.Stderr, "Usage with SSH:\n")
506-
fmt.Fprintf(os.Stderr, " 1. Start the client: %s -l 2222 -t tunnel.example.com -d ssh.target.com:22\n", os.Args[0])
546+
fmt.Fprintf(os.Stderr, " 1. Start the client: %s -l 2222 -t cdn.example.com -d ssh.target.com:22\n", os.Args[0])
507547
fmt.Fprintf(os.Stderr, " 2. Connect via: ssh -p 2222 user@localhost\n\n")
548+
fmt.Fprintf(os.Stderr, "Notes:\n")
549+
fmt.Fprintf(os.Stderr, " - Proxy authentication is supported via URL format user:pass@host\n")
550+
fmt.Fprintf(os.Stderr, " - SOCKS5h variant will resolve hostnames through the proxy\n")
551+
fmt.Fprintf(os.Stderr, " - Debug mode will show proxy connection details and errors\n\n")
508552
fmt.Fprintf(os.Stderr, "For more information: https://github.com/blyon/darkflare\n")
509553
}
510554

server/main.go

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ type Server struct {
3636
isAppMode bool
3737
allowDirect bool
3838
silent bool
39+
redirect string
3940
}
4041

41-
func NewServer(destHost, destPort string, appCommand string, debug bool, allowDirect bool, silent bool) *Server {
42+
func NewServer(destHost, destPort string, appCommand string, debug bool, allowDirect bool, silent bool, redirect string) *Server {
4243
s := &Server{
4344
destHost: destHost,
4445
destPort: destPort,
@@ -47,6 +48,7 @@ func NewServer(destHost, destPort string, appCommand string, debug bool, allowDi
4748
isAppMode: appCommand != "",
4849
allowDirect: allowDirect,
4950
silent: silent,
51+
redirect: redirect,
5052
}
5153

5254
if s.isAppMode && s.debug && !s.silent {
@@ -174,8 +176,12 @@ func (s *Server) handleRequest(w http.ResponseWriter, r *http.Request) {
174176
// Get and decode destination early
175177
encodedDest := r.Header.Get("X-Requested-With")
176178
if encodedDest == "" {
177-
log.Printf("Redirect: %s → https://github.com/doxx/darkflare", clientIP)
178-
http.Redirect(w, r, "https://github.com/doxx/darkflare", http.StatusFound)
179+
redirectURL := s.redirect
180+
if redirectURL == "" {
181+
redirectURL = "https://github.com/doxx/darkflare"
182+
}
183+
log.Printf("Redirect: %s → %s", clientIP, redirectURL)
184+
http.Redirect(w, r, redirectURL, http.StatusFound)
179185
return
180186
}
181187

@@ -421,6 +427,7 @@ func main() {
421427
var allowDirect bool
422428
var appCommand string
423429
var silent bool
430+
var redirect string
424431

425432
flag.Usage = func() {
426433
fmt.Fprintf(os.Stderr, "DarkFlare Server - TCP-over-CDN tunnel server component\n")
@@ -442,6 +449,8 @@ func main() {
442449
fmt.Fprintf(os.Stderr, " Shows connection details and errors\n\n")
443450
fmt.Fprintf(os.Stderr, " -s Silent mode\n")
444451
fmt.Fprintf(os.Stderr, " Suppresses all non-error output\n\n")
452+
fmt.Fprintf(os.Stderr, " -redirect Custom URL to redirect unauthorized requests\n")
453+
fmt.Fprintf(os.Stderr, " Default: GitHub project page\n\n")
445454
fmt.Fprintf(os.Stderr, "Examples:\n")
446455
fmt.Fprintf(os.Stderr, " Basic setup:\n")
447456
fmt.Fprintf(os.Stderr, " %s -o http://0.0.0.0:8080\n\n", os.Args[0])
@@ -463,6 +472,7 @@ func main() {
463472
flag.BoolVar(&debug, "debug", false, "")
464473
flag.BoolVar(&allowDirect, "allow-direct", false, "")
465474
flag.BoolVar(&silent, "s", false, "")
475+
flag.StringVar(&redirect, "redirect", "", "Custom URL to redirect unauthorized requests (default: GitHub project page)")
466476
flag.Parse()
467477

468478
// Parse origin URL
@@ -491,7 +501,7 @@ func main() {
491501
log.Printf("DarkFlare server listening on %s", origin)
492502
}
493503

494-
server := NewServer(originHost, originPort, appCommand, debug, allowDirect, silent)
504+
server := NewServer(originHost, originPort, appCommand, debug, allowDirect, silent, redirect)
495505

496506
log.Printf("DarkFlare server running on %s://%s:%s", originURL.Scheme, originHost, originPort)
497507
if allowDirect {
@@ -585,11 +595,22 @@ func main() {
585595
}
586596

587597
func isLocalIP(ip string) bool {
598+
// Allow 0.0.0.0 as a valid binding address
599+
if ip == "0.0.0.0" {
600+
return true
601+
}
602+
588603
ipAddr := net.ParseIP(ip)
589604
if ipAddr == nil {
590605
return false
591606
}
592607

608+
// Check if it's a loopback address
609+
if ipAddr.IsLoopback() {
610+
return true
611+
}
612+
613+
// Get all network interfaces
593614
interfaces, err := net.Interfaces()
594615
if err != nil {
595616
log.Printf("Error getting network interfaces: %v", err)
@@ -604,16 +625,15 @@ func isLocalIP(ip string) bool {
604625
}
605626

606627
for _, addr := range addrs {
607-
var localIP net.IP
608628
switch v := addr.(type) {
609629
case *net.IPNet:
610-
localIP = v.IP
630+
if v.IP.Equal(ipAddr) {
631+
return true
632+
}
611633
case *net.IPAddr:
612-
localIP = v.IP
613-
}
614-
615-
if localIP.Equal(ipAddr) {
616-
return true
634+
if v.IP.Equal(ipAddr) {
635+
return true
636+
}
617637
}
618638
}
619639
}

0 commit comments

Comments
 (0)