一、概述
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/n/330278.html