0x01 前言

DDNS解析脚本持续更新,后面将新增其他服务商的DNS解析服务,通过调用API实现DDNS功能。因为IPv6的部署已经在快速推进,我也顺应时代的发展,更新脚本,实现对IPv6的支持。

0x02 本地IP地址获取服务

先讲解下新上线的本地IP地址获取服务,我是通过nginx实现相关功能的,完全不需要后端的支持,以下是nginx的配置文件:

server {
  listen                     443 ssl http2;
  server_name                ipv4.ngx.hk;

  ssl_certificate            /usr/local/nginx/ssl/ngx.hk.crt;
  ssl_certificate_key        /usr/local/nginx/ssl/ngx.hk.key;
  ssl_buffer_size            16k;
  ssl_protocols              TLSv1.1 TLSv1.2 TLSv1.3;
  ssl_ecdh_curve             X25519:P-256:P-384:P-224:P-521;
  ssl_ciphers                TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256;
  ssl_prefer_server_ciphers  on;
  ssl_session_timeout        3h;
  ssl_stapling               on;
  ssl_session_tickets        on;

  access_log                 /var/log/nginx/access.log main;

  add_header                 Strict-Transport-Security "max-age=31536000; preload; includeSubDomains" always;
  add_header                 X-Frame-Options SAMEORIGIN;

  gzip                       on;

  location / {
    default_type text/plain;
    return 200 "$remote_addr";
  }
}

以上是:ipv4.ngx.hk 这个域名的配置文件,其中最为重要的是location字段,直接给访客返还200响应码并附带访客的IP地址。通过浏览器打开的效果如下:

没错,及其简单的一个页面,源代码里完全没有一个多余的字符,但这已经满足我们的需求了。而IPv6和IPv4类似,就是listen和server_name有所区别:

  listen                     [::]:443 ssl http2;
  server_name                ipv6.ngx.hk;

监听所有和IPv4一样,nginx会监听我服务器中所有的IPv6地址,虽然我只有一个IPv6地址。

因为我这域名加入了HSTS list,还需要添加80端口的虚拟机配置,以便让访客跳转到HTTPS协议:

# IPv4
server {
  listen                     80;
  server_name                ipv4.ngx.hk;

  access_log                 /var/log/nginx/access.log main;

  gzip                       on;

  return                    301 https://ipv4.ngx.hk;
}

# IPv6
server {
  listen                     [::]:80;
  server_name                ipv6.ngx.hk;
  
  access_log                 /var/log/nginx/access.log main;
  
  gzip                       on;
  
  return                    301 https://ipv6.ngx.hk;
}

其实我有想过只通过一个域名同时监听IPv4和IPv6的,但当客户机同时拥有两种IP的时候,访问我的服务就只能返还一种IP地址,除非在脚本中加入相关代码进行区分。这样过于繁琐,因此我决定将其拆分,形成以下两个域名:

最后是这个服务器的服务商,我计划长期租用OVH的高防VPS,每月仅3.5美元,1个核心,2G内存,百兆端口不限量,还带抗DDOS服务。这价格是及其良心,为什么不用?就是延迟高点,所以在新版的脚本里调整了HTTP超时时长为30秒。

也正是只运行一个nginx,这个资源的VPS也足够用一段很长的时间了,价格也是我能承受得起的。

0x03 准备

脚本仅支持通过python3调用,需要通过pip3安装以下依赖包:

pip3 install aliyun-python-sdk-core-v3 aliyun-python-sdk-alidns requests

然后到使用以下命令将源码克隆到本地:

git clone https://gitlab.ngx.hk/aliyun/DDNS.git

也可以访问我的GitHub镜像:

克隆到本地后先将配置文件复制一份并重命名为config.conf,然后进行修改:

{
  "0": {
    "access_key_id": "",
    "access_Key_secret": "",
    "domain": "",
    "sub_domain": "",
    "ttl": "",
    "ip_ver": 4
  },
  "1": {
    "access_key_id": "",
    "access_Key_secret": "",
    "domain": "",
    "sub_domain": "",
    "ttl": "",
    "ip_ver": 6
  }
}

脚本支持同时为同一个域名添加IPv4和IPv6的DNS记录,如:

IPv4:https://ip.ngx.hk -> 51.75.251.225
IPv6:https://ip.ngx.hk -> 2001:41d0:305:2100:0:0:0:68c0

这时候的配置文件如下:

{
  "0": {
    "access_key_id": "aaaaaaaaaaaaaaaaaaaa",
    "access_Key_secret": "bbbbbbbbbbbbbbbbbbb",
    "domain": "ngx.hk",
    "sub_domain": "ip",
    "ttl": "600",
    "ip_ver": 4
  },
  "1": {
    "access_key_id": "aaaaaaaaaaaaaaaaaaaa",
    "access_Key_secret": "bbbbbbbbbbbbbbbbbbb",
    "domain": "ngx.hk",
    "sub_domain": "ip",
    "ttl": "600",
    "ip_ver": 6
  }
}

也可以为不同域名添加记录,此时只要按需修改domain和sub_domain即可。如果只需要添加单一IP版本,则需要删除多余的配置信息,如:

{
  "0": {
    "access_key_id": "aaaaaaaaaaaaaaaaaaaa",
    "access_Key_secret": "bbbbbbbbbbbbbbbbbbb",
    "domain": "ngx.hk",
    "sub_domain": "ip",
    "ttl": "600",
    "ip_ver": 4
  }
}

而最后的“ip_ver”则是指定IP版本的配置信息,上一个“ttl”则需要根据实际情况进行选择,非腾讯云DNS解析服务的VIP,最小ttl为600,此时请勿填写小于600的数,否则会报错。

0x04 脚本更新与执行

脚本仅修改了小部分代码,首先是本地IP检测的部分:

# 获取IP地址,支持v4与v6
def my_ip(i_ip_ver):
    if i_ip_ver == 4:
        get_ip_value = requests.get('https://ipv4.ngx.hk', timeout=30).content.decode().strip('\n')
    else:
        get_ip_value = requests.get('https://ipv6.ngx.hk', timeout=30).content.decode().strip('\n')
    return get_ip_value

该函数会根据传入的IP类型访问不同的域名,从而获取到自身的IP并返还。

因为新增了IPv6,因此在新增与更新域名解析的函数也需要稍作调整:

# 更新子域名信息
def update_dns(ali_ctl, sub_domain, dns_value, ttl, dns_record_id, ip_ver):
    request = UpdateDomainRecordRequest.UpdateDomainRecordRequest()
    request.set_RR(sub_domain)
    request.set_Value(dns_value)
    request.set_RecordId(dns_record_id)
    request.set_TTL(ttl)
    request.set_accept_format('json')

    if ip_ver == 4:
        request.set_Type('A')
    else:
        request.set_Type('AAAA')

    result = ali_ctl.do_action_with_exception(request)
    return result


# 新增子域名解析
def add_dns(ali_ctl, dns_value, domain, sub_domain, ttl, ip_ver):
    request = AddDomainRecordRequest.AddDomainRecordRequest()
    request.set_DomainName(domain)
    request.set_RR(sub_domain)
    request.set_Value(dns_value)
    request.set_TTL(ttl)

    if ip_ver == 4:
        request.set_Type('A')
    else:
        request.set_Type('AAAA')

    result = ali_ctl.do_action_with_exception(request)
    return result

其余部分则未作修改。脚本的执行的方式与之前无异,使用python3调用脚本即可:

[root@web ~]# python3 /usr/local/services_data/shell/DDNS/aliyun_ddns.py

0x05 结语

完整的代码可留意我的私有gitlab与GitHub镜像:

如果有其他功能需求或建议,请通过电子邮件与我取得联系。如果有BUG,请在GitHub提issues。

之前版本的相关文章请留意以下链接: