總之先產生 Key,然後我這邊是使用 hinet 可以支援的最高標準: RSA/SHA256,長度 1024,會需要花一點時間在執行。
$ dnssec-keygen -r /dev/random -a RSASHA256 -b 1024 -n ZONE mkx.tw
Generating key pair.........++++++ .++++++
Kmkx.tw.+008+59265
接著用 dnssec-signzone 來簽署, -S 是智慧型簽署,只要把你要簽署的檔案放到目前的資料夾中就可以了,所以我就先 ln 把我自己的 zone file 弄到目前的資料夾底下(檔名就設成 zone,以我的為例是 mkx.tw),程式會自己去讀檔案裡面的配置,然後逐一簽署:
$ ln -s /path/to/mkx.tw.fwd ./mkx.tw
$ dnssec-signzone -S -z mkx.tw
Fetching ZSK 59265/RSASHA256 from key repository.
Verifying the zone using the following algorithms: RSASHA256.
Zone fully signed:
Algorithm: RSASHA256: KSKs: 0 active, 0 stand-by, 0 revoked
ZSKs: 1 active, 0 stand-by, 0 revoked
mkx.tw.signed
這邊會產生兩個檔案: dsset-mkx.tw 跟 mkx.tw.signed。
然後就可以來修改 config 檔 (named.conf)
options {
...
dnssec-enable yes;
dnssec-validation yes;
...
}
zone "mkx.tw" IN {
file "/path/to/mkx.tw.signed";
};
最後到 hinet 網域註冊那邊登記 DS 記錄,這時候需要打開 dsset-mkx.tw 來看一下
$ cat dsset-mkx.tw
mkx.tw. IN DS 59265 8 1 DF0619E7A7CD1DD2DEDB9D431637C905ACE6B299
mkx.tw. IN DS 59265 8 2 D14507C8639B06B1CAD8516F8E997A9D824FD07BE04B4E75D06A0754 CB737FFF
以我的例子來說,59265 就是 key tag,而 hinet 表示 DS 記錄長度需要 64,一開始不太懂所以試了幾次,結果發現原來就是第二行的後面那兩串去掉中間的空白,嗯 ... 長度是 64 沒錯啦,不過 hinet 網頁真的寫得不清不楚啊 ...
2016年11月24日 星期四
2016年11月14日 星期一
[C/C++] Prefix/Postfix Increment/Decrement Operators
Prefix/Postfix Increment/Decrement Operators
今天在研究 Sequence Point 的時候發現一個有趣的 expression:
int i = 0, j;
j = ++++++i;
這邊就不探討 sequence point 的問題了,直接來說關於這行
++++++i 是什麼鬼東西。R-value 跟 L-value
首先要知道關於 rvalue 跟 lvalue,而他們最簡單且籠統的定義就是:
- rvalue: = 右邊的東西
- lvalue: = 左邊的東西
進一步來說,lvalue 就是只你可以『給值』的東西,是有實體記憶體的,例如說一般變數:
int x;
,所以你可以給值:
x = 3;
,那 rvalue 呢?一般來說是不是 lvalue 的都叫做 rvalue。
這也太籠統了吧?!舉個例子來看看:
3
似乎很有道理,因為你應該不會寫出像這樣的 code:
3 = x;
吧?因為 3 不能給值,所以我們把他歸類為 rvalue。
當然 rvalue 跟 lvalue 並不是像我這種憨人所想得這麼簡單,否則網路上也不會這麼多文章再探討 rvalue 跟 lvalue 了,但畢竟這不是這篇文章要講的重點,所以就不詳細說明了。
++++++i;
回到這鬼玩意兒,聰明的你可能知道他應該是長這個樣子:
++ ++ ++i;
你可以再更靠近一點:
++ ++ ++i;
看不出來的話我們在更進一步表示一下:
++ ( ++ ( ++i ) );
對 C 跟 C++ 來說這鬼玩意兒就是這樣解釋的。
看懂之後那問題來了,這行 code 是正確的嗎?
首先講一下 C++,對 C++ 來說,
- Prefix Operator (++x): 回傳的是 lvalue
- Postfix Operator (x++): 回傳的是 rvalue
Prefix versions of the built-in operators return references and postfix versions return values. [1]
既然 ++x 是回傳 lvalue 代表我們可以繼續修改他回傳的記憶體,所以那個鬼玩意兒對 C++ 來說最後 i 的結果就是 3。
那對 C 來說呢?很抱歉,兩個都不是回傳 lvalue。
這也意味著在最裡面那個括號做完以後是不能修改的,當然就不能在對他做 ++ 囉,所以 C 的編譯器在編譯的時候就會報錯:
test.c: In function ‘main’:
test.c:3:7: error: lvalue required as increment operand
++++++i;
^
結論
Reference
- http://en.cppreference.com/w/cpp/language/operator_incdec
- https://stackoverflow.com/questions/21351799/postfix-prefix-increment-l-value-and-r-value-in-c-and-c
[C/C++] Function 參數裡的 void
在 C/C++ 裡面,如果 function 回傳的 type 是 void 的話,代表這個 function 沒有回傳任何東西。
但是如果是在參數裡面呢?
在 C 跟 C++ 中,代表的是 foo 這個 function 不接受任何參數,但是
在 C 跟 C++ 的解釋卻不一樣。對 C 來說 foo 可以接收任意數的參數,但是 C++ 的解釋跟 foo(void) 一樣。
也就是說,以下的 code:
在 C 編譯時不會有任何問題,但是在 C++ 編譯的時候會跳錯誤:
但是如果是在參數裡面呢?
void foo(void);
在 C 跟 C++ 中,代表的是 foo 這個 function 不接受任何參數,但是
void foo();
在 C 跟 C++ 的解釋卻不一樣。對 C 來說 foo 可以接收任意數的參數,但是 C++ 的解釋跟 foo(void) 一樣。
也就是說,以下的 code:
// test.c
void foo() {}
int main () {
foo (1, 2, 3, 4);
foo ("hello world");
return 0;
}
在 C 編譯時不會有任何問題,但是在 C++ 編譯的時候會跳錯誤:
test.c: In function ‘int main()’:
test.c:6:19: error: too many arguments to function ‘void foo()’
foo(1, 2, 3, 4);
^
test.c:1:6: note: declared here
void foo() {}
^
test.c:7:22: error: too many arguments to function ‘void foo()’
foo("hello world");
^
test.c:1:6: note: declared here
void foo() {}
Reference
2016年11月10日 星期四
C: pointer arithmetic
從 http://stackoverflow.com/a/394777 得到了我想要的答案。
當你寫 (a_pointer + a_number) 的時候,實際上是:
總之先拿 code 來觀察一下,
會得到以下的結果(記憶體當然不會一樣,不過可以觀察一下差距)
a = 0x7fff56c39650
a + 1 = 0x7fff56c39654
// 相差了 4 bytes,也就是一個 int 大小
&a = 0x7fff56c39650
&a + 1 = 0x7fff56c39678
// 相差了 40 bytes,也就是一個 a 的大小(sizeof(int) * 10 = 4 * 10)
&p = 0x7fff56c39640
&p + 1 = 0x7fff56c39648
// 相差了 8 bytes,也就是一個 pointer 大小(64bit 的系統下)
當你寫 (a_pointer + a_number) 的時候,實際上是:
(a_pointer + (a_number * sizeof(*a_pointer)))
總之先拿 code 來觀察一下,
#include <stdio .h>
int main() {
int a[10];
int *p = a;
printf("a = %p\n", a);
printf("a + 1 = %p\n", a + 1);
printf("&a = %p\n", &a);
printf("&a + 1 = %p\n", &a + 1);
printf("&p = %p\n", &p);
printf("&p + 1 = %p\n", &p + 1);
return 0;
}
會得到以下的結果(記憶體當然不會一樣,不過可以觀察一下差距)
a = 0x7fff56c39650
a + 1 = 0x7fff56c39654
// 相差了 4 bytes,也就是一個 int 大小
&a = 0x7fff56c39650
&a + 1 = 0x7fff56c39678
// 相差了 40 bytes,也就是一個 a 的大小(sizeof(int) * 10 = 4 * 10)
&p = 0x7fff56c39640
&p + 1 = 0x7fff56c39648
// 相差了 8 bytes,也就是一個 pointer 大小(64bit 的系統下)
2016年11月9日 星期三
SQL 七種 JOIN 方法
面試群暉的時候被問到 SQL 的 OUTER JOIN 跟 INNER JOIN 的差別,壓跟沒想到這間會問到跟 Web 有關的 ... 是我自己準備不周 Orz
不過查了一下發現其實很簡單,一張圖就可以全部弄懂了:
不過查了一下發現其實很簡單,一張圖就可以全部弄懂了:
回到面試被問的問題,
INNER JOIN 就是最中間那張圖, A 跟 B 的交集。
而 OUTER JOIN 有三種:
- LEFT OUTER JOIN: 就是 A
- RIGHT OUTER JOIN: 就是 B
- FULL OUTER JOIN: 就是 A 跟 B 的聯集
2016年11月8日 星期二
C++ Virtual Function
因為準備面試所以複習了一下實作 C++ 多型 (Polymorphism) 的 virtual function。
Virtual function 的主要目的是要在 runtime 的時候解決 switch 的問題,於是我們不需要實際寫一個 switch 去判斷現在的目標是什麼 type。
直接看 code :
其中變數 yuujinA, yuujinB 的型別同樣都是 Otoko*,但是分別指到不同的 class (Ikemen, Otaku)。
在 runtime 的時候,我不需要去寫:
當然更不用:
只需要在 class 裡面宣告、定義 virtual function,在 runtime 的時候便會自動呼叫對應的 virtual function。
所以儘管 yuujinA 跟 yuujinB 有同樣的型別 Otoko*,runtime 的時候呼叫的 virtual function 便會依照他們實際是指到哪個 class ,再去做對應的 function call。
而沒有加上 virtual 的 function,例如 whoami,就只會去看 yuujinA, yuujinB 宣告的時候的 type 去做對應的 function call。
<<名詞解釋>>
Otoko: 男人
Ikemen: 帥哥
Otaku: 阿宅
yuujinA: 友人A
yuujinB: 友人B
Virtual function 的主要目的是要在 runtime 的時候解決 switch 的問題,於是我們不需要實際寫一個 switch 去判斷現在的目標是什麼 type。
直接看 code :
#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
class Otoko {
public:
virtual bool can_ask_line_id() = 0;
};
class Ikemen: public Otoko {
public:
virtual bool can_ask_line_id() {
return true;
}
};
class Otaku: public Otoko {
public:
virtual bool can_ask_line_id() {
cerr << "死ね!!" << endl;
return false;
}
};
int main(int argc, char* argv[]) {
Otoko *yuujinA = new Ikemen(),
*yuujinB = new Otaku();
cout << (yuujinA->can_ask_line_id() ? "No problem" : "Impossible") << endl;
cout << (yuujinB->can_ask_line_id() ? "No problem" : "Impossible") << endl;
delete yuujinA;
delete yuujinB;
return 0;
}
其中變數 yuujinA, yuujinB 的型別同樣都是 Otoko*,但是分別指到不同的 class (Ikemen, Otaku)。
在 runtime 的時候,我不需要去寫:
if (yuujinA 是 Ikemen) {
} else if (yuujinA 是 Otaku) {
} else {
}
當然更不用:
switch (yuujinA 的型別) {
case Ikemen:
case Otaku:
}
只需要在 class 裡面宣告、定義 virtual function,在 runtime 的時候便會自動呼叫對應的 virtual function。
所以儘管 yuujinA 跟 yuujinB 有同樣的型別 Otoko*,runtime 的時候呼叫的 virtual function 便會依照他們實際是指到哪個 class ,再去做對應的 function call。
而沒有加上 virtual 的 function,例如 whoami,就只會去看 yuujinA, yuujinB 宣告的時候的 type 去做對應的 function call。
<<名詞解釋>>
Otoko: 男人
Ikemen: 帥哥
Otaku: 阿宅
yuujinA: 友人A
yuujinB: 友人B
2013年6月23日 星期日
[RPi] Raspbian 上架設 pptpd
首先準備一台 RPi ( 廢話 )
因為我是用 static IP 所以就不用設定 AP ( router )
先檢查這兩個模組:
$> modprobe ip_nat_pptp
$> modprobe ip_conntrack_pptp
正常來說應該不會有什麼問題,至少我的 RPi 上沒有顯示任何錯誤
沒問題以後就直接安裝
$> apt-get install pptpd
接下來到 /etc/pptpd.conf 設定 localip 和 remoteip
我將這兩個分開變成:
localip 192.168.59.1 # RPi 上的 IP ,但是不是對外的那個,可以隨便設定
remoteip 192.168.79.1-100 # 設定 100 組 IP 給使用者用
然後到設定檔 /etc/ppp/pptpd-options
這邊查了不少資料,以下是我的設定檔:
name pptpd
refuse-pap
refuse-chap
refuse-mschap
require-mschap-v2
接著設定登入的帳號密碼
格式為:
client server secret IP addresses
之間用 tab 作區隔,可以使用 * 萬用字元。
之後設定 ip forward,要去修改 /etc/sysctl.conf
把 net.ipv4.ip_forward=1 註解拿掉,也就是要讓他可以 forward ipv4
接著讓系統知道設定有修改過了,要 Update
$> sudo sysctl -p
最後要去 iptables
$> iptables -t nat -A POSTROUTING -s {remoteips} -o eth0 -j MASQUERADE
其中 {remoteips} 就是剛剛在 /etc/pptpd.conf 設定的
以我的設定為例,最簡單的方式就是 192.168.79.0/24 ( mask 掉全部 )
這樣設定完以後,重新啟動 pptpd
$> service pptpd restart
不過有些網站還是上不去,後來找到一個網頁:
http://www.tomatosoft.biz/blog/2011/10/21/cant-access-certain-site-with-pptp/
照他的設定:
$> iptables -I FORWARD -p tcp --syn -i ppp+ -j TCPMSS --set-mss 1356
因為我是用 static IP 所以就不用設定 AP ( router )
先檢查這兩個模組:
$> modprobe ip_nat_pptp
$> modprobe ip_conntrack_pptp
正常來說應該不會有什麼問題,至少我的 RPi 上沒有顯示任何錯誤
沒問題以後就直接安裝
$> apt-get install pptpd
接下來到 /etc/pptpd.conf 設定 localip 和 remoteip
我將這兩個分開變成:
localip 192.168.59.1 # RPi 上的 IP ,但是不是對外的那個,可以隨便設定
remoteip 192.168.79.1-100 # 設定 100 組 IP 給使用者用
然後到設定檔 /etc/ppp/pptpd-options
這邊查了不少資料,以下是我的設定檔:
name pptpd
refuse-pap
refuse-chap
refuse-mschap
require-mschap-v2
require-mppe-128
ms-dns <DNS-IP1>
ms-dns <DNS-IP2> #可以設定多組 DNS
proxyarp
nodefaultroute
debug
dump
lock
nobsdcomp
logfile /var/log/pptpd.log #log file
novj
novjccomp
idle 2592000
接著設定登入的帳號密碼
格式為:
client server secret IP addresses
之間用 tab 作區隔,可以使用 * 萬用字元。
之後設定 ip forward,要去修改 /etc/sysctl.conf
把 net.ipv4.ip_forward=1 註解拿掉,也就是要讓他可以 forward ipv4
接著讓系統知道設定有修改過了,要 Update
$> sudo sysctl -p
最後要去 iptables
$> iptables -t nat -A POSTROUTING -s {remoteips} -o eth0 -j MASQUERADE
其中 {remoteips} 就是剛剛在 /etc/pptpd.conf 設定的
以我的設定為例,最簡單的方式就是 192.168.79.0/24 ( mask 掉全部 )
這樣設定完以後,重新啟動 pptpd
$> service pptpd restart
不過有些網站還是上不去,後來找到一個網頁:
http://www.tomatosoft.biz/blog/2011/10/21/cant-access-certain-site-with-pptp/
照他的設定:
$> iptables -I FORWARD -p tcp --syn -i ppp+ -j TCPMSS --set-mss 1356
原本不能連上的網頁就連上了。
( 打完收工 )
之後有遇到問題再說 ... 目前這樣已經大部分都可以連了 :)
訂閱:
文章 (Atom)
