Easy-rsa生成密钥证书

本来一直都是用PPTP的,简单方便,但最近移动的宽带不知道换了什么路由还是怎么回事,居然一直无法拨通,只有换成OpenVPN了,但是换成OpnVPN麻烦的是需要证书和密钥什么的,比较啰嗦。因为密钥经常需要更新或者需要新增,所以在这里记下来。

首先拷贝一份配置样本,如果路径不对那么用find找吧。

cp -r /usr/share/easy-rsa/ /etc/openvpn/

切换目录,执行:

cd  /etc/openvpn/easy-rsa
source ./vars
./clean-all
./build-ca

生成服务器密钥和客户端密钥

./build-key-server server
./build-key client

生成过程中会提示输入一些信息,直接回车默认,选择[y/n]的都选y,客户端如果需要可以把client改成你需要的名字。

生成Diffie Hellman参数

./build-dh

在OpenVPN的配置文件server.conf中注意文件的路径问题,然后重启载入既可以了。

关于Kodi字幕插件的开发

最近把家里的HDPC终于改成Debian了,起初一直在Windows 10下,但经过长时间的使用,装着E5200芯的老机器终于拉不动了,启动都要卡半天。思索了半天,干脆换到了Debian下。没去试现在的安卓X86版本和凤凰系统,是因为不想过于折腾了,虽说Debian并不是个好的娱乐平台,但好在安装Kodi倒是很方便对这个系统也比较熟悉,而我也仅仅用它就可以了。

安装的是Debian 9.4版本, Kodi是17.6的。设置什么的轻车熟路,电影、电视、直播啥的都基本没问题,但找遍了网上现有的中文字幕插件,就没一个可以用的,有的说是给15的版本可以用,但我没试而且也不想换版本。没办法了,只有自己改吧。

在这里真要吐槽一下Kodi的官方资料,英文的不说,而且是积极的简单,什么函数基本上就是一句话解释,连示例都没有一个,不过还好,综合了很多现成的源码,基本上了解了它字幕插件的思路和一些函数方法。代码是基于网络现有的插件基础上改的,字幕来源于字幕库。

首先是搜索函数,一番查验这个到是简单,原先的代码找不到内容是因为网站页面div的class改了,所以把bs的查找规则调整就ok了。

def Search( item ):
    subtitles_list = []

    log( __name__ ,"Search for [%s] by name" % (os.path.basename( item['file_original_path'] ),))
    if item['mansearch']:
        url = ZIMUKU_API % (item['mansearchstr'])
    else:
        url = ZIMUKU_API % (item['title'])
    try:
        socket = urllib.urlopen(url)
        data = socket.read()
        socket.close()
        soup = BeautifulSoup(data,'html.parser')
    except:
        return
    results = soup.find_all("div", class_="item prel clearfix")
    for it in results:
        moviename = it.find("div", class_="title").a.text.encode('utf-8')
        iurl = it.find("div", class_="title").a.get('href').encode('utf-8')
        movieurl = '%s%s' % (ZIMUKU_BASE, iurl)
        try:
            socket = urllib.urlopen(movieurl)
            data = socket.read()
            socket.close()
            soup = BeautifulSoup(data,'html.parser').find("table", class_="table")
            soup = soup.find("tbody")
        except:
            return
        subs = soup.find_all("tr")
        for sub in subs:
            name = sub.a.text.encode('utf-8')
            if name.split('.')[-1] not in ['zip','Zip','ZIP']: continue
            flag = sub.img.get('src').split('/')[-1].split('.')[0].encode('utf-8')
            lang = FLAG_DICT.get(flag,'unkonw')
            link = '%s%s' % (ZIMUKU_BASE, sub.a.get('href').encode('utf-8'))

            if lang == '英':
                subtitles_list.append({"language_name":"English", "filename":name, "link":link, "language_flag":'en', "rating":"0", "lang":lang})
            else:
                subtitles_list.append({"language_name":"Chinese", "filename":name, "link":link, "language_flag":'zh', "rating":"0", "lang":lang})

而下载函数就麻烦了一点,看原来代码是获取下载地址后直接下载,而实际上我在网站下载时发现网站使用了301重定向,并且在访问下载地址时,网站做了防爬虫处理,需要在头里带上Referer,否则系统是不会给你正确的定向地址的,经过改动的代码如下:

def Download(url,lang):
    try: shutil.rmtree(__temp__)
    except: pass
    try: os.makedirs(__temp__)
    except: pass

    exts = [".srt", ".sub", ".smi", ".ssa", ".ass" ]
    try:
        socket = urllib.urlopen( url )
        data = socket.read()
        soup = BeautifulSoup(data,'html.parser')
        url = soup.find("li", class_="li dlsub").a.get('href').encode('utf-8')
        socket = urllib.urlopen(url)

        socket = urllib.urlopen(url)
        data = socket.read()
        soup = BeautifulSoup(data,'html.parser')
        div = soup.find('div',class_='down clearfix')
        li = div.find('li')
        headers['Referer'] = url

        req = urllib2.Request(li.a.get('href'),headers=headers)
        resp = urllib2.urlopen(req)
        socket = urllib.urlopen(resp.geturl())
        data = socket.read()
        socket.close()
    except:
        return []
    if len(data) < 1024: return []
    tempfile = os.path.join(__temp__, "subtitles.zip")
    xbmc.log(tempfile)
    with open(tempfile, "wb") as subFile: subFile.write(data)
    subFile.close()
    xbmc.sleep(500)
    lists = unZip(tempfile)
    lists = [i for i in lists if os.path.splitext(i)[1] in exts]

    if len(lists) == 1:
        return lists[0]
    else:
        index = [i.split('/')[-1] for i in lists]
        sel = xbmcgui.Dialog().select('请选择压缩包中的字幕', index)
        if sel == -1: sel = 0
        return lists[sel]

经过调整,大的问题没有了,不过些小的地方,原代码里貌似是只能在Windows下用的,因为好像它是用Winrar来解压的,而我在Debian下使用,所以只能考虑Zip文件了,至于能不能用rar包还有单独的srt等文件,以后折腾吧。

def getFileList(path):
    fileslist = []
    for d in os.listdir(path):
        if os.path.isdir(path+d):
            fileslist.extend(getFileList(path+d+'/'))
        if os.path.isfile(path+d):
            fileslist.append(path+d)
    return fileslist

def unZip(filepath):
    zip_file = zipfile.ZipFile(filepath,'r')
    for names in zip_file.namelist():
        if type(names) == str and names[-1] != '/':
            utf8name = names.decode('gbk')
            data = zip_file.read(names)
            fo = open(os.path.join(__temp__, utf8name), "w")
            fo.write(data)
            fo.close()
        else:
            zip_file.extract(names,__temp__)
    return getFileList(__temp__+'/')

总结一下啊,用惯了Python3后用2真的不习惯,并且在Kodi里测试也是非常的不方便,改动一下需要重新进入才行,经过测试在Linux和Windows下都没问题,版本从17到最新的18,至于更低的版本则没测试,接下来要把各种字幕扩展名的文件下载功能补全,等到某一天有心情折腾了再说吧。附地址:https://pan.baidu.com/s/1GxAod4Xdll-3pvM_OOru8A

更新:由于上次改的有太多的局限性,所以继续抽时间改了改,现在这个版本继续支持Linux和Windows,并且文件格式由单纯的zip扩展到rar的压缩,还包括了各种未压缩的字幕格式,由于网上并没有发现7z的字幕压缩包,所以就没有考虑这个格式了。但现在由于格式的增多,就带来了一些问题,为了这个插件的正常使用,在Windows下必须要安装WinRAR并且目录还得是C:\Program Files\WinRAR,在Linux下需要安装unrar,否则的话会下载失败,其他没有要求,注意这点即可。

贴上代码:

def getFileList(path):
    fileslist = []
    for d in os.listdir(path):
        if os.path.isdir(path+d):
            fileslist.extend(getFileList(path+d+'/'))
        if os.path.isfile(path+d):
            fileslist.append(path+d)
    return fileslist

def extractCompress(file):
    path  = __temp__ + '/subtitles/'
    if os.path.isdir(path): shutil.rmtree(path)
    if not os.path.isdir(path): os.mkdir(path)

    if file.lower().endswith('zip'):
        zipFile = zipfile.ZipFile(file,'r')
        for names in zipFile.namelist():
            if type(names) == str and names[-1] != '/':
                utf8name = names.decode('gbk')
                data = zipFile.read(names)
                with open(path+utf8name, 'wb') as f: f.write(data)
            else:
                zipFile.extract(names,path)
        return getFileList(path)

    if file.lower().endswith('rar'):
        if platform.system() == 'Windows':
            rarPath = 'C:\Program Files\WinRAR'
            sysPath = os.getenv('Path')
            if 'winrar' not in sysPath.lower(): os.environ["Path"] = sysPath+';'+rarPath
            command = "winrar x -ibck %s %s" % (file, path)
        if platform.system() == 'Linux':
            command = 'unrar x %s %s' % (file, path)
        res = os.system(command)
        if res == 0: return getFileList(path)

def Search( item ):
    subtitles_list = []

    log(__name__ ,"Search for [%s] by name" % os.path.basename(item['file_original_path']))
    if item['mansearch']:
        url = ZIMUKU_API % (item['mansearchstr'])
    else:
        url = ZIMUKU_API % (item['title'])
    try:
        socket = urllib.urlopen(url)
        data = socket.read()
        socket.close()
        soup = BeautifulSoup(data,'html.parser')
    except:
        return
    results = soup.find_all("div", class_="item prel clearfix")
    for it in results:
        moviename = it.find("div", class_="title").a.text.encode('utf-8')
        iurl = it.find("div", class_="title").a.get('href').encode('utf-8')
        movieurl = '%s%s' % (ZIMUKU_BASE, iurl)
        try:
            socket = urllib.urlopen(movieurl)
            data = socket.read()
            socket.close()
            soup = BeautifulSoup(data,'html.parser').find("table", class_="table")
            soup = soup.find("tbody")
        except:
            return
        subs = soup.find_all("tr")
        for sub in subs:
            name = sub.a.text.encode('utf-8')
            flag = sub.img.get('src').split('/')[-1].split('.')[0].encode('utf-8')
           .get(flag,'unkonw')
            link = '%s%s' % (ZIMUKU_BASE, sub.a.get('href').encode('utf-8'))

            if lang == '英':
                subtitles_list.append({"language_name":"English", "filename":name, "link":link, "language_flag":'en', "rating":"0", "lang":lang})
            else:
                subtitles_list.append({"language_name":"Chinese", "filename":name, "link":link, "language_flag":'zh', "rating":"0", "lang":lang})

    if subtitles_list:
        for it in subtitles_list:
            listitem = xbmcgui.ListItem(label=it["language_name"],
                                  label2=it["filename"],
                                  iconImage=it["rating"],
                                  thumbnailImage=it["language_flag"]
                                  )

            listitem.setProperty( "sync", "false" )
            listitem.setProperty( "hearing_imp", "false" )

            url = "plugin://%s/?action=download&link=%s&lang=%s" % (__scriptid__,
                                                                        it["link"],
                                                                        it["lang"]
                                                                        )
            xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=url,listitem=listitem,isFolder=False)

def Download(url,lang):
    try: shutil.rmtree(__temp__)
    except: pass
    try: os.makedirs(__temp__)
    except: pass

    exts = [".srt", ".sub", ".smi", ".ssa", ".ass" ]
    try:
        socket = urllib.urlopen( url )
        data = socket.read()
        soup = BeautifulSoup(data,'html.parser')
        url = soup.find("li", class_="li dlsub").a.get('href').encode('utf-8')
        socket = urllib.urlopen(url)

        socket = urllib.urlopen(url)
        data = socket.read()
        soup = BeautifulSoup(data,'html.parser')
        div = soup.find('div',class_='down clearfix')
        li = div.find('li')
        headers['Referer'] = url

        req = urllib2.Request(li.a.get('href'),headers=headers)
        resp = urllib2.urlopen(req)
        fileName = resp.headers['Content-Disposition'].replace('"','').split('=')[1]

        socket = urllib.urlopen(resp.geturl())
        data = socket.read()
        socket.close()
    except:
        return []
    if len(data) < 1024: return []
    tempfile = os.path.join(__temp__, "subtitles.%s" % fileName.split('.')[-1])
    xbmc.log(tempfile)
    with open(tempfile, "wb") as subFile: subFile.write(data)
    xbmc.sleep(100)
    if fileName.split('.')[-1].lower() in ('zip','rar'):
        lists = extractCompress(tempfile)
    else:
        lists = [tempfile]

    lists = [i for i in lists if os.path.splitext(i)[1] in exts]

    if len(lists) == 1:
        return lists[0]
    else:
        index = [i.split('/')[-1] for i in lists]
        sel = xbmcgui.Dialog().select('请选择压缩包中的字幕', index)
        if sel == -1: sel = 0
        return lists[sel]

贴上下载地址:点击下载

PPTP客户端连接VPN的详细记录

为了工作方便,利用动态域名最近在公司里做了个VPN服务器,这样回到家后可以继续和公司同处一个局域网下,方便一些应急的时候不至于急急忙忙往公司跑。

系统继续是把做成路由的Debian,尽管它本身也已经是个VPN服务器了,但奈何现在坑爹的运营商,分配不到一个公网IP,所以这个服务器歇菜了。

首先安装客户端了,命令:aptitude install pptp-linux;安装完创建连接:pptpsetup –create 连接名称 –server 你的服务器 –username 你的账户 –password 你的密码 –encrypt。这一步具体可以用命令:/usr/sbin/pptpsetup –help,这个可以看到详细的说明格式。执行完这一步之后在/etc/ppp/chap-secrets这个文件会多出两行,但多出的第一行是注释掉的说明,第二行才是参数,格式如此:你的账户 pptp "你的密码" *,注意别掉了星号。还有在/etc/ppp/peers/这个目录下多出一个以连接名称命名的文件,里面的格式基本如此:

# written by pptpsetup
pty "pptp 你的服务器 --nolaunchpppd"
lock
noauth
nobsdcomp
nodeflate
name 你的用户名
remotename 你的连接名称
ipparam 你的连接名称
require-mppe-128

现在已经可以使用pon 你的连接名称来连接vpn服务器了。

快速在Debian上部署路由功能

用了一段时间的Ubuntu后,对于它四个桌面的切换,老是经常卡死,并且在换到17.04版本后,即使在固态硬盘和16G内存的帮助下用着N3150的处理器,感觉还是有点卡,于是乎就切换到了Debian阵营来了。也正因为装系统的次数太频繁了,所以重新整理了一下迅速部署路由功能,现在可以说在重新安装系统的情况下也可以在三分钟分钟内重新建立路由。

废话少说,步骤开始,切换到管理员账户,安装软件:

aptitude install hostapd bridge-utils dnsmasq

配置网络接口:mousepad /etc/network/interfaces

auto lo
iface lo inet loopback
auto lan0   #有线网卡名称
iface lan0 inet manual
auto wlan0  #无线网卡名称
iface wlan0 inet manual
auto br0 #自定义的接口
iface br0 inet static
address 192.168.147.1  本机局域网地址 别的机器网关就是它了
netmask 255.255.255.0
broadcast 192.168.147.255
bridge-ports lan0 wlan0 #把两真实网卡桥连
bridge_fd 9
bridge_hello 2
bridge_maxage 12
bridge_stp off

配置无线控制:mousepad /etc/hostapd/hostapd.conf

interface=wlan0  #无线网卡名称
bridge=br0   # 自定义的
driver=nl80211
ssid=Ubuntu  # 本热点的名称
# country_code=US
hw_mode=g  # 模式
channel=11  # 频道
dtim_period=1
rts_threshold=2347
fragm_threshold=2346
macaddr_acl=0
# accept_mac_file=/etc/hostapd/hostapd.accept #MAC地址限制,需要建立这个文件
# deny_mac_flie=/etc/hostapd/hostapd.deny
auth_algs=3
ieee80211n=1
ht_capab=[HT40-][SHORT-GI-40][DSSS_CCK-40]
wpa=2
wpa_passphrase=88888888  # 热点密码
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP CCMP
rsn_pairwise=CCMP

还有一个要改的:mousepad /etc/default/hostapd

RUN_DAEMON="yes"
DAEMON_CONF="/etc/hostapd/hostapd.conf"

配置DNS服务器和DHCP服务器:mousepad /etc/dnsmasq.conf

cache-size=4096
listen-address=192.168.147.1,127.0.0.1
resolv-file=/etc/resolv.dnsmasq.conf
conf-dir=/etc/dnsmasq.d

interface=br0
expand-hosts
domain=example.com
dhcp-range=192.168.147.50,192.168.147.150,12h
dhcp-option=3,192.168.147.1
dhcp-option=6,192.168.147.1

创建resolv.dnsmasq.conf文件:mousepad /etc/resolv.dnsmasq.conf

nameserver 58.20.127.170
nameserver 58.20.127.238

打开数据包转发:mousepad /etc/sysctl.conf

net.ipv4.ip_forward = 1

最后,还有一个问题,如果Debian在9之前的版本里,还有rc.local文件,那么直接可以rc.local文件里加上:mousepad /etc/rc.local

iptables -t nat -A POSTROUTING -o wlan1 -j MASQUERADE

但是,在9之后的版本里,已经没有了rc.local文件,所以就要把这个规则加到文件里了。创建自启动配置文件在网络启动之前的文件夹中,并赋予可执行权限:

touch /etc/network/if-pre-up.d/iptables
chmod +x /etc/network/if-pre-up.d/iptables

编辑该文件:mousepad /etc/network/if-pre-up.d/iptables

#!/bin/sh
/sbin/iptables-restore < /etc/iptables

执行规则定义,然后保存成文件:

iptables -t nat -A POSTROUTING -o wlan1 -j MASQUERADE
iptables-save > /etc/iptables

也可以使用:mousepad /etc/iptables,如下内容:

# Generated by iptables-save v1.6.0 on Mon Mar 26 10:32:21 2018
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [20:1340]
:POSTROUTING ACCEPT [20:1340]
-A POSTROUTING -o ppp0 -j MASQUERADE
COMMIT
# Completed on Mon Mar 26 10:32:21 2018

重启完成~