2017年2月22日水曜日

Arch Linux上にSoftEther VPNサーバを簡単に構築

今までxl2tpとOpenSwanでL2TP/IPsec VPNサーバを構築していましたが、SoftEther VPNで簡単に構築することができました。

L2TP/IPsecだけでなく、SSTP、OpenVPNでの接続にも対応しています。

現在の環境は、LAN用NICとhostapdまとめてbr0にブリッジ接続しています。
このbr0にSoftEther VPNサーバをブリッジさせます。

まずSoftEther VPNをインストール
$ yaourt -S softethervpn-git

SoftEther VPNの起動
$ sudo systemctl start softethervpn-server


ここからはWindows等GUIが使えるPCからリモートで設定します。

まずSoftEther VPN Server Managerを公式サイトからダウンロード
http://www.softether-download.com/ja.aspx?product=softether

起動し、 新しい接続設定の作成 からホスト名を入力保存。

接続しようとするとSoftEther VPNサーバのパスワードを訊かれるので設定します。


まず仮想HUBを作成します。

"仮想HUBの管理"→"ユーザーの管理"→"新規作成"

ユーザー名とパスワードを設定して保存。


IPsec/L2TPの有効化

"IPsec / L2TP 設定"→ "L2TP サーバー昨日を有効にする (L2TP over IPsec)"にチェック


ブリッジ設定

今回はVPN通信用のtapデバイスを作成し、これをbr0に追加させます。

"ローカルブリッジ設定"を開き、

"仮想HUB"にさっき作成した仮想HUBを選択。
"新しい tap デバイスとのブリッジ接続"を選択。
"新しい tap デバイス名"に分かりやすいように名前を付ける。今回はvpn0としました。

tapデバイス名で設定した名前は"tap_デバイス名"としてネットワークに追加されます。


br0にtapデバイスを追加する

$ sudo brctl addif br0 tap_vpn0


500、4500、1701ポートを開放する
$ sudo iptables -A INPUT -p udp --dport 500 -j ACCEPT
$ sudo iptables -A INPUT -p udp --dport 4500 -j ACCEPT
$ sudo iptables -A INPUT -p udp --dport 1701 -j ACCEPT


これでVPN接続が可能になります。


接続できたら設定の永続化

ブリッジの設定(systemd-networkdの場合)

$ sudo vim /etc/systemd/network/tap_vpn0.netdev
[NetDev]
Name=tap_vpn0
Kind=tap

$ sudo vim /etc/systemd/network/tap_vpn0.network
[Match]
Name=tap_vpn0

[Network]
Bridge=br0

$ sudo iptables-save > /etc/iptables/iptables.rules
$ sudo systemctl enable softethervpn-server.service

ブリッジ周りの設定はそのままSystemdに任せてしまうと、VPNサーバ起動前にブリッジの設定が始まってしまうので先にtapデバイスを作成しています。


WindowsからSSTP接続する場合、証明書のインストールが必要になります。
mmc → 証明書(ローカルコンピュータ) → 信頼されたルート証明機関 → 証明書 にインストールすることで認証が可能になります。

2017年2月20日月曜日

LineageOSでNow on Tapを有効化する

1, 設定→ボタン→ホームボタン長押しの動作

"検索アシスタント"を選択

2, Googleアプリ→設定→画面の検索

"ホームボタンを押し続け…に指示します。"をオンにする

3, 設定→アプリ→歯車アイコン→アシストと音声入力→アシストアプリ

"Google アプリ"を選択

2017年2月19日日曜日

Android Canvasに時計を描画する


public static String timeZoneId = "Asia/Tokyo";  //タイムゾーンを変更できるようにする
private void draw() {
        Canvas canvas = holder.lockCanvas();
        canvas.drawColor(Color.GRAY);
        Paint paint = new Paint();

        // 中心座標からCANVAS_SIZE_MINの85%に黒色の円を描画
        paint.setColor(Color.BLACK);
        canvas.drawCircle(CENTER_POS[0], CENTER_POS[1],
                (float) CANVAS_SIZE_MIN / 2f * 0.85f, paint);

        // 中心座標からCANVAS_SIZE_MINの80%に白色の円を描画
        paint.setColor(Color.WHITE);
        canvas.drawCircle(CENTER_POS[0], CENTER_POS[1],
                (float) CANVAS_SIZE_MIN / 2f * 0.8f, paint);

        // 中心座標からCANVAS_SIZE_MINの70%に文字盤を描画
        paint.setColor(Color.BLACK);
        paint.setTextSize(CANVAS_SIZE_MIN / 15); // 文字サイズ
        float fontPos = CANVAS_SIZE_MIN / 2f * 0.7f;  // フォント描画位置
        float dialWidth;  // 文字の横幅
        float dialHeight = paint.descent() + paint.ascent();  // 文字の縦幅
        for (int _i = 0; _i < 12; _i++) {
            dialWidth = paint.measureText(String.valueOf(_i == 0 ? 12 : _i));  //文字の横幅
            canvas.drawText(String.valueOf(_i == 0 ? 12 : _i),
                    (float) ((Math.sin(Math.toRadians(_i * 30)) * fontPos)
                            + CENTER_POS[0]) - (dialWidth / 2),
                    (float) ((-Math.cos(Math.toRadians(_i * 30)) * fontPos)
                            + CENTER_POS[1]) - (dialHeight / 2),
                    paint);
        }

        // 針の長さを設定
        float HOUR_HAND_LENGTH = (float) CANVAS_SIZE_MIN / 2f * 0.5f;  // 短針
        float MINUTE_HAND_LENGTH = (float) CANVAS_SIZE_MIN / 2f * 0.6f;  // 長針
        float SECOND_HAND_LENGTH = (float) CANVAS_SIZE_MIN / 2f * 0.7f;  // 秒針
        float END_HAND_LENGTH = (float) CANVAS_SIZE_MIN / 2f * 0.1f;  //針の尻尾部分

        //針の太さを設定
        float HOUR_HAND_WIDTH = (float) CANVAS_SIZE_MIN / 30f;
        float MINUTE_HAND_WIDTH = (float) CANVAS_SIZE_MIN / 40f;
        float SECOND_HAND_WIDTH = (float) CANVAS_SIZE_MIN / 50f;

        Date now = new Date(System.currentTimeMillis());  //現在時刻の取得

        // 時を取得
        DateFormat formatter = new SimpleDateFormat("HH");  // 形式を時間に設定
        formatter.setTimeZone(TimeZone.getTimeZone(timeZoneId));  // 選択したタイムゾーンを適用
        float hour = Float.parseFloat(formatter.format(now));  // 現在時刻に設定

        // 分を取得
        formatter = new SimpleDateFormat("mm");  // 形式を分に設定
        formatter.setTimeZone(TimeZone.getTimeZone(timeZoneId));  // 設定したタイムゾーンを適用
        float minute = Float.parseFloat(formatter.format(now));  // 現在時刻に設定

        // 秒を取得
        formatter = new SimpleDateFormat("ss");  // 形式を秒に設定
        formatter.setTimeZone(TimeZone.getTimeZone(timeZoneId));  // 設定したタイムゾーンを適用
        float second = Float.parseFloat(formatter.format(now));  // 現在時刻に設定

        // アナログ時計用に短針と長針を修正
        // アナログ時計では短針・長針がスムーズに動くため、その修正を加える
        // 60秒を100%として、1%=0.6秒、秒 / 0.6で現在の秒針が何%かが分かる
        // 1分を100%とし、1%=0.01分、秒針の% * 0.01で+何分したら良いのかが分かる
        // 時間も同様に1時間を100%とし、1%=0.01時間、長針の% * 0.01で+何時間したら良いのかが分かる
        hour += (minute / 0.6f) * 0.01f;
        minute += (second / 0.6f) * 0.01f;

        // 針の位置を計算
        // 短針の角度 = 時間 * 30, 長針の角度 = 分 * 6, 秒針の角度 = 秒 * 6
        // θ = 角度 * π / 180
        // x = Sinθ * 針の長さ, y = -Cosθ * 針の長さ で原点からの座標が分かる
        float[] hourPos = {(float) Math.sin(Math.toRadians(hour * 30)),
                (float) -Math.cos(Math.toRadians(hour * 30))};
        float[] minutePos = {(float) Math.sin(Math.toRadians(minute * 6)),
                (float) -Math.cos(Math.toRadians(minute * 6))};
        float[] secondPos = {(float) Math.sin(Math.toRadians(second * 6)),
                (float) -Math.cos(Math.toRadians(second * 6))};

        // 短針の描画
        paint.setStrokeWidth(HOUR_HAND_WIDTH);
        canvas.drawLine(CENTER_POS[0], CENTER_POS[1],
                hourPos[0] * HOUR_HAND_LENGTH + CENTER_POS[0],
                hourPos[1] * HOUR_HAND_LENGTH + CENTER_POS[1], paint);
        canvas.drawLine(CENTER_POS[0], CENTER_POS[1],
                -hourPos[0] * END_HAND_LENGTH + CENTER_POS[0],
                -hourPos[1] * END_HAND_LENGTH + CENTER_POS[1], paint);

        // 長針の描画
        paint.setStrokeWidth(MINUTE_HAND_WIDTH);
        canvas.drawLine(CENTER_POS[0], CENTER_POS[1],
                minutePos[0] * MINUTE_HAND_LENGTH + CENTER_POS[0],
                minutePos[1] * MINUTE_HAND_LENGTH + CENTER_POS[1], paint);
        canvas.drawLine(CENTER_POS[0], CENTER_POS[1],
                -minutePos[0] * END_HAND_LENGTH + CENTER_POS[0],
                -minutePos[1] * END_HAND_LENGTH + CENTER_POS[1], paint);

        // 秒針の描画
        paint.setStrokeWidth(SECOND_HAND_WIDTH);
        canvas.drawLine(CENTER_POS[0], CENTER_POS[1],
                secondPos[0] * SECOND_HAND_LENGTH + CENTER_POS[0],
                secondPos[1] * SECOND_HAND_LENGTH + CENTER_POS[1], paint);
        canvas.drawLine(CENTER_POS[0], CENTER_POS[1],
                -secondPos[0] * END_HAND_LENGTH + CENTER_POS[0],
                -secondPos[1] * END_HAND_LENGTH + CENTER_POS[1], paint);

        holder.unlockCanvasAndPost(canvas);
}

// 時計更新用のサブクラス
class ClockUpdate extends Thread {
    public void run() {
        try {
            draw();
            Thread.sleep(100);  // 100/1000秒ごとに更新
        } catch (Exception e) {
            break;
        }
    }
}

// 時計更新用のサブクラスをスレッド化
private ClockUpdate clockUpdate = new ClockUpdate();