MacOS X で自動的に OCN IPv6 に接続する Python スクリプト

一昨日の記事の続きです。
実は OCN IPv6 を使っているのですが、たまに L2TP での接続が切れてしまっていることがあるので、
自動復旧するようなスクリプトを書きたかったのです。

OSX で OCN IPv6 を使うような方は自前でもっと立派なスクリプトなどを書いているとはおもいますが、
役に立つかもしれないので、公開したいと思います。

使い方

/usr/local に wide-dhcp6 がインストールされていることが前提です。


% ipv6.py --ifnam=en1 --server=60.37.nn.nnn --user=hogehoge@one.ocn.ne.jp --passwd=hogehoge

実行例


% ipv6.py --ifnam=en1 --server=60.37.nn.nnn --user=hogehoge@one.ocn.ne.jp --passwd=hogehoge
ifnam=en1 server=60.37.nn.nnn user=hogehoge@one.ocn.ne.jp passwd=xxxx
ping6 失敗: 0
ping6 失敗: 1
ping6 失敗: 2
ping6 失敗: 3
ping6 失敗: 4
ping6 失敗: 5
ping6 失敗: 6
ping6 失敗: 7
ping6 失敗: 8
IPv6 で接続されていません
pppd を開始しました: ppp0
dhcp6c を起動しました
ネットワーク: 2001:380:nnn:nn::
rtadvd を起動しました
add net default: gateway ppp0

以後 ping6 が 10回失敗すると再接続を行います。

はじめての Pythonスクリプトなので、優しいツッコミ大歓迎です。

コード


#!/usr/bin/env python2.5
#-*- coding: utf-8 -*-

import getopt
import os
import re
import sys
import time

#
#
#
def file_create(path, content):
try:
f = open(path, 'w')
f.write(content)
f.close()
except IOError, e:
print >> sys.stderr, e
raise
except Exception, e:
print >> sys.stderr, e
raise

#
#
#
def sysctl_on(s):
try:
p = os.popen('sysctl ' + s, 'r')
if (p.readline() == (s + ': 1\n')):
p.close()
else:
p.close()
try:
p = os.popen('sysctl -w ' + s + '=1', 'r')
if (p.readline() != (s + ': 0 -> 1\n')):
return (False)
p.close()
except OSError, e:
print >> sys.stderr, e
raise
except Exception, e:
print >> sys.stderr, e
raise
except IOError, e:
print >> sys.stderr, e
raise
except Exception,e :
print >> sys.stderr, e
raise
return (True)

#
#
#
def ppp_connect():
os.system('killall pppd >/dev/null 2>&1')
time.sleep(1)
ifnam = None
pattern = re.compile(r'Connect:\s*(\w+)', re.I)
try:
p = os.popen('pppd', 'r')
for line in p.readlines():
mo = pattern.search(line)
if (mo):
ifnam = mo.group(1)
p.close()
except OSError, e:
print >> sys.stderr, e
raise
except Exception, e:
print >> sys.stderr, e
raise
return (ifnam)

#
#
#
def daemon_run(cmd, pif):
try:
f = open(pif, 'r')
pid = f.read()
f.close()
except IOError, e:
pid = 0
except Exception, e:
pid = 0
if (pid != 0):
try:
os.kill(int(pid), 15)
time.sleep(1)
os.kill(int(pid), 9)
except OSError, e:
nop = 0
except Exception, e:
print >> sys.stderr, e
raise
try:
os.system(cmd + ' >/dev/null 2>&1 &')
except OSError, e:
print >> sys.stderr, e
raise
except Exception, e:
print >> sys.stderr, e
raise

#
#
#
def get_network(ifnam):
net = None
pattern = re.compile(r'\s*inet6\s*(\w+):(\w*):(\w*):(\w*):(\w*):(\w*):(\w*):(\w*)', re.I)
try:
p = os.popen('ifconfig ' + ifnam, 'r')
for line in p.readlines():
mo = pattern.search(line)
if (mo):
net = mo.group(1) + ':' + mo.group(2) + ':' + mo.group(3) + ':' + mo.group(4) + '::'
p.close()
except OSError, e:
print >> sys.stderr, e
raise
except Exception, e:
print >> sys.stderr, e
raise
return (net)

#
#
#
def main(argv = None):
if argv is None:
argv = sys.argv
try:
opts, args = getopt.getopt(argv[1:], 'hv', ['ifnam=', 'server=', 'user=', 'passwd='])
except getopt.error, msg:
return (-1)
ifnam = None
server = None
user = None
passwd = None
for o, a in opts:
if (o in ("--ifnam")):
ifnam = a
if (o in ("--server")):
server = a
if (o in ("--user")):
user = a
if (o in ("--passwd")):
passwd = a
if ( ( ifnam == None) or (server == None) or (user == None) or (passwd == None)):
return (-1)
print 'ifnam=' + ifnam + ' server=' + server + ' user=' + user + ' passwd=xxxx'
while (True):
try:
err_cnt = 0
for i in range(10):
r = os.system('ping6 -c 1 www.ocnipv6.jp > /dev/null 2>&1')
if ( ( r <> 0) and (err_cnt != 9)):
print 'ping6 失敗: ' + str(err_cnt)
err_cnt = err_cnt + 1
time.sleep(1)
continue
elif (err_cnt == 9):
print 'IPv6 で接続されていません'
file_create('/etc/ppp/options', '#\ndebug\ndump\nnoauth\nupdetach\nnovj\nplugin L2TP.ppp\n+ipv6\nl2tpnoipsec\nl2tpmode connect\nremoteaddress ' + server + '\n\nplugin /System/Library/SystemConfiguration/PPPController.bundle/contents/PlugIns/PPPDialogs.ppp\nuser ' + user + '\npassword ' + passwd + '\n')
if (sysctl_on('net.inet6.ip6.forwarding') == False):
print 'sysctl 失敗'
break
ppp_ifnam = ppp_connect()
if ( ppp_ifnam == None):
print 'pppd 失敗'
os.system('killall pppd >/dev/null 2>&1')
time.sleep(1)
break
print 'pppd を開始しました: ' + ppp_ifnam
file_create('/usr/local/etc/dhcp6c.conf.hostmode', 'interface ' + ppp_ifnam + ' {\n send ia-pd 0;\n};\n\nid-assoc pd 0 {\n prefix-interface ' + ifnam + ' {\n sla-id 1;\n sla-len 0;\n };\n};\n')
daemon_run('/usr/local/sbin/dhcp6c -c /usr/local/etc/dhcp6c.conf.hostmode -dD -f ' + ppp_ifnam, '/var/run/dhcp6c.pid')
print 'dhcp6c を起動しました'
time.sleep(2)
network = get_network(ifnam)
if (network == None):
print 'ネットワーク取得失敗'
break
print 'ネットワーク: ' + network
file_create('/etc/rtadvd.conf', ifnam + ':\\\n :addrs#1:addr="' + network + '":prefixlen#64:\n')
daemon_run('rtadvd ' + ifnam + ' -f', '/var/run/rtadvd.pid')
print 'rtadvd を起動しました'
os.system('route delete -inet6 default > /dev/null 2>&1')
os.system('route add -inet6 default -interface ' + ppp_ifnam)
else:
print 'IPv6 で接続中です'
time.sleep(10)
except Exception, e:
print >> sys.stderr, e
continue
except KeyboardInterrupt, e:
print '終了します'
break

if __name__ == "__main__":
sys.exit(main())