1. 程式人生 > >python搭建ssserver限制端口連接數

python搭建ssserver限制端口連接數

時間 是把 ipv 間隔 bin logging lis only rst

新建文件,編寫下面內容,保存為socket.py文件。放到ssserver.exe所在文件夾

#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright 2015 Falseen
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# 功能:限制客戶端數量(基於ip判斷)
#
# 使用說明:1.將此文件放在ss根目錄中即可生效,不用做其他設置(需要重新運行ss)。
# 2.修改53、54行的 clean_time 和 ip_numbers 為你想要的數值。
# 3.如果你的服務器有ipv6,並且你想讓ip4和ip6分開限制,則可以設置 only_port 為 False 。
#
#
# 原理:默認情況下,ss在運行的時候會引用系統中的socket文件,但是把這個socket文件放到ss目錄之後,ss就會引用這個我們自定義的socket文件。
# 然後在這個文件中再引用真正的socket包,並在原socket的基礎上加以修改,最終ss調用的就是經過我們修改的socket文件了。
#
# 所以理論上任何引用了socket包的python程序都可以用這個文件來達到限制連接ip數量的目的。
#

from __future__ import absolute_import, division, print_function, \
with_statement, nested_scopes

import sys

del sys.modules[‘socket‘]

import sys
import time
import logging
import types

path = sys.path[0]
sys.path.pop(0)

import socket # 導入真正的socket包

sys.path.insert(0, path)

clean_time = 60 # 設置清理ip的時間間隔,在此時間內無連接的ip會被清理
ip_numbers = 1 # 設置每個端口的允許通過的ip數量,即設置客戶端ip數量
only_port = True # 設置是否只根據端口判斷。如果為 True ,則只根據端口判斷。如果為 False ,則會嚴格的根據 ip+端口進行判斷。

# 動態path類方法
def re_class_method(_class, method_name, re_method):
method = getattr(_class, method_name)
info = sys.version_info
if info[0] >= 3:
setattr(_class, method_name,
types.MethodType(lambda *args, **kwds: re_method(method, *args, **kwds), _class))
else:
setattr(_class, method_name,
types.MethodType(lambda *args, **kwds: re_method(method, *args, **kwds), None, _class))

# 動態path實例方法
def re_self_method(self, method_name, re_method):
method = getattr(self, method_name)
setattr(self, method_name, types.MethodType(lambda *args, **kwds: re_method(method, *args, **kwds), self, self))

# 處理Tcp連接
def re_accept(old_method, self, *args, **kwds):

while True:

return_value = old_method(self, *args, **kwds)
self_socket = return_value[0]
if only_port:
server_ip_port = ‘%s‘ % self.getsockname()[1]
else:
server_ip_port = ‘%s_%s‘ % (self.getsockname()[0], self.getsockname()[1])

client_ip = return_value[1][0]

client_ip_list = [x[0].split(‘#‘)[0] for x in self._list_client_ip[server_ip_port]]
if len(self._list_client_ip[server_ip_port]) == 0:
logging.debug("[re_socket] first add %s" % client_ip)
self._list_client_ip[server_ip_port].append([‘%s#%s‘ % (client_ip, time.time()), self_socket])
return return_value

if client_ip in client_ip_list:
logging.debug("[re_socket] update socket in %s" % client_ip)
_ip_index = client_ip_list.index(client_ip)
self._list_client_ip[server_ip_port][_ip_index][0] = ‘%s#%s‘ % (client_ip, time.time())
self._list_client_ip[server_ip_port][_ip_index].append(self_socket)
return return_value

else:
if len(self._list_client_ip[server_ip_port]) < ip_numbers:
logging.debug("[re_socket] add %s" % client_ip)
self._list_client_ip[server_ip_port].append([‘%s#%s‘ % (client_ip, time.time()), self_socket])
return return_value

for x in [x for x in self._list_client_ip[server_ip_port]]:
is_closed = True
if time.time() - float(x[0].split(‘#‘)[1]) > clean_time:

for y in x[1:]:
try:
y.getpeername() # 判斷連接是否關閉
is_closed = False
break
except: # 如果拋出異常,則說明連接已經關閉,這時可以關閉套接字
logging.debug("[re_socket] close and remove the time out socket 1/%s" % (len(x[1:])))
x.remove(y)

if not is_closed:
logging.debug(‘[re_socket] the %s still exists and update last_time‘ % str(x[1].getpeername()[0]))
_ip_index = client_ip_list.index(x[0].split(‘#‘)[0])
self._list_client_ip[server_ip_port][_ip_index][0] = ‘%s#%s‘ % (x[0].split(‘#‘)[0], time.time())

else:
logging.info("[re_socket] remove time out ip and add new ip %s" % client_ip )
self._list_client_ip[server_ip_port].remove(x)
self._list_client_ip[server_ip_port].append([‘%s#%s‘ % (client_ip, time.time()), self_socket])
return return_value

if int(time.time()) % 5 == 0:
logging.debug("[re_socket] the port %s client more then the %s" % (server_ip_port, ip_numbers))

# 處理Udp連接
def re_recvfrom(old_method, self, *args, **kwds):

while True:
return_value = old_method(*args, **kwds)
self_socket = ‘‘
if only_port:
server_ip_port = ‘%s‘ % self.getsockname()[1]
else:
server_ip_port = ‘%s_%s‘ % (self.getsockname()[0], self.getsockname()[1])
client_ip = return_value[1][0]
client_ip_list = [x[0].split(‘#‘)[0] for x in self._list_client_ip[server_ip_port]]

if len(self._list_client_ip[server_ip_port]) == 0:
logging.debug("[re_socket] first add %s" % client_ip)
self._list_client_ip[server_ip_port].append([‘%s#%s‘ % (client_ip, time.time()), self_socket])
return return_value

if client_ip in client_ip_list:
logging.debug("[re_socket] update socket in %s" % client_ip)
_ip_index = client_ip_list.index(client_ip)
self._list_client_ip[server_ip_port][_ip_index][0] = ‘%s#%s‘ % (client_ip, time.time())
return return_value
else:
if len(self._list_client_ip[server_ip_port]) < ip_numbers:
logging.debug("[re_socket] add %s" % client_ip)
self._list_client_ip[server_ip_port].append([‘%s#%s‘ % (client_ip, time.time()), self_socket])
return return_value

for x in [x for x in self._list_client_ip[server_ip_port]]:
is_closed = True
if time.time() - float(x[0].split(‘#‘)[1]) > clean_time:

for y in x[1:]:
try:
y.getpeername() # 判斷連接是否關閉
is_closed = False
break
except: # 如果拋出異常,則說明連接已經關閉,這時可以關閉套接字
logging.debug("[re_socket] close and remove the time out socket 1/%s" % (len(x[1:])))
x.remove(y)

if not is_closed:
logging.debug(‘[re_socket] the %s still exists and update last_time‘ % str(x[1].getpeername()[0]))
_ip_index = client_ip_list.index(x[0].split(‘#‘)[0])
self._list_client_ip[server_ip_port][_ip_index][0] = ‘%s#%s‘ % (x[0].split(‘#‘)[0], time.time())

else:
logging.info("[re_socket] remove time out ip and add new ip %s" % client_ip )
self._list_client_ip[server_ip_port].remove(x)
self._list_client_ip[server_ip_port].append([‘%s#%s‘ % (client_ip, time.time()), self_socket])
return return_value

if int(time.time()) % 5 == 0:
logging.debug("[re_socket] the port %s client more then the %s" % (server_ip_port, ip_numbers))
new_tuple = [b‘‘, return_value[1]]
return_value = tuple(new_tuple)
return return_value

def re_bind(old_method, self, *args, **kwds):
if only_port:
port = ‘%s‘ % args[0][1]
else:
port = ‘%s_%s‘ % (args[0][0], args[0][1])
self._list_client_ip[port] = []
re_self_method(self, ‘recvfrom‘, re_recvfrom)
old_method(self, *args, **kwds)

setattr(socket.socket, ‘_list_client_ip‘, {})
re_class_method(socket.socket, ‘bind‘, re_bind)
re_class_method(socket.socket, ‘accept‘, re_accept)

python搭建ssserver限制端口連接數