天域至尊 发表于 2020-3-1 23:39

【闹腾】python实现本地流量转发

本帖最后由 天域至尊 于 2020-3-1 23:42 编辑

前一段时间在家上班,家里有一个老的办公软件希望能够映射到公网,奈何端口什么的都是写死的,只能在本地端口进行链接,就写了一个流量转发的小脚本,来实现。

我所实现的流量转发就是把发往本地ip某个端口的数据转发到别的地方。当然,Linux和windows都有现成的东西,所以如果大家需要,建议使用系统自带的功能,好用且稳定。
举例Windows的转发命令(需要管理员权限)
netsh interface portproxy add v4tov4 listenaddress="本地ip"listenport=本地端口 connectaddress="服务端IP" connectport=服务端端口
Linux和其他系统的命令,建议大家自己找找

下面是我自己编写的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

defin_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)

defout_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博客,请大家不要误会抄袭。

jmc06 发表于 2022-2-4 19:07

楼主你简直是个天才,你写的红字也是意味深远。。。我已经get到了你的意思,哈哈~~

天域至尊 发表于 2020-3-4 12:13

py看考场 发表于 2020-3-3 13:48
没有学习过网络编程,这里的流量转发是代{过}{滤}理的意思吗

差不多吧,把发往本地的流量转发到别的地方

雷_影 发表于 2020-3-1 23:49

不错.....

yinsugege 发表于 2020-3-1 23:58

有技术真好            

过往温柔的你 发表于 2020-3-2 00:13

撒功能,百度yun?

xiaoxi2011 发表于 2020-3-2 00:28

学习了,谢谢分享

闰土168 发表于 2020-3-2 07:46

挺方便啊

cangyue0609 发表于 2020-3-2 12:04

一般负载应用时用的比较多,可以转发到不固定ip地址

jixiangyh 发表于 2020-3-2 19:40

思路不错,谢谢分享~~

zucker 发表于 2020-3-2 20:03

当然,该脚本的用处并不仅仅限于此处,相信大家懂得。

我不懂

mokson 发表于 2020-3-3 11:13

页: [1] 2 3
查看完整版本: 【闹腾】python实现本地流量转发