今天配置sshd的時候,發現openssh-server不同過xinetd依然可以得到tcp-wrappers的知識,好奇之下就察看了 sshd和tcp-wrapper的代碼,做成筆記寫在下面。這些筆記對想使用tcp-wrappers的程序員來說有一定的參考價值。
一些基礎知識
什麼是ssh
ssh secure shell,是用戶在進行傳輸的時候使用的一種保密協議。本來這是爲telnet登錄開發的一種保密性更好的協議,它有RSA(公鑰),DSA(密鑰)兩 種加密方式,通信的雙方倒入同樣的公鑰和密鑰來進行通信,就算是使用公鑰,因爲解碼的複雜性很大,所以保密性依然很好。
什麼是openssh
這是openbsd開發組開發的一個ssh實現,廣泛的用於linux等操作系統上,其中包括了sshd(ssh遠程登錄守護進程),sftp(加ssh的ftp守護子系統),ssh(遠程登錄程序等組件)。
什麼是tcp-wrappers
tcp-wrappers是一個驗證ip合法性的函數庫,其還包括了一個驗證ip合法性的守護進程程序。
openssh-server如何使用Tcp-wrapperts
平 時,tcp-wrappers都是和xinetd或者inetd一起工作,xinetd調用tcp-wrappers來進行IP合法性的檢查。而sshd 則不同,雖然其也可以工作在xinetd後面,但是在獨立運行的時候,sshd依然可以使用tcp-wrappers來進行ip合法性的驗證。看下面的代 碼(截取至sshd.c第942-957)
#ifdef LIBWRAP
/* XXX LIBWRAP noes not know about IPv6 */
{
struct request_info req;
request_init(&req, RQ_DAEMON, av0, RQ_FILE, sock_in, NULL);
fromhost(&req);
if (!hosts_access(&req)) {
close(sock_in);
close(sock_out);
refuse(&req);
}
/*XXX IPv6 verbose("Connection from %.500s port %d", eval_client(&req), remote_port); */
}#endif
/* LIBWRAP */
其中的host_access就是Tcp-wrapperts的api,其功能就是判斷進來的ip是否可以訪問sshd。如果返回false,則close掉socket_in,換句話說,要使用tcp-Wrappert,只需要這麼一個函數就足夠了。
而host_access API則查找用戶定義好的hosts.allow和hosts.deny。這兩個文件的位置可以在編譯Tcp-Wrappert的時候指定,一般的發行版都把這兩個文件給放到了/etc下面。
Tcp-wrapperts自己如何工作
這 些代碼在host_access.c裏面,其中host_access這個函數要查找兩個表,一個是hosts.allow,一個是 hosts.deny。如果在hosts.allow裏面,待驗證ip是合法的,則返回YES這個結果;如果hosts.allow匹配不通過,則在 hosts.deny裏面匹配,如果匹配通過,則返回NO;默認返回YES。參考下面的代碼。
struct request_info *request;
{
int verdict;
if (resident <= 0)
resident++;
verdict = setjmp(tcpd_buf);
if (verdict != 0)
return (verdict == AC_PERMIT);
if (table_match(hosts_allow_table, request))
return (YES);
if (table_match(hosts_deny_table, request))
return (NO);
return (YES);
}
在這個文件裏面,還有兩個重要的變量。就是
char *hosts_deny_table = HOSTS_DENY;
這兩個變量指定了這個函數庫所需要的hosts.allow和hosts.deny的位置,它們通過HOST_ALLOW 和 HOSTS_DENY這兩個宏得到路徑,而這些都會在編譯的時候指定,運行時無法修改。這也算是小小的不便吧。