Tommy 碎碎念
https://blog.teatime.com.tw/
Tommy Wu's blog
tommy
2024-03-19T11:50:25Z
-
hyper-v 突然無法啟動任何虛擬主機
https://blog.teatime.com.tw/1/post/494
<p>上星期把在 Windows 10 裡頭的 hyper-v 中的 Debian 主機由 11 升級到 12, 重開機後, 發現在 build android 時會有錯誤, 弄了一天才發現是<a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1036755" target="_blank" rel="noopener"> kernel 的問題</a>, 換回原本 Debian 11 的舊 kernel 後, 果然可以正常運作.</p>
<p>今天試著自己加上 patch 後, 做了一個 6.1.27 的 kernel 來用, 結果重開機後, 發現無法正常開機, 想到自己做的 kernel 是 unsigned 的, 安全開機要關閉才可以. 結果關了之後, 反而整個 VM 就無法打開了. 試著弄一個空的 VM 也不行, 把安全開機改回去也不行.</p>
<p>上網 google 找了一下, 發現<a href="https://communities.vmware.com/t5/Nested-Virtualization/hyper-v-crashing/td-p/522812" target="_blank" rel="noopener">以前的版本有類似的問題</a>, 果然惡意探索保護中的流量控制防護 (CFG) 關閉之後就可以正常啟動 VM 了 (只針對 vmcompute.exe 關閉就可以).</p>
<p>不過上星期到剛剛, 也沒更新系統, 不知道為什麼重開 VM 就有這問題.</p>
Software
Windows 10
2023-06-27T20:32:57Z
tommy
-
Linux 上面的 samba 加入 AD 之後的一些問題
https://blog.teatime.com.tw/1/post/485
<p>記錄一下當 Linux 上面透過 krb5-user 與 winbind 加入 AD 之後的一些小問題.</p><ul><li>kinit 執行會失敗</li></ul>通常是因為.... 大小寫不一樣造成的. 要確定帳號 @ 後面的 domain 要跟 krb5.conf 中的完全一樣.<br /><ul><li>本機上的使用者無法透過 passwd 修改本機密碼</li></ul><p> 這個部份是在 /etc/pam.d/common-password (不同的系統可能名稱不一樣), 通常會加上一筆</p><pre class="bash"><div class="insertcode">password <span class="br0">[</span><span class="re2">success</span>=<span class="nu0">2</span> <span class="re2">default</span>=ignore<span class="br0">]</span> pam_krb5.so</div></pre><p>的設定在 pam_unix.so 之前. 所以在執行 passwd 時, 就會去異動 AD 上的密碼, 但該使用者又非 AD 帳號, 所以會有問題.</p><p>這時可以在 pam_krb5.so 後面加上 minimum_uid=10000 的參數 (數字自行決定, 就是 AD mapping 過來的帳號的最小值), 這樣子就可以避免這個問題了. </p><ul><li> 有些帳號與群組使用 wbinfo -g 或 wbinfo -u 時可以查到, 但無法在 samba 中使用</li></ul><p>通常出現這情形時, 使用 wbinfo -i (--user-info 或 --group-info) 時, 會無法正常取得資料. 透過 getent passwd 或 getent group 查詢時也會查不到 (所以設定好後, 建議用 getent passwd/group 來驗證是否可用, 不要用 wbinfo -u/-g).</p><p>這個問題有可能是因為在 smb.conf 中有加上這個參數造成的:</p><pre class="bash"><div class="insertcode">winbind normalize names = Yes</div></pre><p>移除後就應該會正常了 (當初不知是那兒抄來的參數... 想不起來為什麼會用到).</p><ul><li>samba 分享出來的路徑, 根目錄 (其他的也有可能) 無法寫入新的檔案或目錄.</li></ul><p>這個不確定是不是 samba 新版本造成的, 因為一直以來相同的設定都可以用.</p><p>我們習慣在 smb.conf 中對該分享設定</p><pre class="ini"><div class="insertcode"> create mode <span class="sy0">=</span><span class="re2"> 644</span><br /> directory mode <span class="sy0">=</span><span class="re2"> 755</span><br /> force user <span class="sy0">=</span><span class="re2"> nobody</span><br /> force group <span class="sy0">=</span><span class="re2"> nogroup</span><br /> force create mode <span class="sy0">=</span><span class="re2"> 644</span><br /> force directory mode <span class="sy0">=</span><span class="re2"> 755</span><br /> create mask <span class="sy0">=</span><span class="re2"> 0644</span></div></pre><p>發現在新的機器上會有這個問題. 後來是改成 664 與 775 的設定, 然後把該目錄下面的權限把 group 的寫入權限也加上後, 就可以正常使用了.</p>
Linux
Software
2017-03-23T10:00:34Z
tommy
-
Apache 使用 AD 帳號密碼認證的處理
https://blog.teatime.com.tw/1/post/484
<p><a href="https://httpd.apache.org/" target="_blank">Apache</a> 本身有 <a href="https://httpd.apache.org/docs/2.4/mod/mod_authnz_ldap.html" target="_blank">mod_authnz_ldap</a> 這個模組可以支援 ldap 的認證. 使用上並不困難, 使用下列的設定就可以:</p><pre class="apache"><div class="insertcode"> <<span>Location</span> /><br /> <span>AuthName</span> <span>"Enter AD's Username/Password"</span><br /> <span>AuthType</span> Basic<br /> <span>AuthBasicProvider</span> ldap<br /> <span>AuthLDAPBindDN</span> <span>"CN=xxx,CN=Users,DC=xxx,DC=xxx,DC=xxx,DC=xx"</span><br /> <span>AuthLDAPBindPassword</span> <span>"password"</span><br /> <span>AuthLDAPURL</span> <span>"ldap://adserver:3268/DC=xxx,DC=xxx,DC=xxx,DC=xx?sAMAccountName?sub?(objectClass=*)"</span><br /> <span>AuthLDAPGroupAttributeIsDN</span> <span>on</span><br /> <span>require</span> ldap-<span>group</span> CN=DEPT_xxx,DC=xxx,DC=xxx,DC=xxx,DC=xx<br /> <span>require</span> ldap-<span>user</span> xxx<br /> <span>ErrorDocument</span> <span>401</span> <span>"Please use AD's username and password to login."</span><br /> </<span>Location</span>></div></pre><p>是先透過一個帳號去 bind, 然後檢查帳號密碼是否正確, 再去判斷是否在允許的帳號或群組內.</p><p>我們用上面的設定跑了一陣子, 最近因為群組的設定有些變動, 會有 nested group 的情形, 就是群組內有另一個群組, 並不是直接是使用者. 這時發現上面的設定就不能正常運作了. </p><p>依據 <a name="AuthLDAPMaxSubGroupDepth" href="https://httpd.apache.org/docs/2.4/mod/mod_authnz_ldap.html#authldapmaxsubgroupdepth" target="_blank" title="AuthLDAPMaxSubGroupDepth">AuthLDAPMaxSubGroupDepth</a> <a name="authldapmaxsubgroupdepth" id="authldapmaxsubgroupdepth" title="authldapmaxsubgroupdepth"></a> 的預設值, 應該會檢查 10 層內的群組成員才對, 不過... 實際上就是不能用.</p><p>試了一陣子, 發現在 <a name="AuthLDAPSubGroupClass" href="https://httpd.apache.org/docs/2.4/mod/mod_authnz_ldap.html#authldapsubgroupattribute" target="_blank" title="AuthLDAPSubGroupClass">AuthLDAPSubGroupClass</a> <a name="authldapsubgroupclass" id="authldapsubgroupclass" title="authldapsubgroupclass"></a>的預設值只有 groupOfNames groupOfUniqueNames 這兩個, 而在 Windows AD 裡頭, 群組的 objectClass 屬性是 top; group, 所以 apache 在查詢時, 並不知道那是一個群組.</p><pre class="apache"><div class="insertcode"> AuthLDAPSubGroupClass <span>group</span></div></pre><p>加上這個設定後, 重啟 apache 就可以正常的驗證到子群組的成員了. </p>
Linux
Software
2017-03-22T10:42:55Z
tommy
-
安裝 xware (迅雷遠程下載) 下載迅雷離線的檔案
https://blog.teatime.com.tw/1/post/482
<p>最早的時候, 是用一台 VM 跑迅雷來下載 (比較快沒錯), 不過後來買了 NAS 之後, 就改用 <a href="https://www.synology.com/zh-tw/" target="_blank">Synology</a> 裡頭的 Download Station 來下載迅雷離線上的檔案 (用的應該是 <a href="https://github.com/iambus/xunlei-lixian" target="_blank">xunlei-lixian 這個軟體</a>), 雖然速度不快, 但是擺著沒多久也一樣能抓完. 不過.... 這幾天, 突然連不上, 一直說我的密碼不對, 不過用瀏覽器連上都正常. 所以.... 就試著裝 <a href="http://luyou.xunlei.com/forum-51-1.html" target="_blank">xware</a> 來用.</p><p>基本上, xware 就是迅雷的 linux 版本, 一開始的版本, 使用上並沒有任何限制, 不過在 1.0.31 版本之後, 就改用試用版的方式, 每個版本都只有三個月的試用期限, 所以.... 網路上教人安裝的都是 1.0.31 的版本.</p><p>安裝與使用不難, 就是抓了對應的 zip 版本, 回來解開來之後, 執行 portal 就可以了. (這部份 google 一下應該就有一堆) </p><p>那... 這篇只是要記錄一下我自己碰到的問題與解決方法.</p><ul><li>Synology DS1813+ 無法正常執行</li></ul><p>這個應該會有找不到 libz.so.1 的訊息. 因為 Synology 在這機器上的 DSM 是 x86-64 的版本, 而抓回來的 xware 1.0.31 是 x86 的版本, 而 DSM 上頭雖然有支援 x86 的程式, 不過並沒有包含 x86 的 zlib 元件. 可以自行到 x86 或 x86-64 的 Linux 上頭找 x86 的 libz.so.1.2.8 來用就可以 (應該任何 1.2.x 版本都可以).</p><p>以 Debian x86-64 來說, 可以在 /lib/i386-linux-gnu/ 底下找到這個檔案, 複製到 NAS 的 /lib/i686/ 底下, 再做一個 libz.so.1 的 symlink 就可以正常執行了.</p><pre class="bash"><div class="insertcode">root<span class="sy0">@</span>DS1813:<span class="sy0">/</span>lib<span class="sy0">/</span>i686<span class="co0"># ls -la libz*</span><br />lrwxrwxrwx <span class="nu0">1</span> root root <span class="nu0">13</span> Jul <span class="nu0">27</span> <span class="nu0">15</span>:<span class="nu0">24</span> libz.so.1 -<span class="sy0">></span> libz.so.1.2.8<br /><span class="re5">-r-xr-xr-x</span> <span class="nu0">1</span> root root <span class="nu0">112284</span> Jul <span class="nu0">27</span> <span class="nu0">15</span>:<span class="nu0">24</span> libz.so.1.2.8</div></pre><ul><li>在 ARM 的 linux 上頭,無法正常執行</li></ul><p>這問題其實與前一個問題是一樣的, 只是不知道為什麼 xware 的 armel_v5te 裡頭的檔案, 在 armv7l 的系統上, 用 ldd 看不出任何需要的 .so 檔案, 執行時也不是出現找不到某個 .so 的檔案, 而是出現 No suh file or directory 的訊息. 因為猜不出是少那個東西, 就先用 file 看一下那個檔案的資訊:</p><pre class="bash"><div class="insertcode">fw2:<span class="sy0">/</span>var<span class="sy0">/</span>spool<span class="sy0">/</span>thunder<span class="co0"># file portal</span><br />portal: ELF <span class="nu0">32</span>-bit LSB executable, ARM, EABI5 version <span class="nu0">1</span> <span class="br0">(</span>SYSV<span class="br0">)</span>, dynamically linked, interpreter <span class="sy0">/</span>lib<span class="sy0">/</span>ld-linux.so.3, <span class="kw1">for</span> GNU<span class="sy0">/</span>Linux 2.6.22, not stripped</div></pre><p>看起來是需要 /lib/ld-linux.so.3 這個檔案. 不過, 在近期的 Debian 上頭 (其他的版本應該也是), 支援 multi-arch 的關係, 很多的 shared library 是分在 /lib/ 下頭的不同目錄. 所以這個檔麼實際是在 /lib/arm-linux-gnueabihf/ (這是 armhf 的版本, 如果是用 armel 的版本, 應該會是/lib/arm-linux-gnueabi/ 下面), 只要自己做一個 symlink 就可以:</p><pre class="bash"><div class="insertcode">fw2:<span class="sy0">/</span>lib<span class="co0"># ls -la ld-linux*</span><br />lrwxrwxrwx <span class="nu0">1</span> root root <span class="nu0">30</span> Jul <span class="nu0">20</span> 02:<span class="nu0">22</span> ld-linux-armhf.so.3 -<span class="sy0">></span> arm-linux-gnueabihf<span class="sy0">/</span>ld-<span class="nu0">2.23</span>.so<br />lrwxrwxrwx <span class="nu0">1</span> root root <span class="nu0">33</span> Jul <span class="nu0">28</span> <span class="nu0">16</span>:07 ld-linux.so.3 -<span class="sy0">></span> arm-linux-gnueabihf<span class="sy0">/</span>ld-linux.so.3</div></pre><p>我的機器上是加了上頭的 symlink 就可以正常執行了 (如果不行, 應該是有少其他的 .so 吧, 要自己試看看, 如果用 x86 的版本來看, 需要的是下頭的 .so:</p><pre class="bash"><div class="insertcode">mail:<span class="sy0">/</span>var<span class="sy0">/</span>spool<span class="sy0">/</span>thunder<span class="co0"># ldd portal</span><br /> libz.so.1 =<span class="sy0">></span> <span class="sy0">/</span>lib<span class="sy0">/</span>i386-linux-gnu<span class="sy0">/</span>libz.so.1 <span class="br0">(</span>0xf776c000<span class="br0">)</span><br /> libdl.so.2 =<span class="sy0">></span> <span class="sy0">/</span>lib<span class="sy0">/</span>i386-linux-gnu<span class="sy0">/</span>libdl.so.2 <span class="br0">(</span>0xf7767000<span class="br0">)</span><br /> libc.so.6 =<span class="sy0">></span> <span class="sy0">/</span>lib<span class="sy0">/</span>i386-linux-gnu<span class="sy0">/</span>libc.so.6 <span class="br0">(</span>0xf75b3000<span class="br0">)</span><br /> <span class="sy0">/</span>lib<span class="sy0">/</span>ld-linux.so.2 <span class="br0">(</span>0x56606000<span class="br0">)</span></div></pre><ul><li>下載位置的對應</li></ul><p>正常執行後, 在 /tmp/thunder/volumes/ 目錄下會有對應的磁碟機與實際路徑. 預設 xware 會使用所有有權限的 mount point (會產生 ThunderDB 目錄), 為了限制存取的目錄, 可以透過 xware 安裝目錄下的 cfg/thunder_mounts.cfg 的檔案來限制 (新版好像可以用白名單的方式, 不過... 1.0.31 似乎只能用黑名單的方式處理)</p><pre class="ini"><div class="insertcode">invalid_mounts<br /><span class="br0">{</span><br /> /dev/mapper/vg-tmp /var/tmp<br /> tmpfs /dev/shm<br /><span class="br0">}</span></div></pre><p>每行第一個是 mount 的 device, 第二個是 mount 的路徑.</p><p>除了這個方式外, 就是利用權限來控制, 可以用一個帳號來執行 xware, 然後任何 mount point 都不要給這個帳號寫入的權限. 接著在 /media/ 下面建一個目錄, 給這個帳號寫入的權限, 再用 mount --bind 的方式, 把實際要存放的路徑 (當然該帳號要有寫入權限) mount 到這個目錄就可以. </p>用 xware 跑了幾天, 感覺比 NAS 上頭用的 xunlei-lixian 似乎下載速度快了一些. 也許該早點換過來用...
Linux
Software
2016-07-29T06:29:49Z
tommy
-
修正 Cisco AnyConnect 在 Windows 無法正常使用問題
https://blog.teatime.com.tw/1/post/481
<p>在安裝 <a href="http://www.infradead.org/ocserv/" target="_blank">OpenConnect VPN server</a> 之後, 有使用 AnyConnect 的 client 試過, 發現一直無法正常連線. (應該說可以連線, 但是在啟用網卡沒多久後會跳到修護網卡然後就說無法正常連線)</p><p>查了一下 Google, 似乎都只有提到下面兩種作法:</p><ul><li><a href="http://www.robertschultz.org/cisco-anyconnect-vpn-with-windows-8-fixed/" target="_blank">修改 vpnva 的 DisplayName 值</a>. </li><li><a href="https://www.reddit.com/r/Windows10/comments/34duvd/cisco_anyconnect_still_broken_on_10074/" target="_blank">停用 ipv6, 改 ipv4 為 dhcp</a>.</li></ul><p>不過... 我試了都沒用.... 原本打算放棄, 後來發現, 有些機器上又可以正常使用, 比對一下, 似乎有裝 OpenConnect Client 或 OpenVPN 的都無法正常使用. 所以懷疑可能是與 TAP 網卡有衝突... 就試著把 TAP 網卡停用, 果然就可以正常連線了.</p><p>不過由於每次要用 AnyConnect 就要停用 TAP 網卡, 要用 OpenConnect 或 OpenVPN 就要去啟用 TAP 網卡, 用滑鼠做比較麻煩, 就試著用 netsh 指令來做. 不過... 這需要使用到網卡名稱, 而預設安裝後, 在英文下可能是 "Local Area Network X", 而中文下可能是 "區域網路 X", 不太好下指令... 所以就先到控制台把這個網卡名改成比較容易使用的 TAP0901, 然後用下面的指令停用:</p><pre class="winbatch"><div class="insertcode">netsh interface set interface name=TAP0901 admin=<span class="kw2">disable</span></div></pre><p>要啟用就用:</p><pre class="winbatch"><div class="insertcode">netsh interface set interface name=TAP0901 admin=<span class="kw2">enable</span></div></pre><p>這樣只要點一下就能做到啟用與停用的動作.</p>
Software
VPN
2016-07-16T11:32:15Z
tommy
-
讓 FileZilla 儲存所選擇的憑證, 而非只能儲存站台本身的憑證
https://blog.teatime.com.tw/1/post/478
<p>由於<a href="https://blog.teatime.com.tw/1/post/477" target="_blank">之前提到改用 Let's Encrypt 來產生憑證</a>之後, 會造成平均每兩個月就會更換一次憑證, 而 <a href="https://filezilla-project.org/index.php" target="_blank">FileZilla</a> 本身只能儲存並信任站台本身的憑證, 所以... 變成每次更換憑證會就會要求再信任一次.</p><p>所以, 就改了一下 FileZilla, 把憑證儲存的地方, 改成依據目前選擇查閱的憑證來儲存 (這時會改存 CN 而不是 Host, 而 Port 一律為 0), 然後在每次檢查信任憑證的地方, 改成檢查所有的憑證, 只要有一個是信任的就可以.</p><pre class="diff"><div class="insertcode">diff -Nurp filezilla.orig/src/interface/verifycertdialog.cpp filezilla/src/interface/verifycertdialog.cpp<br /><span class="re3">--- filezilla.orig/src/interface/verifycertdialog.cpp 2016-05-25 16:19:18.590183991 +0800</span><br /><span class="re4">+++ filezilla/src/interface/verifycertdialog.cpp 2016-05-26 13:14:03.897443962 +0800</span><br /><span class="re6">@@ -147,6 +147,7 @@ void CVerifyCertDialog::ShowVerification</span><br /> XRCCTRL<span class="br0">(</span>*m_pDlg, "ID_ALWAYS", wxCheckBox<span class="br0">)</span>->Hide<span class="br0">(</span><span class="br0">)</span>;<br /> <span class="br0">}</span><br /> <br /><span class="re8">+ m_curSelect = <span class="nu0">0</span>;</span><br /> m_certificates = notification.GetCertificates<span class="br0">(</span><span class="br0">)</span>;<br /> if <span class="br0">(</span>m_certificates.size<span class="br0">(</span><span class="br0">)</span> == <span class="nu0">1</span><span class="br0">)</span> <span class="br0">{</span><br /> XRCCTRL<span class="br0">(</span>*m_pDlg, "ID_CHAIN_DESC", wxStaticText<span class="br0">)</span>->Hide<span class="br0">(</span><span class="br0">)</span>;<br /><span class="re6">@@ -230,6 +231,52 @@ void CVerifyCertDialog::ShowVerification</span><br /> m_pDlg = <span class="nu0">0</span>;<br /> <span class="br0">}</span><br /> <br /><span class="re8">+wxString CVerifyCertDialog::GetCNValue<span class="br0">(</span>const wxString& dn<span class="br0">)</span></span><br /><span class="re8">+<span class="br0">{</span></span><br /><span class="re8">+ wxStringTokenizer tokens<span class="br0">(</span>dn, _T<span class="br0">(</span>","<span class="br0">)</span><span class="br0">)</span>;</span><br /><span class="re8">+</span><br /><span class="re8">+ std::list<wxString> tokenlist;</span><br /><span class="re8">+ while <span class="br0">(</span>tokens.HasMoreTokens<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span></span><br /><span class="re8">+ tokenlist.push_back<span class="br0">(</span>tokens.GetNextToken<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span>;</span><br /><span class="re8">+</span><br /><span class="re8">+ wxString prefix = _T<span class="br0">(</span>"CN="<span class="br0">)</span>;</span><br /><span class="re8">+ int len = prefix.Length<span class="br0">(</span><span class="br0">)</span>;</span><br /><span class="re8">+</span><br /><span class="re8">+ wxString value;</span><br /><span class="re8">+</span><br /><span class="re8">+ bool append = false;</span><br /><span class="re8">+</span><br /><span class="re8">+ auto iter = tokenlist.begin<span class="br0">(</span><span class="br0">)</span>;</span><br /><span class="re8">+ while <span class="br0">(</span>iter != tokenlist.end<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span></span><br /><span class="re8">+ <span class="br0">{</span></span><br /><span class="re8">+ if <span class="br0">(</span>!append<span class="br0">)</span></span><br /><span class="re8">+ <span class="br0">{</span></span><br /><span class="re8">+ if <span class="br0">(</span>iter->Left<span class="br0">(</span>len<span class="br0">)</span> != prefix<span class="br0">)</span></span><br /><span class="re8">+ <span class="br0">{</span></span><br /><span class="re8">+ ++iter;</span><br /><span class="re8">+ continue;</span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ if <span class="br0">(</span>!value.empty<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span></span><br /><span class="re8">+ value += _T<span class="br0">(</span>"\n"<span class="br0">)</span>;</span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ else</span><br /><span class="re8">+ <span class="br0">{</span></span><br /><span class="re8">+ append = false;</span><br /><span class="re8">+ value += _T<span class="br0">(</span>","<span class="br0">)</span>;</span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ value += iter->Mid<span class="br0">(</span>len<span class="br0">)</span>;</span><br /><span class="re8">+ if <span class="br0">(</span>iter->Last<span class="br0">(</span><span class="br0">)</span> == '\\'<span class="br0">)</span></span><br /><span class="re8">+ <span class="br0">{</span></span><br /><span class="re8">+ value.RemoveLast<span class="br0">(</span><span class="br0">)</span>;</span><br /><span class="re8">+ append = true;</span><br /><span class="re8">+ len = <span class="nu0">0</span>;</span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ auto remove = iter++;</span><br /><span class="re8">+ tokenlist.erase<span class="br0">(</span>remove<span class="br0">)</span>;</span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ return value;</span><br /><span class="re8">+<span class="br0">}</span></span><br /><span class="re8">+</span><br /> void CVerifyCertDialog::ParseDN<span class="br0">(</span>wxWindow* parent, const wxString& dn, wxSizer* pSizer<span class="br0">)</span><br /> <span class="br0">{</span><br /> pSizer->Clear<span class="br0">(</span>true<span class="br0">)</span>;<br /><span class="re6">@@ -329,11 +376,28 @@ bool CVerifyCertDialog::IsTrusted<span class="br0">(</span>CCerti</span><br /> <br /> LoadTrustedCerts<span class="br0">(</span><span class="br0">)</span>;<br /> <br /><span class="re7">- unsigned int len;</span><br /><span class="re7">- CCertificate cert = notification.GetCertificates<span class="br0">(</span><span class="br0">)</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span>;</span><br /><span class="re7">- const unsigned char* data = cert.GetRawData<span class="br0">(</span>len<span class="br0">)</span>;</span><br /><span class="re8">+ for <span class="br0">(</span>unsigned int i = <span class="nu0">0</span>; i < notification.GetCertificates<span class="br0">(</span><span class="br0">)</span>.size<span class="br0">(</span><span class="br0">)</span>; ++i<span class="br0">)</span> <span class="br0">{</span></span><br /><span class="re8">+ if <span class="br0">(</span>i > 0<span class="br0">)</span> <span class="br0">{</span></span><br /><span class="re8">+ unsigned int len;</span><br /><span class="re8">+ CCertificate cert = notification.GetCertificates<span class="br0">(</span><span class="br0">)</span><span class="br0">[</span>i<span class="br0">]</span>;</span><br /><span class="re8">+ const unsigned char* data = cert.GetRawData<span class="br0">(</span>len<span class="br0">)</span>;</span><br /><span class="re8">+ wxString sCN = GetCNValue<span class="br0">(</span>cert.GetSubject<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span>;</span><br /> <br /><span class="re7">- return IsTrusted<span class="br0">(</span>notification.GetHost<span class="br0">(</span><span class="br0">)</span>, notification.GetPort<span class="br0">(</span><span class="br0">)</span>, data, len, false<span class="br0">)</span>;</span><br /><span class="re8">+ if <span class="br0">(</span>IsTrusted<span class="br0">(</span>sCN, 0, data, len, false<span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span></span><br /><span class="re8">+ return true;</span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ else <span class="br0">{</span></span><br /><span class="re8">+ unsigned int len;</span><br /><span class="re8">+ CCertificate cert = notification.GetCertificates<span class="br0">(</span><span class="br0">)</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span>;</span><br /><span class="re8">+ const unsigned char* data = cert.GetRawData<span class="br0">(</span>len<span class="br0">)</span>;</span><br /><span class="re8">+</span><br /><span class="re8">+ if <span class="br0">(</span>IsTrusted<span class="br0">(</span>notification.GetHost<span class="br0">(</span><span class="br0">)</span>, notification.GetPort<span class="br0">(</span><span class="br0">)</span>, data, len, false<span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span></span><br /><span class="re8">+ return true;</span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ return false;</span><br /> <span class="br0">}</span><br /> <br /> bool CVerifyCertDialog::DoIsTrusted<span class="br0">(</span>const wxString& host, int port, const unsigned char* data, unsigned int len, std::list<CVerifyCertDialog::t_certData> const& trustedCerts<span class="br0">)</span><br /><span class="re6">@@ -465,7 +529,10 @@ void CVerifyCertDialog::LoadTrustedCerts</span><br /> <br /> data.host = GetTextElement<span class="br0">(</span>cert, "Host"<span class="br0">)</span>;<br /> data.port = GetTextElementInt<span class="br0">(</span>cert, "Port"<span class="br0">)</span>;<br /><span class="re7">- if <span class="br0">(</span>data.host.empty<span class="br0">(</span><span class="br0">)</span> || data.port < <span class="nu0">1</span> || data.port > 65535<span class="br0">)</span></span><br /><span class="re8">+ if <span class="br0">(</span>data.port == 0<span class="br0">)</span> <span class="br0">{</span></span><br /><span class="re8">+ // use for non-first cert</span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ else if <span class="br0">(</span>data.host.empty<span class="br0">(</span><span class="br0">)</span> || data.port < <span class="nu0">1</span> || data.port > 65535<span class="br0">)</span></span><br /> remove = cert;<br /> <br /> int64_t activationTime = GetTextElementInt<span class="br0">(</span>cert, "ActivationTime", <span class="nu0">0</span><span class="br0">)</span>;<br /><span class="re6">@@ -498,20 +565,35 @@ void CVerifyCertDialog::LoadTrustedCerts</span><br /> <br /> void CVerifyCertDialog::SetPermanentlyTrusted<span class="br0">(</span>CCertificateNotification const& notification<span class="br0">)</span><br /> <span class="br0">{</span><br /><span class="re7">- const CCertificate certificate = notification.GetCertificates<span class="br0">(</span><span class="br0">)</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span>;</span><br /><span class="re8">+ wxString sCN = _T<span class="br0">(</span>""<span class="br0">)</span>;</span><br /><span class="re8">+ const CCertificate certificate = notification.GetCertificates<span class="br0">(</span><span class="br0">)</span><span class="br0">[</span>m_curSelect<span class="br0">]</span>;</span><br /> unsigned int len;<br /> const unsigned char* const data = certificate.GetRawData<span class="br0">(</span>len<span class="br0">)</span>;<br /> <br /> CReentrantInterProcessMutexLocker mutex<span class="br0">(</span>MUTEX_TRUSTEDCERTS<span class="br0">)</span>;<br /> LoadTrustedCerts<span class="br0">(</span><span class="br0">)</span>;<br /> <br /><span class="re7">- if <span class="br0">(</span>IsTrusted<span class="br0">(</span>notification.GetHost<span class="br0">(</span><span class="br0">)</span>, notification.GetPort<span class="br0">(</span><span class="br0">)</span>, data, len, true<span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span></span><br /><span class="re7">- return;</span><br /><span class="re8">+ if <span class="br0">(</span>m_curSelect > 0<span class="br0">)</span> <span class="br0">{</span></span><br /><span class="re8">+ sCN = GetCNValue<span class="br0">(</span>certificate.GetSubject<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span>;</span><br /><span class="re8">+ if <span class="br0">(</span>IsTrusted<span class="br0">(</span>sCN, 0, data, len, true<span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span></span><br /><span class="re8">+ return;</span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ else <span class="br0">{</span></span><br /><span class="re8">+ if <span class="br0">(</span>IsTrusted<span class="br0">(</span>notification.GetHost<span class="br0">(</span><span class="br0">)</span>, notification.GetPort<span class="br0">(</span><span class="br0">)</span>, data, len, true<span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span></span><br /><span class="re8">+ return;</span><br /><span class="re8">+ <span class="br0">}</span></span><br /> <span class="br0">}</span><br /> <br /> t_certData cert;<br /><span class="re7">- cert.host = notification.GetHost<span class="br0">(</span><span class="br0">)</span>;</span><br /><span class="re7">- cert.port = notification.GetPort<span class="br0">(</span><span class="br0">)</span>;</span><br /><span class="re8">+ if <span class="br0">(</span>m_curSelect > 0<span class="br0">)</span> <span class="br0">{</span></span><br /><span class="re8">+ cert.host = sCN;</span><br /><span class="re8">+ cert.port = <span class="nu0">0</span>;</span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ else <span class="br0">{</span></span><br /><span class="re8">+ cert.host = notification.GetHost<span class="br0">(</span><span class="br0">)</span>;</span><br /><span class="re8">+ cert.port = notification.GetPort<span class="br0">(</span><span class="br0">)</span>;</span><br /><span class="re8">+ <span class="br0">}</span></span><br /> cert.len = len;<br /> cert.data = new unsigned char<span class="br0">[</span>len<span class="br0">]</span>;<br /> memcpy<span class="br0">(</span>cert.data, data, len<span class="br0">)</span>;<br /><span class="re6">@@ -534,8 +616,14 @@ void CVerifyCertDialog::SetPermanentlyTr</span><br /> AddTextElement<span class="br0">(</span>xCert, "Data", ConvertHexToString<span class="br0">(</span>data, len<span class="br0">)</span><span class="br0">)</span>;<br /> AddTextElement<span class="br0">(</span>xCert, "ActivationTime", static_cast<int64_t><span class="br0">(</span>certificate.GetActivationTime<span class="br0">(</span><span class="br0">)</span>.get_time_t<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span>;<br /> AddTextElement<span class="br0">(</span>xCert, "ExpirationTime", static_cast<int64_t><span class="br0">(</span>certificate.GetExpirationTime<span class="br0">(</span><span class="br0">)</span>.get_time_t<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span>;<br /><span class="re7">- AddTextElement<span class="br0">(</span>xCert, "Host", notification.GetHost<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span>;</span><br /><span class="re7">- AddTextElement<span class="br0">(</span>xCert, "Port", notification.GetPort<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span>;</span><br /><span class="re8">+ if <span class="br0">(</span>m_curSelect > 0<span class="br0">)</span> <span class="br0">{</span></span><br /><span class="re8">+ AddTextElement<span class="br0">(</span>xCert, "Host", sCN<span class="br0">)</span>;</span><br /><span class="re8">+ AddTextElement<span class="br0">(</span>xCert, "Port", <span class="nu0">0</span><span class="br0">)</span>;</span><br /><span class="re8">+ <span class="br0">}</span></span><br /><span class="re8">+ else <span class="br0">{</span></span><br /><span class="re8">+ AddTextElement<span class="br0">(</span>xCert, "Host", notification.GetHost<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span>;</span><br /><span class="re8">+ AddTextElement<span class="br0">(</span>xCert, "Port", notification.GetPort<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span>;</span><br /><span class="re8">+ <span class="br0">}</span></span><br /> <br /> m_xmlFile.Save<span class="br0">(</span>true<span class="br0">)</span>;<br /> <span class="br0">}</span><br /><span class="re6">@@ -590,6 +678,7 @@ void CVerifyCertDialog::OnCertificateCho</span><br /> int sel = event.GetSelection<span class="br0">(</span><span class="br0">)</span>;<br /> if <span class="br0">(</span>sel < <span class="nu0">0</span> || sel > <span class="br0">(</span>int<span class="br0">)</span>m_certificates.size<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><br /> return;<br /><span class="re8">+ m_curSelect = sel;</span><br /> DisplayCert<span class="br0">(</span>m_pDlg, m_certificates<span class="br0">[</span>sel<span class="br0">]</span><span class="br0">)</span>;<br /> <br /> m_pDlg->Layout<span class="br0">(</span><span class="br0">)</span>;<br />diff -Nurp filezilla.orig/src/interface/verifycertdialog.h filezilla/src/interface/verifycertdialog.h<br /><span class="re3">--- filezilla.orig/src/interface/verifycertdialog.h 2016-05-25 15:15:10.164819057 +0800</span><br /><span class="re4">+++ filezilla/src/interface/verifycertdialog.h 2016-05-26 13:14:03.897443962 +0800</span><br /><span class="re6">@@ -28,6 +28,7 @@ private:</span><br /> <br /> bool DisplayCert<span class="br0">(</span>wxDialogEx* pDlg, const CCertificate& cert<span class="br0">)</span>;<br /> <br /><span class="re8">+ wxString GetCNValue<span class="br0">(</span>const wxString& dn<span class="br0">)</span>;</span><br /> void ParseDN<span class="br0">(</span>wxWindow* parent, const wxString& dn, wxSizer* pSizer<span class="br0">)</span>;<br /> void ParseDN_by_prefix<span class="br0">(</span>wxWindow* parent, std::list<wxString>& tokens, wxString prefix, const wxString& name, wxSizer* pSizer, bool decode = false<span class="br0">)</span>;<br /> <br /><span class="re6">@@ -50,6 +51,7 @@ private:</span><br /> wxSizer* m_pSubjectSizer<span class="br0">{</span><span class="br0">}</span>;<br /> wxSizer* m_pIssuerSizer<span class="br0">{</span><span class="br0">}</span>;<br /> int line_height_<span class="br0">{</span><span class="br0">}</span>;<br /><span class="re8">+ unsigned int m_curSelect;</span><br /> <br /> void OnCertificateChoice<span class="br0">(</span>wxCommandEvent& event<span class="br0">)</span>;<br /> <span class="br0">}</span>;</div></pre><p>patch 可以由這兒抓: <a href="http://www.teatime.com.tw/~tommy/mypatch/filezilla_3.18.0_trust_cert.patch" target="_blank">http://www.teatime.com.tw/~tommy/mypatch/filezilla_3.18.0_trust_cert.patch</a> </p><p>這個 patch 不久前<a href="https://trac.filezilla-project.org/ticket/10842" target="_blank">送給作者</a>, 不過被否決了. 所以.... 有需要就自己處理吧, 或到 <a href="https://sourceforge.net/projects/filezillapv/" target="_blank">FileZillaPV</a> 去抓我做好的執行檔.</p>
Patch
FTP
Software
2016-05-28T20:50:15Z
tommy
-
修正 ProxyDroid 2.7.x 自動連線無法正常使用的問題
https://blog.teatime.com.tw/1/post/476
<p><a href="https://github.com/madeye/proxydroid" target="_blank">ProxyDroid</a> 自 2.7.0 版本開始, 在我的手機上自動連線的功能就無法正常使用. 只能把 ProxyDroid 的程式打開去點才能正常使用. 連同桌面上的 widget 也一樣, 啟用的功能無法正常運作.</p><p>今天試著用 adb logcat 查了一下, 發現有 java.lang.NullPointerException 的問題:</p><pre class="bash"><div class="insertcode">E<span class="sy0">/</span>ProxyDroidService<span class="br0">(</span><span class="nu0">20295</span><span class="br0">)</span>: Error setting up port forward during connect<br />E<span class="sy0">/</span>ProxyDroidService<span class="br0">(</span><span class="nu0">20295</span><span class="br0">)</span>: java.lang.NullPointerException: Attempt to invoke virtual method <span class="st_h">'int java.lang.String.length()'</span> on a null object reference<br />E<span class="sy0">/</span>ProxyDroidService<span class="br0">(</span><span class="nu0">20295</span><span class="br0">)</span>: at org.proxydroid.ProxyDroidService.enableProxy<span class="br0">(</span>ProxyDroidService.java:<span class="nu0">263</span><span class="br0">)</span><br />E<span class="sy0">/</span>ProxyDroidService<span class="br0">(</span><span class="nu0">20295</span><span class="br0">)</span>: at org.proxydroid.ProxyDroidService.handleCommand<span class="br0">(</span>ProxyDroidService.java:<span class="nu0">394</span><span class="br0">)</span><br />E<span class="sy0">/</span>ProxyDroidService<span class="br0">(</span><span class="nu0">20295</span><span class="br0">)</span>: at org.proxydroid.ProxyDroidService<span class="re4">$3</span>.run<span class="br0">(</span>ProxyDroidService.java:<span class="nu0">715</span><span class="br0">)</span><br />E<span class="sy0">/</span>ProxyDroidService<span class="br0">(</span><span class="nu0">20295</span><span class="br0">)</span>: at java.lang.Thread.run<span class="br0">(</span>Thread.java:<span class="nu0">818</span><span class="br0">)</span></div></pre><p>應該是 certificate 這個變數是 null 所造成的問題, 加上了檢查的動作就正常了.</p><p>由於原作者沒有打開 issue 的功能, 只好 <a href="https://github.com/twu2/proxydroid" target="_blank">fork 出來</a>再利用 pull request 送出這個 patch. 順便把 wifi-ap 模式的支援也加入.</p><p>目前看起來應該<a href="https://github.com/madeye/proxydroid/commits/master" target="_blank">有被作者接受</a>. 所以... 希望下一版會正常. </p><p>等不及下一版的可以抓這個回去試看看: <a href="http://www.teatime.com.tw/~tommy/files/proxydroid-2.7.9-2.7.4.apk" target="_blank">http://www.teatime.com.tw/~tommy/files/proxydroid-2.7.9-2.7.4.apk </a> </p><p> </p><p> </p>
Patch
Software
Android
2016-05-17T10:52:35Z
tommy
-
Avaya VPN Client 在 Windows 10 使用的問題
https://blog.teatime.com.tw/1/post/471
<p>上星期把家裡那台 ThinkPad W510 升級到 Windows 10 之後, 發現 Avaya VPN Client 無法正常連線. 看 log 的資料, 是可以正常連上, 不過取得 IP 之後, 會出現 Activating vpn adapter failed 的錯誤而中斷. 因為還有備用的 OpenVPN 可以用, 所以就放著沒去管它.</p><p>今天有空就找了一下問題. 首先用系統管理員身份執行 Avaya VPN Client (這樣才能修改 log 設定), 然後去把 Logging Level 改成 Debug, 再連線看看. 會看到錯誤發生如下:</p><pre class="winbatch"><div class="insertcode"><span class="nu0">2015</span><span class="sy0">/</span><span class="nu0">8</span><span class="sy0">/</span><span class="nu0">13</span> <span class="nu0">14</span><span class="co2">:15:43.600 [SSLC] -D-Entering CSslTunAdapter::Open() [Ln:106].</span><br /><span class="nu0">2015</span><span class="sy0">/</span><span class="nu0">8</span><span class="sy0">/</span><span class="nu0">13</span> <span class="nu0">14</span><span class="co2">:15:43.600 [SSLC] -D-Entering CSslTunAdapter::RetrieveVPNAdapterInfo() [Ln:268].</span><br /><span class="nu0">2015</span><span class="sy0">/</span><span class="nu0">8</span><span class="sy0">/</span><span class="nu0">13</span> <span class="nu0">14</span><span class="co2">:15:43.600 [SSLC] -D-Entering CSslTunAdapter::RetrieveVPNAdapterInfo() [Ln:270]. szAdapterRegkey = SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}, szComponenetId = nt_nvca</span><br /><span class="nu0">2015</span><span class="sy0">/</span><span class="nu0">8</span><span class="sy0">/</span><span class="nu0">13</span> <span class="nu0">14</span><span class="co2">:15:43.601 [SSLC] -D-Leaving CSslTunAdapter::RetrieveVPNAdapterInfo(). [Ln:379].RetCode = 1</span><br /><span class="nu0">2015</span><span class="sy0">/</span><span class="nu0">8</span><span class="sy0">/</span><span class="nu0">13</span> <span class="nu0">14</span><span class="co2">:15:43.601 [SSLC] -D-RetrieveVPNAdapterInfo function failed Error code = 1, Adapters count = 0.</span><br /><span class="nu0">2015</span><span class="sy0">/</span><span class="nu0">8</span><span class="sy0">/</span><span class="nu0">13</span> <span class="nu0">14</span><span class="co2">:15:43.601 [SSLC] -E-Driver installation problem or Multiple VPN adapters present in local system.</span></div></pre><p>用 regedit 看了一下那個機碼的內容, 發現 ComponenetId 的內容大小寫不一樣, 就全部改成小寫試看看.</p><p>果然, 這樣子改了之後, 就沒有這個錯誤, 而可以繼續執行下去 (為什麼呢? 同樣的程式, 在 Windows 7-8.1 都正常可以用, 怎麼到 Win10 就大小寫有差別了?)...</p><p>不過, 還是無法正常使用, 在 banner 處理之後, 又出現錯誤... 看 log 是在處理 route table 時發生錯誤.</p><pre class="winbatch"><div class="insertcode"><span class="nu0">2015</span><span class="sy0">/</span><span class="nu0">8</span><span class="sy0">/</span><span class="nu0">13</span> <span class="nu0">13</span><span class="co2">:58:35.188 [SSLC] -D-Leaving CDomainNameSrv::RegUpdateTapIfDnsInfo(). [Ln:486].RetCode = 1</span><br /><span class="nu0">2015</span><span class="sy0">/</span><span class="nu0">8</span><span class="sy0">/</span><span class="nu0">13</span> <span class="nu0">13</span><span class="co2">:58:35.188 [SSLC] -D-Entering CDomainNameSrv::RegUpdateGlobalDnsSuffixList() [Ln:509].DnsSuffixlist = domain.tahsda.org.tw</span><br /><span class="nu0">2015</span><span class="sy0">/</span><span class="nu0">8</span><span class="sy0">/</span><span class="nu0">13</span> <span class="nu0">13</span><span class="co2">:58:35.190 [SSLC] -E-RegQueryValueEx api failed. Error code = 2.</span></div></pre><p>這次只看到 RegQueryValueEx() 錯誤, 沒顯示是去查那個資料.... 由錯誤代碼 2 來看, 是找不到檔案的錯誤....</p><p>所以, 動用 procmon.exe 來查看是讀那兒的資料讀不到... 發現應該是</p><pre class="winbatch"><div class="insertcode">HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\SearchList</div></pre><p><br />這個讀不到... 這時發現, Windows 10 安裝後, 居然沒有這個參數值.... 比對一下 Windows 8.1 的內容, 自已建立一個 REG_SZ 的 SearchList 來用, 果然可以正常執行了.</p><p> </p><hr />PS1: 剛發現重開機後, 網卡那邊的 ComponentId 會被還原, 所以... 寫了一個小程式每次重開機來改一下.<p> </p><p><a href="http://www.teatime.com.tw/~tommy/files/CheckAvayaVPNAdpater.7z" target="_blank">http://www.teatime.com.tw/~tommy/files/CheckAvayaVPNAdpater.7z</a> </p><p>有需要的抓回去試看看吧. </p><p> </p><p> </p>
Software
Windows 10
2015-08-13T14:08:28Z
tommy
-
使用 ffmpeg 透過 rtsp 轉資料給 Darwin Streaming Server 播放
https://blog.teatime.com.tw/1/post/467
<p>這幾天發現原本使用 <a href="http://www.videolan.org/vlc/" target="_blank">VLC</a> 將電視卡的訊號轉送到 <a href="http://dss.macosforge.org/" target="_blank">Darwin Streaming Server</a> 播放的功能沒有作用了. 我記得之前最後一次試好像有半年了吧.... 與之前的差異應該就是 Kernel 不一樣 (v4l2 的 driver 可能有變), Debian 版本不一樣 (幾個星期前由 stable 轉到 unstable 使用), 加上 VLC 的版本不一樣 (之前應該只有 2.0.x 的版本, 目前是 2.1.1).</p><p>kernel, 特地抓舊的 3.4 與 3.10 的版本來測, 結果一樣. VLC, 自己編個 2.1.0 來用, 結果一樣.... 想編個 2.0.x 的版本, 結果一直試不成功. Debian 的版本..... 想到要由備份放回去就懶了... 加上, 除了 VLC 不能讀到 v4l2 出來的資料外, 其他的程式 (<a href="http://www.mplayerhq.hu" target="_blank">mencoder</a>, <a href="http://www.ffmpeg.org/" target="_blank">ffmpeg</a>) 都很正常, 看起來應該是 VLC 本身的問題才對. 不過.... 到 VLC 的網站, 又看不到有人反應相同的問題.... 難道只有我碰到?</p><p>由於 ffmpeg 與 mencoder 仍可以用, 所以就乾脆換個程式來處理. 先試了 mencoder, 實在找不出把資料串流出去的方式, 似乎都只能存成檔案. 所以... 就改用 ffmpeg 來處理.</p><p>由於 ffmpeg 對於 v4l2 的支援參數, 似乎沒有 VLC 來的細, 所以, 很多東西我們必須先用 v4l2-ctl 或 v4lctl 來設定, 然後再用 ffmpeg 來轉檔.</p><p>VLC 在與 Darwin Streaming Server 搭配時, 是去指定 .sdp 檔案在產生的 local 路徑... 不過在 ffmpeg 上頭, 並沒有看到類似的參數, 試了很久, 終於發現直接送到 rtsp://dss_server/file.sdp 這樣的路徑, DSS 收到就會自動產生 file.sdp 出來了.</p><p>所以... 用類似下面的 script 來轉:</p><pre class="bash"><div class="insertcode"><span class="sy0">/</span>usr<span class="sy0">/</span>bin<span class="sy0">/</span><span class="kw2">ffmpeg</span> <span class="re5">-re</span> <span class="re5">-f</span> alsa <span class="re5">-i</span> hw:<span class="nu0">1</span>,<span class="nu0">0</span> <span class="re5">-f</span> v4l2 <span class="re5">-s</span> 720x480 <span class="re5">-i</span> <span class="sy0">/</span>dev<span class="sy0">/</span>video0 <span class="re5">-ac</span> <span class="nu0">2</span> -c:a libfdk_aac -b:a 32k -c:v libx264 -b:v 768k <span class="re5">-f</span> rtsp rtsp:<span class="sy0">//</span>127.0.0.1<span class="sy0">/</span>live_tv.sdp</div></pre><p>如果 CPU 不夠快, 指定 bitrate 的方式可能會效果不太好....可以考慮改用 preset 的方式來處理.</p><pre class="bash"><div class="insertcode"><span class="sy0">/</span>usr<span class="sy0">/</span>bin<span class="sy0">/</span><span class="kw2">ffmpeg</span> <span class="re5">-re</span> <span class="re5">-f</span> alsa <span class="re5">-i</span> hw:<span class="nu0">1</span>,<span class="nu0">0</span> <span class="re5">-f</span> v4l2 <span class="re5">-s</span> 720x480 <span class="re5">-i</span> <span class="sy0">/</span>dev<span class="sy0">/</span>video0 <span class="re5">-ac</span> <span class="nu0">2</span> -c:a libfdk_aac -b:a 32k -c:v libx264 <span class="re5">-preset</span> superfast <span class="re5">-f</span> rtsp rtsp:<span class="sy0">//</span>127.0.0.1<span class="sy0">/</span>live_tv.sdp</div></pre><p>我試過在 Celeron 847E 的 CPU 上頭, 使用 veryfast, superfast, ultrafaster 這三個 preset, 都仍可以維持 fps 在 30 以上, 畫質也不錯 (用 faster 就偶爾會掉到 fps 30 以下)... 如果指定 bitrate 的方式來處理, 不管設大或小, 都只有 fps 1x 的表現.</p><p>至於頻寬... 看起來 superfast 約在 250KB/s-350KB/s 之間跳動, 算是可以接受的大小. </p>
Linux
Software
2013-12-13T09:59:54Z
tommy
-
ownCloud imap (or others) backend support? lost after re-configure...
https://blog.teatime.com.tw/1/post/449
<p>上星期把 <a href="https://owncloud.com/" target="_blank">ownCloud</a> 裝起來用, 因為是用現成的主機, 所以就直接用 imap 的方式來驗證帳號. </p><p>設定上其實很簡單, 不過.... 就設計的邏輯來看, 整個系統雖然有個 External user support 的應用程式可以用, 啟用後, 又找不到任何地方可以設定.... 原來, 沒有介面, 要自己去改 config/config.php 才可以.</p><p>網路上找到的設定如下:</p><pre class="php"><div class="insertcode"><pre class="php" style="font-family: monospace"><span class="kw2"><?php</span><br /><span class="kw1">require_once</span><span class="br0">(</span><a href="http://www.php.net/dirname"><span class="kw3">dirname</span></a><span class="br0">(</span><span class="kw4">__FILE__</span><span class="br0">)</span><span class="sy0">.</span><span class="st_h">'/../apps/user_external/lib/imap.php'</span><span class="br0">)</span><span class="sy0">;</span><br /><span class="re0">$CONFIG</span> <span class="sy0">=</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a> <span class="br0">(</span><br /> <span class="st_h">'instanceid'</span> <span class="sy0">=></span> <span class="st_h">'xxxxx'</span><span class="sy0">,</span><br /> <span class="st_h">'passwordsalt'</span> <span class="sy0">=></span> <span class="st_h">'xxxxx,<br /> '</span>datadirectory<span class="st_h">' => '</span><span class="sy0">/</span><span class="kw2">var</span><span class="sy0">/</span>www<span class="sy0">/</span>owncloud<span class="sy0">/</span>data<span class="st_h">',<br /> '</span>dbtype<span class="st_h">' => '</span><a href="http://www.php.net/mysql"><span class="kw3">mysql</span></a><span class="st_h">',<br /> '</span>version<span class="st_h">' => '</span>5<span class="sy0">.</span>0<span class="sy0">.</span>15<span class="st_h">',<br /> '</span>dbname<span class="st_h">' => '</span>owncloud<span class="st_h">',<br /> '</span>dbhost<span class="st_h">' => '</span>localhost<span class="st_h">',<br /> '</span>dbtableprefix<span class="st_h">' => '</span>oc_<span class="st_h">',<br /> '</span>dbuser<span class="st_h">' => '</span>xxxx<span class="st_h">',<br /> '</span>dbpassword<span class="st_h">' => '</span>xxxxx<span class="st_h">',<br /> '</span>installed<span class="st_h">' => true,<br /> '</span>loglevel<span class="st_h">' => '</span><span class="nu0">2</span><span class="st_h">',<br /> '</span>user_backends<span class="st_h">' =><br /> array (<br /> 0 =><br /> array (<br /> '</span><span class="kw2">class</span><span class="st_h">' => '</span>OC_User_IMAP<span class="st_h">',<br /> '</span>arguments<span class="st_h">' =><br /> array (<br /> 0 => '</span><span class="br0">{</span>localhost<span class="sy0">/</span>novalidate<span class="sy0">-</span>cert<span class="sy0">:</span><span class="nu0">143</span><span class="br0">}</span><span class="st_h">',<br /> ),<br /> ),<br /> ),<br /> '</span>forcessl<span class="st_h">' => true,<br />);</span></pre></div></pre><p>就是一開始加上用的模組, 再去設定就可以.</p><p>不過.... 昨天設定老婆的手機上的 ownCloud client 時, 居然不能登入.... 用 browser 登入又可以. 找了半天, 終於發現原本自行在 config/config.php 加上的那一行 require_once 不見了....</p><p>原來, 只要在系統管理員在網頁上改過設定, 就會重寫 config/config.php, 但是.... 就只有 $CONFIG 會被寫入, 自己另外加上的程式碼會不見.</p><p>這時... 透過 browser 進來時, 應該在 index.php 裡頭會去處理到, 所以會載入所需要的模組, 仍可以正常的登入. 不過... 使用 android client 時, 似乎不是透過這方式來連線, 所以.... 會找不到帳號密碼.</p><p>由於怕不小心忘了會不能用, 所以就改了一下程式, 在寫入 config.php 時, 去載入自己的另一個 config.local.php 設定檔, 這樣就可以把自己另外加的程式碼放到 config.local.php, 而系統重新寫入時不會去影響到.</p><p>patch 如下:</p><pre class="diff"><div class="insertcode"><pre class="diff" style="font-family: monospace">--- owncloud/lib/config.orig.php 2013-07-19 21:50:05.244784602 +0800<br /><span class="re4">+++ owncloud/lib/config.php <span class="nu0">2013</span>-07-<span class="nu0">19</span> <span class="nu0">21</span>:<span class="nu0">51</span>:<span class="nu0">14.421748091</span> +0800</span><br /><span class="re6">@@ -<span class="nu0">157</span>,<span class="nu0">7</span> +<span class="nu0">157</span>,<span class="nu0">7</span> @@</span><br /> // Create a php file ...<br /> $defaults = new OC_Defaults;<br /> <br /><span class="re7">- $content = "<?php\n\$CONFIG = ";</span><br /><span class="re8">+ $content = "<?php\nif <span class="br0">(</span>file_exists<span class="br0">(</span>dirname<span class="br0">(</span>__FILE__<span class="br0">)</span>.'/config.local.php'<span class="br0">)</span><span class="br0">)</span>\n include<span class="br0">(</span>dirname<span class="br0">(</span>__FILE__<span class="br0">)</span>.'/config.local.php'<span class="br0">)</span>;\n\$CONFIG = ";</span><br /> $content .= var_export<span class="br0">(</span>self::$cache, true<span class="br0">)</span>;<br /> $content .= ";\n";</pre></div></pre><br />這樣應該可以避免不小心修改設定造成無法登入的情形吧. (不過要是那天升級忘了, 可能又會碰到吧)
Patch
Software
2013-07-20T11:16:19Z
tommy