Forward proxy fundamentals including HTTP CONNECT, SOCKS protocols, authentication, and use cases for privacy, security, and access control
Scope: Forward proxy concepts, HTTP CONNECT method, SOCKS protocol, use cases Lines: ~350 Last Updated: 2025-10-27 Format Version: 1.0 (Atomic)
Activate this skill when:
Forward Proxy (this skill):
Client → Forward Proxy → Internet → Server
[client's agent]
Reverse Proxy (see proxies-reverse-proxy):
Client → Internet → Reverse Proxy → Backend Servers
[server's agent]
Purpose: Tunnel TCP connections through HTTP proxy
CONNECT example.com:443 HTTP/1.1
Host: example.com:443
Proxy-Authorization: Basic dXNlcjpwYXNz
HTTP/1.1 200 Connection Established
[TLS handshake begins]
[Encrypted data flows]
Use Cases:
SOCKS4 (older, IPv4 only):
1. Client → SOCKS: Connect request
2. SOCKS → Server: TCP connection
3. SOCKS → Client: Success/Failure
4. Data flows transparently
SOCKS5 (modern, recommended):
Use Case: Corporate proxy requiring credentials
# ❌ Bad: Credentials in URL
import requests
response = requests.get(
'http://api.example.com/data',
proxies={
'http': 'http://user:pass@proxy.corp.com:8080',
'https': 'http://user:pass@proxy.corp.com:8080'
}
)
# ✅ Good: Secure credential handling
import requests
import os
proxies = {
'http': f'http://{os.environ["PROXY_HOST"]}:{os.environ["PROXY_PORT"]}',
'https': f'http://{os.environ["PROXY_HOST"]}:{os.environ["PROXY_PORT"]}'
}
auth = (os.environ['PROXY_USER'], os.environ['PROXY_PASS'])
response = requests.get(
'http://api.example.com/data',
proxies=proxies,
auth=auth
)
Benefits:
Use Case: Route all traffic through SOCKS proxy
# ❌ Bad: DNS leaks
import requests
proxies = {
'http': 'socks5://localhost:1080',
'https': 'socks5://localhost:1080'
}
response = requests.get('http://api.example.com/data', proxies=proxies)
# DNS resolution happens locally, leaking information
# ✅ Good: DNS through SOCKS proxy
import requests
proxies = {
'http': 'socks5h://localhost:1080', # 'h' = DNS through proxy
'https': 'socks5h://localhost:1080'
}
response = requests.get('http://api.example.com/data', proxies=proxies)
Benefits:
import socket
import threading
from typing import Tuple
class ForwardProxy:
def __init__(self, host: str = '0.0.0.0', port: int = 8888):
self.host = host
self.port = port
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
def start(self):
self.server.bind((self.host, self.port))
self.server.listen(100)
print(f"[*] Proxy listening on {self.host}:{self.port}")
while True:
client_socket, addr = self.server.accept()
print(f"[*] Connection from {addr}")
thread = threading.Thread(target=self.handle_client, args=(client_socket,))
thread.daemon = True
thread.start()
def handle_client(self, client_socket: socket.socket):
try:
request = client_socket.recv(4096)
# Parse request line
first_line = request.split(b'\r\n')[0]
method, url, version = first_line.split(b' ')
if method == b'CONNECT':
self.handle_connect(client_socket, url)
else:
self.handle_http(client_socket, request, url)
except Exception as e:
print(f"[!] Error: {e}")
finally:
client_socket.close()
def handle_connect(self, client_socket: socket.socket, url: bytes):
"""Handle HTTPS CONNECT tunnel"""
host, port = url.decode().split(':')
try:
# Connect to target
remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
remote.connect((host, int(port)))
# Send success response
client_socket.send(b'HTTP/1.1 200 Connection Established\r\n\r\n')
# Bidirectional forwarding
client_socket.setblocking(False)
remote.setblocking(False)
while True:
# Client → Server
try:
data = client_socket.recv(4096)
if data:
remote.sendall(data)
except BlockingIOError:
pass
# Server → Client
try:
data = remote.recv(4096)
if data:
client_socket.sendall(data)
except BlockingIOError:
pass
except Exception as e:
print(f"[!] CONNECT error: {e}")
client_socket.send(b'HTTP/1.1 502 Bad Gateway\r\n\r\n')
def handle_http(self, client_socket: socket.socket, request: bytes, url: bytes):
"""Handle plain HTTP requests"""
try:
# Extract host and path
host_line = [l for l in request.split(b'\r\n') if l.startswith(b'Host:')][0]
host = host_line.split(b': ')[1].decode()
# Connect to target
remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
remote.connect((host, 80))
# Forward request
remote.sendall(request)
# Forward response
while True:
data = remote.recv(4096)
if not data:
break
client_socket.sendall(data)
remote.close()
except Exception as e:
print(f"[!] HTTP error: {e}")
if __name__ == '__main__':
proxy = ForwardProxy(port=8888)
proxy.start()
package main
import (
"fmt"
"golang.org/x/net/proxy"
"io"
"net"
"net/http"
"time"
)
func main() {
// Create SOCKS5 dialer
dialer, err := proxy.SOCKS5("tcp", "localhost:1080",
&proxy.Auth{
User: "username",
Password: "password",
},
proxy.Direct,
)
if err != nil {
panic(err)
}
// Use SOCKS5 for HTTP client
httpTransport := &http.Transport{
Dial: dialer.Dial,
}
httpClient := &http.Client{
Transport: httpTransport,
Timeout: 10 * time.Second,
}
// Make request through SOCKS5
resp, err := httpClient.Get("https://api.example.com/data")
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Printf("Response: %s\n", body)
}
// Direct TCP connection through SOCKS5
func tcpThroughSocks5() {
dialer, _ := proxy.SOCKS5("tcp", "localhost:1080", nil, proxy.Direct)
conn, err := dialer.Dial("tcp", "example.com:80")
if err != nil {
panic(err)
}
defer conn.Close()
// Use connection
conn.Write([]byte("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"))
buffer := make([]byte, 4096)
n, _ := conn.Read(buffer)
fmt.Printf("Response: %s\n", buffer[:n])
}
// Node.js HTTP request through proxy
import https from 'https';
import { HttpsProxyAgent } from 'https-proxy-agent';
const proxyAgent = new HttpsProxyAgent({
host: 'proxy.example.com',
port: 8080,
auth: 'user:password'
});
const options = {
hostname: 'api.example.com',
path: '/data',
method: 'GET',
agent: proxyAgent
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('Response:', data);
});
});
req.on('error', (error) => {
console.error('Error:', error);
});
req.end();
// Axios with proxy
import axios from 'axios';
const response = await axios.get('https://api.example.com/data', {
proxy: {
protocol: 'http',
host: 'proxy.example.com',
port: 8080,
auth: {
username: process.env.PROXY_USER!,
password: process.env.PROXY_PASS!
}
}
});
console.log(response.data);
# Environment variables
export http_proxy="http://proxy.example.com:8080"
export https_proxy="http://proxy.example.com:8080"
export no_proxy="localhost,127.0.0.1,*.local"
# With authentication
export http_proxy="http://user:pass@proxy.example.com:8080"
export https_proxy="http://user:pass@proxy.example.com:8080"
# SOCKS5
export ALL_PROXY="socks5://localhost:1080"
# HTTP proxy
git config --global http.proxy http://proxy.example.com:8080
git config --global https.proxy http://proxy.example.com:8080
# SOCKS5
git config --global http.proxy socks5://localhost:1080
git config --global https.proxy socks5://localhost:1080
# Unset proxy
git config --global --unset http.proxy
git config --global --unset https.proxy
// ~/.docker/config.json
{
"proxies": {
"default": {
"httpProxy": "http://proxy.example.com:8080",
"httpsProxy": "http://proxy.example.com:8080",
"noProxy": "localhost,127.0.0.1"
}
}
}
# ✅ Good: Fallback and retry logic
import requests
from requests.exceptions import ProxyError, Timeout
def fetch_with_proxy(url: str, proxies: dict, retries: int = 3):
for attempt in range(retries):
try:
response = requests.get(url, proxies=proxies, timeout=10)
return response
except ProxyError:
print(f"Proxy error, attempt {attempt + 1}/{retries}")
if attempt == retries - 1:
# Fallback to direct connection
return requests.get(url, timeout=10)
except Timeout:
print(f"Timeout, attempt {attempt + 1}/{retries}")
raise Exception("Failed after all retries")
// PAC file for smart proxy routing
function FindProxyForURL(url, host) {
// Direct for local addresses
if (isPlainHostName(host) ||
shExpMatch(host, "*.local") ||
isInNet(host, "10.0.0.0", "255.0.0.0") ||
isInNet(host, "172.16.0.0", "255.240.0.0") ||
isInNet(host, "192.168.0.0", "255.255.0.0")) {
return "DIRECT";
}
// Use proxy for everything else
return "PROXY proxy.example.com:8080; DIRECT";
}
# ✅ Good: Health check before use
import requests
def is_proxy_healthy(proxy_url: str) -> bool:
try:
response = requests.get(
'http://httpbin.org/ip',
proxies={'http': proxy_url, 'https': proxy_url},
timeout=5
)
return response.status_code == 200
except:
return False
proxy = "http://proxy.example.com:8080"
if is_proxy_healthy(proxy):
# Use proxy
pass
else:
# Use alternative or direct
pass
Symptoms: 407 Proxy Authentication Required Common Causes:
Solution:
from urllib.parse import quote
username = "user@domain" # Example - use actual credentials from environment
password = "p@ss:word" # Example - use actual credentials from environment
proxy = f"http://{quote(username)}:{quote(password)}@proxy.example.com:8080"
Symptoms: Certificate verification failures Common Causes:
Solution:
# Add proxy's CA certificate
import requests
response = requests.get(
'https://api.example.com/data',
proxies={'https': 'http://proxy.example.com:8080'},
verify='/path/to/proxy-ca-bundle.crt'
)
Symptoms: High latency through proxy Common Causes:
Solution:
# Use connection pooling
import requests
from requests.adapters import HTTPAdapter
session = requests.Session()
adapter = HTTPAdapter(pool_connections=10, pool_maxsize=20)
session.mount('http://', adapter)
session.mount('https://', adapter)
session.proxies = {
'http': 'http://proxy.example.com:8080',
'https': 'http://proxy.example.com:8080'
}
# Reuse session for multiple requests
for url in urls:
response = session.get(url)
proxies-reverse-proxy - Reverse proxy patterns and use casesproxies-nginx-configuration - Nginx as forward/reverse proxyprotocols-http-fundamentals - HTTP protocol basicsnetworking-tls-troubleshooting - SSL/TLS debuggingcontainers-docker-networking - Container proxy configurationLast Updated: 2025-10-27