Synology群晖NAS外部IP更新通知

  在我的群晖DS211j上使用DDNS服务时经常出现长时间无法正常更新IP的现象1,这对于需要经常从外部访问的我来说是个很大的问题,于是写了段Python2脚本在NAS上监控外部IP地址的变化,如果发现改变将发送新的IP地址到指定的邮箱。3

1. 脚本

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#! 强制默认编码为utf-8
import sys
reload(sys)
sys.setdefaultencoding('utf8')

# 配置
# SMTP服务器 用户 密码
smtp_server = 'SMTP SERVER'
smtp_port   = 25
smtp_usr    = 'SMTP USERNAME'
smtp_pwd    = 'SMTP PASSWORD'

# 发送接受邮箱地址
#! 发送邮箱需是smtp_usr有权操作的邮箱
from_addr   = 'FROM EMAIL ADDRESS'
to_addr     = 'TO EMAIL ADDRESS'

# 获取外网IP的网址 可以是
# http://ifconfig.me/ip
# http://ip.3322.net
# http://members.3322.org/dyndns/getip
ip_check_server = 'http://ip.3322.net'

# 记录文件路径
log_file    = '/tmp/ipcheck.log'

# 邮件主题 
# 内容为新的IP
mail_subject = 'IP check message'

import os, urllib2, smtplib
from datetime import datetime

class CheckIP(object):
    def __init__(self):
        self.logs = []
        self.openLog()

    def __del__(self):
        self.saveLog()

    def openLog(self):
        if not os.path.isfile(log_file):
            open(log_file, 'w').close()
        with open(log_file, 'r') as f:
            self.logs = f.readlines()
        if not self.logs or len(self.logs) < 2:
            self.logs = ['\n', '----\n']
        # 确保第二行永远是分隔符
        self.logs[1] = '----\n'

    def saveLog(self):
        with open(log_file, 'w') as f:
            f.writelines(self.logs)

    def getOldIP(self):
        return self.logs[0].strip()

    def setNewIP(self, new_ip):
        if new_ip:
            self.logs[0] = '{}\n'.format(new_ip)

    def sendMail(self, msg):
        if not msg:
            return
        data = {'from_addr' : from_addr,
                'to_addr'   : to_addr,
                'subject'   : mail_subject,
                'msg'       : msg }
        msg = 'From: {from_addr}\r\nTo: {to_addr}\r\nSubject: {subject}\r\n\r\n{msg}'.format(**data)
        try:
            smtp = smtplib.SMTP()
            # smtp.set_debuglevel(1)
            smtp.connect(smtp_server, smtp_port)
            smtp.login(smtp_usr, smtp_pwd)
            smtp.sendmail(from_addr, to_addr, msg)   
            smtp.quit()
        except Exception, e:
            return False, 'send mail fail. {}'.format(e)
        return True, None

    def log(self, msg, need_mail = False):
        if not msg:
            return
        print(msg)
        log_msg = '{}\t{}\n'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), msg)
        # 检查最近的记录,如果相同仅更新时间
        try:
            last_log = self.logs[2].split('\t')[1].strip()
            if last_log == msg:
                self.logs[2] = log_msg
            else:
                self.logs.insert(2, log_msg)
        except Exception, e:
            self.logs.insert(2, log_msg)

        if need_mail:
            self.sendMail(msg)

    def checkIP(self):
        old_ip = self.getOldIP()
        try:
            url = urllib2.Request(ip_check_server)
            res = urllib2.urlopen(url)
            new_ip = res.read().strip('\r\n ')
        except Exception, e:
            self.log('get ip fail. {}'.format(e), True)
            return
        if old_ip == new_ip:
            return self.log('IP unchanged.')
        res, msg = self.sendMail('IP Changed. {}'.format(new_ip))
        if not res:
            return self.log(msg)
        self.setNewIP(new_ip)
        self.log('IP changed. {}'.format(new_ip))

    def cleanLog(self):
        self.logs[2:] = []

    def run(self):
        if len(sys.argv) == 1:
            return self.checkIP()
        if '--clean' in sys.argv:
            return self.cleanLog()
        print('argument error.')

if __name__ == '__main__':
    ip = CheckIP()
    ip.run()

Source on gist

  • 将上述代码另存为文本,并按脚本中的注释正确设置SMTP服务器、账户、密码、发送及接收邮箱地址
  • 将文件上传至NAS,如/root/ipcheck.py
  • 使用root账户登陆NAS将该文件权限设置为可执行chmod 744 /root/ipcheck.py
  • 执行/root/ipcheck.py测试,正常情况下你设置的接收邮箱将会收到一个包含NAS当前IP地址的邮件,如果没有请检查前面的操作是否正确。

2. 设定定时任务

  用root账户执行vi /etc/crontab4,在打开的文件末尾添加如下内容:

*/10        *        *        *        *        root        /root/ipcheck.py

  其中*/10意为每10分钟检查一次外部IP。

  最后执行命令重启cron

/usr/syno/etc.defaults/rc.d/S04crond.sh stop && sleep 1 && /usr/syno/etc.defaults/rc.d/S04crond.sh start

  至此,NAS将每隔一段时间检查外部IP,一旦发现地址变化就会发送邮件通知。

3. 其它

  • /tmp/ipcheck.txt为默认保存当前ip地址信息及日志的文件,每次检查ip地址时都跟此文件内容比较,如果不同则发送通知邮件

REF:

  向StartSSL申请个人域名SSL证书


  1. 貌似这是群晖DDNS服务的通病,在DSM4.2已经允许设置多个DDNS服务,不过为以防万一,自行监控IP变化也不失为一个好的预防手段。 

  2. 群晖NAS DSM上默认不自带Python,需要从套件中心中安装。 

  3. 不仅仅只适用于群晖NAS,只要安装了Python的*nix系统均可正常使用。 

  4. 简单的vi操作: i进入编辑模式 esc 退出当前模式 : 进入命令行输入模式 w 保存内容 q 退出。