Linux中獲取本機的最新IPv6地址_更新ddns的腳本


Linux中獲取本機的最新IPv6地址_更新ddns的腳本

轉載注明來源: 本文鏈接 來自osnosn的博客,寫於 2019-11-07.

運營商提供ipv6地址。
路由器后有台linux機器,通過eui64方式自動配置ipv6地址。
但是,運營商會定時強制路由器重撥,導致ipv6的前綴(prefix)變化。
雖然linux會馬上自動配置新的ipv6地址。但舊的ipv6地址不會馬上消失。
舊ipv6需要等超時expired后才刪除,有時要等2000多秒(30多分鍾)。
這段時間主機會有兩個ipv6地址。如果不能正確找出新的ipv6地址去更新ddns,則這段時間無法訪問主機。

通過查看 ip addr show 發現每個ip后面一行給出了expired時間。
新ip的expired時間總是比舊ip大。這樣就可以找出最新的ipv6地址了。

以下是shell腳本,會顯示出ipv4地址,和最新的ipv6(eui64)地址。

#!/bin/sh
ip addr show|grep -A1 'inet [^f:]'|sed -nr 's#^ +inet ([0-9.]+)/[0-9]+ brd [0-9./]+ scope global .*#\1#p'
ip addr show|grep -v deprecated|grep -A1 'inet6 [^f:]'|sed -nr ':a;N;s#^ +inet6 ([a-f0-9:]+)/.+? scope global .*? valid_lft ([0-9]+sec) .*#\2 \1#p;ta'|grep 'ff:fe'|sort -nr|head -n1|cut -d' ' -f2

顯示ipv6的腳本執行步驟是,

  • ip addr show
  • 去除 deprecated 地址
  • 挑出inet6地址,並同時顯示下一行
  • 把expired時間和ipv6地址,通過正則找出來,並顯示在同一行。超時時間在前,ip在后。
  • 過濾出eui64地址
  • 根據時間的長短,反向排序
  • 輸出第一行
  • 輸出第二列(ip)

如果要把這個地址保存到變量,用來更新ddns,就這樣寫。

#!/bin/sh
ipv4=$(ip addr show|grep -A1 'inet [^f:]'|sed -nr 's#^ +inet ([0-9.]+)/[0-9]+ brd [0-9./]+ scope global .*#\1#p')
ipv6=$(ip addr show|grep -v deprecated|grep -A1 'inet6 [^f:]'|sed -nr ':a;N;s#^ +inet6 ([a-f0-9:]+)/.+? scope global .*? valid_lft ([0-9]+sec) .*#\2 \1#p;ta'|grep 'ff:fe'|sort -nr|head -n1|cut -d' ' -f2)
#echo "my ipv6 is:" $ipv6
# 如果路由器有公網ipv4,可以讓ddns根據來源ip自動檢測
wget --no-check-certificate -q -O - 'https://ipv4.dynv6.com/api/update?hostname=myhostname.dynv6.net&token=mytoken.......mytoken&ipv4=auto&ipv6='$ipv6

python3 的腳本例子。

#!/usr/bin/python3
# -*- coding: utf-8 -*- #

import urllib.request
import ssl
import subprocess
import re

def getIP():
   #interface='eth0'
   interface=''
   output=subprocess.getoutput('/sbin/ip addr show '+interface+'|grep -v deprecated')
   ipv4=re.findall(r' inet ([\d.]+)/(\d+) brd [\d./]+ scope global ',output,re.M|re.I)
   ipv6=re.findall(r' inet6 ([^f:][\da-f:]+)/(\d+) scope global .+?\n.+? valid_lft (\d+)sec ',output,re.M|re.I)

   # eui64的ipv6地址按超時時間排序,其他的排前面
   def my_key(a):
      if a[0].find('ff:fe')>4:
         return int(a[2])
      else:
         return -1
   ipv6.sort(key=my_key,reverse=True) #反向排序
   #print('ipv4=',ipv4)
   #print('ipv6=',ipv6)

   return (ipv4,ipv6)

def updateddns(ipv4,ipv6):
   context = ssl._create_unverified_context()
   opener = urllib.request.build_opener(urllib.request.HTTPSHandler(context=context)) #不驗證證書
   header={
       'Accept':'*/*',
       'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 1.1.4322; .NET CLR 2.0.50727)',
       'Accept-Encoding':'none',
   }
   #host='https://dynv6.com/api/update?hostname=myhostname.dynv6.net&token=mytoken.......mytoken&ipv4='+ipv4+'&ipv6='+ipv6
   #如果路由器有公網ipv4,可以讓ddns根據來源ip自動檢測
   host='https://ipv4.dynv6.com/api/update?hostname=myhostname.dynv6.net&token=mytoken.......mytoken&ipv4=auto&ipv6='+ipv6
   req=urllib.request.Request(host, b'',header)
   content=opener.open(req, timeout=20)
   print(content.read().decode('utf8'))
   return True

if __name__=='__main__':
   ipv4,ipv6=getIP()
   updateddns(ipv4[0][0],ipv6[0][0])

這個是OpenWRT路由器中的lua腳本。

如果你的路由器是OpenWRT,可以用這個腳本直接跑在路由器中。
這個腳本獲取的是路由器本身的ipv4和ipv6(非eui64).

#!/usr/bin/lua

require("luci.sys")
local a=luci.sys.exec('/sbin/ip addr show pppoe-wan')
local ipv4=string.match(a," inet ([%d%.]+) peer ")
local ipv6=string.match(a," inet6 ([%a%d:]+)/[0-9]+ scope global ")
-- lua的注釋為兩個減號
--print(ipv4,ipv6)

cc=luci.sys.exec("/bin/wget --no-check-certificate -q -O - 'https://dynv6.com/api/update?hostname=myhostname.dynv6.net&token=mytoken.......mytoken&ipv4="..ipv4.."&ipv6="..ipv6.."'")

---end---

轉載注明來源: 本文鏈接 來自osnosn的博客


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM