کم و بیش در زندگی روزمره ممکن است از تحریم شکن هایی مثل شکن و ... استفاده کرده باشین.
در این پست کوتاه قصد دارم نحوه عملکرد این نوع تحریم شکن هارو بررسی کنیم.
پراکسی فوروارد یا Forward Proxy سروری هست که بین گروهی از ماشینهای سرویس گیرنده و اینترنت قرار میگیرد. وقتی کلاینتها request هایشان را ارسال میکنند، Forward-Proxy بعنوان یک واسط عمل میکند و request ها را از کلاینت ها میگیرد و در سمت دیگر، به سمت وب سرورهای مقصدشان میفرستد و در نهایت پاسخ وب سرورها را گرفته و به کلاینتها بر میگرداند.
سوال اینجاست که این نوع پراکسی به چه دردی میخورد یا به عبارتی در کجا کاربرد دارد؟
در جواب باید گفت که این نوع از پراکسی، از اطلاعات هویتی کلاینتها یا به اصطلاح خودمان، از identity کلاینتها حفاظت میکند. به این صورت که اگر از یک فوروارد پراکسی استفاده کنیم، در آن صورت فقط آدرس IP کلاینتها حفظ میشود و در request header که به سمت وب سرور در نهایت ارسال میشود، آدرس IP پراکسی قابل مشاهده است.
تنها کاری که نیاز هست انجام بشه اینه که تمام درخواست های DNS ما به آدرس سرور ForwardProxy تبدیل بشود.
import sys, socket, argparse from dnslib import DNSRecord, DNSHeader, RR, A, QTYPE, DNSError from os import environ from socketserver import ThreadingUDPServer, DatagramRequestHandler allow_all = False w_list = [] args = None class PacketHandler(DatagramRequestHandler): # DatagramRequestHandler def handle(self) -> None: data = self.rfile.read(512) # Maximum UDP Packet Size is 512 Byte if args.debug: # Show Client Address (if debug) print("Accept Request from : ", self.client_address[0]) try: packet = DNSRecord.parse(data) # Parse DNS Packet for question in packet.questions: # Iterate over questions ( however most of DNS Servers even BIND support single question) requested_domain_name = question.get_qname() # Get the requested name reply_packet = packet.reply() # Generate Reply packet if (not allow_all) and (w_list != [] and ( not any(s[1:] in str(requested_domain_name) for s in w_list))): # Check the Whitelist try: realip = socket.gethostbyname(requested_domain_name.idna()) # Get Real IP Address except Exception as e: if args.debug: print(e) realip = args.ip
reply_packet.add_answer(
RR(requested_domain_name, rdata=A(realip), ttl=60)) # Append Address to replies
if args.debug:
print("Request: %s --> %s" % (requested_domain_name.idna(), realip))
else:
reply_packet.add_answer(RR(requested_domain_name, rdata=A(args.ip), ttl=60)) # Fake the address
if args.debug:
print("Request: %s --> %s" % (requested_domain_name.idna(), args.ip))
self.wfile.write(reply_packet.pack()) # send Packed UDP Response to the client
except DNSError as err:
if args.debug:
print(err)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Process input')
parser.add_argument("--ip", help="set listen ip address, set to ENV to get it from PUB_IP Env Variable",
action="store", type=str, default="0.0.0.0")
parser.add_argument("--whitelist",
help="Whitelisted Domain. use ALL or DNS_ALLOW_ALL=YES Env variable for access all domain",
action="store", type=str, default="Empty")
parser.add_argument("--port", help="set listen port", action="store", type=int, default=53)
parser.add_argument("--debug", help="enable debug logging", action="store_true")
args = parser.parse_args()
if str(args.ip).upper() == "ENV":
args.ip = environ.get("PUB_IP")
if args.debug:
print('IP: %s Port: %s' % (args.ip, args.port))
if environ.get("DNS_ALLOW_ALL") == "YES" or args.whitelist == "ALL":
allow_all = True
else:
if args.whitelist != "Empty":
with open(args.whitelist) as f:
w_list.extend(f.read().splitlines())
try:
udp_sock = ThreadingUDPServer(("0.0.0.0", args.port), PacketHandler)
udp_sock.serve_forever()
except KeyboardInterrupt:
if args.debug:
print("done.")
python3 test.py --ip 185.x.x.x
تنظیم nginx به عنوان Forward proxy
nano /etc/nginx/nginx.conf user www-data; worker_processes auto; error_log /var/log/nginx/error.log notice; pid /var/run/nginx.pid; worker_rlimit_nofile 65535; events { worker_connections 4096; multi_accept on; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header Cache-Control "no-cache, no-store, must-revalidate" always; add_header Pragma "no-store" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Xss-Protection "1; mode=block" always; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; server_tokens off; #ssl_protocols TLSv1.2 TLSv1.3; #ssl_prefer_server_ciphers on; #ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM SHA256:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK'; #ssl_ecdh_curve secp384r1; #ssl_session_cache shared:SSL:10m; #ssl_session_timeout 10m; add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; client_max_body_size 2G; #gzip on; include /etc/nginx/conf.d/*.conf; } stream { server { resolver 8.8.8.8 ipv6=off; listen 443; ssl_preread on; proxy_pass $ssl_preread_server_name:443; } }
nano /etc/nginx/conf.d/base.conf server { listen 80 default_server; listen [::]:80 default_server; server_name _; return 301 https://$host$request_uri; }
منابع:
https://www.baeldung.com/nginx-forward-proxy