Windows10のネットワーク一覧にLinux(samba)を表示したい

Windows 10でsambaの共有がネットワーク一覧に見えないじゃないですか。それを何とかする話。
OSはdebian

見えない原因はSMB1が無効化されて探索プロトコルがNetBIOSからWS-Discoveryに変更されたからみたいです。ではsambaでWS-Discoveryを有効にすればよいかというとそんな設定はありません。(ここまで調べるのに無駄に時間かかった…)で対策ですが、こんな理由でWindowsのSMB1を再有効にしたくないのでなんかあるでしょと調べたところ、githubにwsddというものが公開されているのでこれを導入することで解決できます。

では導入していきましょう。まず普通にcloneしてきます。(面倒なので全部rootでやりましたが、きちんと行いたい方は適宜読み替えてください。)
あ、python3がインストールされている必要があります。

# git clone https://github.com/christgau/wsdd.git

必要なファイルをコピーして…

# cp -pf ./wsdd/src/wsdd.py /usr/local/bin/wsdd   
# cp -pf ./wsdd/etc/systemd/wsdd.service /etc/systemd/system

systemdの設定ファイルを編集します。ExecStartのパスが/usr/binになっているのと実行ユーザのコメントアウト

# vi /etc/systemd/system/wsdd.service
# cat /etc/systemd/system/wsdd.service
[Unit]
Description=Web Services Dynamic Discovery host daemon
; Start after the network has been configured
After=network-online.target
Wants=network-online.target
; It makes sense to have Samba running when wsdd starts, but is not required
;Wants=smb.service

[Service]
Type=simple
ExecStart=/usr/local/bin/wsdd --shortlog
; Replace those with an unprivledged user/group that matches your environment,
; like nobody/nogroup or daemon:daemon or a dedicated user for wsdd
#User=nobody
#Group=nobody

[Install]
WantedBy=multi-user.target

最後にsystemdのリロード、wsddの起動、wsddの自動起動設定を行って終了です。

# systemctl daemon-reload
# systemctl start wsdd
# systemctl enable wsdd

Windows10からLinuxが見えたでしょうか?お疲れ様でした。

TwitterIrcGatewayをmono 6で動かす

twitterTLS 1.2限定になって無事TwitterIrcGatewayが死亡したわけですが、ここはソースいじってLinux(debian 9)環境のmono(6.0.0.319)で動かそうという話。ソースはopentigリポジトリから、編集はVisual Studio 2017 Community版で行いました。なおそれまでdebian 7で動かしていたものをTLS 1.2対応が必要になって環境ごとバージョンアップしたら動かなくなったのであれこれやりましたが、先に結論から言うとmono 6で動かないのはTLS 1.2関係なかったです。

この記事はやったことを羅列していくのであまり原因について調べていませんというかそんな余裕ないです。

蛇足

ちなみに本稿と関係ないですが、WindowsTLS 1.2の対応はターゲットフレームワークを.NET 4.5にしてMainの頭に

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

と書いておけばいいです。monoではなくても動きました。理由はよくわかってません。レジストリをいじるハックが出回ってるのでソースいじりたくない人はそちらでもいいと思います。

本題

本題に入ります。まず、debian公式のmonoは古いのでまず公式のmonoをインストールします。何度も言うように動かない原因は別にあったので今となっては必要あるかはわかりませんが!

# apt install apt-transport-https dirmngr gnupg ca-certificates
# apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
# echo "deb https://download.mono-project.com/repo/debian stable-stretch main" | tee /etc/apt/sources.list.d/mono-official-stable.list
# apt-get update
# apt-get install mono-devel ca-certificates-mono

次にローカル環境にソースコードをcloneしてきて、Visual Studioで開き、すべてのプロジェクトのターゲットフレームワークをv4.5にします。これも必要あるかはわかりません!がこの記事はやったことをただ書いていきます。

git clone https://github.com/opentig/TwitterIrcGateway.git

ここから本題です。monoでTwitterIrcGatewayが動かないのは、TwitterIrcGatewayCore内AddInManager.cs 150行目_sessionがnullになっておりここで止まるからです。ということでnullにならないようにしましょう。同ファイル63,64行目に問題がります。

            _server = ServerProxy.GetTransparentProxy() as Server;
            _session = SessionProxy.GetTransparentProxy() as Session;

これを

            _server = (Server)ServerProxy.GetTransparentProxy();
            _session = (Session)SessionProxy.GetTransparentProxy();

こうします。なんでこれで動くのかは例によってわかっていません。これでRelease設定でビルドしてBin/Releaseディレクトリ内ファイルをアップロードすれば終わりです。

お疲れ様でした。

Windows 10 October 2018 Update(1809)同士のリモートデスクトップができない

あまり情報がなくて再現パターンがはっきりとわからないのですがウチの環境は100%再現しているので書く。

事象としては、Windows 10(1809)からWindows 10 Pro(1809)にRDPすると画面が黒くなる、ログオンできてもフリーズするなどして操作できません。接続の状態は良好なので回線速度の問題ではないと思います。ホストと同じネットワークにいるWindows 8 Proには問題なく接続できますしandroid端末からは問題なくWindows 10 Pro(1809)にRDPできています。

私の環境を書いておくと、
・外部からVPNを用いてWindows 10(1809)からWindows 10 Pro(1809)にアクセス
・リモートマシンの指定はIPアドレス
・ログインアカウントはMSアカウントに紐づけ
これくらいでいいかな?

VPNがないとどうだとか、マシン名で指定するとどうなるかとか条件ははいろいろと確かめたいのだけど、しばらく試せないので保留。

ぐぐってみた感じ1809のmstsc.exeのバグのようで古いmstsc.exeを持ってくることで解決しました。参考までに試したmstsc.exe取得もとはWindows 8 Pro, Windows 10 Pro(1511)。Windows\System32配下から下記のファイルを取得し、適当なフォルダに格納します。

> tree /F
│  mstsc.exe
│  mstscax.dll
│
└─ja-JP
        mstsc.exe.mui
        mstscax.dll.mui

Windows Helloに対応していると(?)Windows Helloのログオン画面が出るのですが、ホストが対応していないのか設定が足りないのか接続できません。キャンセルしてパスワード認証することでログオンできます。1809のmstsc.exeでは出ないのでたぶんこの辺り改修があったのでしょう。

UWPウインドウからパッケージ名を取りたい

UWPアプリはApplicationFrameWindowクラスウインドウの子供にWindows.UI.Core.CoreWindowクラスウインドウが別プロセスでいるのでそこからプロセスIDを取得してよしなに。って感じの説明がぐぐるとヒットしますが、UWPウインドウがアクティブの場合、Windows.UI.Core.CoreWindowクラスウインドウが何故か存在しません。そこでApplicationFrameWindowクラスウインドウから情報を取得ってことになりますなるなった。

SHGetPropertyStoreForWindowを呼び出してIID_IPropertyStoreからPKEY_AppUserModel_IDを取得することでパッケージを取得できます。

IPropertyStore store;
Guid IID_IPropertyStore = new Guid("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99");
SHGetPropertyStoreForWindow(window.Handle, ref IID_IPropertyStore, out store);
PropertyKey PKEY_AppUserModel_ID = new PropertyKey(
    new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"),
    5);
store.GetValue(ref PKEY_AppUserModel_ID, out PROPVARIANT v);
appName = Marshal.PtrToStringUni(v.value);

twitter公式で9E2F88E3.Twitter_wgeqdkkx372wm!x554f661dyd360y462cy8743yf8a99b7d41dbxが取れたら成功。

Zabbix v3.4でmirakurunの監視効率化を図る

更新しないといったなあれはry

yarukizero.hatenablog.jp

はい前回の続きです。
というか前回の記事の推敲中に気づいたのですが、Zabbix v3.4から追加された依存アイテムでmirakurunへのアクセス数を1回にできることが分かったので早速対応したという。

まずZabbixのmirakurun.confは前回と比べ驚きの1行に。

UserParameter=mirakurun.status,curl -Ss http://localhost:40772/api/status

でもって定義したmirakurun.statusを受け取るアイテムを作成します。そこから各種ステータス値を取るアイテムを追加していくわけですがアイテムのタイプをZabbixエージェントから依存アイテムに変更。マスターアイテムに先ほど追加したJSONを指定します。
f:id:azumyar:20180331230951p:plain

任意のキー名を決めたら保存処理タブに移って保存前の処理ステップにJSON Pathを追加、キーのパスを記述します。pidが取りたい場合$process.pidで。必要なアイテムを作り終わったら再度グラフを作っていきます。グラフに関しては特に迷うところないと思いますので割愛。

f:id:azumyar:20180331231831p:plain


お疲れ様でした。

mirakurunをZabbixで監視したい

mirakurunとchinachuγは導入済みの前提で話が進みます。当方の環境はdebianでZabbixは3.4。

mirakurun公式がもっているmuninプラグインみたいことをZabbixでもやりたい!という導入から。で方針としてmirakurunのstatus APIを叩いてJSONをパースすればよいという方向。まずはコマンドからJSONをよしなにパースしてくれるjqを導入する。

apt-get install jq

これでcurlと組み合わせて

curl http://localhost:40772/api/status | jq -r .process.pid

こうするとプロセスIDが取れる。IPアドレスとポートは設定の環境に合わせて読み替えてほしい。このままだと進捗が表示されていまい困ったことになるので-sオプションで進捗は非表示に。でもエラーの場合はなんかほしいので-Sもつけちゃう。

方針が決まったところで/etc/zabbix/zabbix_agentd.d に設定ファイルmirakurun.confを置いてstatus APIを叩いてユーザパラメータに格納していく。zabbixエージェントが古い場合はこのディレクトリ存在しないのでzabbix_agentd.confのinclude設定を有効化すればいい。

UserParameter=mirakurun.memory[*],curl -Ss http://localhost:40772/api/status | jq -r .process.memoryUsage.$1
UserParameter=mirakurun.stream[*],curl -Ss http://localhost:40772/api/status | jq -r .streamCount.$1
UserParameter=mirakurun.error[*],curl -Ss http://localhost:40772/api/status | jq -r .errorCount.$1
UserParameter=mirakurun.timer[*],curl -Ss http://localhost:40772/api/status | jq -r .timerAccuracy.$1.avg
UserParameter=mirakurun.events,curl -Ss http://localhost:40772/api/status | jq -r .epg.storedEvents 

ユーザパラメータを定義したらzabbix-agentを再起動。


続いてZabbix Serverの設定。
ここからは文章で書くのめどいのでスクリーンショットを貼っていく。

こんな感じでアイテムを作って
f:id:azumyar:20180331063951p:plain

f:id:azumyar:20180331064450p:plain

こんな感じでグラフにする

f:id:azumyar:20180331065020p:plain

f:id:azumyar:20180331065137p:plain



今回特に触れないけど録画のストレージ容量はchinachuのほうのAPIから同じ感じで取得できるしグラフもかける。

30秒毎にTCPセッションがはられるのは無駄な気しかしないのでキャッシュするなにがしを噛ましたほうがいい気がするがおいおい。まだ構築したばかりで運用はこれからなので気づいたことがあればアップデートされるかもしれないしされないと思う。

Xamarin.AndroidでISerializableする話

結論=>無意味。JSONあたりにシリアライズして文字列としてやり取りしよう。

以下結論に至るまでことの顛末を記す。
Androidな開発でクラスをシリアライズすることは多々ある。Activityの遷移とか保存とかでBundkeにシリアライズして受け渡したりとか。そこでクラスを作る。Javaのシリアライザを使いたいのでJava.Lang.Objectから派生しよう。

class JavaSerializable : Java.Lang.Object, Java.IO.ISerializable { }

ところがこれだと復元時に例外が発生し、復元されない。

E/AndroidRuntime(15922): FATAL EXCEPTION: main
E/AndroidRuntime(15922): Process: App1.App1, PID: 15922
E/AndroidRuntime(15922): android.runtime.JavaProxyThrowable: System.NotSupportedException: Unable to activate instance of type App1.Moc from native handle 0x1d (key_handle 0x2bc79163). ---> System.MissingMethodException: No constructor found for App1.Moc::.ctor(System.IntPtr, Android.Runtime.JniHandleOwnership) ---> Java.Interop.JavaLocationException: Exception of type 'Java.Interop.JavaLocationException' was thrown.

原因はXamarinがインスタンスの復旧処理を行う場合(IntPtr, Android.Runtime.JniHandleOwnership)なコンストラクタを介して行うからだそうだ。つまり下記で回避できる。

class JavaSerializable : Java.Lang.Object, Java.IO.ISerializable {
    public JavaSerializable() { }
    public JavaSerializable(
        IntPtr handle,
        Android.Runtime.JniHandleOwnership transfer
    ) : base(handle, transfer) { }
}


しかしこれでエラーは出なくなるもののよくよく見るとメンバが規定値で復元されていない。調べてみるとJavaのISerializableはコンパイラがreadObject, writeObjectメソッドを生成して処理するけどXamarinはそんなことしてくれないので自分で作って保存復元処理を書く必要がある。それを踏まえてついでにコードの再利用を鑑みると下の感じに。

class JavaSerializable : Java.Lang.Object, Java.IO.ISerializable {
    public JavaSerializable() { }
    public JavaSerializable(
        IntPtr handle,
        Android.Runtime.JniHandleOwnership transfer
    ) : base(handle, transfer) { }

    [Export("readObject", Throws = new[] {
        typeof (Java.IO.IOException),
        typeof (Java.Lang.ClassNotFoundException)})]
    private void __ReadObject(Java.IO.ObjectInputStream source) {
        var byteArray = new byte[source.Available()];
        source.Read(byteArray);
        using (var memStream = new MemoryStream()) {
            var binForm = new BinaryFormatter();
            memStream.Write(byteArray, 0, byteArray.Length);
            memStream.Seek(0, SeekOrigin.Begin);
            var obj = binForm.Deserialize(memStream);
            this.Obj = obj;
        }
    }

    [Export("writeObject", Throws = new[] {
        typeof (Java.IO.IOException),
        typeof (Java.Lang.ClassNotFoundException)})]
    private void __WriteObject(Java.IO.ObjectOutputStream destination) {
        var bf = new BinaryFormatter();
        using (var ms = new MemoryStream()) {
            bf.Serialize(ms, this.Obj);

            destination.Write(ms.ToArray());
        }
    }

    public object Obj { get; set; }
}


C#だと*thisの差し替えなんてことはできないので折衷案としてプロパティObjに保存したいクラスを格納して~といった感じになるなった。しかしObjがobject型なのはキモい。ジェネリックを使ってタイプセーフにしたいところである。が、ISerializableなクラスをジェネリッククラスにすると復元時にジェネリックパラメータが不明なので復元できない。困った。

さて途中でお気づきだと思うが自分でbyteにシリアライズ、デシリアライズするならクラス化の必要なくbyteでBndleにputすればよい気がするし、今時ならJSONシリアライズしてやりとりしたほうが絶対再利用性が高い。

という感じで結論に至る。