ADSL

安装Python3.6
yum install python36
yum install python36-pip
yum install mysql-devel
yum -y install python36-devel
安装依赖
安装虚拟环境
pip install virtualenvwrapper
设置环境变量
mkdir /opt/envs
export WORKON_HOME="/opt/envs"
source /usr/bin/virtualenvwrapper.sh
创建虚拟目录
mkvirtualenv -p python3 adsl
安装依赖包
backcall==0.1.0
certifi==2018.11.29
chardet==3.0.4
coreapi==2.3.3
coreschema==0.0.4
decorator==4.4.0
defusedxml==0.5.0
diff-match-patch==20181111
Django==1.11.17
django-cors-headers==2.4.0
django-crispy-forms==1.7.2
django-filter==2.1.0
django-formtools==2.1
django-guardian==1.4.9
django-import-export==1.2.0
django-pure-pagination==0.3.0
django-redis==4.10.0
django-reversion==3.0.3
django-simple-captcha==0.4.6
djangorestframework==3.9.1
djangorestframework-jwt==1.11.0
drf-extensions==0.4.0
et-xmlfile==1.0.1
future==0.17.1
httplib2==0.12.0
idna==2.8
ipython==7.5.0
ipython-genutils==0.2.0
itypes==1.1.0
jdcal==1.4
jedi==0.13.3
Jinja2==2.10
Markdown==3.0.1
MarkupSafe==1.1.0
mysqlclient==1.3.10
oauthlib==3.0.1
odfpy==1.4.0
openpyxl==2.5.14
parso==0.4.0
pexpect==4.7.0
pickleshare==0.7.5
Pillow==5.4.1
prompt-toolkit==2.0.9
ptyprocess==0.6.0
pycryptodome==3.7.3
Pygments==2.4.0
PyJWT==1.7.1
python-dateutil==2.8.0
python3-openid==3.1.0
pytz==2018.9
PyYAML==3.13
qrcode==6.0
raven==6.10.0
redis==3.1.0
requests==2.21.0
requests-oauthlib==1.2.0
six==1.12.0
social-auth-app-django==3.1.0
social-auth-core==3.0.0
tablib==0.12.1
traitlets==4.3.2
unicodecsv==0.14.1
uritemplate==3.0.0
urllib3==1.24.1
wcwidth==0.1.7
xlrd==1.2.0
XlsxWriter==1.1.2
xlwt==1.3.0

引入Django-suit

https://github.com/darklow/django-suit

https://github.com/darklow/django-suit.git

表结构设计

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models
from datetime import datetime
from django.contrib.auth import get_user_model

# Create your models here.

User = get_user_model()



LOCATION = (
('NanJing', '南京'),
)



DDNS_STATUS = (
('success', '成功'),
('failer', '失败')
)
class DetailInfo(models.Model):
"""
公网IP详情
"""
current_ip = models.GenericIPAddressField(verbose_name=u'公网IP')
last_ip = models.ForeignKey('self', verbose_name='上一次IP', null=True, blank=True, related_name='sub_ip')
location = models.CharField(max_length=100, verbose_name=u"地点", choices=LOCATION, default='NanJing')
add_time = models.DateTimeField(default=datetime.now, verbose_name=u'添加时间')
user = models.ForeignKey(User, verbose_name="用户", null=True, blank=True)
status = models.CharField(max_length=100, verbose_name='DDNS状态', choices=DDNS_STATUS, default='success')
log = models.FileField(max_length=100,null=True, blank=True,upload_to="logs/ddns/%Y/%m/%d",verbose_name=u"ddns日志")

class Meta:
verbose_name = "公网IP"
verbose_name_plural = verbose_name

def __str__(self):
return self.current_ip
API接口配置
from rest_framework import serializers
from .models import DetailInfo


class DetailInfoSerializer1(serializers.ModelSerializer):
# 覆盖当前model user字段
user = serializers.HiddenField(default=serializers.CurrentUserDefault())

# API 返回数据,表单不需要提交
add_time = serializers.DateTimeField(read_only=True, format="%Y-%m-%d %H:%M:%S")
class Meta:
model = DetailInfo
fields = "__all__"


class DetailInfoSerializer(serializers.ModelSerializer):
last_ip = DetailInfoSerializer1(read_only=True)
# 覆盖当前model user字段
user = serializers.HiddenField(default=serializers.CurrentUserDefault())

# API 返回数据,表单不需要提交
add_time = serializers.DateTimeField(read_only=True, format="%Y-%m-%d %H:%M:%S")

class Meta:
model = DetailInfo
fields = "__all__"

API地址

  • http://adsl.laohulab.com:8090/
  • http://adsl.laohulab.com:8090/adsl/index/
导入历史数据
# -*- coding: utf-8 -*-
__author__ = 'jianhu.yong'
__date__ = '19-5-10 下午1:29'

import sys
import os
from dateutil.parser import parse

pwd = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(pwd)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "adsl.settings")

import django
django.setup()

from detail.models import DetailInfo

f = open(os.path.join(pwd, 'db_tools/data/adsl.txt'), 'rb')
wan_ips = f.readlines()
for index, value in enumerate(wan_ips):
current_ip = str(value, encoding='utf-8').strip().split()[-1]
add_time = parse(" ".join(str(value, encoding='utf-8').strip().split()[0:-1]))
ins, status = DetailInfo.objects.get_or_create(current_ip=current_ip, add_time=add_time)

ins.current_ip = current_ip
ins.add_time = add_time

if index != 0:
last_ip = str(wan_ips[index-1], encoding='utf-8').split()[-1]
add_time = parse(" ".join(str(wan_ips[index-1], encoding='utf-8').split()[0:-1]))
ins.last_ip, status = DetailInfo.objects.get_or_create(current_ip=last_ip, add_time=add_time)
ins.save()
ADSL更新脚本
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2019/3/10 17:11
# @Author : Jianhu Yong
# @File : update_ddns.py


'''
good: 更新成功,域名的IP地址已经更新,同时会返回本次更新成功的IP,用空格隔开,如:good 1.2.3.4
nochg: 更新成功,但没有改变IP。一般这种情况为本次提交的IP跟上一次的一样
notfqdn: 未有激活花生壳的域名
nohost: 域名不存在或未激活花生壳
abuse: 请求失败,频繁请求或验证失败时会出现
!donator: 表示此功能需要付费用户才能使用,如https
911: 系统错误
doc: http://service.oray.com/question/3820.html
'''

import requests
import os
import re
import base64
import smtplib
from email.mime.text import MIMEText
from email.header import Header
from email.mime.multipart import MIMEMultipart
import json
import logging
from logging import FileHandler
from logging import Formatter
from datetime import datetime
try:
import configparser
except ImportError:
import ConfigParser as configparser


class Adsl(object):
def __init__(self, domain, username, password, check_url, update_url, token):
'''
初始化参数
:param domain:
:param username:
:param password:
:param check_url:
:param update_url:
'''
self.domain = domain
self.username = username
self.password = password
self.check_url = check_url
self.update_url = update_url
self.token = token

def get_current_ip(self):
'''
获取当前公网IP地址
:return:
'''
res = requests.get(url=self.check_url)
if res.status_code == 200:
myip = re.search('\d+\.\d+\.\d+\.\d+', res.text).group()
return myip

def update(self, current_ip, last_ip):
'''
更新公网IP地址至花生壳服务器
:param myip:
:return:
'''
code = "{}:{}".format(self.username, self.password)
code = code.encode()
auth_code = base64.b64encode(code)
header = {
'Host': 'ddns.oray.com',
'Authorization': 'Basic {}'.format(auth_code.decode()),
'User-Agent': 'Oray'
}

params = {
'hostname': self.domain,
'myip': current_ip
}

res = requests.get(url=self.update_url, params=params, headers=header)

if res.status_code == 200:
if 'good' in res.text:
status = 'good'
elif 'nochg' in res.text:
status = 'nochg'
else:
status = 'failer'
self._create_log(res.text)
self._create_recode(current_ip)
self._sent_mail(current_ip, last_ip, status)

def _create_recode(self, current_ip):
api = 'http://127.0.0.1:8000/ip/'
data = {
"current_ip": current_ip,
}

# 构造请求头
# headers = {'Content-Type': 'application/json'}
headers = {}
headers['Authorization'] = 'JWT {}'.format(self.token)
files = {
"log": open(os.path.join(base_dir, 'ddns.log'))
}


res = requests.post(api, data=data, headers=headers, files=files)
pass


def _create_log(self, res):
LOG_FORMAT = ("%(levelname)s | %(asctime)s | %(message)s")
LOG_LEVEL = logging.INFO

# messaging logger
INFO_LOG_FILE = os.path.join(base_dir, 'ddns.log')
info_log_logger = logging.getLogger(INFO_LOG_FILE)
info_log_logger.setLevel(LOG_LEVEL)
info_log_logger_file_handler = FileHandler(INFO_LOG_FILE, mode='w')
info_log_logger_file_handler.setLevel(LOG_LEVEL)
info_log_logger_file_handler.setFormatter(Formatter(LOG_FORMAT))
info_log_logger.addHandler(info_log_logger_file_handler)

info_log_logger.info(res)

def _sent_mail(self, current_ip, last_ip, status):
auth_code = "glnaxjbqiicbbjgj"
mail_host = 'smtp.qq.com'
mail_user = '120731842@qq.com'
mail_pass = auth_code
mail_sender = mail_user
#mail_receivers = ['jianhu.yong@genewiz.com.cn']
mail_receivers = ['120731842@qq.com', 'jianhu.yong@genewiz.com.cn']

subject = '【LAOHULAB】公网IP变更通知'
message = MIMEMultipart()

mail_msg = '''
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<table width="420" cellpadding="0" cellspacing="0" border="0" align="left" style="border:1px solid #505050; ">
<tr>
<td width="420">
<table width="420" cellpadding="0" cellspacing="0" border="0" align="left" bgcolor="#0072c6">
<tr>
<td width="420" bgcolor="#0072c6">

<table width="420" cellpadding="0" cellspacing="0" border="0" align="center" bgcolor="#0072c6">
<tr>
<td width="30" valign="middle" style="color:#0072c6; font-family:'Segoe UI',Arial,sans-serif; font-size:12px; font-weight:bold; padding:25px 0 15px;">&ndash;</td>
<td width="360" valign="middle" style="color:#ffffff; font-family:'Segoe UI',Arial,sans-serif; font-size:12px; font-weight:bold; padding:25px 0 15px;">
<img height="35" src="https://www.genewiz.com.cn//assets/img/gwz/GWLOGO_TOPLEFT.PNG" alt="GENEWIZ" border="0">
</td>
<td width="30" valign="middle" style="color:#0072c6; font-family:'Segoe UI',Arial,sans-serif; font-size:12px; font-weight:bold; padding:25px 0 15px;">&ndash;</td>
</tr>
<tr>
<td width="30" valign="middle" style="color:#0072c6; font-family:'Segoe UI',Arial,sans-serif; font-size:12px; font-weight:bold; padding:5px 0 25px;">&ndash;</td>
<td width="360" valign="middle" style="color:#ffffff; font-family:'Segoe UI',Arial,sans-serif; font-size:12px; font-weight:bold; padding:5px 0 25px;">
<h1 style="color:#ffffff; font-family:'Segoe UI Light','Segoe UI',Arial,sans-serif; font-size:20px; font-weight:100; line-height:40px; margin:0">
公网IP地址变更通知!
</h1>
</td>
<td width="30" valign="middle" style="color:#0072c6; font-family:'Segoe UI',Arial,sans-serif; font-size:12px; font-weight:bold; padding:5px 0 25px;">&ndash;</td>
</tr>
</table>

</td>
</tr>
</table>

<table width="420" cellpadding="0" cellspacing="0" border="0" align="center">
<tr>
<td width="30" valign="middle" bgcolor="#e6e6e7" style="color:#e6e6e7; border-bottom:1px solid #d8d8d8;font-family:'Segoe UI',Arial,sans-serif; font-size:12px; padding:15px 0;">&ndash;</td>
<td width="360" valign="middle" bgcolor="#e6e6e7" style="color:#505050;border-bottom:1px solid #d8d8d8; font-family:'Segoe UI',Arial,sans-serif; font-size:12px; padding:15px 0 20px;">
<h2 style="font-family:'Segoe UI Light','Segoe UI',Arial,sans-serif; font-size:20px; font-weight:100; line-height:30px; margin:0; padding:0;">
ADSL
</h2>
<p>
<strong>状态:</strong> {0}
</p>
<p>
<strong>域名:</strong> {1}
</p>
<p>
<strong>当前IP:</strong> {2}
</p>
<p>
<strong>上一次IP:</strong> {3}
</p>
<p>
<strong>时间:</strong> {4}
</p>
</td>
<td width="30" valign="middle" bgcolor="#e6e6e7" style="color:#e6e6e7; border-bottom:1px solid #d8d8d8;font-family:'Segoe UI',Arial,sans-serif; font-size:12px; padding:15px 0;">&ndash;</td>
</tr>
</table>

<table width="420" cellpadding="0" cellspacing="0" border="0" align="left">
<tr>
<td width="30" valign="middle" style="color:#ffffff; font-family:'Segoe UI',Arial,sans-serif; font-size:12px; padding:10px 0;">&ndash;</td>
<td width="360" valign="middle" style="color:#505050; font-family:'Segoe UI',Arial,sans-serif; font-size:12px; padding:20px 0;">
<table width="360" cellpadding="0" cellspacing="0" border="0">
<tr>
<td width="360" valign="top" style="color:#505050; font-family:'Segoe UI Light','Segoe UI',Arial,sans-serif; font-size:12px; font-weight:100;">
<p style="color:red">
本邮件是由系统自动发出的,请不要回复本邮件!
</p>
<p>LAOHULAB | 南京</p>
<p>Copyright© {5} LAOHULAB Power By Jianhu Yong</p>
</td>
</tr>
</table>
</td>
<td width="30" valign="middle" style="color:#ffffff; font-family:'Segoe UI',Arial,sans-serif; font-size:12px; padding:10px 0;">&ndash;</td>
</tr>
</table>

</td>
</tr>
</table>
'''.format(status, self.domain, current_ip, last_ip, datetime.now().strftime("%Y-%m-%d %H:%I:%S"), datetime.now().year)

message.attach(MIMEText(mail_msg, 'html', 'utf-8'))

att1 = MIMEText(open(os.path.join(base_dir, 'ddns.log')).read(), 'base64', 'utf-8')
att1["Content-Type"] = 'application/octet-stream'
att1["Content-Disposition"] = 'attachment; filename="ddns.log"'
message.attach(att1)
# message = MIMEText(mail_msg, 'html', 'utf-8')
message['From'] = Header(mail_sender)
message['To'] = Header(','.join(mail_receivers))
message['Subject'] = Header(subject, 'utf-8')
try:
smtpObj = smtplib.SMTP_SSL()
smtpObj.connect(mail_host, 465)
smtpObj.login(mail_user,mail_pass)
smtpObj.sendmail(mail_sender, mail_receivers, message.as_string())
smtpObj.close()
return True
except Exception as e:
print(e)
return False


if __name__ == "__main__":

# 获取项目根目录
base_dir = os.path.dirname(os.path.abspath(__file__))

# 获取配置文件信息
config = configparser.ConfigParser()
with open(os.path.join(base_dir, 'ddns.ini')) as fp:
config.read_file(fp)

domain = config.get('ddns', 'domain')
username = config.get('ddns', 'username')
password = config.get('ddns', 'password')
check_url = config.get('ddns', 'check_url')
update_url = config.get('ddns', 'update_url')
list_url = config.get('ddns', 'list_url')
login_url = config.get('ddns', 'login_url')
adsl_api = config.get('ddns', 'adsl_api')
api_username = config.get('api-auth', 'username')
api_password = config.get('api-auth', 'password')

# 登陆验证
login_data = {
'username': api_username,
'password': api_password
}

# 构造请求头
headers = {'Content-Type': 'application/json'}

# 获取 JWT token
res = requests.post(login_url, data=json.dumps(login_data), headers=headers)
jwt_token = json.loads(res.text).get('token')
headers['Authorization'] = 'JWT {}'.format(jwt_token)

adsl_ins = Adsl(
domain=domain,
username=username,
password=password,
check_url=check_url,
update_url=update_url,
token=jwt_token
)

current_ip = adsl_ins.get_current_ip()

res = requests.get(adsl_api, headers=headers)
res = json.loads(res.text)
last_ip = res.get('results')[0].get('current_ip')

if current_ip != last_ip:
adsl_ins.update(current_ip, last_ip)
配置文件
[ddns]
domain = laohulab.com
username = xxxx
password = xxxx
check_url = http://ddns.oray.com/checkip
update_url = http://ddns.oray.com/ph/update/
list_url = http://127.0.0.1:8090/adsl/index/
login_url = http://127.0.0.1:8090/login/
adsl_api = http://127.0.0.1:8090/ip/

[api-auth]
username = xxxx
password = xxxx
0%