/* ADMsmb utility  its for get the  netbios name ! of a remote host */
/* u can see the definition of netbios to rfc1001 & rfc1002         */
/* ADMsmb (c) ADM                                                   */
/* Thx 2 clement for the patch against the silly nmbd !             */
/* Tnx 2 IRQ for porting to FreeBSD                                 */

#define NMBHDRSIZE 13


struct nmbhdr
  {
    unsigned short id;

    unsigned char R:1;
    unsigned char opcode:4;
    unsigned char AA:1;
    unsigned char TC:1;
    unsigned char RD:1;
    unsigned char RA:1;
    unsigned char unless:2;
    unsigned char B:1;
    unsigned char RCODE:4;


    unsigned short que_num;
    unsigned short rep_num;
    unsigned short num_rr;
    unsigned short num_rrsup;
    unsigned char namelen;
  };


struct typez
  {
    u_short type;
    u_short type2;
  };

extern FILE *trace;
extern int silly_server;
unsigned long
host2ip (char *serv)
{
  struct sockaddr_in sinn;
  struct hostent *hent;

  hent = gethostbyname (serv);
  if (hent == NULL)
    return 0;
  bzero ((char *) &sinn, sizeof (sinn));
  memcpy ((char *) &sinn.sin_addr, hent->h_addr, hent->h_length);
  return sinn.sin_addr.s_addr;
}


int ADMsmb (u_long ip, char *netbioz)
{
  struct sockaddr_in sin_src,sin_dst;
  struct nmbhdr *nmb, *nmb2;

  struct typez *typz;

  int socket_client, bha, timeout = 0;
  int longueur = sizeof (struct sockaddr_in);
  int optval;
  char *data;
  char *dataz;
  char buffer[1024];
  char buffer2[1024];
  char namezz[1024];
  char name[34] = "CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\0";
  char c;

  socket_client = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);

 if (ip == 0) {
   printf("bad host name !\n");
   exit (-1); 
 }
 
  bzero (buffer, sizeof (buffer));
  bzero (buffer2, sizeof (buffer2));

  if (silly_server)
    {
      optval=1;
      setsockopt(socket_client,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval));
      fflush(stdout);
      sin_src.sin_family = AF_INET;
      sin_src.sin_port = htons (137);
      sin_src.sin_addr.s_addr = INADDR_ANY;
      if (bind(socket_client,(struct sockaddr *) &sin_src,sizeof(sin_src))==(-1))
        {
          perror("bind");
          return(-1);
        }

    } 
  
  sin_dst.sin_family = AF_INET;
  sin_dst.sin_port = htons (137);
  sin_dst.sin_addr.s_addr = ip;

  nmb = (struct nmbhdr *) buffer;
  data = (char *) (buffer + NMBHDRSIZE);
  typz = (struct typez *) (buffer + NMBHDRSIZE + 33);
  nmb2 = (struct nmbhdr *) (buffer2);
  dataz = (char *) (buffer2 + 50 + 7);


  bzero (namezz, sizeof (namezz));
  memcpy (data, name, strlen (name) + 1);

  /* play with the netbios query format :) */

  nmb->id = 0x666;
  nmb->R = 0;			/* 0 for question 1 for response */
  nmb->opcode = 0;		/* 0 = query */
  nmb->que_num = htons (1);	/* i have only 1 question :) */
  nmb->namelen = 0x20;
  typz->type = 0x2100;
  typz->type2 = 0x0100;

  sendto (socket_client, buffer, 50, 0, (struct sockaddr *) &sin_dst, longueur);
  usleep (10000);
  sendto (socket_client, buffer, 50, 0, (struct sockaddr *) &sin_dst, longueur);


  if ((fcntl (socket_client, F_SETFL, O_NONBLOCK)) == -1)
    {
      return (-1);
    }





  for (timeout = 0; timeout < 50; timeout++)
    {
      usleep (100000);

      if (recvfrom (socket_client, buffer2,sizeof(buffer2), 0, (struct sockaddr *) &sin_dst, &(int) longueur) != -1)
	{         

	  if (nmb2->rep_num != 0)
	    {
	      bha = 0;

	      for (;;)
		{

		  c = *(dataz + bha);
		  if (c != '\x20')
		    {

		      namezz[bha] = c;
		      bha++;
		    }
		  if (c == '\x20')
		    break;
		}
	      	      
	      memcpy (netbioz,namezz,strlen(namezz));
	      return (0);
	      break;
	    } else  
	         return (-1); 
	}


    }

return (-1);


}
