diff --git a/.gitignore b/.gitignore index 24e7908..200ff53 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ env dist build gfw/DNS_IP_traffic_info.txt +ffmpeg.exe diff --git a/ffmpeg/note.txt b/ffmpeg/note.txt new file mode 100644 index 0000000..3fa8375 --- /dev/null +++ b/ffmpeg/note.txt @@ -0,0 +1 @@ +add ffmpeg.exe here to build for windows \ No newline at end of file diff --git a/gfw/Android/README.md b/gfw/Android/README.md deleted file mode 100644 index 5c9cbac..0000000 --- a/gfw/Android/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# نحوه اجرا -1. ابتدا کد پایتون را روی گوشی (یا کامپیوتر) اجرا کنید
-(ویدئو آموزشی از نحوه اجرای کد پایتون در گوشی های اندرویدی https://t.me/ircfspace/124) -2. کانفیگ HTTP را روی nekobox یا matsuri بسازید مطابق شکل زیر - -

-اگر پایتون روی گوشی اجرا شده آدرس 127.0.0.1 و اگر روی کامپیوتر باشد ادرس ip کامپیوتر مثلا 192.168.1.2 را میدهید
-

-اگر روی vpn mode هستید باید ترافیک پایتون را از vpn مستثنی کنید
-

-3. در صورت تمایل میتوانید بجای ساخت کانفیگ ، فایل آماده json را import کنید (و بعد باید پایتون را از vpn مستثنی کنید) - -# رفع اشکال -- برنامه v2rayNG روی گوشی از پروتکل HTTP پشتیبانی نمیکند بنابراین از nekobox یا matsuri استفاده کنید -- اگر مشکل loading video دارید از نت ایرانسل استفاده کنید -- از داخل کد ، num_fragment را میتوانید از 10 تا 100 یا حتی بیشتر به دلخواه تنظیم کنید -- زمان fragment_sleep را از 0.001 تا 0.01 به دلخواه تنظیم کنید - -# آپدیت 30-2-1402 -- قسمت logging از کد حذف شد چون نیاز به دسترسی برای نوشتن فایل داشت و در برخی گوشی ها خطا میداد. -- تمام print ها کامنت شد که پردازش روی گوشی ایجاد نکند -- کانفیگ مخصوص nekobox و matsuri قرار داده شد diff --git a/gfw/Android/matsuri_http_config.json b/gfw/Android/matsuri_http_config.json deleted file mode 100644 index 8d627d8..0000000 --- a/gfw/Android/matsuri_http_config.json +++ /dev/null @@ -1,137 +0,0 @@ -{ - "dns": { - "fallbackStrategy": "disabled_if_any_match", - "hosts": {}, - "queryStrategy": "UseIPv4", - "servers": [ - { - "address": "https://8.8.8.8/dns-query", - "domains": [], - "uidList": [] - } - ] - }, - "inbounds": [ - { - "listen": "127.0.0.1", - "port": 2080, - "protocol": "socks", - "settings": { - "auth": "noauth", - "udp": true - }, - "sniffing": { - "destOverride": [ - "http", - "tls", - "quic" - ], - "enabled": true, - "metadataOnly": false, - "routeOnly": true - }, - "tag": "socks" - }, - { - "listen": "127.0.0.1", - "port": 9080, - "protocol": "http", - "settings": { - "allowTransparent": true - }, - "sniffing": { - "destOverride": [ - "http", - "tls" - ], - "enabled": true, - "metadataOnly": false, - "routeOnly": true - }, - "tag": "http" - }, - { - "listen": "127.0.0.1", - "port": 6450, - "protocol": "dokodemo-door", - "settings": { - "address": "8.8.8.8", - "network": "tcp,udp", - "port": 53 - }, - "tag": "dns-in" - } - ], - "log": { - "loglevel": "error" - }, - "outbounds": [ - { - "domainStrategy": "AsIs", - "protocol": "http", - "settings": { - "servers": [ - { - "address": "127.0.0.1", - "port": 4500 - } - ] - }, - "streamSettings": { - "network": "tcp", - "tcpSettings": {} - }, - "tag": "proxy" - }, - { - "protocol": "freedom", - "tag": "direct" - }, - { - "protocol": "freedom", - "tag": "bypass" - }, - { - "protocol": "blackhole", - "tag": "block" - }, - { - "protocol": "dns", - "settings": { - "userLevel": 1 - }, - "tag": "dns-out" - } - ], - "policy": { - "levels": { - "1": { - "connIdle": 30 - } - }, - "system": { - "statsOutboundDownlink": true, - "statsOutboundUplink": true - } - }, - "routing": { - "domainStrategy": "AsIs", - "rules": [ - { - "inboundTag": [ - "dns-in" - ], - "outboundTag": "dns-out", - "type": "field" - }, - { - "ip": [ - "geoip:private" - ], - "outboundTag": "bypass", - "type": "field" - } - ] - }, - "stats": {} -} \ No newline at end of file diff --git a/gfw/Android/neko_http_config.json b/gfw/Android/neko_http_config.json deleted file mode 100644 index f262944..0000000 --- a/gfw/Android/neko_http_config.json +++ /dev/null @@ -1,142 +0,0 @@ -{ - "dns": { - "rules": [ - { - "auth_user": [ - "fakedns" - ], - "server": "dns-remote" - }, - { - "disable_cache": true, - "domain_suffix": [ - ".arpa.", - ".arpa" - ], - "server": "dns-block" - }, - { - "disable_cache": true, - "inbound": [ - "tun-in" - ], - "server": "dns-fake" - } - ], - "servers": [ - { - "address": "https://8.8.8.8/dns-query", - "address_resolver": "dns-direct", - "tag": "dns-remote" - }, - { - "address": "https://223.5.5.5/dns-query", - "address_resolver": "dns-local", - "detour": "direct", - "tag": "dns-direct" - }, - { - "address": "underlying://0.0.0.0", - "detour": "direct", - "tag": "dns-local" - }, - { - "address": "rcode://success", - "tag": "dns-block" - }, - { - "address": "fakedns://198.18.0.0/15", - "strategy": "ipv4_only", - "tag": "dns-fake" - } - ], - "strategy": "ipv4_only" - }, - "inbounds": [ - { - "listen": "127.0.0.1", - "listen_port": 6450, - "override_address": "8.8.8.8", - "override_port": 53, - "tag": "dns-in", - "type": "direct" - }, - { - "domain_strategy": "", - "endpoint_independent_nat": true, - "inet4_address": [ - "172.19.0.1/28" - ], - "sniff": true, - "stack": "system", - "tag": "tun-in", - "type": "tun" - }, - { - "domain_strategy": "", - "listen": "127.0.0.1", - "listen_port": 2080, - "sniff": true, - "tag": "mixed-in", - "type": "mixed" - } - ], - "log": { - "level": "panic" - }, - "outbounds": [ - { - "password": "", - "server": "127.0.0.1", - "server_port": 4500, - "username": "", - "type": "http", - "tag": "proxy", - "domain_strategy": "" - }, - { - "tag": "direct", - "type": "direct" - }, - { - "tag": "bypass", - "type": "direct" - }, - { - "tag": "block", - "type": "block" - }, - { - "tag": "dns-out", - "type": "dns" - } - ], - "route": { - "auto_detect_interface": true, - "rules": [ - { - "outbound": "dns-out", - "port": [ - 53 - ] - }, - { - "inbound": [ - "dns-in" - ], - "outbound": "dns-out" - }, - { - "ip_cidr": [ - "224.0.0.0/3", - "ff00::/8" - ], - "outbound": "block", - "source_ip_cidr": [ - "224.0.0.0/3", - "ff00::/8" - ] - } - ] - } -} \ No newline at end of file diff --git a/gfw/Android/pyprox_HTTPS_v1.0.py b/gfw/Android/pyprox_HTTPS_v1.0.py deleted file mode 100644 index 5d23542..0000000 --- a/gfw/Android/pyprox_HTTPS_v1.0.py +++ /dev/null @@ -1,503 +0,0 @@ -#!/usr/bin/env python3 - -import dns.message # --> pip install dnspython -import dns.rdatatype -import requests # --> pip install requests -from pathlib import Path -import os -import base64 -import socket -import threading -import time -import random - - - - -listen_PORT = 4500 # pyprox listening to 127.0.0.1:listen_PORT - -num_fragment = 87 # total number of chunks that ClientHello devided into (chunks with random size) -fragment_sleep = 0.001 # sleep between each fragment to make GFW-cache full so it forget previous chunks. LOL. - -log_every_N_sec = 10 # every 30 second , update log file with latest DNS-cache statistics - -# DNS_url = 'https://cloudflare-dns.com/dns-query?dns=' # not working in iran , ip blocked -# DNS_url = 'https://dns.google/dns-query?dns=' # not working in iran , ip blocked -# DNS_url = 'https://doh.opendns.com/dns-query?dns=' # not working in iran , ip blocked -# DNS_url = 'https://secure.avastdns.com/dns-query?dns=' # not working in iran , ip blocked -# DNS_url = 'https://doh.libredns.gr/dns-query?dns=' # not working in iran , ip blocked -DNS_url = 'https://dns.electrotm.org/dns-query?dns=' -# DNS_url = 'https://dns.bitdefender.net/dns-query?dns=' -# DNS_url = 'https://cluster-1.gac.edu/dns-query?dns=' - - - - -offline_DNS = { - - - -# ################# twitter working pack ################### -'ocsp.digicert.com': '192.229.211.108', - -'api.twitter.com': '104.244.42.66', -'twitter.com': '104.244.42.1', -'pbs.twimg.com': '93.184.220.70', -'abs-0.twimg.com': '104.244.43.131', -'abs.twimg.com': '152.199.24.185', -'video.twimg.com': '192.229.220.133', -'t.co': '104.244.42.69', -'ton.local.twitter.com':'104.244.42.1', -# ########################################################## - - - -##################### Google working pack ################### -'ocsp.pki.goog': '172.217.16.195', -'googleads.g.doubleclick.net': '45.157.177.108', -'fonts.gstatic.com': '142.250.185.227', -'rr2---sn-vh5ouxa-hju6.googlevideo.com': '213.202.6.141', -'jnn-pa.googleapis.com': '45.157.177.108', -'static.doubleclick.net': '202.61.195.218', -'rr4---sn-hju7en7k.googlevideo.com': '74.125.167.74', -'rr1---sn-hju7en7r.googlevideo.com': '74.125.167.87', -'play.google.com': '142.250.184.238', -'rr3---sn-vh5ouxa-hjuz.googlevideo.com': '134.0.218.206', -'rr3---sn-hju7enel.googlevideo.com': '74.125.98.40', -'download.visualstudio.microsoft.com': '68.232.34.200', -'ocsp.pki.goog': '172.217.16.195', -'i.ytimg.com': '142.250.186.150', -'rr2---sn-hju7enel.googlevideo.com': '74.125.98.39', -'rr2---sn-hju7en7k.googlevideo.com': '74.125.167.72', -'googleads.g.doubleclick.net': '45.157.177.108', -'rr3---sn-4g5lznl6.googlevideo.com': '74.125.173.40', -'jnn-pa.googleapis.com': '89.58.57.45', -'rr3---sn-hju7en7k.googlevideo.com': '74.125.167.73', -'rr1---sn-hju7enll.googlevideo.com': '74.125.98.6', -'rr6---sn-hju7en7r.googlevideo.com': '74.125.167.92', -'play.google.com': '216.58.212.174', -'www.gstatic.com': '142.250.185.99', -'apis.google.com': '172.217.23.110', -'adservice.google.com': '202.61.195.218', -'mail.google.com': '142.250.186.37', -'accounts.google.com': '172.217.16.205', - -# 'lh3.googleusercontent.com': '193.26.157.66', # filtered -'lh3.googleusercontent.com':'142.251.167.132', - -'accounts.youtube.com': '172.217.16.206', -'ssl.gstatic.com': '142.250.184.195', -'fonts.gstatic.com': '172.217.23.99', -'rr4---sn-hju7enll.googlevideo.com': '74.125.98.9', # good -'rr2---sn-hju7enll.googlevideo.com': '74.125.98.7', -'rr1---sn-hju7enel.googlevideo.com': '74.125.98.38', -'rr5---sn-vh5ouxa-hjuz.googlevideo.com': '134.0.218.208', -'i1.ytimg.com': '172.217.18.14', -'plos.org': '162.159.135.42', -'fonts.googleapis.com': '89.58.57.45', -'genweb.plos.org': '104.26.1.141', -'static.ads-twitter.com': '146.75.120.157', -'www.google-analytics.com': '142.250.185.174', -'rr1---sn-vh5ouxa-hju6.googlevideo.com': '213.202.6.140', -'rr5---sn-vh5ouxa-hju6.googlevideo.com': '213.202.6.144', -'rr3---sn-hju7enel.googlevideo.com': '74.125.98.40', -'rr5---sn-nv47zn7y.googlevideo.com': '173.194.15.74', -'safebrowsing.googleapis.com': '202.61.195.218', -'static.doubleclick.net': '193.26.157.66', -'rr5---sn-vh5ouxa-hju6.googlevideo.com': '213.202.6.144', -'rr1---sn-hju7en7r.googlevideo.com': '74.125.167.87', -'rr4---sn-vh5ouxa-hju6.googlevideo.com': '213.202.6.143', -'rr4---sn-hju7en7r.googlevideo.com': '74.125.167.90', -'r1---sn-hju7enel.googlevideo.com': '74.125.98.38', -'rr1---sn-nv47zn7r.googlevideo.com': '173.194.15.38', -'rr2---sn-vh5ouxa-hjuz.googlevideo.com': '134.0.218.205', -'rr4---sn-nv47zn7r.googlevideo.com': '173.194.15.41', -'rr4---sn-hju7en7r.googlevideo.com': '74.125.167.90', - - -'rr4---sn-nv47znel.googlevideo.com': '74.125.98.7', # good -'rr4---sn-nv47lnl7.googlevideo.com':'74.125.98.7', -'rr4---sn-hju7enll.googlevideo.com':'74.125.98.7', -'rr1---sn-vh5ouxa-hju6.googlevideo.com':'74.125.98.7', -'rr3---sn-hju7enel.googlevideo.com':'74.125.98.7', -'rr5---sn-hju7enll.googlevideo.com':'74.125.98.7', -'rr5---sn-vh5ouxa-hjuz.googlevideo.com':'74.125.98.7', -'rr1---sn-nv47ln7z.googlevideo.com':'74.125.98.7', -'rr3---sn-vh5ouxa-hju6.googlevideo.com': '74.125.98.7', - - -'www.google.com': '142.250.186.36', -# 'www.google.com': '216.239.38.120', -'youtube.com':'216.239.38.120', -'www.youtube.com':'216.239.38.120', -'i.ytimg.com':'216.239.38.120', - -# 'yt3.ggpht.com': '64.233.165.198', # filtered -# 'yt3.ggpht.com': '142.250.179.161', # filtered -# 'yt3.ggpht.com': '142.250.186.65', # sometimes work -'yt3.ggpht.com': '142.250.186.36', # most of times work -####################################################### - - -################## DNS over HTTPS IP Address (leave it intact , it must Exist) ###################### -'cloudflare-dns.com':'1.1.1.1', # not working in iran , ip blocked -'dns.google':'8.8.8.8', # not working in iran , ip blocked -'doh.opendns.com':'208.67.222.222', # not working in iran , ip blocked -'secure.avastdns.com':'185.185.133.66', # not working in iran , ip blocked -'doh.libredns.gr':'116.202.176.26', # not working in iran , ip blocked -'dns.electrotm.org':'78.157.42.100', -'dns.bitdefender.net':'34.84.232.67', -'cluster-1.gac.edu':'138.236.128.101', -########################################################################## - -} - - - - - - - - -# ignore description below , its for old code , just leave it intact. -my_socket_timeout = 21 # default for google is ~21 sec , recommend 60 sec unless you have low ram and need close soon -first_time_sleep = 0.1 # speed control , avoid server crash if huge number of users flooding -accept_time_sleep = 0.01 # avoid server crash on flooding request -> max 100 sockets per second - - -DNS_cache = {} # resolved domains -IP_DL_traffic = {} # download usage for each ip -IP_UL_traffic = {} # upload usage for each ip - - -class DNS_over_Fragment: - def __init__(self): - self.url = DNS_url - self.req = requests.session() - self.fragment_proxy = { - 'https': 'http://127.0.0.1:'+str(listen_PORT) - } - - - - def query(self,server_name): - - offline_ip = offline_DNS.get(server_name,None) - if(offline_ip!=None): - # print('offline DNS -->',server_name,offline_ip) - return offline_ip - - cache_ip = DNS_cache.get(server_name,None) - if(cache_ip!=None): - # print('cached DNS -->',server_name,cache_ip) - return cache_ip - - quary_params = { - # 'name': server_name, # no need for this when using dns wire-format , cause 400 err on some server - 'type': 'A', - 'ct': 'application/dns-message', - } - - - # print(f'online DNS Query',server_name) - try: - query_message = dns.message.make_query(server_name,'A') - query_wire = query_message.to_wire() - query_base64 = base64.urlsafe_b64encode(query_wire).decode('utf-8') - query_base64 = query_base64.replace('=','') # remove base64 padding to append in url - - query_url = self.url + query_base64 - ans = self.req.get( query_url , params=quary_params , headers={'accept': 'application/dns-message'} , proxies=self.fragment_proxy) - - # Parse the response as a DNS packet - if ans.status_code == 200 and ans.headers.get('content-type') == 'application/dns-message': - answer_msg = dns.message.from_wire(ans.content) - - resolved_ip = None - for x in answer_msg.answer: - if (x.rdtype == dns.rdatatype.A): - resolved_ip = x[0].address # pick first ip in DNS answer - DNS_cache[server_name] = resolved_ip - # print("################# DNS Cache is : ####################") - # print(DNS_cache) # print DNS cache , it usefull to track all resolved IPs , to be used later. - # print("#####################################################") - break - - # print(f'online DNS --> Resolved {server_name} to {resolved_ip}') - return resolved_ip - else: - print(f'Error: {ans.status_code} {ans.reason}') - except Exception as e: - print(repr(e)) - - - - - - - - - -class ThreadedServer(object): - def __init__(self, host, port): - self.DoH = DNS_over_Fragment() - self.host = host - self.port = port - self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.sock.bind((self.host, self.port)) - - def listen(self): - self.sock.listen(128) # up to 128 concurrent unaccepted socket queued , the more is refused untill accepting those. - - while True: - client_sock , client_addr = self.sock.accept() - client_sock.settimeout(my_socket_timeout) - - time.sleep(accept_time_sleep) # avoid server crash on flooding request - thread_up = threading.Thread(target = self.my_upstream , args =(client_sock,) ) - thread_up.daemon = True #avoid memory leak by telling os its belong to main program , its not a separate program , so gc collect it when thread finish - thread_up.start() - - - - def handle_client_request(self,client_socket): - # Receive the CONNECT request from the client - data = client_socket.recv(16384) - - - if(data[:7]==b'CONNECT'): - server_name , server_port = self.extract_servername_and_port(data) - elif( (data[:3]==b'GET') or (data[:4]==b'POST')): - q_line = str(data).split('\r\n') - q_url = q_line[0].split()[1] - q_url = q_url.replace('http://','https://') - # print('redirect http to HTTPS',q_url) - response_data = 'HTTP/1.1 302 Found\r\nLocation: '+q_url+'\r\nProxy-agent: MyProxy/1.0\r\n\r\n' - client_socket.sendall(response_data.encode()) - client_socket.close() - return None - else: - # print('Unknown Method',str(data[:10])) - response_data = b'HTTP/1.1 400 Bad Request\r\nProxy-agent: MyProxy/1.0\r\n\r\n' - client_socket.sendall(response_data) - client_socket.close() - return None - - - # print(server_name,'-->',server_port) - - try: - server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.settimeout(my_socket_timeout) - server_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) #force localhost kernel to send TCP packet immediately (idea: @free_the_internet) - - try: - socket.inet_aton(server_name) - # print('legal IP') - server_IP = server_name - except socket.error: - # print('Not IP , its domain , try to resolve it') - server_IP = self.DoH.query(server_name) - - server_socket.connect((server_IP, server_port)) - # Send HTTP 200 OK - response_data = b'HTTP/1.1 200 Connection established\r\nProxy-agent: MyProxy/1.0\r\n\r\n' - client_socket.sendall(response_data) - return server_socket - except Exception as e: - print(repr(e)) - # Send HTTP ERR 502 - response_data = b'HTTP/1.1 502 Bad Gateway\r\nProxy-agent: MyProxy/1.0\r\n\r\n' - client_socket.sendall(response_data) - client_socket.close() - server_socket.close() - return None - - - - - - - - def my_upstream(self, client_sock): - first_flag = True - backend_sock = self.handle_client_request(client_sock) - - if(backend_sock==None): - client_sock.close() - return False - - this_ip = backend_sock.getpeername()[0] - if(this_ip not in IP_UL_traffic): - IP_UL_traffic[this_ip] = 0 - - - while True: - try: - if( first_flag == True ): - first_flag = False - - time.sleep(first_time_sleep) # speed control + waiting for packet to fully recieve - data = client_sock.recv(16384) - #print('len data -> ',str(len(data))) - #print('user talk :') - - if data: - thread_down = threading.Thread(target = self.my_downstream , args = (backend_sock , client_sock) ) - thread_down.daemon = True - thread_down.start() - # backend_sock.sendall(data) - send_data_in_fragment(data,backend_sock) - IP_UL_traffic[this_ip] = IP_UL_traffic[this_ip] + len(data) - - else: - raise Exception('cli syn close') - - else: - data = client_sock.recv(16384) - if data: - backend_sock.sendall(data) - IP_UL_traffic[this_ip] = IP_UL_traffic[this_ip] + len(data) - else: - raise Exception('cli pipe close') - - except Exception as e: - #print('upstream : '+ repr(e) ) - time.sleep(2) # wait two second for another thread to flush - client_sock.close() - backend_sock.close() - return False - - - - - def my_downstream(self, backend_sock , client_sock): - this_ip = backend_sock.getpeername()[0] - if(this_ip not in IP_DL_traffic): - IP_DL_traffic[this_ip] = 0 - - - first_flag = True - while True: - try: - if( first_flag == True ): - first_flag = False - data = backend_sock.recv(16384) - if data: - client_sock.sendall(data) - IP_DL_traffic[this_ip] = IP_DL_traffic[this_ip] + len(data) - else: - raise Exception('backend pipe close at first') - - else: - data = backend_sock.recv(16384) - if data: - client_sock.sendall(data) - IP_DL_traffic[this_ip] = IP_DL_traffic[this_ip] + len(data) - else: - raise Exception('backend pipe close') - - except Exception as e: - #print('downstream '+backend_name +' : '+ repr(e)) - time.sleep(2) # wait two second for another thread to flush - backend_sock.close() - client_sock.close() - return False - - - - def extract_servername_and_port(self,data): - host_and_port = str(data).split()[1] - host,port = host_and_port.split(':') - return (host,int(port)) - - - -def merge_all_dicts(): - full_DNS = {**DNS_cache, **offline_DNS} # merge two dict , need python 3.5 or up - inv_DNS = { v:k for k, v in full_DNS.items()} # inverse mapping to look for domain given ip - stats = {} - for ip in IP_DL_traffic: - up = round(IP_UL_traffic[ip]/(1024.0),3) - down = round(IP_DL_traffic[ip]/(1024.0),3) - host = inv_DNS.get(ip,'?') - if((up>down) and (down<1.0)): # download below 1KB - maybe_filter = 'maybe' - else: - maybe_filter = '-------' - - su = f'UL={up} KB:' - sd = f'DL={down} KB:' - sf = f'filtered={maybe_filter}:' - sh = f'Host={host}:' - stats[ip] = ':'+su+sd+sf+sh - return stats - - - -# only run in separate thread -def log_writer(): - file_name = 'DNS_IP_traffic_info.txt' - BASE_DIR = Path(__file__).resolve().parent - log_file_path = os.path.join(BASE_DIR,file_name) - - with open(log_file_path, "w") as f: - while True: - time.sleep(log_every_N_sec) - all_stats_info = merge_all_dicts() - f.seek(0) - f.write('\n########### new DNS resolved : ##############\n') - f.write(str(DNS_cache).replace(',',',\n')) - f.write('\n#############################################\n') - f.write('\n########### ALL INFO : ######################\n') - f.write(str(all_stats_info).replace('\'','').replace(',','\n').replace(':','\t')) - f.write('\n#############################################\n') - f.flush() - f.truncate() - print("info file writed to",f.name ) - - - -def start_log_writer(): - thread_log = threading.Thread(target = log_writer , args = () ) - thread_log.daemon = True - thread_log.start() - - - - - -def send_data_in_fragment(data , sock): - L_data = len(data) - indices = random.sample(range(1,L_data-1), num_fragment-1) - indices.sort() - # print('indices=',indices) - - i_pre=0 - for i in indices: - fragment_data = data[i_pre:i] - i_pre=i - # print('send ',len(fragment_data),' bytes') - - # sock.send(fragment_data) - sock.sendall(fragment_data) - - time.sleep(fragment_sleep) - - fragment_data = data[i_pre:L_data] - sock.sendall(fragment_data) - # print('----------finish------------') - - - - -if (__name__ == "__main__"): - print('Logging disabled in Android version') - # start_log_writer() - print ("Now listening at: 127.0.0.1:"+str(listen_PORT)) - ThreadedServer('',listen_PORT).listen() - - - - diff --git a/gfw/Android/v2rayN_http_config.json b/gfw/Android/v2rayN_http_config.json deleted file mode 100644 index c1f512a..0000000 --- a/gfw/Android/v2rayN_http_config.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "log": { - "loglevel": "warning" - }, - - "inbounds": [ - { - "listen": "127.0.0.1", - "port": 10808, - "protocol": "socks", - "settings": { - "auth": "noauth", - "udp": true, - "userLevel": 8 - }, - "sniffing": { - "destOverride": [ - "http", - "tls" - ], - "enabled": true - }, - "tag": "socks" - }, - { - "listen": "127.0.0.1", - "port": 10809, - "protocol": "http", - "settings": { - "userLevel": 8 - }, - "tag": "http" - } - ], - - - "outbounds": [ - - { - "tag": "pyprox", - "protocol": "http", - "settings": { - "servers": [ - { - "address": "127.0.0.1", - "port": 4500 - } - ] - } - }, - - - { - "protocol": "freedom", - "settings": {}, - "tag": "direct" - }, - { - "protocol": "blackhole", - "settings": { - "response": { - "type": "http" - } - }, - "tag": "block" - } - ], - - - - - "routing": { - "domainMatcher": "mph", - "domainStrategy": "IPIfNonMatch", - "rules": [ - { - "type": "field", - "port": "0-65535", - "outboundTag": "pyprox", - "enabled": true - } - ] - } - - -} diff --git a/gfw/Direct_DoH/How_Make_Our_DoH/DoH_json_format_test.py b/gfw/Direct_DoH/How_Make_Our_DoH/DoH_json_format_test.py deleted file mode 100644 index be18780..0000000 --- a/gfw/Direct_DoH/How_Make_Our_DoH/DoH_json_format_test.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python3 - -import requests # --> pip install requests -import json - - - -# DNS_url = 'https://your.site:8443/mygoogle/resolve?name=' -# DNS_url = 'https://your.site:8443/mycloudflare/dns-query?name=' - -DNS_url = 'https://8.8.8.8/resolve?name=' -# DNS_url = 'https://8.8.4.4/resolve?name=' -# DNS_url = 'https://1.1.1.1/dns-query?name=' - -query = 'youtube.com' - - -allow_insecure = True # set true to allow certificate domain mismatch - - -class DNS_over_Fragment: - def __init__(self): - self.url = DNS_url - self.req = requests.session() - - - def query(self,server_name): - - quary_params = { - 'name': server_name, - 'type': 'A', - 'ct': 'application/dns-json', - } - - - print(f'online DNS Query',server_name) - try: - - query_url = self.url + server_name - ans = self.req.get( query_url , params=quary_params , headers={'accept': 'application/dns-json'} , verify=(not allow_insecure) ) - - # Parse the response as a DNS packet - if (ans.status_code == 200): - answer_msg = json.loads(ans.content) - - # resolved_ip = answer_msg['Answer'][0]['data'] - resolved_ip = None - - for x in answer_msg['Answer']: - if (x['type'] == 1): - resolved_ip = x['data'] # pick first ip in DNS answer - break - - print(f'online DNS --> Resolved {server_name} to {resolved_ip}') - return resolved_ip - else: - print(f'Error: {ans.status_code} {ans.reason}') - except Exception as e: - print(repr(e)) - - - - -if (__name__ == "__main__"): - DoH = DNS_over_Fragment() - DoH.query(query) - - diff --git a/gfw/Direct_DoH/How_Make_Our_DoH/DoH_wire_format_test.py b/gfw/Direct_DoH/How_Make_Our_DoH/DoH_wire_format_test.py deleted file mode 100644 index 01f4afa..0000000 --- a/gfw/Direct_DoH/How_Make_Our_DoH/DoH_wire_format_test.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python3 - -import dns.message # --> pip install dnspython -import dns.rdatatype -import requests # --> pip install requests -import base64 - - -# DNS_url = 'https://your.site:8443/mygoogle/dns-query?dns=' -# DNS_url = 'https://your.site:8443/mycloudflare/dns-query?dns=' - -# DNS_url = 'https://8.8.8.8/dns-query?dns=' -# DNS_url = 'https://8.8.4.4/dns-query?dns=' -DNS_url = 'https://1.1.1.1/dns-query?dns=' -# DNS_url = 'https://dns.electrotm.org/dns-query?dns=' - -query = 'youtube.com' - -allow_insecure = True # set true to allow certificate domain mismatch - - -class DNS_over_Fragment: - def __init__(self): - self.url = DNS_url - self.req = requests.session() - - - def query(self,server_name): - - quary_params = { - # 'name': server_name, # no need for this when using dns wire-format , cause 400 err on some server - 'type': 'A', - 'ct': 'application/dns-message', - } - - - print(f'online DNS Query',server_name) - try: - query_message = dns.message.make_query(server_name,'A') - query_wire = query_message.to_wire() - query_base64 = base64.urlsafe_b64encode(query_wire).decode('utf-8') - query_base64 = query_base64.replace('=','') # remove base64 padding to append in url - - query_url = self.url + query_base64 - ans = self.req.get( query_url , params=quary_params , headers={'accept': 'application/dns-message'} , verify=(not allow_insecure) ) - - # Parse the response as a DNS packet - if ans.status_code == 200 and ans.headers.get('content-type') == 'application/dns-message': - answer_msg = dns.message.from_wire(ans.content) - - resolved_ip = None - for x in answer_msg.answer: - if (x.rdtype == dns.rdatatype.A): - resolved_ip = x[0].address # pick first ip in DNS answer - break - - print(f'online DNS --> Resolved {server_name} to {resolved_ip}') - return resolved_ip - else: - print(f'Error: {ans.status_code} {ans.reason}') - except Exception as e: - print(repr(e)) - - - - -if (__name__ == "__main__"): - DoH = DNS_over_Fragment() - DoH.query(query) - - - - diff --git a/gfw/Direct_DoH/How_Make_Our_DoH/README.md b/gfw/Direct_DoH/How_Make_Our_DoH/README.md deleted file mode 100644 index ab695d9..0000000 --- a/gfw/Direct_DoH/How_Make_Our_DoH/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# how to make your DoH server -1. install nginx
-apt install nginx-light -2. add these line in file - /etc/nginx/sites-available/default
- -# cloudflare HTTPS port [ 443 , 2053 , 2083 , 2087 , 2096 , 8443 ] -server { - listen 8443 ssl default_server; - ssl_certificate /root/my_cert/your_cert.pem; - ssl_certificate_key /root/my_cert/your_cert.key; - location /mycloudflare/ { - proxy_pass https://cloudflare-dns.com:443/; - } - location /mygoogle/ { - proxy_pass https://dns.google:443/; - } -} - - -3. reload nginx
-systemctl daemon-reload
-systemctl restart nginx
- -4. use your DoH
-Json Format: -DNS_url = 'https://your.site:8443/mygoogle/resolve?name=' -DNS_url = 'https://your.site:8443/mycloudflare/dns-query?name=' -Wire Format: -DNS_url = 'https://your.site:8443/mygoogle/dns-query?dns=' -DNS_url = 'https://your.site:8443/mycloudflare/dns-query?dns=' - -5. you can put your.site behind cloudflare but ensure that your.domain is resolved to clean ip - -# Additional Tutorial: -1. we have two DNS query standard (some server only support WIRE format)
-JSON format: -https://dns.google/resolve?name=yahoo.com -https://cloudflare-dns.com/dns-query?name=yahoo.com -WIRE format: -https://dns.google/dns-query?dns=B64encode -https://cloudflare-dns.com/dns-query?dns=B64encode -2. test your server with curl
-curl -H "accept: application/dns-json" https://your.site:8443/mygoogle/resolve?name=yahoo.com - curl -H "accept: application/dns-json" https://your.site:8443/mycloudflare/dns-query?name=yahoo.com - - - diff --git a/gfw/Direct_DoH/README.md b/gfw/Direct_DoH/README.md deleted file mode 100644 index 8b5f4f5..0000000 --- a/gfw/Direct_DoH/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Direct DNS-Over-Https (DoH) - -# چیه این ؟ -- مستقیم تمام ip ها را از DNS over HTTPS (DoH) میگیرد بدون دخل و تصرف -- مقدار DNS_url را باید گزینه ای بگذارید که ایپی اش مسدود نباشد. مثلا سرور گوگل 8.8.8.8 روی یک نت مسدود و روی نت دیگر باز است -- اگر ip هایی که DoH برمیگرداند روی نت شما فیلتر نباشد ، سایت بالا خواهد آمد و محدودیت های comment و live و ... برطرف میشود -- تعداد فرگمنت را بین 10 تا 100 امتحان کنید و زمان فرگمنت بین 0.001 تا 0.01 -- کافیست اسکریپت Direct_DoH.py را اجرا کنید مشابه توضیحات صفحه اول diff --git a/gfw/Direct_DoH/pyprox_HTTPS_v2.0_DirectDoH.py b/gfw/Direct_DoH/pyprox_HTTPS_v2.0_DirectDoH.py deleted file mode 100644 index 745946f..0000000 --- a/gfw/Direct_DoH/pyprox_HTTPS_v2.0_DirectDoH.py +++ /dev/null @@ -1,411 +0,0 @@ -#!/usr/bin/env python3 - -import dns.message # --> pip install dnspython -import dns.rdatatype -import requests # --> pip install requests -from pathlib import Path -import os -import base64 -import socket -import threading -import time -import random - - -listen_PORT = 4500 # pyprox listening to 127.0.0.1:listen_PORT - -num_fragment = 87 # total number of chunks that ClientHello devided into (chunks with random size) -fragment_sleep = 0.001 # sleep between each fragment to make GFW-cache full so it forget previous chunks. LOL. - -log_every_N_sec = 30 # every 30 second , update log file with latest DNS-cache statistics - -allow_insecure = True # set true to allow certificate domain mismatch in DoH - - - -# DNS_url = 'https://8.8.4.4/dns-query?dns=' # blocked? -# DNS_url = 'https://8.8.8.8/dns-query?dns=' # blocked? -# DNS_url = 'https://1.1.1.1/dns-query?dns=' # blocked? -# DNS_url = 'https://cloudflare-dns.com/dns-query?dns=' # blocked? -# DNS_url = 'https://dns.google/dns-query?dns=' # blocked? -# DNS_url = 'https://doh.opendns.com/dns-query?dns=' # blocked? -# DNS_url = 'https://secure.avastdns.com/dns-query?dns=' # blocked? -# DNS_url = 'https://doh.libredns.gr/dns-query?dns=' # blocked? -# DNS_url = 'https://dns.electrotm.org/dns-query?dns=' -# DNS_url = 'https://dns.bitdefender.net/dns-query?dns=' -DNS_url = 'https://cluster-1.gac.edu/dns-query?dns=' - - - - -offline_DNS = { - -################## DNS over HTTPS IP Address (leave it intact , it must Exist) ###################### -'cloudflare-dns.com':'1.1.1.1', -'dns.google':'8.8.8.8', -'doh.opendns.com':'208.67.222.222', -'secure.avastdns.com':'185.185.133.66', -'doh.libredns.gr':'116.202.176.26', -'dns.electrotm.org':'78.157.42.100', -'dns.bitdefender.net':'34.84.232.67', -'cluster-1.gac.edu':'138.236.128.101', -########################################################################## - -} - - - - - -# ignore description below , its for old code , just leave it intact. -my_socket_timeout = 21 # default for google is ~21 sec , recommend 60 sec unless you have low ram and need close soon -first_time_sleep = 0.1 # speed control , avoid server crash if huge number of users flooding -accept_time_sleep = 0.01 # avoid server crash on flooding request -> max 100 sockets per second - - -DNS_cache = {} # resolved domains -IP_DL_traffic = {} # download usage for each ip -IP_UL_traffic = {} # upload usage for each ip - - -class DNS_over_Fragment: - def __init__(self): - self.url = DNS_url - self.req = requests.session() - self.fragment_proxy = { - 'https': 'http://127.0.0.1:'+str(listen_PORT) - } - - - - def query(self,server_name): - - offline_ip = offline_DNS.get(server_name,None) - if(offline_ip!=None): - print('offline DNS -->',server_name,offline_ip) - return offline_ip - - cache_ip = DNS_cache.get(server_name,None) - if(cache_ip!=None): - print('cached DNS -->',server_name,cache_ip) - return cache_ip - - quary_params = { - # 'name': server_name, # no need for this when using dns wire-format , cause 400 err on some server - 'type': 'A', - 'ct': 'application/dns-message', - } - - - print(f'online DNS Query',server_name) - try: - query_message = dns.message.make_query(server_name,'A') - query_wire = query_message.to_wire() - query_base64 = base64.urlsafe_b64encode(query_wire).decode('utf-8') - query_base64 = query_base64.replace('=','') # remove base64 padding to append in url - - query_url = self.url + query_base64 - ans = self.req.get( query_url , params=quary_params , headers={'accept': 'application/dns-message'} , proxies=self.fragment_proxy , verify=(not allow_insecure)) - - # Parse the response as a DNS packet - if ans.status_code == 200 and ans.headers.get('content-type') == 'application/dns-message': - answer_msg = dns.message.from_wire(ans.content) - - resolved_ip = None - for x in answer_msg.answer: - if (x.rdtype == dns.rdatatype.A): - resolved_ip = x[0].address # pick first ip in DNS answer - DNS_cache[server_name] = resolved_ip - print("################# DNS Cache is : ####################") - print(DNS_cache) # print DNS cache , it usefull to track all resolved IPs , to be used later. - print("#####################################################") - break - - print(f'online DNS --> Resolved {server_name} to {resolved_ip}') - return resolved_ip - else: - print(f'Error: {ans.status_code} {ans.reason}') - except Exception as e: - print(repr(e)) - - - - - - - - - -class ThreadedServer(object): - def __init__(self, host, port): - self.DoH = DNS_over_Fragment() - self.host = host - self.port = port - self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.sock.bind((self.host, self.port)) - - def listen(self): - self.sock.listen(128) # up to 128 concurrent unaccepted socket queued , the more is refused untill accepting those. - - while True: - client_sock , client_addr = self.sock.accept() - client_sock.settimeout(my_socket_timeout) - - time.sleep(accept_time_sleep) # avoid server crash on flooding request - thread_up = threading.Thread(target = self.my_upstream , args =(client_sock,) ) - thread_up.daemon = True #avoid memory leak by telling os its belong to main program , its not a separate program , so gc collect it when thread finish - thread_up.start() - - - - def handle_client_request(self,client_socket): - # Receive the CONNECT request from the client - data = client_socket.recv(16384) - - - if(data[:7]==b'CONNECT'): - server_name , server_port = self.extract_servername_and_port(data) - elif( (data[:3]==b'GET') - or (data[:4]==b'POST') - or (data[:4]==b'HEAD') - or (data[:7]==b'OPTIONS') - or (data[:3]==b'PUT') - or (data[:6]==b'DELETE') - or (data[:5]==b'PATCH') - or (data[:5]==b'TRACE') ): - - q_line = str(data).split('\r\n') - q_req = q_line[0].split() - q_method = q_req[0] - q_url = q_req[1] - q_url = q_url.replace('http://','https://') - print('************************@@@@@@@@@@@@***************************') - print('redirect',q_method,'http to HTTPS',q_url) - response_data = 'HTTP/1.1 302 Found\r\nLocation: '+q_url+'\r\nProxy-agent: MyProxy/1.0\r\n\r\n' - client_socket.sendall(response_data.encode()) - client_socket.close() - return None - else: - print('Unknown Method',str(data[:10])) - response_data = b'HTTP/1.1 400 Bad Request\r\nProxy-agent: MyProxy/1.0\r\n\r\n' - client_socket.sendall(response_data) - client_socket.close() - return None - - - print(server_name,'-->',server_port) - - try: - server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.settimeout(my_socket_timeout) - server_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) #force localhost kernel to send TCP packet immediately (idea: @free_the_internet) - - try: - socket.inet_aton(server_name) - # print('legal IP') - server_IP = server_name - except socket.error: - # print('Not IP , its domain , try to resolve it') - server_IP = self.DoH.query(server_name) - - server_socket.connect((server_IP, server_port)) - # Send HTTP 200 OK - response_data = b'HTTP/1.1 200 Connection established\r\nProxy-agent: MyProxy/1.0\r\n\r\n' - client_socket.sendall(response_data) - return server_socket - except Exception as e: - print(repr(e)) - # Send HTTP ERR 502 - response_data = b'HTTP/1.1 502 Bad Gateway (is IP filtered?)\r\nProxy-agent: MyProxy/1.0\r\n\r\n' - client_socket.sendall(response_data) - client_socket.close() - server_socket.close() - return None - - - - - - - - def my_upstream(self, client_sock): - first_flag = True - backend_sock = self.handle_client_request(client_sock) - - if(backend_sock==None): - client_sock.close() - return False - - this_ip = backend_sock.getpeername()[0] - if(this_ip not in IP_UL_traffic): - IP_UL_traffic[this_ip] = 0 - - - while True: - try: - if( first_flag == True ): - first_flag = False - - time.sleep(first_time_sleep) # speed control + waiting for packet to fully recieve - data = client_sock.recv(16384) - #print('len data -> ',str(len(data))) - #print('user talk :') - - if data: - thread_down = threading.Thread(target = self.my_downstream , args = (backend_sock , client_sock) ) - thread_down.daemon = True - thread_down.start() - # backend_sock.sendall(data) - send_data_in_fragment(data,backend_sock) - IP_UL_traffic[this_ip] = IP_UL_traffic[this_ip] + len(data) - - else: - raise Exception('cli syn close') - - else: - data = client_sock.recv(16384) - if data: - backend_sock.sendall(data) - IP_UL_traffic[this_ip] = IP_UL_traffic[this_ip] + len(data) - else: - raise Exception('cli pipe close') - - except Exception as e: - #print('upstream : '+ repr(e) ) - time.sleep(2) # wait two second for another thread to flush - client_sock.close() - backend_sock.close() - return False - - - - - def my_downstream(self, backend_sock , client_sock): - this_ip = backend_sock.getpeername()[0] - if(this_ip not in IP_DL_traffic): - IP_DL_traffic[this_ip] = 0 - - - first_flag = True - while True: - try: - if( first_flag == True ): - first_flag = False - data = backend_sock.recv(16384) - if data: - client_sock.sendall(data) - IP_DL_traffic[this_ip] = IP_DL_traffic[this_ip] + len(data) - else: - raise Exception('backend pipe close at first') - - else: - data = backend_sock.recv(16384) - if data: - client_sock.sendall(data) - IP_DL_traffic[this_ip] = IP_DL_traffic[this_ip] + len(data) - else: - raise Exception('backend pipe close') - - except Exception as e: - #print('downstream '+backend_name +' : '+ repr(e)) - time.sleep(2) # wait two second for another thread to flush - backend_sock.close() - client_sock.close() - return False - - - - def extract_servername_and_port(self,data): - host_and_port = str(data).split()[1] - host,port = host_and_port.split(':') - return (host,int(port)) - - - -def merge_all_dicts(): - full_DNS = {**DNS_cache, **offline_DNS} # merge two dict , need python 3.5 or up - inv_DNS = { v:k for k, v in full_DNS.items()} # inverse mapping to look for domain given ip - stats = {} - for ip in IP_DL_traffic: - up = round(IP_UL_traffic[ip]/(1024.0),3) - down = round(IP_DL_traffic[ip]/(1024.0),3) - host = inv_DNS.get(ip,'?') - if((up>down) and (down<1.0)): # download below 1KB - maybe_filter = 'maybe' - else: - maybe_filter = '-------' - - su = f'UL={up} KB:' - sd = f'DL={down} KB:' - sf = f'filtered={maybe_filter}:' - sh = f'Host={host}:' - stats[ip] = ':'+su+sd+sf+sh - return stats - - - -# only run in separate thread -def log_writer(): - file_name = 'DNS_IP_traffic_info.txt' - BASE_DIR = Path(__file__).resolve().parent - log_file_path = os.path.join(BASE_DIR,file_name) - - with open(log_file_path, "w") as f: - while True: - time.sleep(log_every_N_sec) - all_stats_info = merge_all_dicts() - f.seek(0) - f.write('\n########### new DNS resolved : ##############\n') - f.write(str(DNS_cache).replace(',',',\n')) - f.write('\n#############################################\n') - f.write('\n########### ALL INFO : ######################\n') - f.write(str(all_stats_info).replace('\'','').replace(',','\n').replace(':','\t')) - f.write('\n#############################################\n') - f.flush() - f.truncate() - print("info file writed to",f.name ) - - - -def start_log_writer(): - thread_log = threading.Thread(target = log_writer , args = () ) - thread_log.daemon = True - thread_log.start() - - - - - -def send_data_in_fragment(data , sock): - L_data = len(data) - indices = random.sample(range(1,L_data-1), num_fragment-1) - indices.sort() - # print('indices=',indices) - - i_pre=0 - for i in indices: - fragment_data = data[i_pre:i] - i_pre=i - # print('send ',len(fragment_data),' bytes') - - # sock.send(fragment_data) - sock.sendall(fragment_data) - - time.sleep(fragment_sleep) - - fragment_data = data[i_pre:L_data] - sock.sendall(fragment_data) - print('----------finish------------') - - - - -if (__name__ == "__main__"): - start_log_writer() - print ("Now listening at: 127.0.0.1:"+str(listen_PORT)) - ThreadedServer('',listen_PORT).listen() - - - - diff --git a/gfw/Irancell/README.md b/gfw/Irancell/README.md deleted file mode 100644 index e3eaa2b..0000000 --- a/gfw/Irancell/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# بهینه شده برای ایرانسل -- یوتیوب و توییتر -- اگر کار نکرد تعداد فرگمنت را از 14 به 87 افزایش و زمان فرگمنت را از 0.01 به 0.001 کاهش دهید diff --git a/gfw/Irancell/pyprox_HTTPS_v1.0_irancell.py b/gfw/Irancell/pyprox_HTTPS_v1.0_irancell.py deleted file mode 100644 index 26d2e8e..0000000 --- a/gfw/Irancell/pyprox_HTTPS_v1.0_irancell.py +++ /dev/null @@ -1,490 +0,0 @@ -#!/usr/bin/env python3 - -import dns.message # --> pip install dnspython -import dns.rdatatype -import requests # --> pip install requests -from pathlib import Path -import os -import base64 -import socket -import threading -import time -import random - - -listen_PORT = 4500 # pyprox listening to 127.0.0.1:listen_PORT - -num_fragment = 14 # total number of chunks that ClientHello devided into (chunks with random size) -fragment_sleep = 0.01 # sleep between each fragment to make GFW-cache full so it forget previous chunks. LOL. - -log_every_N_sec = 10 # every 30 second , update log file with latest DNS-cache statistics - -# DNS_url = 'https://cloudflare-dns.com/dns-query?dns=' # not working in iran , ip blocked -# DNS_url = 'https://dns.google/dns-query?dns=' # not working in iran , ip blocked -# DNS_url = 'https://doh.opendns.com/dns-query?dns=' # not working in iran , ip blocked -# DNS_url = 'https://secure.avastdns.com/dns-query?dns=' # not working in iran , ip blocked -# DNS_url = 'https://doh.libredns.gr/dns-query?dns=' # not working in iran , ip blocked -DNS_url = 'https://dns.electrotm.org/dns-query?dns=' -# DNS_url = 'https://dns.bitdefender.net/dns-query?dns=' -# DNS_url = 'https://cluster-1.gac.edu/dns-query?dns=' - - - - -offline_DNS = { - - - -# ################# twitter working pack ################### -'ocsp.digicert.com': '192.229.211.108', - -'api.twitter.com': '104.244.42.66', -'twitter.com': '104.244.42.1', -'pbs.twimg.com': '93.184.220.70', -'abs-0.twimg.com': '104.244.43.131', -'abs.twimg.com': '152.199.24.185', -'video.twimg.com': '192.229.220.133', -'t.co': '104.244.42.69', -'ton.local.twitter.com':'104.244.42.1', -# ########################################################## - - - -##################### Google working pack ################### -'ocsp.pki.goog': '172.217.16.195', -'googleads.g.doubleclick.net': '45.157.177.108', -'fonts.gstatic.com': '142.250.185.227', -'rr2---sn-vh5ouxa-hju6.googlevideo.com': '213.202.6.141', -'jnn-pa.googleapis.com': '45.157.177.108', -'static.doubleclick.net': '202.61.195.218', -'rr4---sn-hju7en7k.googlevideo.com': '74.125.167.74', -'rr1---sn-hju7en7r.googlevideo.com': '74.125.167.87', -'play.google.com': '142.250.184.238', -'rr3---sn-vh5ouxa-hjuz.googlevideo.com': '134.0.218.206', -'rr3---sn-hju7enel.googlevideo.com': '74.125.98.40', -'download.visualstudio.microsoft.com': '68.232.34.200', -'ocsp.pki.goog': '172.217.16.195', -'i.ytimg.com': '142.250.186.150', -'rr2---sn-hju7enel.googlevideo.com': '74.125.98.39', -'rr2---sn-hju7en7k.googlevideo.com': '74.125.167.72', -'googleads.g.doubleclick.net': '45.157.177.108', -'rr3---sn-4g5lznl6.googlevideo.com': '74.125.173.40', -'jnn-pa.googleapis.com': '89.58.57.45', -'rr3---sn-hju7en7k.googlevideo.com': '74.125.167.73', -'rr1---sn-hju7enll.googlevideo.com': '74.125.98.6', -'rr6---sn-hju7en7r.googlevideo.com': '74.125.167.92', -'play.google.com': '216.58.212.174', -'www.gstatic.com': '142.250.185.99', -'apis.google.com': '172.217.23.110', -'adservice.google.com': '202.61.195.218', -'mail.google.com': '142.250.186.37', -'accounts.google.com': '172.217.16.205', - -# 'lh3.googleusercontent.com': '193.26.157.66', # filtered -'lh3.googleusercontent.com':'142.251.167.132', - -'accounts.youtube.com': '172.217.16.206', -'ssl.gstatic.com': '142.250.184.195', -'fonts.gstatic.com': '172.217.23.99', -'rr4---sn-hju7enll.googlevideo.com': '74.125.98.9', # good -'rr2---sn-hju7enll.googlevideo.com': '74.125.98.7', -'rr1---sn-hju7enel.googlevideo.com': '74.125.98.38', -'rr5---sn-vh5ouxa-hjuz.googlevideo.com': '134.0.218.208', -'i1.ytimg.com': '172.217.18.14', -'plos.org': '162.159.135.42', -'fonts.googleapis.com': '89.58.57.45', -'genweb.plos.org': '104.26.1.141', -'static.ads-twitter.com': '146.75.120.157', -'www.google-analytics.com': '142.250.185.174', -'rr1---sn-vh5ouxa-hju6.googlevideo.com': '213.202.6.140', -'rr5---sn-vh5ouxa-hju6.googlevideo.com': '213.202.6.144', -'rr3---sn-hju7enel.googlevideo.com': '74.125.98.40', -'rr5---sn-nv47zn7y.googlevideo.com': '173.194.15.74', -'safebrowsing.googleapis.com': '202.61.195.218', -'static.doubleclick.net': '193.26.157.66', -'rr5---sn-vh5ouxa-hju6.googlevideo.com': '213.202.6.144', -'rr1---sn-hju7en7r.googlevideo.com': '74.125.167.87', -'rr4---sn-vh5ouxa-hju6.googlevideo.com': '213.202.6.143', -'rr4---sn-hju7en7r.googlevideo.com': '74.125.167.90', -'r1---sn-hju7enel.googlevideo.com': '74.125.98.38', -'rr1---sn-nv47zn7r.googlevideo.com': '173.194.15.38', -'rr2---sn-vh5ouxa-hjuz.googlevideo.com': '134.0.218.205', -'rr4---sn-nv47zn7r.googlevideo.com': '173.194.15.41', -'rr4---sn-hju7en7r.googlevideo.com': '74.125.167.90', - - -'rr4---sn-nv47znel.googlevideo.com': '74.125.98.7', # good -'rr4---sn-nv47lnl7.googlevideo.com':'74.125.98.7', -'rr4---sn-hju7enll.googlevideo.com':'74.125.98.7', -'rr1---sn-vh5ouxa-hju6.googlevideo.com':'74.125.98.7', -'rr3---sn-hju7enel.googlevideo.com':'74.125.98.7', -'rr5---sn-hju7enll.googlevideo.com':'74.125.98.7', -'rr5---sn-vh5ouxa-hjuz.googlevideo.com':'74.125.98.7', -'rr1---sn-nv47ln7z.googlevideo.com':'74.125.98.7', -'rr3---sn-vh5ouxa-hju6.googlevideo.com': '74.125.98.7', - - -'www.google.com': '142.250.186.36', -# 'www.google.com': '216.239.38.120', -'youtube.com':'216.239.38.120', -'www.youtube.com':'216.239.38.120', -'i.ytimg.com':'216.239.38.120', - -# 'yt3.ggpht.com': '64.233.165.198', # filtered -# 'yt3.ggpht.com': '142.250.179.161', # filtered -# 'yt3.ggpht.com': '142.250.186.65', # sometimes work -'yt3.ggpht.com': '142.250.186.36', # most of times work -####################################################### - - -################## DNS over HTTPS IP Address (leave it intact , it must Exist) ###################### -'cloudflare-dns.com':'1.1.1.1', # not working in iran , ip blocked -'dns.google':'8.8.8.8', # not working in iran , ip blocked -'doh.opendns.com':'208.67.222.222', # not working in iran , ip blocked -'secure.avastdns.com':'185.185.133.66', # not working in iran , ip blocked -'doh.libredns.gr':'116.202.176.26', # not working in iran , ip blocked -'dns.electrotm.org':'78.157.42.100', -'dns.bitdefender.net':'34.84.232.67', -'cluster-1.gac.edu':'138.236.128.101', -########################################################################## - -} - - - - - -# ignore description below , its for old code , just leave it intact. -my_socket_timeout = 21 # default for google is ~21 sec , recommend 60 sec unless you have low ram and need close soon -first_time_sleep = 0.1 # speed control , avoid server crash if huge number of users flooding -accept_time_sleep = 0.01 # avoid server crash on flooding request -> max 100 sockets per second - - -DNS_cache = {} # resolved domains -IP_DL_traffic = {} # download usage for each ip -IP_UL_traffic = {} # upload usage for each ip - - -class DNS_over_Fragment: - def __init__(self): - self.url = DNS_url - self.req = requests.session() - self.fragment_proxy = { - 'https': 'http://127.0.0.1:'+str(listen_PORT) - } - - - - def query(self,server_name): - - offline_ip = offline_DNS.get(server_name,None) - if(offline_ip!=None): - print('offline DNS -->',server_name,offline_ip) - return offline_ip - - cache_ip = DNS_cache.get(server_name,None) - if(cache_ip!=None): - print('cached DNS -->',server_name,cache_ip) - return cache_ip - - quary_params = { - # 'name': server_name, # no need for this when using dns wire-format , cause 400 err on some server - 'type': 'A', - 'ct': 'application/dns-message', - } - - - print(f'online DNS Query',server_name) - try: - query_message = dns.message.make_query(server_name,'A') - query_wire = query_message.to_wire() - query_base64 = base64.urlsafe_b64encode(query_wire).decode('utf-8') - query_base64 = query_base64.replace('=','') # remove base64 padding to append in url - - query_url = self.url + query_base64 - ans = self.req.get( query_url , params=quary_params , headers={'accept': 'application/dns-message'} , proxies=self.fragment_proxy) - - # Parse the response as a DNS packet - if ans.status_code == 200 and ans.headers.get('content-type') == 'application/dns-message': - answer_msg = dns.message.from_wire(ans.content) - - resolved_ip = None - for x in answer_msg.answer: - if (x.rdtype == dns.rdatatype.A): - resolved_ip = x[0].address # pick first ip in DNS answer - DNS_cache[server_name] = resolved_ip - print("################# DNS Cache is : ####################") - print(DNS_cache) # print DNS cache , it usefull to track all resolved IPs , to be used later. - print("#####################################################") - break - - print(f'online DNS --> Resolved {server_name} to {resolved_ip}') - return resolved_ip - else: - print(f'Error: {ans.status_code} {ans.reason}') - except Exception as e: - print(repr(e)) - - - - - - - - - -class ThreadedServer(object): - def __init__(self, host, port): - self.DoH = DNS_over_Fragment() - self.host = host - self.port = port - self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.sock.bind((self.host, self.port)) - - def listen(self): - self.sock.listen(128) # up to 128 concurrent unaccepted socket queued , the more is refused untill accepting those. - - while True: - client_sock , client_addr = self.sock.accept() - client_sock.settimeout(my_socket_timeout) - - time.sleep(accept_time_sleep) # avoid server crash on flooding request - thread_up = threading.Thread(target = self.my_upstream , args =(client_sock,) ) - thread_up.daemon = True #avoid memory leak by telling os its belong to main program , its not a separate program , so gc collect it when thread finish - thread_up.start() - - - - def handle_client_request(self,client_socket): - # Receive the CONNECT request from the client - data = client_socket.recv(16384) - - - if(data[:7]==b'CONNECT'): - server_name , server_port = self.extract_servername_and_port(data) - elif( (data[:3]==b'GET') or (data[:4]==b'POST')): - q_line = str(data).split('\r\n') - q_url = q_line[0].split()[1] - q_url = q_url.replace('http://','https://') - print('redirect http to HTTPS',q_url) - response_data = 'HTTP/1.1 302 Found\r\nLocation: '+q_url+'\r\nProxy-agent: MyProxy/1.0\r\n\r\n' - client_socket.sendall(response_data.encode()) - client_socket.close() - return None - else: - print('Unknown Method',str(data[:10])) - response_data = b'HTTP/1.1 400 Bad Request\r\nProxy-agent: MyProxy/1.0\r\n\r\n' - client_socket.sendall(response_data) - client_socket.close() - return None - - - print(server_name,'-->',server_port) - - try: - server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.settimeout(my_socket_timeout) - server_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) #force localhost kernel to send TCP packet immediately (idea: @free_the_internet) - - server_IP = self.DoH.query(server_name) - server_socket.connect((server_IP, server_port)) - # Send HTTP 200 OK - response_data = b'HTTP/1.1 200 Connection established\r\nProxy-agent: MyProxy/1.0\r\n\r\n' - client_socket.sendall(response_data) - return server_socket - except Exception as e: - print(repr(e)) - # Send HTTP ERR 502 - response_data = b'HTTP/1.1 502 Bad Gateway\r\nProxy-agent: MyProxy/1.0\r\n\r\n' - client_socket.sendall(response_data) - client_socket.close() - server_socket.close() - return None - - - - - - - - def my_upstream(self, client_sock): - first_flag = True - backend_sock = self.handle_client_request(client_sock) - - if(backend_sock==None): - client_sock.close() - return False - - this_ip = backend_sock.getpeername()[0] - if(this_ip not in IP_UL_traffic): - IP_UL_traffic[this_ip] = 0 - - - while True: - try: - if( first_flag == True ): - first_flag = False - - time.sleep(first_time_sleep) # speed control + waiting for packet to fully recieve - data = client_sock.recv(16384) - #print('len data -> ',str(len(data))) - #print('user talk :') - - if data: - thread_down = threading.Thread(target = self.my_downstream , args = (backend_sock , client_sock) ) - thread_down.daemon = True - thread_down.start() - # backend_sock.sendall(data) - send_data_in_fragment(data,backend_sock) - IP_UL_traffic[this_ip] = IP_UL_traffic[this_ip] + len(data) - - else: - raise Exception('cli syn close') - - else: - data = client_sock.recv(16384) - if data: - backend_sock.sendall(data) - IP_UL_traffic[this_ip] = IP_UL_traffic[this_ip] + len(data) - else: - raise Exception('cli pipe close') - - except Exception as e: - #print('upstream : '+ repr(e) ) - time.sleep(2) # wait two second for another thread to flush - client_sock.close() - backend_sock.close() - return False - - - - - def my_downstream(self, backend_sock , client_sock): - this_ip = backend_sock.getpeername()[0] - if(this_ip not in IP_DL_traffic): - IP_DL_traffic[this_ip] = 0 - - - first_flag = True - while True: - try: - if( first_flag == True ): - first_flag = False - data = backend_sock.recv(16384) - if data: - client_sock.sendall(data) - IP_DL_traffic[this_ip] = IP_DL_traffic[this_ip] + len(data) - else: - raise Exception('backend pipe close at first') - - else: - data = backend_sock.recv(16384) - if data: - client_sock.sendall(data) - IP_DL_traffic[this_ip] = IP_DL_traffic[this_ip] + len(data) - else: - raise Exception('backend pipe close') - - except Exception as e: - #print('downstream '+backend_name +' : '+ repr(e)) - time.sleep(2) # wait two second for another thread to flush - backend_sock.close() - client_sock.close() - return False - - - - def extract_servername_and_port(self,data): - host_and_port = str(data).split()[1] - host,port = host_and_port.split(':') - return (host,int(port)) - - - -def merge_all_dicts(): - full_DNS = {**DNS_cache, **offline_DNS} # merge two dict , need python 3.5 or up - inv_DNS = { v:k for k, v in full_DNS.items()} # inverse mapping to look for domain given ip - stats = {} - for ip in IP_DL_traffic: - up = round(IP_UL_traffic[ip]/(1024.0),3) - down = round(IP_DL_traffic[ip]/(1024.0),3) - host = inv_DNS.get(ip,'?') - if((up>down) and (down<1.0)): # download below 1KB - maybe_filter = 'maybe' - else: - maybe_filter = '-------' - - su = f'UL={up} KB:' - sd = f'DL={down} KB:' - sf = f'filtered={maybe_filter}:' - sh = f'Host={host}:' - stats[ip] = ':'+su+sd+sf+sh - return stats - - - -# only run in separate thread -def log_writer(): - file_name = 'DNS_IP_traffic_info.txt' - BASE_DIR = Path(__file__).resolve().parent - log_file_path = os.path.join(BASE_DIR,file_name) - - with open(log_file_path, "w") as f: - while True: - time.sleep(log_every_N_sec) - all_stats_info = merge_all_dicts() - f.seek(0) - f.write('\n########### new DNS resolved : ##############\n') - f.write(str(DNS_cache).replace(',',',\n')) - f.write('\n#############################################\n') - f.write('\n########### ALL INFO : ######################\n') - f.write(str(all_stats_info).replace('\'','').replace(',','\n').replace(':','\t')) - f.write('\n#############################################\n') - f.flush() - f.truncate() - print("info file writed to",f.name ) - - - -def start_log_writer(): - thread_log = threading.Thread(target = log_writer , args = () ) - thread_log.daemon = True - thread_log.start() - - - - - -def send_data_in_fragment(data , sock): - L_data = len(data) - indices = random.sample(range(1,L_data-1), num_fragment-1) - indices.sort() - # print('indices=',indices) - - i_pre=0 - for i in indices: - fragment_data = data[i_pre:i] - i_pre=i - # print('send ',len(fragment_data),' bytes') - - # sock.send(fragment_data) - sock.sendall(fragment_data) - - time.sleep(fragment_sleep) - - fragment_data = data[i_pre:L_data] - sock.sendall(fragment_data) - print('----------finish------------') - - - - -if (__name__ == "__main__"): - # start_log_writer() - print ("Now listening at: 127.0.0.1:"+str(listen_PORT)) - ThreadedServer('',listen_PORT).listen() - - - - diff --git a/gfw/Irancell/v2rayN_HTTPS_config.json b/gfw/Irancell/v2rayN_HTTPS_config.json deleted file mode 100644 index c1f512a..0000000 --- a/gfw/Irancell/v2rayN_HTTPS_config.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "log": { - "loglevel": "warning" - }, - - "inbounds": [ - { - "listen": "127.0.0.1", - "port": 10808, - "protocol": "socks", - "settings": { - "auth": "noauth", - "udp": true, - "userLevel": 8 - }, - "sniffing": { - "destOverride": [ - "http", - "tls" - ], - "enabled": true - }, - "tag": "socks" - }, - { - "listen": "127.0.0.1", - "port": 10809, - "protocol": "http", - "settings": { - "userLevel": 8 - }, - "tag": "http" - } - ], - - - "outbounds": [ - - { - "tag": "pyprox", - "protocol": "http", - "settings": { - "servers": [ - { - "address": "127.0.0.1", - "port": 4500 - } - ] - } - }, - - - { - "protocol": "freedom", - "settings": {}, - "tag": "direct" - }, - { - "protocol": "blackhole", - "settings": { - "response": { - "type": "http" - } - }, - "tag": "block" - } - ], - - - - - "routing": { - "domainMatcher": "mph", - "domainStrategy": "IPIfNonMatch", - "rules": [ - { - "type": "field", - "port": "0-65535", - "outboundTag": "pyprox", - "enabled": true - } - ] - } - - -} diff --git a/gfw/asset/IP_Log.png b/gfw/asset/IP_Log.png deleted file mode 100644 index 7da923c..0000000 Binary files a/gfw/asset/IP_Log.png and /dev/null differ diff --git a/gfw/asset/customize_params.png b/gfw/asset/customize_params.png deleted file mode 100644 index 4972372..0000000 Binary files a/gfw/asset/customize_params.png and /dev/null differ diff --git a/gfw/asset/firefox_proxy.png b/gfw/asset/firefox_proxy.png deleted file mode 100644 index 5d8473b..0000000 Binary files a/gfw/asset/firefox_proxy.png and /dev/null differ diff --git a/gfw/asset/install_packages.png b/gfw/asset/install_packages.png deleted file mode 100644 index 4c38411..0000000 Binary files a/gfw/asset/install_packages.png and /dev/null differ diff --git a/gfw/asset/neko_bypass_app.jpg b/gfw/asset/neko_bypass_app.jpg deleted file mode 100644 index bcf4f43..0000000 Binary files a/gfw/asset/neko_bypass_app.jpg and /dev/null differ diff --git a/gfw/asset/neko_http_config.jpg b/gfw/asset/neko_http_config.jpg deleted file mode 100644 index 590df7b..0000000 Binary files a/gfw/asset/neko_http_config.jpg and /dev/null differ diff --git a/gfw/asset/neko_http_menu.jpg b/gfw/asset/neko_http_menu.jpg deleted file mode 100644 index 893539a..0000000 Binary files a/gfw/asset/neko_http_menu.jpg and /dev/null differ diff --git a/gfw/asset/offline_DNS.png b/gfw/asset/offline_DNS.png deleted file mode 100644 index 8ab37cc..0000000 Binary files a/gfw/asset/offline_DNS.png and /dev/null differ diff --git a/gfw/asset/slide2.png b/gfw/asset/slide2.png deleted file mode 100644 index 82a3762..0000000 Binary files a/gfw/asset/slide2.png and /dev/null differ diff --git a/gfw/asset/swiss_army.png b/gfw/asset/swiss_army.png deleted file mode 100644 index 522686c..0000000 Binary files a/gfw/asset/swiss_army.png and /dev/null differ diff --git a/gfw/asset/temp.txt b/gfw/asset/temp.txt deleted file mode 100644 index a9a5aec..0000000 --- a/gfw/asset/temp.txt +++ /dev/null @@ -1 +0,0 @@ -tmp diff --git a/gfw/asset/v2ray_custom.png b/gfw/asset/v2ray_custom.png deleted file mode 100644 index e723dfd..0000000 Binary files a/gfw/asset/v2ray_custom.png and /dev/null differ