├── flask_app ├── static │ ├── img │ │ ├── favicon.ico │ │ └── topback.gif │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ ├── css │ │ └── style.css │ └── js │ │ ├── html5shiv.min.js │ │ ├── respond.min.js │ │ ├── common.js │ │ └── moment.min.js ├── config.py ├── templates │ ├── login.html │ ├── clients.html │ ├── mappings.html │ ├── index.html │ └── base.html ├── server_views.py ├── __init__.py └── api.py ├── requires.txt ├── README.md ├── common.py ├── utils.py ├── protocol.py ├── client.py └── server.py /flask_app/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/revoll/AnyProxy/HEAD/flask_app/static/img/favicon.ico -------------------------------------------------------------------------------- /flask_app/static/img/topback.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/revoll/AnyProxy/HEAD/flask_app/static/img/topback.gif -------------------------------------------------------------------------------- /flask_app/static/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/revoll/AnyProxy/HEAD/flask_app/static/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /flask_app/static/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/revoll/AnyProxy/HEAD/flask_app/static/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /flask_app/static/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/revoll/AnyProxy/HEAD/flask_app/static/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /flask_app/static/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/revoll/AnyProxy/HEAD/flask_app/static/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /requires.txt: -------------------------------------------------------------------------------- 1 | # python3.7 2 | # python3-setuptools 3 | # python3-pip 4 | # virtualenv 5 | loguru 6 | flask 7 | flask-login 8 | flask-mail 9 | flask-moment 10 | flask-bootstrap -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AnyProxy 2 | AnyProxy是一个可穿透NAT的端口映射软件。它能够将局域网内的主机端口,映射到公网主机上,实现类似“花生壳”的功能。 3 | 4 | AnyProxy使用Python语言实现,并基于Flask实现了Web监控。主要特点:支持任意的TCP和UDP端口的代理;支持多台主机同时连接;支持客户端主机的动态连接、暂停、恢复及删除。 5 | 6 | 7 | ### 如何使用 8 | -------------------------------------------------------------------------------- /common.py: -------------------------------------------------------------------------------- 1 | class ProxyError(Exception): 2 | pass 3 | 4 | 5 | class RunningStatus: 6 | """状态转移图: PREPARE ----> RUNNING (<==> PENDING) ----> STOPPED """ 7 | PREPARE = 0 8 | RUNNING = 1 9 | PENDING = 3 10 | STOPPED = 5 11 | -------------------------------------------------------------------------------- /flask_app/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | class Config: 5 | """ Application Configurations """ 6 | SECRET_KEY = os.environ.get(u'SECRET_KEY') or os.urandom(24) 7 | SSL_DISABLE = True 8 | 9 | MAIL_SERVER = os.environ.get(u'MAIL_SERVER') 10 | MAIL_PORT = int(os.environ.get(u'MAIL_PORT') or u'25') 11 | MAIL_USERNAME = os.environ.get(u'MAIL_USERNAME') 12 | MAIL_PASSWORD = os.environ.get(u'MAIL_PASSWORD') 13 | MAIL_SUBJECT_PREFIX = u'[PySite]' 14 | MAIL_SENDER = u'PySite Admin <%s>' % os.environ.get(u'MAIL_USERNAME') 15 | MAIL_NOTIFICATION = u'MAIL NOTIFICATION BOYD HERE....' 16 | 17 | @staticmethod 18 | def init_app(app): 19 | pass 20 | -------------------------------------------------------------------------------- /flask_app/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | 4 | {% block title %}Login{% endblock title %} 5 | 6 | 7 | {% block main_content %} 8 | 9 |
| 创建时间 | 17 |客户端ID | 18 |名称 | 19 |公网地址 | 20 |协议流量 | 21 |TCP映射数 | 22 |TCP流量 | 23 |UDP映射数 | 24 |UDP流量 | 25 |相关操作 | 26 |
|---|---|---|---|---|---|---|---|---|---|
| {{ moment(clients[c]['start_time']).format('YYYY-MM-DD HH:mm:ss') }} | 32 |{{ clients[c]['client_id'] }} | 33 |{{ clients[c]['client_name'] }} | 34 |{{ clients[c]['tcp_e_addr'][0] }} | 35 |{{ stringify_bytes_val(clients[c]['total_statistic'][0] + clients[c]['total_statistic'][1] - clients[c]['tcp_statistic'][0] - clients[c]['tcp_statistic'][1] - clients[c]['udp_statistic'][0] - clients[c]['udp_statistic'][1]) }} | 36 |37 | {{ len(clients[c]['tcp_maps']) }} 38 | | 39 |{{ stringify_bytes_val(clients[c]['tcp_statistic'][0] + clients[c]['tcp_statistic'][1]) }} | 40 |41 | {{ len(clients[c]['udp_maps']) }} 42 | | 43 |{{ stringify_bytes_val(clients[c]['udp_statistic'][0] + clients[c]['udp_statistic'][1]) }} | 44 |45 | {% if clients[c]['is_alive'] %} 46 | 47 | {% else %} 48 | 49 | {% endif %} 50 | 51 | | 52 |
| 创建时间 | 16 |客户端端口 | 17 |公网地址 | 18 |服务端端口 | 19 |上传流量 | 20 |下载流量 | 21 |流量统计 | 22 |相关操作 | 23 |
|---|---|---|---|---|---|---|---|
| {{ moment(clients[idx[1]]['tcp_maps'][idx[0]]['create_time']).format('YYYY-MM-DD HH:mm:ss') }} | 30 |{{ clients[idx[1]]['client_name'] }} ({{ clients[idx[1]]['tcp_maps'][idx[0]]['client_port'] }}) | 31 |{{ clients[idx[1]]['tcp_e_addr'][0] + ':' + clients[idx[1]]['tcp_e_addr'][1] }} | 32 |TCP: {{ idx[0] }} | 33 |{{ stringify_bytes_val(clients[idx[1]]['tcp_maps'][idx[0]]['statistic'][0]) }} | 34 |{{ stringify_bytes_val(clients[idx[1]]['tcp_maps'][idx[0]]['statistic'][1]) }} | 35 |{{ stringify_bytes_val(clients[idx[1]]['tcp_maps'][idx[0]]['statistic'][0] + clients[idx[1]]['tcp_maps'][idx[0]]['statistic'][1]) }} | 36 |37 | 38 | 39 | | 40 |
| {{ moment(clients[idx[1]]['udp_maps'][idx[0]]['create_time']).format('YYYY-MM-DD HH:mm:ss') }} | 44 |{{ clients[idx[1]]['client_name'] }} ({{ clients[idx[1]]['udp_maps'][idx[0]]['client_port'] }}) | 45 |{{ clients[idx[1]]['udp_e_addr'][0] + ':' + clients[idx[1]]['udp_e_addr'][1] }} | 46 |UDP: {{ idx[0] }} | 47 |{{ stringify_bytes_val(clients[idx[1]]['udp_maps'][idx[0]]['statistic'][0]) }} | 48 |{{ stringify_bytes_val(clients[idx[1]]['udp_maps'][idx[0]]['statistic'][1]) }} | 49 |{{ stringify_bytes_val(clients[idx[1]]['udp_maps'][idx[0]]['statistic'][0] + clients[idx[1]]['udp_maps'][idx[0]]['statistic'][1]) }} | 50 |51 | 52 | 53 | | 54 |
', //返回顶部按钮
13 | controlattrs:{offsetx:30,offsety:80},//返回按钮固定位置
14 | anchorkeyword:"#top",
15 | state:{
16 | isvisible:false,
17 | shouldvisible:false
18 | },scrollup:function(){
19 | if(!this.cssfixedsupport){
20 | this.$control.css({opacity:0});
21 | }
22 | var dest=isNaN(this.setting.scrollto)?this.setting.scrollto:parseInt(this.setting.scrollto);
23 | if(typeof dest=="string"&&jQuery("#"+dest).length==1){
24 | dest=jQuery("#"+dest).offset().top;
25 | }else{
26 | dest=0;
27 | }
28 | this.$body.animate({scrollTop:dest},this.setting.scrollduration);
29 | },keepfixed:function(){
30 | var $window=jQuery(window);
31 | var controlx=$window.scrollLeft()+$window.width()-this.$control.width()-this.controlattrs.offsetx;
32 | var controly=$window.scrollTop()+$window.height()-this.$control.height()-this.controlattrs.offsety;
33 | this.$control.css({left:controlx+"px",top:controly+"px"});
34 | },togglecontrol:function(){
35 | var scrolltop=jQuery(window).scrollTop();
36 | if(!this.cssfixedsupport){
37 | this.keepfixed();
38 | }
39 | this.state.shouldvisible=(scrolltop>=this.setting.startline)?true:false;
40 | if(this.state.shouldvisible&&!this.state.isvisible){
41 | this.$control.stop().animate({opacity:1},this.setting.fadeduration[0]);
42 | this.state.isvisible=true;
43 | }else{
44 | if(this.state.shouldvisible==false&&this.state.isvisible){
45 | this.$control.stop().animate({opacity:0},this.setting.fadeduration[1]);
46 | this.state.isvisible=false;
47 | }
48 | }
49 | },init:function(){
50 | jQuery(document).ready(function($){
51 | var mainobj=scroll_to_top;
52 | var iebrws=document.all;
53 | mainobj.cssfixedsupport=!iebrws||iebrws&&document.compatMode=="CSS1Compat"&&window.XMLHttpRequest;
54 | mainobj.$body=(window.opera)?(document.compatMode=="CSS1Compat"?$("html"):$("body")):$("html,body");
55 | mainobj.$control=$('