Tommy 碎碎念
https://blog.teatime.com.tw/
Tommy Wu's blog
tommy
2024-03-29T14:10:39Z
-
讓 Nginx 的 real_ip 模組找不到對應的 header 時, 使用 proxy protocol 傳入的 IP
https://blog.teatime.com.tw/1/post/493
<p>最近把 DNS 轉到 <a href="https://www.cloudflare.com/" target="_blank" rel="noopener">Cloudflare</a> 使用, 原本在主機上使用 <a href="https://www.haproxy.org/" target="_blank" rel="noopener">HAProxy</a> 把 SSL 的封包轉到個別對應的軟體是使用 Proxy Protocol 將來源 IP 通知處理的軟體. 在改用 Cloudflare 之後, 這個 IP 就變成 Cloudflare 的 IP 了. 這個在需要知道來源 IP 的軟體上, 就反而造成問題.</p>
<p>通常會走 Cloudflare 進來的, 也都是網頁的服務 (其他同樣使用 SSL 走 443 的服務, 也不需要透過 Cloudflare 處理, 通常可以在 DNS 上另外設定來避開). 依據 Cloudflare 的作法, 是應該使用 HTTP 的 header CF-Connecting-IP 來取得真實的來源 IP. 不過.... 由於我這邊是先透過 HAProxy 處理過, 混雜了來自 Cloudflare 與沒經過 Cloudflare 的封包 (例如內部網路的機器), 這時, 就變成使用 CF-Connecting-IP 時, 非來自 Cloudflare 的 IP 變成 HAProxy 的 127.0.0.1, 如果使用 Proxy Protocol 時, 那些透過 Cloudflare 的封包, 來源 IP 又全變成 Cloudflare 的 IP 了.</p>
<p>看了一下 <a href="https://nginx.org/" target="_blank" rel="noopener">Nginx</a> 的 real_ip 模組設定, <a href="http://nginx.org/en/docs/http/ngx_http_realip_module.html" target="_blank" rel="noopener">real_ip_header</a> 就只能設定一種, 不能有多重的設定, 所以就只好看一下 source, 自己動手來修改.</p>
<pre class="language-diff"><code>--- nginx-1.23.3/src/http/modules/ngx_http_realip_module.c.orig 2023-03-19 11:18:38.033783262 +0800
+++ nginx-1.23.3/src/http/modules/ngx_http_realip_module.c 2023-03-19 11:17:30.029338872 +0800
@@ -157,7 +157,8 @@
case NGX_HTTP_REALIP_XREALIP:
if (r->headers_in.x_real_ip == NULL) {
- return NGX_DECLINED;
+ //return NGX_DECLINED;
+ goto try_proxy_protocol;
}
value = &r->headers_in.x_real_ip->value;
@@ -170,7 +171,8 @@
xfwd = r->headers_in.x_forwarded_for;
if (xfwd == NULL) {
- return NGX_DECLINED;
+ //return NGX_DECLINED;
+ goto try_proxy_protocol;
}
value = NULL;
@@ -178,6 +180,7 @@
break;
case NGX_HTTP_REALIP_PROXY:
+try_proxy_protocol:
if (r->connection->proxy_protocol == NULL) {
return NGX_DECLINED;
}
@@ -219,7 +222,8 @@
}
}
- return NGX_DECLINED;
+ //return NGX_DECLINED;
+ goto try_proxy_protocol;
}
found:
</code></pre>
<p>修改的方式其實不難, 這邊的處理雖然是用 switch case 來獨立處理, 不過可以發現其實是不是透過 Proxy Protocol 處理過, 是有方法可以判斷的, 所以我們只要在其中每一種用來取得 real_ip 的 case 中, 如果最後沒有處理到, 就轉給 Proxy Protocol 那一段來處理就可以.</p>
<p>這樣子修改後, 我們依舊可以在 Nginx 中設定</p>
<pre class="language-nginx"><code>real_ip_header CF-Connecting-IP;</code></pre>
<p>就算是沒有這個 header 的來源, 一樣仍透過 Proxy Protocol 處理, 就算也沒透過 Proxy Protocol, 一樣可以判斷出來而不會造成問題.</p>
Linux
Patch
Nginx
2023-03-24T10:08:25Z
tommy
-
新玩具 NanoPi R2S/R4S
https://blog.teatime.com.tw/1/post/492
<p>由於家裡的其中一台 firewall 使用的 CompuLab 的 Intense-PC 這半年老是在執行 php script 時發生 coredump, 加上硬碟應該也有壞軌, smartd 每天都發信通知有問題, 所以想找機器來換掉它. 因為做的事不複雜, 也不需要太多的效能就能處理, 加上之前買來用的 <a href="https://blog.teatime.com.tw/1/post/462" target="_blank">Utilite</a> 都能運作, 所以考慮買個雙網卡的耗能低小機器來處理就可以.</p><p>上淘寶找了一下, x86 的機器有兩個網卡的有 celeron 847 (跟那個 Intense-PC 一樣, 不過看起來多數都沒貨, 都改成比較新的 CPU 了) 跟 1037U, 還是 J1800/J1900. 而 arm based 的機器, 雖然因為樹梅派的關係, 比以往多了不少, 不過多數都還是只有一個網卡. 後來突然想到, 可能是找的方向不對, 改用 "軟路由" 去找, 果然除了一堆 J1800 的機器外, 也出現了 NanoPi 的 <a href="https://wiki.friendlyarm.com/wiki/index.php/NanoPi_R2S" target="_blank">R2S</a> 跟 <a href="https://wiki.friendlyarm.com/wiki/index.php/NanoPi_R4S" target="_blank">R4S</a>. </p><p>比較了一下優缺點:</p><p> </p><ul><li>x86 的機器效能比較好, R2S/R4S 比較省電</li><li>x86 的機器有 VGA 可以接顯示器, R2S/R4S 只有 serial console 可以用</li><li>R2S/R4S 應該比較有可 "玩" 性, 如果買 x86 的機器, 可能直接硬碟複製一下就繼續使用了</li><li>R2S/R4S 比較便宜</li></ul><p> </p><p>最後決定買台 R2S 或 R4S 來玩. 不過要買比較便宜但只有 1G 記憶體的 R2S 還是比較貴, 但有 4G 記憶體的 R4S 呢? 後來為了怕被我玩壞, 乾脆各買一台回來試看看 (兩台加一起的錢跟一台 x86 的小機器差不多).<br />不過在玩過機器後, 如果目前讓我選, 應該只會選擇 R4S 就好, 理由如下:</p><p> </p><ul><li>R4S 的記憶體多了些</li><li>R4S 的速度快了一些</li><li>R4S 在同樣的環境下, 溫度比 R2S 少 8 度</li><li>最重要的是, R2S 其中一個網卡是使用 USB 介面的 R8153B, 在比較重度的使用 (其實我覺得一點都不 "重度"), 會有網卡 timeout 的問題 (雖然會恢復, 但總會有突然頓一下的感覺)</li></ul><p> </p><p>買的時候, 建議也買個 USB2ART 的設備回來當 console 用, 不然在一開始安裝系統時, 會不太方便使用 (怕開機有問題看不到, 到時網路連不上, 很難找到問題).<br />不過 USB2ART 這東西, 因為樹梅派的關係, 台灣的拍賣網站也有一堆, 價差不會很大, 也可以在台灣買就好 (不過 R2S/R4S 價差很大, 建議直接由淘寶買比較划算). </p><p>兩個都是使用 MicroSD 卡當儲存設備, 應該一般常見的 class 10 的卡就能用 (我是拿之前手機換下來的卡來用), 可能是有 cache 的關係, 實際使用並不會覺得 I/O 慢 (只有把系統複製過上去, 最後執行 sync 時會慢).<br />至於 rootfs 的製作, 可以參老<a href="https://wiki.debian.org/Arm64Port">這篇</a>, 使用 debootstrap 的方式處理, 或者參考<a href="https://www.kulesz.me/post/160-debian-bullseye-sysvinit-arm64-install/" target="_blank">這篇</a>, 使用 VM 的方式來處理.<br />使用 debootstrap 應該比較快, 不過如果習慣用 aptitude 來安裝軟體的話, 可能使用 VM 的方式會好一些, 因為在 x86-64 的 Debian 上用 chroot 的方式跑 arm/arm64 的環境時, 使用 aptitude 在最後執行安裝作業時, 常常有 coredump 的情形.</p><p>至於 bootloader/uboot 的部分, 可以由 <a href="https://github.com/friendlyarm/" target="_blank">friendlyarm 的 github</a> 抓 source code 回來編譯, 也可以抓別人做好的直接用.<br />我是建議直接用 <a href="https://www.armbian.com/" target="_blank">Armbian</a> 做好的版本. R2S 可以用<a href="https://imola.armbian.com/apt/pool/main/l/linux-u-boot-nanopi-r2s-current/" target="_blank">這個</a>, R4S 可以用<a href="https://imola.armbian.com/apt/pool/main/l/linux-u-boot-nanopi-r4s-current/" target="_blank">這個</a>.</p><p>SD 卡的前 16MB 是用來放 bootloader/uboot 的, 所以分割區要由 16M 之後開始用, 第一個分區是建議用一個 ext4 的分區放 kernel 跟 ramdisk, 我自己是給 1G 的空間, 不然可能裝個幾個 kerne/ramdisk 就放不下了.<br />uboot 支援 extlinux 的方式載入 kernel 跟 ramdisk, 所以建一個 extlinux/extlinux.conf 來載入會比使用 uboot 的 script 容易些.<br />至於實際的 linux 分區, 可以用 ext4/f2fs/btrfs/xfs 都可以, 我習慣是用 lvm 搭配 xfs 來使用, 比較方便做 snapshot 來備份.</p><p>Kernel 可以抓 <a href="https://github.com/friendlyarm/uboot-rockchip.git" target="_blank">friendlyarm 的 github</a> 上的 nanopi-r2-v5.10.y 分支來使用, R2S/R4S 可以共用相同的 kernel, 只不過 R2S 使用 rk3328-nanopi-r2-rev00.dtb, 而 R4S 使用 rk3399-nanopi-r4s.dtb.<br />上面的 kernel 是 5.10.60, 可以自己用 patch 到最新的 <a href="https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/log/?h=linux-5.10.y" target="_blank">linux-5.10.y 分支</a> (使用 git 或抓 patch 檔回來都可以).</p><p>另外關於 R2S 的 R8153B 網卡, 用的是 r8152 這個驅動程式, 在我的機器上, 直接用上面 kernel 含的 v1.11.11 版本, 會抓不到網卡, 所以抓<a href="https://github.com/wget/realtek-r8152-linux" target="_blank">這個</a>的 v2.15 回來用, 可以正常使用.<br />只不過這個網卡當成 LAN 使用時, 在透過 NFS 把系統備份到 NAS 上時, 會發生 timeout 的問題, 所以我就把 LAN 跟 WAN 互換來用.</p><p>網卡的名稱可以透過 udev 來改, 產生 /etc/udev/rules.d/70-persistent-net.rules 內容如下:</p><pre class="ini"><div class="insertcode"># R2S<br /># r8152 usb nic<br /><span class="re1">SUBSYSTEM</span><span class="sy0">=</span><span class="re2">=</span><span class="st0">"net"</span>, ACTION<span class="sy0">=</span><span class="re2">=</span><span class="st0">"add"</span>, DRIVERS<span class="sy0">=</span><span class="re2">=</span><span class="st0">"r8152"</span>, NAME<span class="sy0">=</span><span class="st0">"ethext"</span><br /># rockchip built-in nic<br /><span class="re1">SUBSYSTEM</span><span class="sy0">=</span><span class="re2">=</span><span class="st0">"net"</span>, ACTION<span class="sy0">=</span><span class="re2">=</span><span class="st0">"add"</span>, DRIVERS<span class="sy0">=</span><span class="re2">=</span><span class="st0">"rk_gmac-dwmac"</span>, NAME<span class="sy0">=</span><span class="st0">"ethint"</span></div></pre><p> </p><p> 如果是 R4S 的話, 內容如下:</p><pre class="ini"><div class="insertcode"># R4S<br /># r8169<br /><span class="re1">SUBSYSTEM</span><span class="sy0">=</span><span class="re2">=</span><span class="st0">"net"</span>, ACTION<span class="sy0">=</span><span class="re2">=</span><span class="st0">"add"</span>, DRIVERS<span class="sy0">=</span><span class="re2">=</span><span class="st0">"r8169"</span>, NAME<span class="sy0">=</span><span class="st0">"ethint"</span><br /># rockchip built-in nic<br /><span class="re1">SUBSYSTEM</span><span class="sy0">=</span><span class="re2">=</span><span class="st0">"net"</span>, ACTION<span class="sy0">=</span><span class="re2">=</span><span class="st0">"add"</span>, DRIVERS<span class="sy0">=</span><span class="re2">=</span><span class="st0">"rk_gmac-dwmac"</span>, NAME<span class="sy0">=</span><span class="st0">"ethext"</span></div></pre><p> </p><p>另外, R2S 的 r8152 網卡, 會在每次載入模組時, 重新設定 mac address, 如果需要固定的 mac address, 可以在 /etc/network/interfaces 中, 針對該網卡在 pre-up 時執行 ifconfig 去設定 mac address.<br />例如:</p><pre class="ini"><div class="insertcode">auto ethext<br />iface ethext inet static<br /> address 192.168.1.1<br /> netmask 255.255.255.0<br /> pre-up ifconfig ethext hw ether <span class="nu0">11</span>:<span class="nu0">22</span>:<span class="nu0">33</span>:<span class="nu0">44</span>:<span class="nu0">55</span>:<span class="nu0">66</span></div></pre><p> </p><p>依據之前使用 Utilite 的經驗, arm linux 在搞定 uboot/kernel/rootfs 之後, 使用上與 x86 的 linux 並沒有什麼不同. 所以後面 linux 的部份也沒什麼好提了.</p><p>在系統安裝測試正常後, 要把鋁合金的外殼裝上, 就沒辦法把 serial console 接出來用了 (建議以後設計外殼時, 把 serial console 也接出來吧, 不然沒畫面輸出, 又沒 console 可以接, 有問題實在很不方便. 我一度還想找個電鑽來挖洞把接線出來用).</p><div id="gtx-trans" style="position: absolute; left: 783px; top: 663px"><div class="gtx-trans-icon"></div></div>
Linux
2022-01-02T08:54:39Z
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
-
架設 OpenConnect VPN server
https://blog.teatime.com.tw/1/post/480
<p>在 Debian 中安裝 <a href="http://www.infradead.org/ocserv/" target="_blank">OpenConnect VPN server</a> 其實很簡單, 應該只要一行 apt-get install ocserv 指令就可以了.</p><p>安裝後只要去修改 /etc/ocserv/ocserv.conf 設定, 改變 tcp-port, udp-port, server-cert, server-key 就可以:</p><pre class="ini"><div class="insertcode"># TCP and UDP port number<br /># When systemd is running as init, this needs to be adjusted in<br /># the corresponding unit file as well.<br /><span class="re1">tcp-port</span> <span class="sy0">=</span><span class="re2"> 8443</span><br /><span class="re1">udp-port</span> <span class="sy0">=</span><span class="re2"> 8443</span><br /> <br /># The key and the certificates of the server<br /># The key may be a file, or any URL supported by GnuTLS <span class="br0">(</span>e.g.,<br /># tpmkey:uuid<span class="sy0">=</span><span class="re2">xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx</span><span class="co0">;storage=user</span><br /># or pkcs11:object<span class="sy0">=</span><span class="re2">my-vpn-key</span><span class="co0">;object-type=private)</span><br />#<br /># The server-cert file may contain a single certificate, or<br /># a sorted certificate chain.<br />#<br /># There may be multiple server-cert and server-key directives,<br /># but each key should correspond to the preceding certificate.<br /><span class="re1">server-cert</span> <span class="sy0">=</span><span class="re2"> /etc/letsencrypt.sh/certs/default/fullchain.pem</span><br /><span class="re1">server-key</span> <span class="sy0">=</span><span class="re2"> /etc/letsencrypt.sh/certs/default/privkey.pem</span></div></pre><p>預設的 port 是 443, 不過... 通常 443 都給 https 用了, 所以就找別的 port 來用... 如果你的系統是用 systemd (如果不是很久沒更新的版本, 應該都是了), 還用去改 /lib/systemd/system/ocserv.socket 裡頭的設定才可以. </p><p>憑證的部份可以用 <a href="https://letsencrypt.org/" target="_blank">Let's encrypt</a> 的憑證就可以. </p><p>由於 OpenConnect 與 Cisco AnyConnect 基本上是相容的, 只要加上下面的設定就可以:</p><pre class="ini"><div class="insertcode"># This option must be set to true to support legacy CISCO clients.<br /># A side effect of this option is that it will no longer be required<br /># for clients to present their certificate on every connection.<br /># That is they may resume a cookie without presenting a certificate<br /># <span class="br0">(</span>when certificate authentication is used<span class="br0">)</span>.<br /><span class="re1">cisco-client-compat</span> <span class="sy0">=</span><span class="re2"> true</span><br /> <br /># Client profile xml. A sample file exists in doc/profile.xml.<br /># It is required by some of the CISCO clients.<br /># This file must be accessible from inside the worker's chroot.<br /># Note that enabling this option is not recommended as it will allow<br /># the worker processes to open arbitrary files <span class="br0">(</span>when isolate-workers is<br /># set to true<span class="br0">)</span>.<br /><span class="re1">user-profile</span> <span class="sy0">=</span><span class="re2"> /etc/ocserv/profile.xml</span></div></pre><p>user-profile 並非一定要 (有設定這個時, 在 AnyConnect Client 上頭會用名稱取代 ip adreess 或 hostname), profile.xml 的內容如下:</p><pre class="xml"><div class="insertcode"><span class="sc3"><span class="re1"><?xml</span> <span class="re0">version</span>=<span class="st0">"1.0"</span> <span class="re0">encoding</span>=<span class="st0">"UTF-8"</span><span class="re2">?></span></span><br /><span class="sc3"><span class="re1"><AnyConnectProfile</span> <span class="re0">xmlns</span>=<span class="st0">"http://schemas.xmlsoap.org/encoding/"</span> <span class="re0">xmlns:xsi</span>=<span class="st0">"http://www.w3.org/2001/XMLSchema-instance"</span> <span class="re0">xsi:schemaLocation</span>=<span class="st0">"http://schemas.xmlsoap.org/encoding/ AnyConnectProfile.xsd"</span><span class="re2">></span></span><br /> <br /> <span class="sc3"><span class="re1"><ClientInitialization<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"><UseStartBeforeLogon</span> <span class="re0">UserControllable</span>=<span class="st0">"false"</span><span class="re2">></span></span>false<span class="sc3"><span class="re1"></UseStartBeforeLogon<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"><StrictCertificateTrust<span class="re2">></span></span></span>false<span class="sc3"><span class="re1"></StrictCertificateTrust<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"><RestrictPreferenceCaching<span class="re2">></span></span></span>false<span class="sc3"><span class="re1"></RestrictPreferenceCaching<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"><RestrictTunnelProtocols<span class="re2">></span></span></span>IPSec<span class="sc3"><span class="re1"></RestrictTunnelProtocols<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"><BypassDownloader<span class="re2">></span></span></span>true<span class="sc3"><span class="re1"></BypassDownloader<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"><WindowsVPNEstablishment<span class="re2">></span></span></span>AllowRemoteUsers<span class="sc3"><span class="re1"></WindowsVPNEstablishment<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"><CertEnrollmentPin<span class="re2">></span></span></span>pinAllowed<span class="sc3"><span class="re1"></CertEnrollmentPin<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"><CertificateMatch<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"><KeyUsage<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"><MatchKey<span class="re2">></span></span></span>Digital_Signature<span class="sc3"><span class="re1"></MatchKey<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"></KeyUsage<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"><ExtendedKeyUsage<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"><ExtendedMatchKey<span class="re2">></span></span></span>ClientAuth<span class="sc3"><span class="re1"></ExtendedMatchKey<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"></ExtendedKeyUsage<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"></CertificateMatch<span class="re2">></span></span></span><br /> <br /> <span class="sc3"><span class="re1"><BackupServerList<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"><HostAddress<span class="re2">></span></span></span>vpn.teatime.com.tw<span class="sc3"><span class="re1"></HostAddress<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"></BackupServerList<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"></ClientInitialization<span class="re2">></span></span></span><br /> <br /> <span class="sc3"><span class="re1"><ServerList<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"><HostEntry<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"><HostName<span class="re2">></span></span></span>TeaTime VPN Server<span class="sc3"><span class="re1"></HostName<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"><HostAddress<span class="re2">></span></span></span>vpn.teatime.com.tw<span class="sc3"><span class="re1"></HostAddress<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"></HostEntry<span class="re2">></span></span></span><br /> <span class="sc3"><span class="re1"></ServerList<span class="re2">></span></span></span><br /><span class="sc3"><span class="re1"></AnyConnectProfile<span class="re2">></span></span></span></div></pre><p>就是改 HostName 與 HostAddress 就可以.</p><p>至於 client 端的程式, 可以用 OpenConnect 或 Cisco AnyConnect 的都可以 (各平台幾乎都有), 不過建議用 OpenConnect 會比較好用... Cisco 的 AnyConnect 似乎只會保留最後一次連線的設定 (是我不會用嗎?), 如果要連不同的 server, 不能簡單的選擇 profile 來用.</p><p>最後, 通常是直接用 pam 來管理可以連線的使用者 (可以搭配 pam_listfile.so 來控管), 如果要搭配 AD 帳號來用的話, <a href="http://www.infradead.org/ocserv/recipes-ocserv-kerberos.html" target="_blank">官網有篇文章</a>有提到, 不過... 看起來似乎很麻煩... 我會選擇用 pam_script.so 來處理.</p><p>/etc/pam.d/ocserv:</p><pre class="ini"><div class="insertcode">#<br /># /etc/pam.d/ocserv - specify the PAM behaviour of ocserv<br />#<br /> <br />#auth required pam_listfile.so item<span class="sy0">=</span><span class="re2">user sense=allow file=/etc/users/vpn onerr=fail</span><br /> <br /># Standard Un*x authentication.<br />auth required pam_script.so<br /> <br /># Disallow non-root logins when /etc/nologin exists.<br />account required pam_nologin.so<br /> <br /># Uncomment and edit /etc/security/access.conf if you need to set complex<br /># access limits.<br /># account required pam_access.so<br /> <br /># Standard Un*x authorization.<br />account required pam_script.so<br /> <br /># SELinux needs to be the first session rule. This ensures that any<br /># lingering context has been cleared. Without out this it is possible<br /># that a module could execute code in the wrong domain.<br />session <span class="re0"><span class="br0">[</span>success<span class="sy0">=</span><span class="re2">ok ignore=ignore module_unknown=ignore default=bad<span class="br0">]</span></span> pam_selinux.so close</span><br /> <br /># Standard Un*x session setup and teardown.<br />session required pam_script.so<br /> <br /># Set up user limits from /etc/security/limits.conf.<br />session required pam_limits.so<br /> <br /># SELinux needs to intervene at login time to ensure that the process starts<br /># in the proper default security context. Only sessions which are intended<br /># to run in the user's context should be run after this.<br />session <span class="re0"><span class="br0">[</span>success<span class="sy0">=</span><span class="re2">ok ignore=ignore module_unknown=ignore default=bad<span class="br0">]</span></span> pam_selinux.so open</span><br /> <br />password required pam_script.so</div></pre><p>在 Debian 底下, pam_script.so 的指令放 /usr/share/libpam-script 目錄下. 需要有 pam_script_acct, pam_script_auth, pam_script_passwd, pam_script_ses_open, pam_script_ses_close 這幾個檔案 (用不到也要用, 不然 pam 會失敗).</p><p>我們只會用到 pam_script_auth 這一個, 其他的, 可以直接用:</p><pre class="bash"><div class="insertcode"><span class="co0">#!/bin/sh</span><br /> <br /><span class="kw3">exit</span> <span class="nu0">0</span></div></pre><p>表示成功就可以. 而 pam_script_auth 這一個, 我們可以使用 PHP 的 ldap 去做 AD bind 的動作並查詢是否屬於可以使用 VPN 的 group, 就可以透過 AD 來控管可連線的使用者了.</p><p>例如:</p><pre class="php"><div class="insertcode">#!/usr/bin/php -Cq<br /><span class="kw2"><?php</span><br /> <br /><span class="re0">$root_path</span> <span class="sy0">=</span> <a href="http://www.php.net/dirname"><span class="kw3">dirname</span></a><span class="br0">(</span><span class="re0">$argv</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="br0">)</span><span class="sy0">;</span><br /><span class="kw1">if</span> <span class="br0">(</span><span class="re0">$root_path</span> <span class="sy0">!==</span> <span class="st_h">''</span><span class="br0">)</span><br /> <span class="re0">$root_path</span> <span class="sy0">.=</span> <span class="st_h">'/'</span><span class="sy0">;</span><br /><span class="kw1">require_once</span><span class="br0">(</span><span class="re0">$root_path</span><span class="sy0">.</span><span class="st_h">'config.php'</span><span class="br0">)</span><span class="sy0">;</span><br /> <br /><span class="re0">$aGroup</span> <span class="sy0">=</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span><br /> <br /><span class="kw2">function</span> writelog<span class="br0">(</span><span class="re0">$str</span><span class="br0">)</span><br /><span class="br0">{</span><br /> <span class="kw2">global</span> <span class="re0">$root_path</span><span class="sy0">;</span><br /> <br /> <span class="kw1">echo</span> <span class="re0">$str</span><span class="sy0">.</span><span class="st0">"<span class="es1">\n</span>"</span><span class="sy0">;</span><br /> <span class="re0">$fp</span> <span class="sy0">=</span> <a href="http://www.php.net/fopen"><span class="kw3">fopen</span></a><span class="br0">(</span><span class="re0">$root_path</span><span class="sy0">.</span><span class="st_h">'log/ocserv_auth_'</span><span class="sy0">.</span><a href="http://www.php.net/strftime"><span class="kw3">strftime</span></a><span class="br0">(</span><span class="st_h">'%Y%m%d'</span><span class="br0">)</span><span class="sy0">.</span><span class="st_h">'.log'</span><span class="sy0">,</span> <span class="st_h">'at'</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$fp</span><span class="br0">)</span> <span class="br0">{</span><br /> <a href="http://www.php.net/fputs"><span class="kw3">fputs</span></a><span class="br0">(</span><span class="re0">$fp</span><span class="sy0">,</span> <a href="http://www.php.net/strftime"><span class="kw3">strftime</span></a><span class="br0">(</span><span class="st_h">'%H:%M:%S'</span><span class="br0">)</span><span class="sy0">.</span><span class="st0">" <span class="es4">$str</span><span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <a href="http://www.php.net/fclose"><span class="kw3">fclose</span></a><span class="br0">(</span><span class="re0">$fp</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="kw1">return</span><span class="sy0">;</span><br /><span class="br0">}</span><br /> <br /><span class="kw2">function</span> getAllGroupForGroup<span class="br0">(</span><span class="re0">$ldap</span><span class="sy0">,</span> <span class="re0">$group_dn</span><span class="br0">)</span><br /><span class="br0">{</span><br /> <span class="kw2">global</span> <span class="re0">$base_dn</span><span class="sy0">;</span><br /> <span class="kw2">global</span> <span class="re0">$aGroup</span><span class="sy0">;</span><br /> <br /> <span class="re0">$sr</span> <span class="sy0">=</span> <a href="http://www.php.net/ldap_search"><span class="kw3">ldap_search</span></a><span class="br0">(</span><span class="re0">$ldap</span><span class="sy0">,</span> <span class="re0">$base_dn</span><span class="sy0">,</span> <span class="st_h">'(distinguishedName='</span><span class="sy0">.</span><span class="re0">$group_dn</span><span class="sy0">.</span><span class="st_h">')'</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$data</span> <span class="sy0">=</span> <a href="http://www.php.net/ldap_get_entries"><span class="kw3">ldap_get_entries</span></a><span class="br0">(</span><span class="re0">$ldap</span><span class="sy0">,</span> <span class="re0">$sr</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$data</span><span class="br0">[</span><span class="st_h">'count'</span><span class="br0">]</span> <span class="sy0"><=</span> <span class="nu0">0</span><span class="br0">)</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">!</span><a href="http://www.php.net/array_key_exists"><span class="kw3">array_key_exists</span></a><span class="br0">(</span><span class="st_h">'memberof'</span><span class="sy0">,</span> <span class="re0">$data</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="br0">)</span><span class="br0">)</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="re0">$cnt</span> <span class="sy0">=</span> <span class="re0">$data</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="br0">[</span><span class="st_h">'memberof'</span><span class="br0">]</span><span class="br0">[</span><span class="st_h">'count'</span><span class="br0">]</span><span class="sy0">;</span><br /> <span class="kw1">for</span> <span class="br0">(</span><span class="re0">$i</span> <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span> <span class="re0">$i</span> <span class="sy0"><</span> <span class="re0">$cnt</span><span class="sy0">;</span> <span class="re0">$i</span><span class="sy0">++</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$group</span> <span class="sy0">=</span> <span class="re0">$data</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="br0">[</span><span class="st_h">'memberof'</span><span class="br0">]</span><span class="br0">[</span><span class="re0">$i</span><span class="br0">]</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">!</span><a href="http://www.php.net/in_array"><span class="kw3">in_array</span></a><span class="br0">(</span><span class="re0">$group</span><span class="sy0">,</span> <span class="re0">$aGroup</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$aGroup</span><span class="br0">[</span><span class="br0">]</span> <span class="sy0">=</span> <span class="re0">$group</span><span class="sy0">;</span><br /> getAllGroupForGroup<span class="br0">(</span><span class="re0">$ldap</span><span class="sy0">,</span> <span class="re0">$group</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="br0">}</span><br /> <span class="kw1">return</span> <span class="kw4">true</span><span class="sy0">;</span><br /><span class="br0">}</span><br /> <br /><span class="kw2">function</span> getAllGroupForUser<span class="br0">(</span><span class="re0">$ldap</span><span class="sy0">,</span> <span class="re0">$empid</span><span class="br0">)</span><br /><span class="br0">{</span><br /> <span class="kw2">global</span> <span class="re0">$base_dn</span><span class="sy0">;</span><br /> <span class="kw2">global</span> <span class="re0">$sec_key</span><span class="sy0">;</span><br /> <span class="kw2">global</span> <span class="re0">$aGroup</span><span class="sy0">;</span><br /> <br /> <span class="re0">$aGroup</span> <span class="sy0">=</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$sr</span> <span class="sy0">=</span> <a href="http://www.php.net/ldap_search"><span class="kw3">ldap_search</span></a><span class="br0">(</span><span class="re0">$ldap</span><span class="sy0">,</span> <span class="re0">$base_dn</span><span class="sy0">,</span> <span class="re0">$sec_key</span><span class="sy0">.</span><span class="st_h">'='</span><span class="sy0">.</span><span class="re0">$empid</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$data</span> <span class="sy0">=</span> <a href="http://www.php.net/ldap_get_entries"><span class="kw3">ldap_get_entries</span></a><span class="br0">(</span><span class="re0">$ldap</span><span class="sy0">,</span> <span class="re0">$sr</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="re0">$data</span><span class="br0">[</span><span class="st_h">'count'</span><span class="br0">]</span> <span class="sy0"><=</span> <span class="nu0">0</span><span class="br0">)</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">!</span><a href="http://www.php.net/array_key_exists"><span class="kw3">array_key_exists</span></a><span class="br0">(</span><span class="st_h">'memberof'</span><span class="sy0">,</span> <span class="re0">$data</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="br0">)</span><span class="br0">)</span><br /> <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="re0">$cnt</span> <span class="sy0">=</span> <span class="re0">$data</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="br0">[</span><span class="st_h">'memberof'</span><span class="br0">]</span><span class="br0">[</span><span class="st_h">'count'</span><span class="br0">]</span><span class="sy0">;</span><br /> <span class="kw1">for</span> <span class="br0">(</span><span class="re0">$i</span> <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span> <span class="re0">$i</span> <span class="sy0"><</span> <span class="re0">$cnt</span><span class="sy0">;</span> <span class="re0">$i</span><span class="sy0">++</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$group</span> <span class="sy0">=</span> <span class="re0">$data</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="br0">[</span><span class="st_h">'memberof'</span><span class="br0">]</span><span class="br0">[</span><span class="re0">$i</span><span class="br0">]</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">!</span><a href="http://www.php.net/in_array"><span class="kw3">in_array</span></a><span class="br0">(</span><span class="re0">$group</span><span class="sy0">,</span> <span class="re0">$aGroup</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$aGroup</span><span class="br0">[</span><span class="br0">]</span> <span class="sy0">=</span> <span class="re0">$group</span><span class="sy0">;</span><br /> getAllGroupForGroup<span class="br0">(</span><span class="re0">$ldap</span><span class="sy0">,</span> <span class="re0">$group</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="br0">}</span><br /> <span class="kw1">return</span> <span class="kw4">true</span><span class="sy0">;</span><br /><span class="br0">}</span><br /> <br /><span class="coMULTI">/*<br /># PAM_SERVICE - the application that's invoking the PAM stack<br /># PAM_TYPE - the module-type (e.g. auth,account,session,password)<br /># PAM_USER - the user being authenticated into<br /># PAM_RUSER - the remote user, the user invoking the application<br /># PAM_RHOST - remote host<br /># PAM_TTY - the controlling tty<br /># PAM_AUTHTOK - password in readable text<br />*/</span><br /><span class="re0">$emp_id</span> <span class="sy0">=</span> <a href="http://www.php.net/getenv"><span class="kw3">getenv</span></a><span class="br0">(</span><span class="st_h">'PAM_USER'</span><span class="br0">)</span><span class="sy0">;</span><br /><span class="re0">$ldap_user</span> <span class="sy0">=</span> <span class="re0">$emp_id</span><span class="sy0">.</span><span class="st_h">'@'</span><span class="sy0">.</span><span class="re0">$mydomain</span><span class="sy0">;</span><br /><span class="re0">$ldap_pass</span> <span class="sy0">=</span> <a href="http://www.php.net/getenv"><span class="kw3">getenv</span></a><span class="br0">(</span><span class="st_h">'PAM_AUTHTOK'</span><span class="br0">)</span><span class="sy0">;</span><br /><span class="re0">$rhost</span> <span class="sy0">=</span> <a href="http://www.php.net/getenv"><span class="kw3">getenv</span></a><span class="br0">(</span><span class="st_h">'PAM_RHOST'</span><span class="br0">)</span><span class="sy0">;</span><br /> <br />writelog<span class="br0">(</span><span class="st0">"user=<span class="es4">$emp_id</span>, rhost=<span class="es4">$rhost</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /><span class="co1">// Attempting fix from http://www.php.net/manual/en/ref.ldap.php#77553</span><br /><a href="http://www.php.net/putenv"><span class="kw3">putenv</span></a><span class="br0">(</span><span class="st_h">'LDAPTLS_REQCERT=never'</span><span class="br0">)</span><span class="sy0">;</span><br /> <br /><span class="re0">$ldap</span> <span class="sy0">=</span> <span class="kw4">false</span><span class="sy0">;</span><br /><span class="kw1">foreach</span> <span class="br0">(</span><span class="re0">$ldap_servers</span> <span class="kw1">as</span> <span class="re0">$server</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$ldap</span> <span class="sy0">=</span> <span class="sy0">@</span><a href="http://www.php.net/ldap_connect"><span class="kw3">ldap_connect</span></a><span class="br0">(</span><span class="st_h">'ldap://'</span><span class="sy0">.</span><span class="re0">$server</span><span class="br0">)</span><span class="sy0">;</span><br /> <a href="http://www.php.net/ldap_set_option"><span class="kw3">ldap_set_option</span></a><span class="br0">(</span><span class="re0">$ldap</span><span class="sy0">,</span> LDAP_OPT_REFERRALS<span class="sy0">,</span> <span class="nu0">0</span><span class="br0">)</span><span class="sy0">;</span><br /> <a href="http://www.php.net/ldap_set_option"><span class="kw3">ldap_set_option</span></a><span class="br0">(</span><span class="re0">$ldap</span><span class="sy0">,</span> LDAP_OPT_PROTOCOL_VERSION<span class="sy0">,</span> <span class="nu0">3</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/strtoupper"><span class="kw3">strtoupper</span></a><span class="br0">(</span><a href="http://www.php.net/substr"><span class="kw3">substr</span></a><span class="br0">(</span><span class="kw4">PHP_OS</span><span class="sy0">,</span> <span class="nu0">0</span><span class="sy0">,</span> <span class="nu0">3</span><span class="br0">)</span><span class="br0">)</span> <span class="sy0">!==</span> <span class="st_h">'WIN'</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$encrypted</span> <span class="sy0">=</span> <a href="http://www.php.net/ldap_start_tls"><span class="kw3">ldap_start_tls</span></a><span class="br0">(</span><span class="re0">$ldap</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">!</span><span class="re0">$encrypted</span><span class="br0">)</span> <span class="br0">{</span><br /> <a href="http://www.php.net/ldap_close"><span class="kw3">ldap_close</span></a><span class="br0">(</span><span class="re0">$ldap</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$ldap</span> <span class="sy0">=</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="kw1">continue</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="br0">}</span><br /> <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">@</span><a href="http://www.php.net/ldap_bind"><span class="kw3">ldap_bind</span></a><span class="br0">(</span><span class="re0">$ldap</span><span class="sy0">,</span> <span class="re0">$ldap_user</span><span class="sy0">,</span> <span class="re0">$ldap_pass</span><span class="br0">)</span> <span class="sy0">===</span> <span class="kw4">false</span><span class="br0">)</span> <span class="br0">{</span><br /> <a href="http://www.php.net/ldap_close"><span class="kw3">ldap_close</span></a><span class="br0">(</span><span class="re0">$ldap</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="re0">$ldap</span> <span class="sy0">=</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <span class="kw1">continue</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="kw1">break</span><span class="sy0">;</span><br /><span class="br0">}</span><br /> <br /><span class="kw1">if</span> <span class="br0">(</span><span class="re0">$ldap</span> <span class="sy0">===</span> <span class="kw4">false</span><span class="br0">)</span> <span class="br0">{</span><br /> writelog<span class="br0">(</span><span class="st0">"bind failed, user=<span class="es4">$emp_id</span>, rhost=<span class="es4">$rhost</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <a href="http://www.php.net/exit"><span class="kw3">exit</span></a><span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="sy0">;</span><br /><span class="br0">}</span><br /> <br />getAllGroupForUser<span class="br0">(</span><span class="re0">$ldap</span><span class="sy0">,</span> <span class="re0">$emp_id</span><span class="br0">)</span><span class="sy0">;</span><br /><a href="http://www.php.net/ldap_close"><span class="kw3">ldap_close</span></a><span class="br0">(</span><span class="re0">$ldap</span><span class="br0">)</span><span class="sy0">;</span><br /><span class="re0">$ldap</span> <span class="sy0">=</span> <span class="kw4">false</span><span class="sy0">;</span><br /> <br /><span class="re0">$in_group</span> <span class="sy0">=</span> <span class="kw4">false</span><span class="sy0">;</span><br /><span class="kw1">foreach</span> <span class="br0">(</span><span class="re0">$aGroup</span> <span class="kw1">as</span> <span class="re0">$group</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="kw1">if</span> <span class="br0">(</span><a href="http://www.php.net/strcasecmp"><span class="kw3">strcasecmp</span></a><span class="br0">(</span><span class="re0">$group</span><span class="sy0">,</span> <span class="re0">$vpn_group</span><span class="br0">)</span> <span class="sy0">==</span> <span class="nu0">0</span><span class="br0">)</span> <span class="br0">{</span><br /> <span class="re0">$in_group</span> <span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br /> <span class="kw1">break</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /><span class="br0">}</span><br /> <br /><span class="kw1">if</span> <span class="br0">(</span><span class="sy0">!</span><span class="re0">$in_group</span><span class="br0">)</span> <span class="br0">{</span><br /> writelog<span class="br0">(</span><span class="st0">"failed, not in VPN group, user=<span class="es4">$emp_id</span>, rhost=<span class="es4">$rhost</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /> <a href="http://www.php.net/exit"><span class="kw3">exit</span></a><span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="sy0">;</span><br /><span class="br0">}</span><br />writelog<span class="br0">(</span><span class="st0">"authenticated, user=<span class="es4">$emp_id</span>, rhost=<span class="es4">$rhost</span>"</span><span class="br0">)</span><span class="sy0">;</span><br /><a href="http://www.php.net/exit"><span class="kw3">exit</span></a><span class="br0">(</span><span class="nu0">0</span><span class="br0">)</span><span class="sy0">;</span></div></pre><p>設定的 config.php 要有下面幾個資料:</p><pre class="php"><div class="insertcode"><span class="kw2"><?php</span><br /> <br /><span class="re0">$ldap_servers</span> <span class="sy0">=</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">(</span><span class="st_h">'192.168.0.1'</span><span class="sy0">,</span> <span class="st_h">'192.168.0.2'</span><span class="br0">)</span><span class="sy0">;</span><br /><span class="re0">$mydomain</span> <span class="sy0">=</span> <span class="st_h">'domain.teatime.com.tw'</span><span class="sy0">;</span><br /><span class="re0">$base_dn</span> <span class="sy0">=</span> <span class="st_h">'DC=domain,DC=teatime,DC=com,DC=tw'</span><span class="sy0">;</span><br /><span class="re0">$sec_key</span> <span class="sy0">=</span> <span class="st_h">'samaccountname'</span><span class="sy0">;</span><br /><span class="re0">$vpn_group</span> <span class="sy0">=</span> <span class="st_h">'CN=VPN,DC=domain,DC=teatime,DC=com,DC=tw'</span><span class="sy0">;</span></div></pre><p>透過這樣的處理, 我覺得比官網那個方式簡單一些.</p>
Linux
VPN
2016-07-15T10:05:35Z
tommy
-
使用 libteam 取代 bonding
https://blog.teatime.com.tw/1/post/479
<p>其實在 <a href="https://github.com/jpirko/libteam" target="_blank">libteam</a> 剛出來的那時候, 就有意把 bonding 換成 libteam 來使用. 不過... 很奇怪的是在我家的環境下, 使用 libteam 產生的網卡會一直在 DOWN 的狀態, 無法正常使用. 這幾年下來, 每隔一陣子就會用新版的 libteam 試看看, 印象中好像上次最後一次試是 1.19 還是 1.21, 依然無法使用.... 不過... 最近試了 1.24 之後, 發現居然可以正常使用了.</p><p>目前 Debian 並沒有在 /etc/network/interfaces 裡頭, 對於 libteam 直接支援, 所以, 必須自己寫一些 script 來跑.</p><p>我目前是把相關的設定放在 /etc/network/teamd 這個目錄下, 然後在 interfaces 設定如下:</p><pre class="ini"><div class="insertcode">auto team0<br />iface team0 inet static<br /> address 192.168.0.1<br /> netmask 255.255.255.0<br /> gateway 192.168.0.254<br /> mtu <span class="nu0">8000</span><br /> pre-up /etc/network/teamd/pre-up.sh<br /> post-up /etc/network/teamd/post-up.sh<br /> post-down /etc/network/teamd/post-down.sh</div></pre><p>透過 pre-up 指令來載入 teamd, 然後透過 post-down 指令來釋放 teamd.</p><p>pre-up.sh:</p><pre class="bash"><div class="insertcode"><span class="co0">#!/bin/bash</span><br /> <br /><span class="re2">TEAMD_DIR</span>=<span class="st0">"/etc/network/teamd"</span><br /><span class="re2">CONF_FILE</span>=<span class="st0">"<span class="es3">${TEAMD_DIR}</span>/<span class="es3">${IFACE}</span>.conf"</span><br /> <br /><span class="kw1">if</span> <span class="br0">[</span> <span class="sy0">!</span> <span class="re5">-f</span> <span class="co1">${CONF_FILE}</span> <span class="br0">]</span>; <span class="kw1">then</span><br /> <span class="kw3">echo</span> <span class="st0">"file not found: <span class="es3">${CONF_FILE}</span>"</span><br /> <span class="kw3">exit</span> <span class="nu0">0</span><br /><span class="kw1">fi</span><br /> <br /><span class="co0"># remove bonding driver</span><br /><span class="br0">[</span> <span class="re5">-d</span> <span class="sy0">/</span>proc<span class="sy0">/</span>net<span class="sy0">/</span>bonding <span class="br0">]</span> <span class="sy0">&&</span> rmmod bonding<br /> <br /><span class="co0"># make sure all slave are down</span><br /><span class="co0">#ip link set eth0 down</span><br /><span class="co0">#ip link set eth1 down</span><br /> <br /><span class="co0"># create device</span><br />teamd <span class="re5">-f</span> <span class="co1">${CONF_FILE}</span> <span class="re5">-d</span><br /> <br /><span class="co0"># make it up</span><br /><span class="kw2">ip link</span> <span class="kw1">set</span> <span class="co1">${IFACE}</span> up</div></pre><p>post-down.sh:</p><pre class="bash"><div class="insertcode"><span class="co0">#!/bin/bash</span><br /> <br /><span class="re2">TEAMD_DIR</span>=<span class="st0">"/etc/network/teamd"</span><br /><span class="re2">CONF_FILE</span>=<span class="st0">"<span class="es3">${TEAMD_DIR}</span>/<span class="es3">${IFACE}</span>.conf"</span><br /> <br /><span class="kw1">if</span> <span class="br0">[</span> <span class="sy0">!</span> <span class="re5">-f</span> <span class="co1">${CONF_FILE}</span> <span class="br0">]</span>; <span class="kw1">then</span><br /> <span class="kw3">echo</span> <span class="st0">"file not found: <span class="es3">${CONF_FILE}</span>"</span><br /> <span class="kw3">exit</span> <span class="nu0">0</span><br /><span class="kw1">fi</span><br /> <br />teamd <span class="re5">-f</span> <span class="co1">${CONF_FILE}</span> <span class="re5">-k</span></div></pre><p>post-up.sh (可有可無, 我是為了避免網卡沒跑起來再執行一次 up 的動作):</p><pre class="bash"><div class="insertcode"><span class="co0">#!/bin/bash</span><br /> <br /><span class="co0"># it might take 10-30 seconds for link up, so try up it by commaind?</span><br /><span class="kw2">ip link</span> <span class="kw1">set</span> <span class="co1">${IFACE}</span> up</div></pre><p>然後是 teamd 的設定 team0.conf:</p><pre class="javascript"><div class="insertcode"><span class="br0">{</span><br /> <span class="st0">"device"</span><span class="sy0">:</span> <span class="st0">"team0"</span><span class="sy0">,</span><br /> <span class="st0">"link_watch"</span><span class="sy0">:</span> <span class="br0">{</span><br /> <span class="st0">"name"</span><span class="sy0">:</span> <span class="st0">"ethtool"</span><br /> <span class="br0">}</span><span class="sy0">,</span><br /> <span class="st0">"ports"</span><span class="sy0">:</span> <span class="br0">{</span><br /> <span class="st0">"eth0"</span><span class="sy0">:</span> <span class="br0">{</span><span class="br0">}</span><span class="sy0">,</span><br /> <span class="st0">"eth1"</span><span class="sy0">:</span> <span class="br0">{</span><span class="br0">}</span><br /> <span class="br0">}</span><span class="sy0">,</span><br /> <span class="st0">"runner"</span><span class="sy0">:</span> <span class="br0">{</span><br /> <span class="st0">"active"</span><span class="sy0">:</span> <span class="kw2">true</span><span class="sy0">,</span><br /> <span class="st0">"fast_rate"</span><span class="sy0">:</span> <span class="kw2">true</span><span class="sy0">,</span><br /> <span class="st0">"name"</span><span class="sy0">:</span> <span class="st0">"lacp"</span><span class="sy0">,</span><br /> <span class="st0">"tx_balancer"</span><span class="sy0">:</span> <span class="br0">{</span><br /> <span class="st0">"balancing_interval"</span><span class="sy0">:</span> <span class="nu0">50</span><span class="sy0">,</span><br /> <span class="st0">"name"</span><span class="sy0">:</span> <span class="st0">"basic"</span><br /> <span class="br0">}</span><span class="sy0">,</span><br /> <span class="st0">"tx_hash"</span><span class="sy0">:</span> <span class="br0">[</span><br /> <span class="st0">"eth"</span><span class="sy0">,</span><br /> <span class="st0">"ipv4"</span><span class="sy0">,</span><br /> <span class="st0">"ipv6"</span><br /> <span class="br0">]</span><br /> <span class="br0">}</span><br /><span class="br0">}</span></div></pre><p>這樣子處理後, 就可以正常使用 ifup/ifdown 來操作, 所以在開機時也能正常使用了.</p><p>跑了幾天後, 發現 libteam 裡頭對於 debug 訊息似乎沒有控管 (有 debug_level 設定, 不過沒作用), 看了 source, 發現有那個設定, 不過... 幾乎沒用到, 都是直接寫出, 所以, 只好改一下跳過了:</p><pre class="diff"><div class="insertcode"><span class="re3">--- libteam-1.24/teamd.orig/teamd.h 2016-04-15 22:41:54.000000000 +0800</span><br /><span class="re4">+++ libteam-1.24/teamd/teamd.h 2016-07-08 00:45:57.534564733 +0800</span><br /><span class="re6">@@ -49,7 +49,10 @@</span><br /> #define teamd_log_err<span class="br0">(</span>args...<span class="br0">)</span> daemon_log<span class="br0">(</span>LOG_ERR, ##args<span class="br0">)</span><br /> #define teamd_log_warn<span class="br0">(</span>args...<span class="br0">)</span> daemon_log<span class="br0">(</span>LOG_WARNING, ##args<span class="br0">)</span><br /> #define teamd_log_info<span class="br0">(</span>args...<span class="br0">)</span> daemon_log<span class="br0">(</span>LOG_INFO, ##args<span class="br0">)</span><br /><span class="re8">+/*</span><br /> #define teamd_log_dbg<span class="br0">(</span>args...<span class="br0">)</span> daemon_log<span class="br0">(</span>LOG_DEBUG, ##args<span class="br0">)</span><br /><span class="re8">+*/</span><br /><span class="re8">+static inline void teamd_log_dbg<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span></span><br /> <br /> #define teamd_log_dbgx<span class="br0">(</span>ctx, val, args...<span class="br0">)</span> \<br /> if <span class="br0">(</span>val <= ctx->debug<span class="br0">)</span> \</div></pre><p>看起來應該是使用 teamd_log_dbgx 來產生 debug log 才對, 不過只有不到 10 行是這樣處理, 其它約有四五十行就直接用 teamd_log_dbg 來產生 log.... 改了之後就看不到這些訊息了 (一天近 200MB 的 log, 對多數人來說是垃圾...)</p><p>目前跑了一陣子, 其實整體的表現看不出與之前用 bonding 有什麼不同.</p>
Linux
2016-07-15T09:48:47Z
tommy
-
使用 sendxmpp 來取代 MSN 通知的功能
https://blog.teatime.com.tw/1/post/470
<p>雖然說 MS 幾年前就說要關閉 MSN 即時通訊的服務, 不過, 相關的伺服器仍持續的運作, 直到<a href="http://ismsndeadyet.com/" target="_blank">這個月的 12 號開始</a>, 所有的伺服器都不接受 MSNP24 以下的協定了, 也就是目前幾乎所有的 MSN 即時通訊的客戶端程式都無法正常運作了 (剩下 skype 可以, 還有<a href="https://messengergeek.wordpress.com/2013/04/23/use-messenger-reviver-2-to-bring-back-messenger-and-beat-skype/" target="_blank">修改過的 WLM 2012</a> 也可以, 不過... 過些時候, 應該除了 skype 之外, 其他的可能都不能用了). 因為一直以來, 都是利用 MSN 即時通訊來發送通知, 現在.... 真的停用了, 只能想別的辦法來取代了.</p><p>找了一下, 發現透過 XMPP 的方式, 可以用來傳送 google talk (雖然官方的 Windows client 已經不能用了, 不過仍有手機或網頁版的程式) 或 facebook messenger 的訊息. </p><p>以這兩種來看, 由於 google 帳號取後較為容易, 所以... 就決定先用 google talk 了 (其實用相同的程式兩者都可以使用).</p><p>目前使用的是 <a href="http://sendxmpp.hostname.sk/" target="_blank">sendxmpp</a> 這個軟體. 在 Debian 裡頭, 版本仍是 1.23 的版本, 建議自己抓 1.24 回來用, 比較沒問題. 先準備一個帳號的設定檔如下:</p><pre class="ini"><div class="insertcode">username: YOUR_GOOGLE_ID<br />jserver: talk.google.com<br />password: YOUR_PASSWORD<br />component: gmail.com</div></pre><p>把 username 設成要發送的 google 帳號, password 設成密碼 (如果有用 authenticator 的話, 要記得產生一組新的密碼給 sendxmpp 使用). 然後在 gmail 裡頭, 把要通知的人加到即時通訊的聮絡人清單裡頭). </p><p>如果上頭那個設定檔檔名是 gtalk.rc 的話, 就使用下面的指令就能把訊息送給指定的收件人了:</p><pre class="bash"><div class="insertcode"><span class="kw3">echo</span> <span class="st0">"test im"</span> <span class="sy0">|</span> sendxmpp <span class="re5">-t</span> <span class="re5">-f</span> gtalk.rc someone<span class="sy0">@</span>gmail.com</div></pre><p>也可以透過檔案來處理, 如:</p><pre class="bash"><div class="insertcode">sendxmpp <span class="re5">-t</span> <span class="re5">-f</span> gtalk.rc <span class="re5">-m</span> message.txt someone<span class="sy0">@</span>gmail.com</div></pre><p>如果有多個收件人, 可以一次都寫在後面 (用空白區隔) 就可以.</p>PS. 如果是使用 1.23 的版本, 那個設定檔的格式不太一樣, 而且有些參數寫在裡頭沒有用, 一定要寫在指令上, 所以... 建議直接用 1.24 的版本吧.
Linux
2015-03-16T14:37:34Z
tommy
-
Linux UEFI 開機
https://blog.teatime.com.tw/1/post/468
<p>原本對於 UEFI 的認識, 認為只要弄一個 FAT32 的 partition, 把 loader 放在 /efi/boot/bootx64.efi 就能夠正常開機了.不過.... 過年後打算更換家裡的主機, 裝起來之後, 因為是用 UEFI 的 BIOS, 所以就打算改用 UEFI 來開機.... 結果, 卡了好幾天...</p><p>自己用 sysresccd 來分割並格式化, 再由目前的備份還原, 再 chroot 進去把原本用的 grub-pc 移除, 改用 grub-efi. 原本認為這樣子應該就可以了, 不過... 試了好多次, 怎麼弄都開不了機.... 最後, 弄了 Debian 的光碟來裝, 裝好居然可以正常開機... 實在看不出來是那兒不一樣了....</p><p>弄了一星期, 終於發現為什麼了.... 原來.... UEFI 並不是所有 FAT32 的格式都能用.... 它是有可能看不懂 FAT32 的空間, 自然會無法開機.</p><p>這與你切的大小或許有關係, 而一般用 gparted 來格式化時, 會看不出警告訊息, 直到自己下指令來格式化, 如:<br /> </p><pre class="bash"><div class="insertcode">mkfs.fat <span class="re5">-F32</span> <span class="sy0">/</span>dev<span class="sy0">/</span>sda1</div></pre><p>有可能會出現</p><pre class="bash"><div class="insertcode">WARNING: Not enough clusters <span class="kw1">for</span> a <span class="nu0">32</span> bit FAT<span class="sy0">!</span></div></pre><p>這時, 做出來的 FAT32 就不會被 UEFI 認得.</p><p>要避免這個問題, 可以加上 -s2 或 -s1 的參數, 如:</p><pre class="bash"><div class="insertcode">mkfs.fat <span class="re5">-F32</span> <span class="re5">-s2</span> <span class="sy0">/</span>dev<span class="sy0">/</span>sda1</div></pre><p>就不會有上面那個警告了, 這時做出來的 partition, 在 UEFI 中就會被認得了.</p><p>總結一下 UEFI grub 的安裝:</p><ul><li>用 sysresccd 透過 UEFI 開機 (非必要, 如果是用傳統的方式開機, 要把 grubx64.efi 放到 /efi/boot/bootx64.efi 才可以)</li><li>modprobe efivars</li><li>把硬碟的 root mount 在 /mnt/custom</li><li>把 boot partition mount 在 /mnt/custom/boot</li><li>把 efi 的 FAT32 partition mount 在 /mnt/custom/boot/efi</li><li>mount -B /dev /mnt/custom/dev</li><li>mount -B /dev/pts /mnt/custom/dev/pts</li><li>mount -B /dev/proc /mnt/custom/proc</li><li>mount -B /dev/sys /mnt/custom/sys</li><li>chroot /mnt/custom /bin/bash</li><li>移除原本的 grub-pc</li><li>apt-get install --reinstall grub-efi-amd64</li><li>grub-install</li><li>一般來說, 上面的 grub-install 不用加參數應該就可以用.</li><li>update-grub</li><li>這樣子應該就會透過 efibootmgr 把開機選項加上了, 開機時就能看到. 如果前面不是用 UEFI 開機進來的, 這個動作會失敗, 這時就要手動把 /boot/efi/debian/grubx64.efi 複製一份到 /boot/efi/boot/bootx64.efi 才可以 (因為預設是看這個檔案)</li></ul><p>其實應該比傳統的 grub 好裝.... 只要是 FAT32 沒弄錯的話... :-(</p>
Linux
2014-02-19T19:25:09Z
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