/*--------------------------------*-C-*---------------------------------*
 * File:        bbsnet_tool.c
 *----------------------------------------------------------------------*
 * for check bbsdata file.
 *
 * All portions of code are copyright by their respective author/s.
 * Copyright (C) 1997 Hong-Yi Du <HYD.bbs@bbs.yzu.edu.tw>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *---------------------------------------------------------------------*/

#define DELIMITER	" \t\n"		/* 定義分界字元 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <signal.h>
#include <setjmp.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

void pperror( char * );
void timeout();
unsigned z;
jmp_buf jmp_buffer;
unsigned z;
struct data
{
  char name[17];
  char domain[32];
  char ip[16];
  char port[6];
}
array[800];

int main()
{
  FILE *fd;
  unsigned long a, b;
  char string[80], *token, temp[80];
  unsigned counter = 1;
  struct hostent *hp, *hp2;
  struct sockaddr_in *to, *to2;

  alarm(0);
  signal( SIGALRM, timeout );
  if(!( fd = fopen( "bbsdata", "r" )))
  pperror( "fopen" );
  while( fgets( string, sizeof( string ), fd ))
  {
    /* 檢查 bbsdata 格式 */
    if( token = strtok( string, DELIMITER )) strncpy( array[counter].name, token, 16 );
    else printf( "第 %d 行發生資料格式錯誤.\n", counter );
    if( token = strtok( 0, DELIMITER )) strncpy( array[counter].domain, token, 31 );
    else printf( "第 %d 行發生資料格式錯誤.\n", counter );
    if( token = strtok( 0, DELIMITER )) strncpy( array[counter].ip, token, 15 );
    else printf( "第 %d 行發生資料格式錯誤.\n", counter );
    if( token = strtok( token, DELIMITER )) strncpy( array[counter].port, token, 5 );
    counter ++;
  }
  fclose( fd );
  /* 檢查 ip 排序 */
  strcpy( temp, array[1].ip );
  a = atoi( strtok( temp, "." )) * 256 * 256 * 256;
  a += atoi( strtok( 0, "." )) * 256 * 256;
  a += atoi( strtok( 0, "." )) * 256;
  a += atoi( strtok( 0, "." ));
  for( z = 2; z < counter; z ++ )
  {
    strcpy( temp, array[z].ip );
    b = atoi( strtok( temp, "." )) * 256 * 256 * 256;
    b += atoi( strtok( 0, "." )) * 256 * 256;
    b += atoi( strtok( 0, "." )) * 256;
    b += atoi( strtok( 0, "." ));
    if( a > b ) printf( "%3u)%16.16s: IP 排序錯誤\n", z, array[z].name );
    a = b;
    /* 檢查 DN 大小寫 */
    if( strpbrk( array[z].domain, "ABCDEFGHIJKLMNOPQRSTUVWXYZ" )
    && !strstr( array[z].domain, "(login:" ))
    printf( "%3u)%16.16s: domain 包含大寫字母 %s\n",
    z, array[z].name, array[z].domain );
    /* 檢查 DN <-> ip */
    to = ( struct sockaddr_in * ) calloc( sizeof( struct sockaddr_in ), 1 );
    to -> sin_family = AF_INET;
    to2 = ( struct sockaddr_in * ) calloc( sizeof( struct sockaddr_in ), 1 );
    to2 -> sin_family = AF_INET;
    if( !inet_aton( array[z].domain, &to -> sin_addr ))
    {
      /* 沒有正查 DN, 檢查反查 DN */
      signal( SIGALRM, timeout );
      alarm(4);
      hp = gethostbyname( array[z].domain );
      alarm(0);
      if( !hp )
      {
        /* 沒有正反查 DN */
        to -> sin_addr.s_addr = inet_addr( array[z].ip );
        signal( SIGALRM, timeout );
        alarm(4);
        hp = gethostbyaddr(( char * ) &( to -> sin_addr ),
        sizeof( struct in_addr ), AF_INET );
        alarm(0);
        if( !hp ) printf( "%3u)%16.16s: 無正反查 DN %s\n",
        z, array[z].name, array[z].ip );
        else
        {
          /* 沒正查有反查 DN */
          printf( "%3u)%16.16s: 無正查 DN %s\n", z, array[z].name, array[z].ip );
          if( strcasecmp( hp -> h_name, array[z].domain ))
          printf( "%3u)%16.16s: IP 與反查 DN 不合 %s,%s(%s)\n",
          z, array[z].name, array[z].domain, array[z].ip, hp -> h_name );
        }
      }
      /* 有正查 DN, 檢查 bbsdata ip 對映 */
      else
      {
        to -> sin_family = hp -> h_addrtype;
        if( hp -> h_length > sizeof( to -> sin_addr ))
        hp -> h_length = sizeof( to -> sin_addr );
        memcpy( &to -> sin_addr, hp -> h_addr, hp -> h_length );
        if( strcmp( inet_ntoa( *( struct in_addr * ) &to -> sin_addr.s_addr ),
        array[z].ip ))
        {
          /* 正查 DN 與 IP 不合,試著檢查 IP 與 反查 DN 合不合,避免 IP alias */
          signal( SIGALRM, timeout );
          alarm(4);
          hp2 = gethostbyaddr(( char * ) &( to2 -> sin_addr ),
          sizeof( struct in_addr ), AF_INET );
          alarm(0);
          if( hp2 && strcasecmp( hp2 -> h_name, array[z].domain ))
          printf( "%3u)%16.16s: 正查 DN 與 IP 不合 %s,%s(%s)\n",
          z, array[z].name, array[z].domain, array[z].ip,
          inet_ntoa(*( struct in_addr * ) &to -> sin_addr.s_addr ));
        }
        if( strncasecmp( array[z].domain, "bbs", 3 ))
        {
          sprintf( string, "bbs%s", strchr( array[z].domain, '.' ));
          signal( SIGALRM, timeout );
          alarm(4);
          hp2 = gethostbyname( string );
          alarm(0);
          if( hp2 )
          {
            to2 -> sin_family = hp2 -> h_addrtype;
            if( hp2 -> h_length > sizeof( to2 -> sin_addr ))
            hp2 -> h_length = sizeof( to2 -> sin_addr );
            memcpy( &to2 -> sin_addr, hp2 -> h_addr, hp2 -> h_length );
            if( !strcmp( inet_ntoa( *( struct in_addr * )
            &to2 -> sin_addr.s_addr ), array[z].ip ))
            printf( "%3u)%16.16s: %s 可用 %s 取代\n",
            z, array[z].name, array[z].domain,
            string );
          }
        }
      }
    }
    setjmp( jmp_buffer );
  }
  return 0;
}

void pperror( char *error_string )
{
  perror( error_string );
  exit(0);
}

void timeout()
{
  printf( "%3u)%16.16s: lookup DNS timeout\n", z, array[z].name );
  longjmp( jmp_buffer, 1 );
  signal( SIGALRM, timeout );
  alarm(4);
}
