本帖最后由 天域至尊 于 2020-3-1 23:42 编辑
前一段时间在家上班,家里有一个老的办公软件希望能够映射到公网,奈何端口什么的都是写死的,只能在本地端口进行链接,就写了一个流量转发的小脚本,来实现。
我所实现的流量转发就是把发往本地ip某个端口的数据转发到别的地方。当然,Linux和windows都有现成的东西,所以如果大家需要,建议使用系统自带的功能,好用且稳定。
举例Windows的转发命令(需要管理员权限)
[Bash shell] 纯文本查看 复制代码 netsh interface portproxy add v4tov4 listenaddress="本地ip" listenport=本地端口 connectaddress="服务端IP" connectport=服务端端口
Linux和其他系统的命令,建议大家自己找找
下面是我自己编写的python脚本源码
python脚本(无需管理员权限)
[Python] 纯文本查看 复制代码 import socket,time,threading
#这里填写本地监听的ip和端口
ip='127.0.0.1'
port=0
#这列填写公网ip和端口
send_ip=''
send_port=0
#以下部分无需修改
#这是用来存放转发到公网数据的队列
outList=[]
#这是用来存放转发到内网数据的队列
inList=[]
#这是队列的锁,防止竞争
outLock=False
inLock=False
#这是用来标记是否发送的断开连接信息
runStation=True
def in_get(sock):
'''
该函数负责监听本地的端口,传入的sock,收到数据后,将其增加到转发到公网的队列中
'''
global outLock,outList,inLock,inList,runStation
while runStation:
try:
try:
data=sock.recv(8192)
time.sleep(0.1)
except Exception as ie:
print(+str(ie))
time.sleep(0.1)
#如果内网发送的空数据,即代表需要断开连接(管家婆特性)
if data==b'':
runStation=False
#这里循环等待锁关闭
while (outLock==True):
time.sleep(0.01)
else:
#打开锁,防止竞争,将数据增加到队列后,关闭锁
outLock=True
outList.append(data)
outLock=False
except Exception as err:
print('inget'+str(err))
print(type(sock))
def in_out(sock):
'''
该函数负责循环检查对内发送的队列是是否有数据
发现存在数据后,将数据转发到内部,并且清空对内转发的队列
'''
global outLock,outList,inLock,inList
while runStation:
try:
if len(inList)!=0:
#这里是判断对内转发的锁是否开启
while (inLock==True):
time.sleep(0.01)
else:
#关闭锁,发送数据,清空队列,打开锁
inLock=True
for i in inList:
sock.send(i)
inList.clear()
inLock=False
else:
time.sleep(0.001)
except Exception as err:
print(err)
def out_get(sock):
'''
该函数负责监听外网数据,收到数据后,将其增加到对内转发队列
'''
global outLock,outList,inLock,inList
while runStation:
try:
data=sock.recv(8192)
time.sleep(0.1)
while (inLock==True):
time.sleep(0.01)
else:
inLock=True
inList.append(data)
inLock=False
except Exception as err:
print('outget'+str(err))
def out_out(sock):
'''
该函数负责对外转发,发现对外转发队列有数据后,判断锁状态,发送数据后清空队列,关闭锁。
'''
global outLock,outList,inLock,inList
while runStation:
try:
if len(outList)!=0:
while (outLock==True):
time.sleep(0.01)
else:
outLock=True
for i in outList:
if i!=b'':
sock.send(i)
outList.clear()
outLock=False
else:
time.sleep(0.001)
except Exception as err:
print(err)
def tcplink(sock, addr,ip,port):
'''
内部建立起连接后,该函数负责统一处理,其中传入的ip和port指的是外网的。
'''
global runStation
print('Accept new connection from %s:%s...' % addr)
#与外网建立连接
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立连接:
s1.connect((ip, port))
#启动线程,开始监听内网
inGet = threading.Thread(target=in_get, args=(sock,))
inGet.start()
#启动多个内网发送线程,提高速度
inOut = threading.Thread(target=in_out, args=(sock,))
inOut.start()
inOut2 = threading.Thread(target=in_out, args=(sock,))
inOut2.start()
inOut3 = threading.Thread(target=in_out, args=(sock,))
inOut3.start()
#启动一个外网监听进程,开始监听
outGet = threading.Thread(target=out_get, args=(s1,))
outGet.start()
#启动多个外网发送线程,提高速度
outOut = threading.Thread(target=out_out, args=(s1,))
outOut.start()
outOut1 = threading.Thread(target=out_out, args=(s1,))
outOut1.start()
outOut2 = threading.Thread(target=out_out, args=(s1,))
outOut2.start()
#在发现连接断开后,即断开内网和外网的套接字
while runStation:
time.sleep(0.5)
else:
try:
sock.close()
s1.close()
except Exception:
pass
print('Connection from %s:%s closed.' % addr)
#新建套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#绑定本地端口
s.bind((ip, port))
#设置最大连接数
s.listen(5)
while True:
# 接受一个新连接:
sock1, addr = s.accept()
#初始化数据
runStation=True
outList=[]
inList=[]
outLock=False
inLock=False
runStation=True
# 创建新线程来处理TCP连接:
t = threading.Thread(target=tcplink, args=(sock1, addr,send_ip,send_port))
t.start()
这样运行python脚本,他就会监听某一个本地端口,将发送到本地端口的tcp流量转发出去,并且把回复的数据转发到本地端口。使运行的程序以为链接的是本地的服务。
当然,该脚本的用处并不仅仅限于此处,相信大家懂得。
原创作品,转载请声明出处。
另:该源码也发布到本人的CSDN博客,请大家不要误会抄袭。
|