一、概述
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
微信扫一扫
支付宝扫一扫