一、概述
NetBIOS-NS(NetBIOS Name Service)是計算機網絡領域中一個重要的協議。它主要負責實現名稱的解析和註冊,是 NetBIOS 網絡的核心。NetBIOS-NS 早期廣泛應用於局域網環境中,如今也經常被用於早期的Windows系統中。在現代計算機網絡中,NetBIOS-NS 已經逐漸被DNS(Domain Name Service)所取代,但 NetBIOS 仍然有其特殊的應用場合。
二、NetBIOS-NS 的工作原理
NetBIOS-NS 首先通過 UDP 端口 137 監聽網絡,等待來自其它計算機的 NetBIOS 函數調用。當一個 NetBIOS 函數調用到達時,NetBIOS-NS 首先通過三次廣播(Broadcast)的方式查詢(Query)網絡上所有節點的名稱表,以獲得使用了該名字的計算機的 IP 地址。如果該名字有多個對應的 IP 地址,則返回所有的 IP 地址。
相反的,如果一個計算機希望把自己的名字註冊到網絡上,它就會向 NetBIOS-NS 發送一個「名字註冊」(Name Registration)請求,NetBIOS-NS 會先查詢網絡上是否已經有其他計算機的名字相同,如果沒有,就向網絡上廣播一個「名字註冊」回復,告訴其它計算機該名字已經被佔用並且提供自身的 IP 地址。如果多個計算機請求同一個名字的註冊,則只有一個計算機能夠註冊成功,後來的請求將被忽略。
三、NetBIOS-NS 端口和服務
NetBIOS-NS 端口使用的是 UDP 協議中的 137 端口,每個使用 NetBIOS-NS 服務的計算機都必須註冊一個 NetBIOS 名字,並向網絡中註冊該服務。當其它計算機需要連接到該服務時,就可以通過名稱傳輸(NetBIOS Name Resolution)查詢該名字的實際 IP 地址,從而建立服務與調用之間的連接。NetBIOS-NS 還有一個充當 NetBIOS 進程間通信服務(NetBIOS Session Service)的標準 TCP/IP 端口,即 139 端口。該端口主要用於實現 SMB(Server Message Block)和 CIFS(Common Internet File System) 等服務。
四、NetBIOS-NS 的安全問題
由於 NetBIOS-NS 在設計之初並沒有考慮安全問題,因此在網絡安全方面存在許多問題。例如,NetBIOS-NS 在註冊名字時沒有進行身份驗證,因此能夠輕易地進行 DNS Spoofing 或者 ARP Spoofing 攻擊,從而實現欺騙性的 DNS 查詢結果。為了避免網絡中出現此類問題,可採用 IPsec 或 VPN 等技術,加密數據協議,如 SMB、NetBIOS 等,並限制 NetBIOS-NS 在網絡中的使用頻率。
五、NetBIOS-NS 的代碼示例
//NetBIOS註冊名字 void nbns_reg_name(unsigned char *name) { unsigned char buff[65536]; memset(buff, 0, sizeof(buff)); struct nbns_header *nbh = (struct nbns_header *) buff; struct nbns_question *nbq = (struct nbns_question *) (buff + sizeof(struct nbns_header)); struct sockaddr_in sin = { 0 }; nbh->id = htons(getpid()); //進程 id,隨機生成 nbh->flags = htons(0x0120); //NBNS標誌,註冊名字 //問題部分 qname(nbq->name, name); //註冊名字 nbq->type = htons(NBNS_TYPE_NB); //類型 nbq->classes = htons(NBNS_CLASS_IN); //類別 sin.sin_family = AF_INET; sin.sin_port = htons(NBNS_PORT); int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); bind(s, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)); sendto(s, buff, sizeof(struct nbns_header) + sizeof(struct nbns_question) + nbq->name_len, 0, &sin, sizeof(sin)); close(s); } //NetBIOS查詢名字 int nbns_query_name(unsigned char *name, char *addr) { unsigned char buff[65536]; struct sockaddr_in sin; struct timeval tv; memset(buff, 0, sizeof(buff)); struct nbns_header *nbh = (struct nbns_header *) buff; struct nbns_question *nbq = (struct nbns_question *) (buff + sizeof(struct nbns_header)); nbh->id = htons(getpid()); //進程 id,隨機生成 nbh->flags = htons(0x0100); //NBNS標誌,查詢名字 //問題部分 qname(nbq->name, name); //查詢名字 nbq->type = htons(NBNS_TYPE_NB); //類型 nbq->classes = htons(NBNS_CLASS_IN); //類別 sin.sin_family = AF_INET; sin.sin_port = htons(NBNS_PORT); sin.sin_addr.s_addr = htonl(INADDR_BROADCAST); int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); setsockopt(s, SOL_SOCKET, SO_BROADCAST, &sin, sizeof(sin)); sendto(s, buff, sizeof(struct nbns_header) + sizeof(struct nbns_question) + nbq->name_len, 0, &sin, sizeof(sin)); fd_set fds; FD_ZERO(&fds); FD_SET(s, &fds); tv.tv_sec = 1; tv.tv_usec = 0; select(s + 1, &fds, NULL, NULL, &tv); if (FD_ISSET(s, &fds)) { struct sockaddr_in client; socklen_t len = sizeof(client); unsigned int buflen = recvfrom(s, buff, sizeof(buff), 0, (struct sockaddr *) &client, &len); struct nbns_answer *nba = (struct nbns_answer *) (buff + sizeof(struct nbns_header) + sizeof(struct nbns_question)); struct sockaddr_in *sinaddr = (struct sockaddr_in *) &nba->resource[nba->ans][6]; memcpy(addr, inet_ntoa(sinaddr->sin_addr), strlen(inet_ntoa(sinaddr->sin_addr)) + 1); close(s); return 1; } close(s); return 0; }
原創文章,作者:VMXTM,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/330278.html