ちゃんと言わない記事

文化的犠牲

YouTubeのMVのコメントで曲の感想や解釈を書いている人がいる. 曲名でググると, ブログで同じように書いてる人がいる. たまに読んだりするが, 解釈は人それぞれさまざまで, なかには「お前本当に歌詞見て曲聴いたのか. 自分の都合を曲に投影してるだけじゃないのか」と思うものまである.

しかし, 的はずれな解釈であったとしても, 作者にとってそれはきっと興味深いことであり, きっとこっそり覗いて「おっ」とか「なるほどなるほど」とか言ってるに違いない(そうじゃない人ももちろんいると思うが). 作者じゃなくても, 熱心な信者やファンが, 自分の考え・思いを確かめに, または正当化とするために割と真剣に見てくれているかもしれない. たとえ, その感想・解釈が他人から見てアレでボロクソ叩かれたとしても, その犠牲は無駄にはならないと思う.

これは, 自分がその犠牲になる記事である[検閲済].

はじめに

今回はこちらの曲になります:

筆者は, このアーティストのこの曲しか知りません. 他の曲も聞いたことあるかもしれませんが, 聞き流しているだけです. アーティストのこともよく知りません. ファンに「お前ちゃんとアーティストのこと調べたのか」と言われれば, それで終わりの記事です. ファンじゃない人間なんてそんなものです. そうじゃなかったら, キャッチーなフレーズとか要らないので.

登場人物

歌詞には「私」と「君」が出てきますが, MVには人は一人しか出てきません. この人にはよく陰がかかり, 体ぜんたいが明るい部分(白)と暗い部分(黒)の二つに分けられています. また, 完全に光が当たって明るいときは, 影が見えています. 青背景のときには, 陰も影もありません.

また, よく[検閲済]とわかりますが, [検閲済]ます.

この白と黒が, 何を表わすのかが結構重要だと思いますが, 正直絞れません.

[検閲済]

冒頭

冒頭3 (24)秒でストーリー終了です. お疲れ様でした. 解散.

一度通して観れば, ほぼ100%の人が君が死んでしまったと考えると思います.

[検閲済]

おわりに

この曲すき.

某VPNの設定を半自動化する小汚い小スクリプト群

何をしているのかわからない人はやらないほうがいいです

俺もわからん.

VPNはセットアップが楽ちん

さらに楽にするために半自動化します. その場しのぎで書いただけで何も考えてません. 使用, 参考にする場合は要注意.

筆者の環境はArch Linuxだが, 執筆時にちょっと書き換えて動作確認はしていない.

はい

連番振りたいが行をあけると無理?

1.こちらを導入:

GitHub - flamusdiu/python-pia: Commandline tool to auto configure PIA services

ポート番号でアルゴリズムを設定してくれるのでこことか参考(特に気にしないのであればUDP 1197でよいと思う):

What's the difference between the OVPN files? - Knowledgebase / Technical / OVPN Files - PIA Support Portal

2. vpn-hosts.txtのリストにプレフィクスを付けるスクリプト:

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

def main():
    path = '/etc/private-internet-access/'
    hosts_file = path + 'vpn-hosts.txt'
    with open(hosts_file) as f:
        lines = f.readlines()
    newlines = ['PIA ' + line for line in lines]
    print(*newlines, sep='')
    yn = input('write to file?[y/N]: ')
    if yn == 'y':
        with open(hosts_file, 'w') as f:
            f.writelines(newlines)

if __name__ == '__main__':
    main()

3. pia.confvpn-hosts.txtを全部突っ込むスクリプト:

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

def main():
    path = '/etc/private-internet-access/'
    hosts_file = path + 'vpn-hosts.txt'
    conf_file = path + 'pia.conf'

    with open(hosts_file, 'r') as f:
        countries = [line.strip().split(',')[0] for line in f.readlines()]
    with open(conf_file, 'r') as f:
        conf_lines = f.readlines()

    for i, line in enumerate(conf_lines):
        if line.startswith('hosts'):
            conf_lines[i] = 'hosts = {}\n'.format(', '.join(countries))
            break

    print(*conf_lines, sep='')

    yn = input('write to file?[y/N]: ')
    if yn == 'y':
        with open(conf_file, 'w') as f:
            f.writelines(conf_lines)

if __name__ == '__main__':
    main()

4. /etc/openvpn/client/以下にOpenVPN設定ファイルを展開:

# pia -a

5. 公開鍵証明書ファイル名にプレフィクス付ける(俺の環境では動いてるが初回は自分で調整して):

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

import os

def main():
    path = '/etc/openvpn/client/'
    pia_confs = [fname for fname in os.listdir(path) if os.path.isfile(path + fname) and fname.startswith('PIA')]

    conf = pia_confs[0]
    with open(path + conf) as f:
        lines = f.readlines()
    names = dict()
    targets = ('ca', 'crl-verify')
    for i, line in enumerate(lines):
        l = line.split(' ')
        if l[0] in targets:
            names[l[0]] = l[1].rstrip()
            if len(names) >= len(targets):
                break
    for tgt, name in names.items():
        pathname, basename = os.path.split(name)
        newname = '{}/pia_{}'.format(pathname, basename)
        if os.path.exists(name):
            os.rename(name, newname)
        names[tgt] = newname

    for cnf in pia_confs:
        with open(path + cnf) as f:
            lines = f.readlines()
        for i, line in enumerate(lines):
            l = line.split(' ')
            for tgt, name in names.items():
                if l[0] == tgt:
                    lines[i] = '{} {}\n'.format(tgt, name)
                    break
        with open(path + cnf, 'w') as f:
            f.writelines(lines)

if __name__ == '__main__':
    main()

6. キルスイッチ

キルスイッチについてはこちらを参照(固定化のデメリットがある):

Internet Kill Switch by Firewall (OpenVPN + iptables) - vanaestea’s blog

DNS

そのままだと/etc/resolv.confVPNサービス側のDNSに書き換えられたと記憶しているが, それが嫌なら, たとえば, resolv.conf

nameserver 1.1.1.1
nameserver 1.0.0.1

のように好きに設定したあと,

# chattr +i /etc/resolv.conf

でイミュータブル属性を付加するとよい(参考: Private Internet Access - ArchWiki).

SOLVED: なぜセグフォ?

最近現実逃避が捗りすぎて困っている.

最近は低レベルのコードとかよくわからないので勉強している(遊んでいるだけ).

このC言語ソースコードは, x86_64のLinuxなら動く環境があると思う.

const unsigned char main[] = { 72, 199, 192, 1, 0, 0, 0, 72, 199, 195, 1, 0, 0, 0, 72, 141, 53, 21, 0, 0, 0, 72, 199, 194, 21, 0, 0, 0, 15, 5, 72, 199, 192, 60, 0, 0, 0, 72, 49, 255, 15, 5, 97, 108, 119, 97, 121, 115, 32, 109, 105, 115, 115, 32, 116, 104, 101, 32, 109, 97, 114, 107, 10 };

Wandboxでは動作した: https://wandbox.org/permlink/KeSJ6KkTDQGUXc3z

しかし自分の環境(Arch Linux)ではセグフォで落ちてしまう. main()に入った瞬間に落ちているようだ.

$ gdb ./a.out 
GNU gdb (GDB) 8.2
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
...
(gdb) r
Starting program: /tmp/tmp.lX2FcrqB9C/a.out 

Program received signal SIGSEGV, Segmentation fault.
0x0000555555556020 in main ()
(gdb) disass 0x0000555555556020
Dump of assembler code for function main:
=> 0x0000555555556020 <+0>:     mov    $0x1,%rax
   0x0000555555556027 <+7>:     mov    $0x1,%rbx
...
End of assembler dump.
(gdb) 

なんもわからん.完全に理解した.

おそらくExec Shieldが働いている(?)のでコンパイル時に-z execstackを渡す必要がある.

文字列を出力するプログラムを楽に難読化(?)する方法

センスは感じられないがBrainfuckを使えばとりあえずぱっと見何やってるかわからない. 配列(とポインタ)さえ扱えればどんな言語でもできるはず. 1時間もかからない.

  1. 入力した文字列を出力するBrainfuckコードを出力するプログラムをインターネット上で見つける.
  2. Brainfuckコードを得る.
  3. 好きな言語に翻訳
  4. 整形
  5. 完成.

完成した例がこちら. 1文字目で張り切りすぎてバランスが悪い. 「み」と「と」だけを使おうと努力はした.

#define Mi while
#define To putchar
char mi[3+10];main(to){
            *(mi+--to)
            +=01+3;Mi(
            *(mi+to++)
            +=01+3,*(mi                 +to--)-=3,10,
            *mi)to;To(                  ++*(mi+to+++
            01));Mi(*(                  mi+to++)-=3,
            ++*(mi+to--                 ),*(mi+01));
*(mi+to+++01)+=3;To(*(mi+to));Mi(*(mi+to++)-=3,++*(mi+to--),
*(mi+to));*(mi+to+++01)-=01+3;To(--*(mi+to));*(mi+to)-=3;Mi
(--        *(mi+to++),                  *(mi+to--)+=
01+        3,*(mi+to))                  ;To(01+*(mi+
to++       +01));Mi(*(                  mi+to++)-=01
+3         ,++*(mi+to                   --),*(mi+to
));        *(mi+to++                    +01)+=3;To
(*(mi+to));*(mi+to                      )+=01+01;
 Mi(*(mi+to++)-=                        3,*(mi+
   to--)+=01+                           01,*(
     mi+to)                             );To
                                        (*


     (mi+to                        +++01
       ));*(                    mi+to
        )+=3;               To(*(mi
         +to));          *(mi+to)
          +=-3+     10;To((*
          (mi+to  ))++);Mi
           (--*(mi+to++)
         ,*(mi+to--
       )+=3,*
     (mi+to
     ));To
     (*(mi
     +to++
      +01));
        *(mi+to)
           -=01+01;Mi(*(mi+to++)-=3,
                 ++*(mi+to--),*(



    mi+to));--*(mi+to+++01);To(*(mi+to));
                               *(mi+to)
                 +=3+3;        Mi(--
                  *(mi+        to
                  ++),*        (mi
                  +to--
                  )+=01
                 +01,*
                (mi+to
                ));++
               *(mi+
               to++
              +01
              );


               To((
               *(mi
               +to)
               )++);
               Mi(*
               (mi+
               to++
               )-=3
               ,*(mi
               +to--
               )-=01
               -3+01
               -3,*(
               mi+to
               ));++
               *(mi+
               to++
               +01)


        ;To(*
        (mi+
        to));
        *(mi
        +to)
        +=01+
        10;To
        ((*(
        mi+to
        ))--);*(mi
        +to)-=01+3;To
        ((*(     mi+to)
        )++);      Mi(*(mi
        +to++         )-=3,*
        (mi+to          --)-=
        01-3+             01-3,
        *(mi+              to));
        --*(
        mi+to
        +++01
        );To(
        *(mi+
        to++)


                          );To(*(
                          mi+ to)
                           +10);}

無題

133565, 39302, 33134, 38327, 32709, 79486, 141338, 29224, 67390, 33156, 135192, 144337, 154547, 21212, 5610, 105208, 21821, 139964, 115775, 30189, 159181, 130547, 125287, 74453, 55876, 133762, 80912, 6067, 79578, 27557, 129153, 138025, 114769, 154497, 140840, 159900, 126286, 42271, 66379, 68012, 36996, 66001, 118864, 48626, 102740, 159973, 8286, 123763, 131668, 23535, 81349, 106040, 147948, 159900, 49912, 146801, 156242, 58531, 35122, 130937, 27382, 65529, 152765, 155236, 132217, 28150, 81048, 74596, 150708, 159973, 21732, 88284, 142556, 18318, 22208, 114975, 67522, 694, 78986, 82151, 23030, 38561, 40287, 61505, 19801, 37301, 79072, 124490, 29043, 10878, 80203, 83226, 30154, 151910, 148669, 18713, 82050, 14420, 87625, 159020, 19723, 25978, 61403, 72963, 158603, 119404, 44367, 154893, 58283, 76993, 103941, 154031, 83569, 32324, 136716, 24366, 70680, 28614, 84925, 149951, 15188, 82340, 74612, 135269, 44609, 68240, 66945, 146670, 28010, 18276, 139655
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
import requests
from bs4 import BeautifulSoup
from collections import defaultdict
from random import choice

def main():
    from argparse import ArgumentParser
    parser = ArgumentParser()
    parser.add_argument('-d', '--decrypt', action='store_true')
    parser.add_argument('-u', '--aozora-url', nargs='?', type=str, default='')
    parser.add_argument('-i', '--aozora-file', nargs='?', type=str, default='')
    parser.add_argument('file', nargs=None, type=str)
    args = parser.parse_args()

    if bool(args.aozora_url) == bool(args.aozora_file):
        sys.exit(1)
    soup = None
    ENCODING = 'sjis'
    if args.aozora_url:
        req = requests.get(args.aozora_url)
        req.raise_for_status()
        soup = BeautifulSoup(req.content, 'lxml', from_encoding=ENCODING)
    else:
        with open(args.aozora_file, 'rb') as f:
            soup = BeautifulSoup(f.read(), 'lxml', from_encoding=ENCODING)
    texts = []
    for node in soup.find_all('div', class_='main_text'):
        for tag in node.find_all(['rp', 'rt']):
            tag.decompose()
        for tag in node.find_all('span', class_='notes'):
            tag.decompose()
        texts.append(node.get_text().replace('\n', '').replace(' ', ''))
    text = ''.join(texts)
    input_text = None
    with open(args.file) as f:
        input_text = f.read()
    if args.decrypt:
        print(''.join(text[int(e.strip())] for e in input_text.split(',')))
    else:
        table = defaultdict(list)
        for i, ch in enumerate(text):
            table[ch].append(i)
        print(', '.join(str(choice(table[ch])) for ch in input_text if ch in table))

if __name__ == '__main__':
    main()

SKB

C言語のmain関数の仮引数について

最近のC言語の規格では, main関数の仮引数は基本的に

int main(void)

int main(int argc, char **argv)

のどちらか(またはこれらと同等のもの)にしなければならない(C99, C11).

のだが, 今日ネット上で

int main(int argc, char **argv, char **envp)

というのを見た. ので調べた.

envpは広く利用されているが, 移植性に問題がある(C99, C11). envpにはargvと同じ形式で環境変数が記憶される. 検索してヒットしたページによると, どうやらUnix系OSでは伝統的に使われていたらしい.

現代的なプログラムで環境変数を取得する場合は標準ライブラリのgetenvを利用するべきである. POSIXシステムならば,

#include <unistd.h>
extern char **environ;

とすることで, envpと同等のグローバル変数environが利用できる.

このリンクの付け方はあまりよろしくない気がする.

あと,なぜ今まで知らなかったのかよくわからないが, argv[argc] == NULLは保証されている.

某ディストリビューションでPythonパッケージを扱う

はじめに

venvを紹介するだけの記事なので知ってる人は帰ってよし.

三行で

$ sudo apt install python3-venv
$ python3 -m venv ${PATH_TO_VIRT_ENV}
$ source ${PATH_TO_VIRT_ENV}/bin/activate

プログラミング言語のパッケージ管理システムは微妙

基本的にディストリビューションのパッケージ管理システムを使うべきだと思う. もし作るなら管理者権限の必要ないものにするべき.

某ディストロの問題

某ディストロのレポジトリはPythonのパッケージがあまり充実していない. しかし, pipでパッケージをインストールするとシステムのプログラムがうまく動作しなくなってしまう. そこ(解決がめんどくさいの)でvenvで仮想環境を作り自由にパッケージを使えるようにする.

やり方

(記憶で書いていて実際に動作を確認していないので注意)

仮想環境を~/Persistent/user_env作成する (user_venvがこの仮想環境の名前になる). シェルはBashと仮定する.

$ echo $SHELL
/bin/bash
$ echo $VENV_PATH
/(省略)/Persistent/user_env
  • pipとvenvをインストール.
$ sudo apt install python3-pip python3-venv
  • 仮想環境を作成.
$ python3 -m vev ${VENV_PATH}
  • 仮想環境をアクティベートする. プロンプトに仮想環境名が表示される.
$ source ${VENV_PATH}/bin/activate
(user_env) $ 
  • 後は好きなように環境構築
(user_env) $ pip install pyjokes
(user_env) $ pyjoke
A programmer walks into a bar and orders 1.38 root beers. The bartender informs her it's a root beer float. She says 'Make it a double!'
  • 仮想環境をディアクティベートすると元の環境に戻ってくる.
(user_env) $ deactivate
$ pyjoke
bash: pyjoke: command not found

はい.