/* vi: set tabstop=4 nocindent noautoindent: */

/**  
@brief   IP Address Tool
@file    ipaddr_tool.c
@author  Fumi Iseki 
@date    2005 09/21
*/



#include "ipaddr_tool.h"




/**
tList*  read_ipaddr_file(char* fn)

ファイルから IPアドレスを読み込んで，[IPアドレス]/[ネットマスク]　の形式に
変換して，リストに格納する．FQDNはIPアドレスに変換される．@n
FQDNでないドメイン名，文字列は / 以後を無視して文字列のままリストに格納する．

データの読み取り時に次の処理が行なわれる．
- 前後の空白,CR,LFは削除される
- 空行は無視される．
- # 以降は無視される．

@param  fn  ファイル名
@return リストへのポインタ
*/
tList*  read_ipaddr_file(char* fn)
{
	tList* lp;
	tList* lt;

	lp = read_tList_file(fn, 2);
	if (lp==NULL) return NULL;

	lt = to_ipaddress_list(lp);
	del_all_tList(&lp);

	return lt;
}




/**
tList*  read_ipaddr_fp(FILE* fp)

ファイルから IPアドレスを読み込んで，[IPアドレス]/[ネットマスク]　の形式に
変換して，リストに格納する．FQDNはIPアドレスに変換される．@n
FQDNでないドメイン名，文字列は / 以後を無視して文字列のままリストに格納する．

データの読み取り時に次の処理が行なわれる．
- 前後の空白,CR,LFは削除される
- 空行は無視される．
- # で始まる，または 空白(複数)# で始まる行は無視される．

@param  fp  ファイルポインタ
@return リストへのポインタ
*/
tList*  read_ipaddr_fp(FILE* fp)
{
	tList* lp;
	tList* lt;

	lp = read_tList_fp(fp, 1);
	if (lp==NULL) return NULL;

	lt = to_ipaddress_list(lp);
	del_all_tList(&lp);

	return lt;
}




/**
tList*  to_ipaddress_list(tList* lp)

リスト中の IPアドレスを [IPアドレス]/[ネットマスク]　の形式に
変換して，新しいリストに格納する．FQDNはIPアドレスに変換される．@n
変換に to_address_num8() を使用．CIDER対応．

FQDNでないドメイン名，文字列は / 以後を無視して文字列のまま 新しいリストに格納する．
後の is_host_in_list()などを高速に行なうための前処理．

@param  lp  変換前（ファイルなどから読み込んだまま）のデータの入ったリスト
@return 変換して新しく生成したリスト．
*/
tList*  to_ipaddress_list(tList* lp)
{
	unsigned char* num;
	char*          addr;
	tList* ls = NULL;
	tList* lt = NULL;

	if (lp==NULL) return NULL;
	if (lp->ldat.key.buf==NULL) return NULL;

	while (lp!=NULL) {
		if (lp->ldat.key.buf!=NULL && strlen((const char*)lp->ldat.key.buf)>0) {
			if ((lp->ldat.key.buf)[0]!='#') {
				num = to_address_num8((char*)lp->ldat.key.buf, 1);
				if (num!=NULL) {
					addr = to_address_char8(num);
					free(num);
					if (addr!=NULL) {
						ls = add_tList_node_str(ls, addr, NULL);
						free(addr);
					}	// ここで addr==NULL となる場合はメモリ不足のみ
				}
				else {
					addr = awk((char*)lp->ldat.key.buf, '/', 1);
					if (addr!=NULL) {
						int i = 0;
						while(addr[i]!='\0' && addr[i]!=',' && addr[i]!=' ') i++;
						addr[i] = '\0';
						ls = add_tList_node_str(ls, addr, NULL);
						free(addr);
					}
				}
				if (lt==NULL) lt = ls;
			}
		}
		lp = lp->next;
	}
	
	return lt;
}




/**
int  is_host_in_list(tList* lp, unsigned char* num, char* hname)

リストlpの キー部に格納されている ホスト情報と num, hname が同じネットワークに属するか
どうかをチェックする．num と hname はどちらか一方が指定されていれば十分である．

先ず，lpのキー部（FQDN）と hname が比較される．つまり，キー部がドメイン名の一部の場合は 
hnameと比較する（後方一致）．@n
次に，lpのキー部がドメイン名でない場合（IPアドレスの場合）は num と比較される．
	
@param  lp     チェックするIPアドレス（文字列）の格納されているリスト．
@param  num    比較するIPアドレス（1byte unsigned 整数型）4Byte．
               8Byte型(addr/mask)でも作動するが，ネットマスク部はされる．
@param  hname  比較するホスト名（文字列）．通常は numから逆引きされたもの．

@retval TRUE   リスト中に同じネットワークに属するエントリが存在する．
@retval FALSE  リスト中に同じネットワークに属するエントリは存在しない．
*/
int  is_host_in_list(tList* lp, unsigned char* num, char* hname)
{
	unsigned char* addr;

	if (lp==NULL) return FALSE;
	if (lp->ldat.key.buf==NULL) return FALSE;
	if (hname==NULL && num==NULL) return FALSE;

	while (lp!=NULL) {
		if (lp->ldat.key.buf!=NULL && strlen((const char*)lp->ldat.key.buf)>0) {
			addr = to_address_num8((char*)lp->ldat.key.buf, 0);
			if (addr==NULL && hname!=NULL) {
				if (!strnrvscmp((const char*)lp->ldat.key.buf, hname, (int)strlen((const char*)lp->ldat.key.buf))) return TRUE;
			}
			else if(addr!=NULL && num!=NULL) {
				if (is_same_network_num(addr, num, &(addr[4]))) return TRUE;
			}
		}
		lp = lp->next;
	}
	
	return FALSE;
}




/**
int  is_ipaddr_num_in_list(tList* lp, unsigned char* num)

リストlpの キー部に格納されている ホスト情報と num が同じネットワークに属するかどうかをチェックする．@n
リストのキー部がFQDNであってもチェック可能．

@param  lp    チェックするIPアドレス（文字列）の格納されているリスト．
@param  num   比較するIPアドレス（バイナリ）4Byte．
              8Byte型(addr/mask)でも作動するが，ネットマスク部は無視される．

@retval TRUE  リスト中に同じネットワークに属するエントリが存在する．
@retval FALSE リスト中に同じネットワークに属するエントリは存在しない．
*/
int  is_ipaddr_num_in_list(tList* lp, unsigned char* num)
{
	unsigned char* addr;

	if (lp==NULL || num==NULL) return FALSE;
	if (lp->ldat.key.buf==NULL) return FALSE;

	while (lp!=NULL) {
		if (lp->ldat.key.buf!=NULL && strlen((const char*)lp->ldat.key.buf)>0) {
			addr = to_address_num8((char*)lp->ldat.key.buf, 1);
			if (addr!=NULL) {
				if (is_same_network_num(num, addr, &(addr[4]))) return TRUE;
			}
		}
		lp = lp->next;
	}
	
	return FALSE;
}




/**
void  print_address_in_list(FILE* fp, tList* lp)

リスト中のドメイン名，またはIPアドレスを表示する．
FQDNはIPアドレスに変換して表示する．

@param  fp  出力先のファイル記述子
@param  lp  ドメイン名またはIPアドレスをキー部に格納したリストへのポインタ
*/
void  print_address_in_list(FILE* fp, tList* lp)
{
	unsigned char* addr;

	while (lp!=NULL) {
		if (lp->ldat.key.buf!=NULL && strlen((const char*)lp->ldat.key.buf)>0) {
			addr = to_address_num8((char*)lp->ldat.key.buf, 1);
			if (addr!=NULL) {	
				fprintf(fp, "[%d.%d.%d.%d/%d.%d.%d.%d]\n", addr[0],addr[1],addr[2],addr[3],addr[4],addr[5],addr[6],addr[7]);
			}
			else { 		// 恐らくドメイン名
				fprintf(fp, "[%s]\n", lp->ldat.key.buf);
			}
		}
		lp = lp->next;
	}
	return;
}



